无驱动的 StarForce 输入表初探
最近股市不爽,多少看了一点,马上要高考了。又有多少学子在和命运赛跑。人生就是赛跑。
没有驱动,在ollydbg下基本没有什么阻力,很顺利的跑起来了。
发现壳把 GetModuleHandleA 函数抽走了,以下是函数原代码:
7C80B6A1 > 8BFF mov edi, edi
7C80B6A3 55 push ebp
7C80B6A4 8BEC mov ebp, esp
7C80B6A6 837D 08 00 cmp dword ptr [ebp+8], 0
7C80B6AA 74 18 je short 7C80B6C4
7C80B6AC FF75 08 push dword ptr [ebp+8]
7C80B6AF E8 C0290000 call 7C80E074
7C80B6B4 85C0 test eax, eax
7C80B6B6 74 08 je short 7C80B6C0
7C80B6B8 FF70 04 push dword ptr [eax+4]
7C80B6BB E8 7D2D0000 call GetModuleHandleW
7C80B6C0 5D pop ebp
7C80B6C1 C2 0400 retn 4
还好,壳只是简单的模拟了一下这个函数:在函数GetModuleHandleW下断,返回后,可以看见一部分:
00C5017C E8 00000000 call 00C50181
00C50181 870424 xchg dword ptr [esp], eax
00C50184 8D40 0F lea eax, dword ptr [eax+F]
00C50187 870424 xchg dword ptr [esp], eax
00C5018A 68 3DE4807C push kernel32.GetModuleHandleW
00C5018F C3 retn
00C50190 5D pop ebp ; 00C00050
00C50191 E9 00000000 jmp 00C50196
00C50196 C2 0400 retn 4
下面还有抽走的另一个函数:
00C50199 64:A1 18000000 mov eax, dword ptr fs:[18]
00C5019F 8B40 30 mov eax, dword ptr [eax+30]
00C501A2 8B40 08 mov eax, dword ptr [eax+8]
00C501A5 ^ E9 E6FFFFFF jmp 00C50190
这个函数眼熟吧,嘿嘿。
又简单的看了一下iat的处理,真有点变态,跳来跳去,不过有一个非常大的漏洞可以利用:
100BA1B7 8B00 mov eax, dword ptr [eax]
100BA1B9 8B0A mov ecx, dword ptr [edx]
100BA1BB 8908 mov dword ptr [eax], ecx
上面的代码是写入iat的地方,这里同样会把正确的函数写入到壳申请的一段数据里。在这里下断,可以看见,壳写入程序的函数名称是最近写入壳里的函数名称,这个没有加密:
0040E318 76B2A8F7 WINMM.PlaySoundA
上面是写入的函数,下面是写入壳里的函数,最下面也就是最后写入的就是正确的函数:
00C70470 76B13894 WINMM.CloseDriver
00C70474 76B1E382 WINMM.DefDriverProc
00C70478 76B154A9 WINMM.DriverCallback
00C7047C 76B12DE5 WINMM.GetDriverModuleHandle
00C70480 76B12DE5 WINMM.GetDriverModuleHandle
00C70484 76B2B7B4 WINMM.winmmDbgOut
00C70488 76B1AAA0 WINMM.MigrateSoundEvents
00C7048C 76B20906 WINMM.NotifyCallbackData
00C70490 76B12E3E WINMM.OpenDriver
00C70494 76B2A8F7 WINMM.PlaySoundA
00C70498 76B2A8F7 WINMM.PlaySoundA
还有加密的函数:
0040E25C 00CE017C
此时的数据如下:
00C70D50 7C874631 kernel32.GetLargestConsoleWindowSize
00C70D54 7C80902D ASCII "NTDLL.RtlGetLastWin32Error"
看一下加密后函数地址处的代码:
00CE017C 64:A1 18000000 mov eax, dword ptr fs:[18]
00CE0182 8B40 34 mov eax, dword ptr [eax+34]
00CE0185 C3 retn
再看一下NTDLL.RtlGetLastWin32Error函数的代码:
7C930331 > 64:A1 18000000 mov eax, dword ptr fs:[18]
7C930337 8B40 34 mov eax, dword ptr [eax+34]
7C93033A C3 retn
上面00C70D54处的NTDLL.RtlGetLastWin32Error就是加密的函数名称,当然还需要获得这个函数的实际地址,然后填充到程序中去。
不过并不完全都是这样,有的就是直接的函数地址,比如:
0040E1E0 00CC01B5
壳中函数是:
00C70EF4 7C862C9C kernel32.GetThreadTimes
00C70EF8 7C80929C kernel32.GetTickCount
看一下00CC01B5处的代码:
00CC01B5 ^\E9 C2FFFFFF jmp 00CC017C
跟随这个跳转:
00CC017C BA 0000FE7F mov edx, 7FFE0000
00CC0181 FF32 push dword ptr [edx]
00CC0183 58 pop eax
00CC0184 F762 04 mul dword ptr [edx+4]
00CC0187 0FACD0 18 shrd eax, edx, 18
00CC018B E9 00000000 jmp 00CC0190
00CC0190 C3 retn
看一下kernel32.GetTickCount的代码:
7C80929C > BA 0000FE7F mov edx, 7FFE0000
7C8092A1 8B02 mov eax, dword ptr [edx]
7C8092A3 F762 04 mul dword ptr [edx+4]
7C8092A6 0FACD0 18 shrd eax, edx, 18
7C8092AA C3 retn
这个就可以直接填充到程序中了。
没有虚拟机,只有输入表加密,没有驱动的脱壳生活里真是太舒服了。如果找到这个加密代码的关键地方也可以直接改代码,使其写入正确的函数,不过这段代码实在是太长太乱了。壳应该是用自己的dll实现解码,不知道直接搞dll能不能实现脱壳。
要是研究一下壳还原代码的算法,是不是可以直接写出脱壳机来呢?太复杂了,还是不要考虑的好。
[课程]Android-CTF解题方法汇总!