keymaker原理-INT 3的插入 (4千字)

看雪資料發表於2015-11-15

記得上次問樹袋熊大哥,大哥回答得挺詳細,但我一直想試一試INT 3斷點是如何插入的。經過兩天的折騰,終於弄明白了,不敢獨享,大哥見笑啦。下面是分析:
目標:英語會話精靈2.0(topbar.exe)序號產生器
使用工具:IDA4.15,Softice
程式使用upx加殼,有改動!部分資源經過XOR加密(檔案尾部)廢話少說,切入正題。
為節省篇幅,只分析其原理:(假設已經知道我們要插入斷點的地址--即已經跟蹤出注冊碼地址)
<1>使用CreateProcessA載入要除錯的程式topbar.exe,獲得控制程式碼hThread
迴圈使用ReadProcessMemory讀取topbar.exe程式地址addr1(47a057),如果此處指令為我們預設指令,則
使用子程式(sub1)修改此處指令為INT 3(CCH),並儲存原指令(5byte)後等待中斷髮生。
sub1 流程
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
dwLength=1Ch
lpBuffer-->PMEMORY_BASIC_INFORMATION(dwLength=1C byte)
lpAddress-->addr1
hProcess-->
invoke  VirtualQueryEx,hProcess,lpAddress,lpBuffer,dwLength(Kernel32.lib)

lpflOldProtect-->
flNewProtect=4;
dwSize-->1000h
lpAddress-->47a000
hProcess-->
invoke  VirtualProtectEx,hProcess,lpAddress,dwSize,flNewProtect,lpflOldProtect
lpNumberOfBytesWritten=0
nSize=5
lpBuffer-->讀取緩衝
lpBaseAddress-->addr1
hProcess-->
invoke ReadProcessMemory,hProcess,lpBaseAddress,lpBuffer,nSize,lpNumberOfBytesWritten
lpflOldProtect-->
flNewProtect=flOldProtect;
dwSize-->1000h
lpAddress-->47a000
hProcess-->
invoke  VirtualProtectEx,hProcess,lpAddress,dwSize,flNewProtect,lpflOldProtect
<2>
&&&&&&&&&&&&&&&&&&&&&&&&&&&
中斷髮生後,由除錯程式(序號產生器)接管,使用GetThreadContext取得topbar.exe的CONTEXT上下文
讀取CONTEXT STRUCT的offset B8h即regEip的值,比較是否程式在此中斷,此時regEip的值應為addr1+1,將regEip
減1,(即恢復IP指標)使用SetThreadContext儲存修改了的CONTEXT結構
指標是恢復了但被修改的指令並沒有恢復,因此下一步就是恢復原來的指令:呼叫sub2
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
sub2 流程
dwLength=1Ch
lpBuffer-->PMEMORY_BASIC_INFORMATION(dwLength=1C byte)
lpAddress-->addr1
hProcess-->
invoke  VirtualQueryEx,hProcess,lpAddress,lpBuffer,dwLength(Kernel32.lib)
lpflOldProtect-->
flNewProtect=4;
dwSize-->1000h
lpAddress-->47a000
hProcess-->
invoke  VirtualProtectEx,hProcess,lpAddress,dwSize,flNewProtect,lpflOldProtect
lpNumberOfBytesWritten=0
nSize=5
lpBuffer-->寫緩衝指向儲存好的指令
lpBaseAddress-->addr1
hProcess-->
invoke WriteProcessMemory,hProcess,lpBaseAddress,lpBuffer,nSize,lpNumberOfBytesWritten
lpflOldProtect-->
flNewProtect=flOldProtect;
dwSize-->1000h
lpAddress-->47a000
hProcess-->
invoke  VirtualProtectEx,hProcess,lpAddress,dwSize,flNewProtect,lpflOldProtect
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
<3>
現在指令也恢復了,被除錯程式可以正常執行了,完了嗎,不對,忘了我們要幹什麼啦,好的,
下一步就是讀取註冊碼(假設我們已經知道註冊碼的位置,在此程式中我們修改的指令的上一條指令POP EAX的EAX中存放
有註冊碼,見附源程式片段):
使用GetThreadContext取得topbar.exe的CONTEXT 結構上下文,
lpContext->CONTEXT 結構
ContextFlags=10007h ; CONTEXT_FULL=CONTEXT_CONTROL OR CONTEXT_INTEGER OR CONTEXT_SEGMENTS
invoke GetThreadContext,hThread,lpContext
此時CONTEXT ->B0h即regEax即為註冊碼的地址,將其存入CONTEXT-->B8h,然後使用ReadProcessMemory讀出註冊碼.
CONTEXT STRUCT
  ContextFlags  DWORD      ?
  iDr0          DWORD      ?
  iDr1          DWORD      ?
  iDr2          DWORD      ?
  。。。
  。。。
  regEdx        DWORD      ?
  regEcx        DWORD      ?
  regEax        DWORD      ?  ;offset B0
  regEbp        DWORD      ?
  regEip        DWORD      ?  ;offset B8
  regCs        DWORD      ?
  regFlag      DWORD      ?
  regEsp        DWORD      ?
  regSs        DWORD      ?
  ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
CONTEXT ENDS
××××××××××××××××××
topbar.exe源程式片段:
:0047A048 8B45F4                  mov eax, dword ptr [ebp-0C]
:0047A04B 8D55F8                  lea edx, dword ptr [ebp-08]
:0047A04E E89DE7F8FF              call 004087F0
:0047A053 8B55F8                  mov edx, dword ptr [ebp-08]
:0047A056 58                      pop eax---》》》註冊碼
:0047A057 E8489EF8FF              call 00403EA4
:0047A05C 0F853D010000            jne 0047A19F
:0047A062 6840000400              push 00040040
:0047A067 B908A24700              mov ecx, 0047A208

* Possible StringData Ref from Code Obj ->"successs!"
                                  |
:0047A06C BA18A24700              mov edx, 0047A218
結論:透過上面的分析,現在我就可以寫出自己的序號產生器,實際上我已經寫了。使用的就是看雪學院下載的win32asm教程第28-29篇的debug篇的一個小程式(只需稍加改動,加入我的程式碼即可)當然,要想向樹袋熊大哥一樣寫出那麼漂亮的介面,那得下一翻大功夫.
如有想試牛刀者,Eamil to me softdim@vip.sina.com,英語會話精靈2.0(topbar.exe)及其序號產生器檔案都不大,是一個很好的學習例子。

相關文章