【文章标题】: 另辟蹊径解除某外挂试用版功能限制
【文章作者】: 不知所谓
【软件名称】: 一流QQ连连看助手 4.93试用版
【下载地址】: 华军软件园
【使用工具】: OD 、Peid 、vb6
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教! 菜鸟水平,高手请移步~~
--------------------------------------------------------------------------------
【详细过程】
任务目的:
1、去除弹出网页
2、去除启动1分钟后自动关闭功能
软件文件基本信息:
文件名 大小 Peid查壳结果
LLKWG.exe 18kb Borland Delphi 6.0 - 7.0
hook.dll 541kb ASProtect 2.1x SKE -> Alexey Solodovnikov
外挂运行原理分析:
用HideOD插件隐藏OD,载入LLKWG.exe并运行,主程序在3秒钟内就退出,外挂主界面却还在,可推知外挂主要功能在Hook.dll文件里,寄生于其它进程而运行。此时查看进程信息,发现外挂寄生在Explorer.exe里。
hook.dll的输出表只有两个函数:HookOn、HookOff,函数实现相当简单,HookOn里只调用了SetWindowsHookEx,HookOff里只调用UnhookWindowsHookEx,显然二者都不是重点。HookProc里只调用CallNextHookEx,也不是我们想要的。
我们来看看主程序入口处的代码:
00403504 > $ 55 push ebp ; 程序入口
00403505 . 8BEC mov ebp, esp
00403507 . 83C4 F0 add esp, -10
0040350A . B8 C4344000 mov eax, 004034C4
0040350F . E8 B4FDFFFF call 004032C8
00403514 . 68 00364000 push 00403600 ; /MutexName = "EXE_MUTEX_LLK"
00403519 . 6A 00 push 0 ; |Inheritable = FALSE
0040351B . 68 01001F00 push 1F0001 ; |Access = 1F0001
00403520 . E8 9FFEFFFF call <jmp.&kernel32.OpenMutexA> ; \OpenMutexA
00403525 . 85C0 test eax, eax
00403527 . 0F85 CC000000 jnz 004035F9
0040352D . 68 10364000 push 00403610 ; /MutexName = "DLL_MUTEX_LLK"
00403532 . 6A 00 push 0 ; |Inheritable = FALSE
00403534 . 68 01001F00 push 1F0001 ; |Access = 1F0001
00403539 . E8 86FEFFFF call <jmp.&kernel32.OpenMutexA> ; \OpenMutexA
0040353E . 85C0 test eax, eax
00403540 . 0F85 B3000000 jnz 004035F9
00403546 . 68 00364000 push 00403600 ; /Arg3 = 00403600 ASCII "EXE_MUTEX_LLK"
0040354B . 6A 00 push 0 ; |Arg2 = 00000000
0040354D . 6A 00 push 0 ; |Arg1 = 00000000
0040354F . E8 40FEFFFF call 00403394 ; \LLKWG.00403394
00403554 . 8B15 A4404000 mov edx, [4040A4] ; LLKWG.00405668
0040355A . 8902 mov [edx], eax
0040355C . 68 20364000 push 00403620 ; /MapName = "SFILEMAP_LLK"
00403561 . 6A 04 push 4 ; |MaximumSizeLow = 4
00403563 . 6A 00 push 0 ; |MaximumSizeHigh = 0
00403565 . 6A 04 push 4 ; |Protection = PAGE_READWRITE
00403567 . 6A 00 push 0 ; |pSecurity = NULL
00403569 . 6A FF push -1 ; |hFile = FFFFFFFF
0040356B . E8 14FEFFFF call <jmp.&kernel32.CreateFileMapping>; \CreateFileMappingA
00403570 . 8B15 A8404000 mov edx, [4040A8] ; LLKWG.0040566C
00403576 . 8902 mov [edx], eax
00403578 . 6A 00 push 0 ; /MapSize = 0
0040357A . 6A 00 push 0 ; |OffsetLow = 0
0040357C . 6A 00 push 0 ; |OffsetHigh = 0
0040357E . 6A 02 push 2 ; |AccessMode = FILE_MAP_WRITE
00403580 . A1 A8404000 mov eax, [4040A8] ; |
00403585 . 8B00 mov eax, [eax] ; |
00403587 . 50 push eax ; |hMapObject
00403588 . E8 2FFEFFFF call <jmp.&kernel32.MapViewOfFile> ; \MapViewOfFile
0040358D . 8B15 A0404000 mov edx, [4040A0] ; LLKWG.00405670
00403593 . 8902 mov [edx], eax
00403595 . E8 1AFEFFFF call <jmp.&kernel32.GetCurrentThreadI>; [GetCurrentThreadId
0040359A . 8B15 A0404000 mov edx, [4040A0] ; LLKWG.00405670
004035A0 . 8B12 mov edx, [edx]
004035A2 . 8902 mov [edx], eax
004035A4 . A1 A0404000 mov eax, [4040A0]
004035A9 . 8B00 mov eax, [eax]
004035AB . 50 push eax ; /BaseAddress
004035AC . E8 1BFEFFFF call <jmp.&kernel32.UnmapViewOfFile> ; \UnmapViewOfFile
004035B1 . E8 D6FEFFFF call <jmp.&Hook.HookOn> ; 调用后外挂主界面出现
004035B6 > 6A 00 push 0 ; /MsgFilterMax = 0
004035B8 . 6A 00 push 0 ; |MsgFilterMin = 0
004035BA . 6A 00 push 0 ; |hWnd = NULL
004035BC . 68 78564000 push 00405678 ; |pMsg = LLKWG.00405678
004035C1 . E8 0EFEFFFF call <jmp.&user32.GetMessageA> ; \GetMessageA
004035C6 . 85C0 test eax, eax
004035C8 .^ 75 EC jnz short 004035B6
004035CA . E8 C5FEFFFF call <jmp.&Hook.HookOff>
004035CF . A1 A8404000 mov eax, [4040A8]
004035D4 . 8B00 mov eax, [eax]
004035D6 . 50 push eax ; /hObject
004035D7 . E8 A0FDFFFF call <jmp.&kernel32.CloseHandle> ; \CloseHandle
004035DC . 6A 00 push 0 ; /lParam = 0
004035DE . 6A 00 push 0 ; |wParam = 0
004035E0 . 6A 1A push 1A ; |Message = WM_WININICHANGE
004035E2 . 68 FFFF0000 push 0FFFF ; |hWnd = HWND_BROADCAST
004035E7 . E8 F0FDFFFF call <jmp.&user32.PostMessageA> ; \PostMessageA
004035EC . A1 A4404000 mov eax, [4040A4]
004035F1 . 8B00 mov eax, [eax]
004035F3 . 50 push eax ; /hObject
004035F4 . E8 83FDFFFF call <jmp.&kernel32.CloseHandle> ; \CloseHandle
...............................
显然,外挂用全局Hook进入其它进程内部,而判断是否Explorer.exe的代码在DllMain里。我决定带壳调试,用Memory Patch方法破解。用OD调试Explorer.exe会带来很多不便,这里先做一个Loader,让外挂运行在Loader里。用vb6把上面的代码写一遍,代码如下
Dim hFileMapping As Long, BaseAddress As Long, Buffer As Long
CreateMutex 0, 0, "EXE_MUTEX_LLK"
hFileMapping = CreateFileMapping(&HFFFFFFFF, 0, 4, 0, 4, "SFILEMAP_LLK")
UnmapViewOfFile MapViewOfFile(hFileMapping, 2, 0, 0, 0)
BaseAddress = LoadLibrary("C:\Program Files\16xia\QQLLK\hook.dll")
把Loader命名为Explorer.exe,外挂正常运行!
第一步先去除弹出网页,由于DllMain里有相关代码,我们在脱壳前又没办法碰它,只好对ShellExecuteA打补丁,Loader代码如下
Dim hModule As Long, pShellExecuteA As Long, Buffer As Long
hModule = LoadLibrary("shell32.dll")
pShellExecuteA = GetProcAddress(hModule, "ShellExecuteA")
Buffer = &H18C2 'retn 18H
WriteProcessMemoryByLong &HFFFFFFFF, pShellExecuteA, Buffer, 3, ByVal 0&
然后去除1分钟后关闭的功能。下API断点,SetSystemTime、GetLocalTime、SetLocalTime、GetTickCount、SetTimer,均没有收获,晕了~~~~~~~~
只好硬着头皮上咯。幸好外挂退出时没忘记跟我们道别~~OD载入并运行Loader后下断点 bp MessageBoxA,大约1分钟后断下,跟着堆栈信息一路出来,发现如下可疑代码
011D76D7 . 33F6 xor esi, esi
011D76D9 > 8B45 F4 mov eax, [ebp-C]
011D76DC . 8B10 mov edx, [eax]
011D76DE . FF52 14 call [edx+14]
011D76E1 . 48 dec eax
011D76E2 . 7C 31 jl short 011D7715
011D76E4 . 8D4D E8 lea ecx, [ebp-18]
011D76E7 . 33D2 xor edx, edx
011D76E9 . 8B45 F4 mov eax, [ebp-C]
011D76EC . 8B18 mov ebx, [eax]
011D76EE . FF53 0C call [ebx+C]
011D76F1 . 8B45 E8 mov eax, [ebp-18]
011D76F4 . BA 34781D01 mov edx, 011D7834 ; ASCII "STOP"
011D76F9 . E8 C6CCF6FF call 011443C4
011D76FE . 74 15 je short 011D7715
011D7700 . 8D4D E4 lea ecx, [ebp-1C]
011D7703 . 33D2 xor edx, edx
011D7705 . 8B45 F4 mov eax, [ebp-C]
011D7708 . 8B18 mov ebx, [eax]
011D770A . FF53 0C call [ebx+C]
011D770D . 8B45 E4 mov eax, [ebp-1C]
011D7710 . E8 E7020000 call 011D79FC
011D7715 > 46 inc esi
011D7716 . BB E9030000 mov ebx, 3E9 ; (3E9)H=(1001)D,循环计数器
011D771B > 8B45 FC mov eax, [ebp-4]
011D771E . 8078 0D 00 cmp byte ptr [eax+D], 0
011D7722 . 74 0D je short 011D7731
011D7724 . 33C0 xor eax, eax
011D7726 . 5A pop edx
011D7727 . 59 pop ecx
011D7728 . 59 pop ecx
011D7729 . 64:8910 mov fs:[eax], edx
011D772C . E9 D2000000 jmp 011D7803
011D7731 > 6A 0A push 0A ; /Timeout = 10. ms
011D7733 . E8 C05CF7FF call 0114D3F8 ; \Sleep
011D7738 . 4B dec ebx
011D7739 .^ 75 E0 jnz short 011D771B ; 10秒一个循环
011D773B . 83FE 06 cmp esi, 6 ; 是否运行了6个10秒?
011D773E ^ 7C 99 jl short 011D76D9 ; 爆破点,改为JMP
011D7740 . 8B45 F4 mov eax, [ebp-C]
011D7743 . 8B10 mov edx, [eax]
011D7745 . FF52 14 call [edx+14]
011D7748 . 8BD0 mov edx, eax
011D774A . 4A dec edx
011D774B . 8D4D E0 lea ecx, [ebp-20]
011D774E . 8B45 F4 mov eax, [ebp-C]
011D7751 . 8B18 mov ebx, [eax]
011D7753 . FF53 0C call [ebx+C]
011D7756 . 8B45 E0 mov eax, [ebp-20]
011D7759 . BA 34781D01 mov edx, 011D7834 ; ASCII "STOP"
011D775E . E8 61CCF6FF call 011443C4
011D7763 . 74 2E je short 011D7793
011D7765 . 8B45 F4 mov eax, [ebp-C]
011D7768 . 8B10 mov edx, [eax]
011D776A . FF52 14 call [edx+14]
011D776D . 8BD0 mov edx, eax
011D776F . 4A dec edx
011D7770 . 8D4D DC lea ecx, [ebp-24]
011D7773 . 8B45 F4 mov eax, [ebp-C]
011D7776 . 8B18 mov ebx, [eax]
011D7778 . FF53 0C call [ebx+C]
011D777B . 8B45 DC mov eax, [ebp-24]
011D777E . 50 push eax
011D777F . B9 ED030000 mov ecx, 3ED
011D7784 . BA 44781D01 mov edx, 011D7844
011D7789 . B8 58781D01 mov eax, 011D7858 ; ASCII "#32770"
011D778E . E8 C9070000 call 011D7F5C
011D7793 > 8B45 F4 mov eax, [ebp-C]
011D7796 . E8 C1B9F6FF call 0114315C
011D779B . C605 9CBA1D01>mov byte ptr [11DBA9C], 0
011D77A2 . 68 30000100 push 10030 ; UNICODE "C:\Documents and Settings\All Users"
011D77A7 . 68 60781D01 push 011D7860
011D77AC . 68 70781D01 push 011D7870
011D77B1 . 8B45 FC mov eax, [ebp-4]
011D77B4 . 8B40 44 mov eax, [eax+44]
011D77B7 . 50 push eax
011D77B8 . E8 A7F3F6FF call 01146B64 ; 这里进去后MessageBox弹出
011D77BD . 6A 01 push 1
011D77BF . 6A 00 push 0
011D77C1 . 6A 00 push 0
011D77C3 . 68 10791D01 push 011D7910 ; ASCII "http://www.168reg.com/view_dev.asp?id=602"
011D77C8 . 6A 00 push 0
011D77CA . 8B45 FC mov eax, [ebp-4]
011D77CD . 8B40 44 mov eax, [eax+44]
011D77D0 . 50 push eax
011D77D1 . E8 6615F9FF call 01168D3C
011D77D6 . 6A 00 push 0 ; /lParam = 0
011D77D8 . 6A 00 push 0 ; |wParam = 0
011D77DA . 6A 10 push 10 ; |Message = WM_CLOSE
011D77DC . 8B45 FC mov eax, [ebp-4] ; |
011D77DF . 8B40 44 mov eax, [eax+44] ; |
011D77E2 . 50 push eax ; |hWnd
011D77E3 . E8 B4F3F6FF call 01146B9C ; \PostMessageA
011D77E8 . 33C0 xor eax, eax
011D77EA . 5A pop edx
011D77EB . 59 pop ecx
011D77EC . 59 pop ecx
011D77ED . 64:8910 mov fs:[eax], edx
011D77F0 . EB 11 jmp short 011D7803
011D77F2 .^ E9 05BEF6FF jmp 011435FC
011D77F7 . E8 68C1F6FF call 01143964
011D77FC . EB 05 jmp short 011D7803
011D77FE . E8 61C1F6FF call 01143964
011D7803 > 33C0 xor eax, eax
011D7805 . 5A pop edx
011D7806 . 59 pop ecx
011D7807 . 59 pop ecx
011D7808 . 64:8910 mov fs:[eax], edx
011D780B . 68 25781D01 push 011D7825
011D7810 > 8D45 DC lea eax, [ebp-24]
011D7813 . BA 06000000 mov edx, 6
011D7818 . E8 BFC7F6FF call 01143FDC
011D781D . C3 retn
查看内存中Hook.dll的基址为0x01140000,爆破点偏移量为0x011D773E-0x01140000=0x9773E,至此所有信息收集完毕~~~
下面给出完整Loader代码:
'API声明
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function CreateMutex Lib "kernel32" Alias "CreateMutexA" (ByVal lpMutexAttributes As Long, ByVal bInitialOwner As Long, ByVal lpName As String) As Long
Private Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" (ByVal hFile As Long, ByVal lpFileMappigAttributes As Long, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As String) As Long
Private Declare Function MapViewOfFile Lib "kernel32" (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long
Private Declare Function UnmapViewOfFile Lib "kernel32" (ByVal lpBaseAddress As Long) As Long
Private Declare Function WriteProcessMemoryByLong Lib "kernel32" Alias "WriteProcessMemory" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByRef lpBuffer As Long, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub Form_Load()
Dim hFileMapping As Long, BaseAddress As Long, Buffer As Long, hModule As Long, pShellExecuteA As Long
'对ShellExecute打补丁,去处弹出网页
hModule = LoadLibrary("shell32.dll")
pShellExecuteA = GetProcAddress(hModule, "ShellExecuteA")
Buffer = &H18C2 'retn 18H
WriteProcessMemoryByLong &HFFFFFFFF, pShellExecuteA, Buffer, 3, ByVal 0&
'启动外挂
CreateMutex 0, 0, "EXE_MUTEX_LLK"
hFileMapping = CreateFileMapping(&HFFFFFFFF, 0, 4, 0, 4, "SFILEMAP_LLK")
UnmapViewOfFile MapViewOfFile(hFileMapping, 2, 0, 0, 0)
BaseAddress = LoadLibrary("C:\Program Files\16xia\QQLLK\hook.dll")
'去除定时关闭
Buffer = &HEB 'JMP
WriteProcessMemoryByLong &HFFFFFFFF, BaseAddress + &H9773E, Buffer, 1, ByVal 0&
'检测外挂是否已退出
Sleep 3000
Timer1.Interval = 100
Timer1.Enabled = True
Form1.Hide
End Sub
Private Sub Timer1_Timer()
If FindWindow("TFormMain", "试用版V4.93") = 0 Then End
End Sub
--------------------------------------------------------------------------------
【后记】:写这篇小东东并非因为我喜欢玩连连看,而是觉得这外挂的保护方式比较特别,有可以借鉴的地方~~而在定时关闭时,没有使用常规的计时函数,而是另开时线程,使用Sleep函数计时~~这些我都没见过,呵呵~~~
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年07月22日
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!