kerberos_API_fix
来源:互联网 发布:js怎么设置transform 编辑:程序博客网 时间:2024/06/06 01:18
前言
学脱壳时, 看到人家用kerberos.exe进行目标程序的API Trace.
可以先不上调试器, 看看cm调用的是哪些API(API名称,参数,API的调用地址).
这样就能先确定一些流程点.
还没等资料看完, 就发现这个工具有些问题.
kerberos.exe在x86下好使, 在win7x64下不好使(运行后不打印TraceAPI的日志).
调了一天, 将kerberos.exe的BUG解决了.
这是我第一次正儿八经的在闭源情况下, 在反汇编层面上为第三方程序修复BUG, 解决了还是很开心.
这工具写得早了, 2007年写的, 可能当时还没有win7x64的环境可以测试. 其实不算是作者的BUG. 这软件狠纯真, 没有对抗, 适合用来学习.
修复后的工具下载点
kerberos API spy v1.13 fixed on Win7X64
软件的原理
- 给出一个要下断点的API配置列表(DllName, ApiName, ApiParameter numbers), 然后根据这个配置单, 对API的头5个字节进行APIHook, 当经过API时, 就能知道API名称, 每个API的参数值, 打印后, 在继续执行API原来的功能.
- API配置单中的API参数数量, 不是能用软件生产的, 不知道作者当时是不是手工码的:)
- 主程序(Hook管理程序)在注册表中写入了配置信息, UI上指定要目标程序后, 主程序启动目标程序(挂住的状态),主程序注入DLL到目标程序(注入DLL做完APIHook), 主程序让目标程序继续跑.
- 由注入的DLL从注册表中配置信息, Hook所有指定的API.
- 当经过Hook过的API时, 记录日志信息(为了提高效率, 满4KB才写磁盘; 任务完成后, 写最后一次日志).
目标软件的GUG
正常情况 : 在winxp下, 可以记录目标软件调用的API信息.
BUG重新环境 : 在win7x64下, 不能记录目标软件调用的API信息.
软件的BUG原因
发现的BUG有2个
BUG1
建立远线程之前, 要打开目标进程.
OpenProcess时, 要求的权限少了, 原来是0x2A, CreateRemoteThread失败, 错误码C05
改成-1后, CreateRemoteThread成功了. 最合适的权限值没有去试验.
发现这个问题, 还不是先看代码, 是去看目标进程中,是否有Hook后的DLL.
发现没有Dll在目标程序中Hook, 去检查2个点, 是HookDll执行完了, 还是没注入成功.
刚开始以为是HookDll由于逻辑不正确, 执行完了, 结果不是:)
然后才去检查是否Hook成功.
004016D4 |. FF75 08 push dword ptr [ebp+8] ; /ProcessId004016D7 |. 6A 00 push 0 ; |Inheritable = FALSE004016D9 6A FF push -1 ; the org value is 0x2a004016DB |. E8 D6140000 call <jmp.&kernel32.OpenProcess> ; \OpenProcess004016E0 |. 0BC0 or eax, eax004016E2 |. 75 0A jnz short 004016EE004016E4 |. BA 9F314000 mov edx, 0040319F ; ASCII "Can't open process"004016E9 |. E9 AE000000 jmp 0040179C004016EE |> 8945 E4 mov dword ptr [ebp-1C], eax004016F1 |. 6A 04 push 4 ; /flProtect = 4004016F3 |. 68 00100000 push 1000 ; |flAllocationType = 1000 (4096.)004016F8 |. FF75 FC push dword ptr [ebp-4] ; |dwSize004016FB |. 6A 00 push 0 ; |lpAddress = NULL004016FD |. 50 push eax ; |hProcess004016FE |. E8 BF140000 call <jmp.&kernel32.VirtualAllocEx> ; \VirtualAllocEx00401703 |. 0BC0 or eax, eax00401705 |. 75 0A jnz short 0040171100401707 |. BA B2314000 mov edx, 004031B2 ; ASCII "Can't allocate memory"0040170C |. E9 8B000000 jmp 0040179C00401711 |> 8945 E0 mov dword ptr [ebp-20], eax00401714 |. 6A 00 push 0 ; /pBytesWritten = NULL00401716 |. FF75 FC push dword ptr [ebp-4] ; |BytesToWrite00401719 |. 68 28404000 push 00404028 ; |Buffer = kerberos.004040280040171E |. 50 push eax ; |Address0040171F |. FF75 E4 push dword ptr [ebp-1C] ; |hProcess00401722 |. E8 AD140000 call <jmp.&kernel32.WriteProcessMemor>; \WriteProcessMemory00401727 |. 0BC0 or eax, eax00401729 |. 75 07 jnz short 004017320040172B |. BA C8314000 mov edx, 004031C8 ; ASCII "Can't write to process memory"00401730 |. EB 6A jmp short 0040179C00401732 |> 68 2D324000 push 0040322D ; /pModule = "kernel32.dll"00401737 |. E8 62140000 call <jmp.&kernel32.GetModuleHandleA> ; \GetModuleHandleA0040173C |. 8945 DC mov dword ptr [ebp-24], eax0040173F |. 68 3A324000 push 0040323A ; /ProcNameOrOrdinal = "LoadLibraryA"00401744 |. 50 push eax ; |hModule00401745 |. E8 5A140000 call <jmp.&kernel32.GetProcAddress> ; \GetProcAddress0040174A |. 0BC0 or eax, eax0040174C |. 75 07 jnz short 004017550040174E |. BA E6314000 mov edx, 004031E6 ; ASCII "Can't get procedure address"00401753 |. EB 47 jmp short 0040179C00401755 |> 8945 F4 mov dword ptr [ebp-C], eax00401758 |. 33C9 xor ecx, ecx0040175A |. 51 push ecx ; /lpThreadId => NULL0040175B |. 51 push ecx ; |dwCreationFlags => 00040175C |. FF75 E0 push dword ptr [ebp-20] ; |lpParameter0040175F |. 50 push eax ; |lpStartAddress00401760 |. 51 push ecx ; |dwStackSize => 000401761 |. 51 push ecx ; |lpThreadAttributes =>00401762 |. FF75 E4 push dword ptr [ebp-1C] ; |hProcess00401765 |. E8 16140000 call <jmp.&kernel32.CreateRemoteThrea>; \CreateRemoteThread0040176A |. 8945 E8 mov dword ptr [ebp-18], eax0040176D |. 6A FF push -1 ; /Timeout = INFINITE0040176F |. 50 push eax ; |hObject00401770 |. E8 59140000 call <jmp.&kernel32.WaitForSingleObje>; \WaitForSingleObject00401775 |. 68 00800000 push 8000 ; /dwFreeType = 8000 (32768.)0040177A |. 6A 00 push 0 ; |dwSize = 00040177C |. FF75 E0 push dword ptr [ebp-20] ; |lpAddress0040177F |. FF75 E4 push dword ptr [ebp-1C] ; |hProcess00401782 |. E8 41140000 call <jmp.&kernel32.VirtualFreeEx> ; \VirtualFreeEx00401787 |. FF75 E8 push dword ptr [ebp-18] ; /hObject0040178A |. E8 E5130000 call <jmp.&kernel32.CloseHandle> ; \CloseHandle0040178F |. FF75 E4 push dword ptr [ebp-1C] ; /hObject00401792 |. E8 DD130000 call <jmp.&kernel32.CloseHandle> ; \CloseHandle
从反汇编实现看出作者不是狠严谨.
* CreateRemoteThread没有加错误检查, 如果没注入成功, 没有给使用者提示.
BUG2
当给定HookApi的配置文件时, 可以给出Dll中的API名称或API序号.
但是作者疏忽了一点, 如果配置文件中的API在当前环境中没有(e.g. user32.dll’s Win32PoolAllocationStats), 这个API在WinXp下有, 在Win7X64下没有.
作者就将这种不存在的WinAPI当作数字去算API地址, 这算出来肯定错了 . 然后就发生访问异常, 注入的DLL崩掉了, 日志也就记不成了.
这个BUG在代码层面的修复方法:如果不是API名称, 要看是不是API序号, 序号中只有数字的, 如果是字母, 不能算API序号.
从反汇编层面, 我简单的修复了一下, 如果不是API名称, 就不Hook.
因为作者给出的配置文件中, 没有给定API是序号的情况, 估计他自己也没有试验这种情况.
10001595 <ke_core.fnHookApi> /$ 55 push ebp ; 下API钩子10001596 |. 8BEC mov ebp, esp10001598 |. 83C4 EC add esp, -141000159B |. 8945 FC mov dword ptr [ebp-4], eax1000159E |. 895D F0 mov dword ptr [ebp-10], ebx100015A1 |. 56 push esi ; 75960000是hDll100015A2 |. 57 push edi100015A3 |. 51 push ecx100015A4 |. 57 push edi ; /ProcNameOrOrdinal100015A5 |. 53 push ebx ; |hModule100015A6 |. E8 11110000 call <jmp.&kernel32.GetProcAddress> ; \GetProcAddress100015AB |. 0BC0 or eax, eax ; get api addr100015AD 74 19 je short <L_CANT_GET_API_ADDR>100015AF 8945 F8 mov dword ptr [ebp-8], eax100015B2 8D4D F4 lea ecx, dword ptr [ebp-C]100015B5 |. 51 push ecx ; /pOldProtect100015B6 |. 6A 40 push 40 ; |NewProtect = PAGE_EXECUTE_READWRITE100015B8 |. 68 00100000 push 1000 ; |Size = 1000 (4096.)100015BD |. 50 push eax ; |Address100015BE |. E8 3B110000 call <jmp.&kernel32.VirtualProtect> ; \修改函数地址为可读写执行100015C3 |. E9 51010000 jmp 10001719100015C8 <ke_core.L_CANT_GET_API_ADDR> E9 73010000 jmp <L_FUN_API_HOOK_END> ; fnIsFunSn不能再调用100015CD 90 nop100015CE 90 nop100015CF 90 nop100015D0 90 nop100015D1 |. 8945 EC mov dword ptr [ebp-14], eax100015D4 |. C605 AC560010>mov byte ptr [100056AC], 0100015DB |. 803D B4570010>cmp byte ptr [100057B4], 0100015E2 |. 75 20 jnz short 10001604100015E4 |. 68 9C540010 push 1000549C100015E9 |. 68 AC560010 push 100056AC100015EE |. E8 65120000 call <AppendLen>100015F3 |. 68 A4550010 push 100055A4100015F8 |. 68 AC560010 push 100056AC100015FD |. E8 56120000 call <AppendLen>10001602 |. EB 0F jmp short 1000161310001604 |> 68 B4570010 push 100057B410001609 |. 68 AC560010 push 100056AC1000160E |. E8 45120000 call <AppendLen>10001613 |> 8B15 70500010 mov edx, dword ptr [10005070]10001619 |. C602 00 mov byte ptr [edx], 01000161C |. 803F 40 cmp byte ptr [edi], 401000161F |. 75 48 jnz short 1000166910001621 |. FF75 EC push dword ptr [ebp-14]10001624 |. 8F45 F8 pop dword ptr [ebp-8]10001627 |. 8D45 F4 lea eax, dword ptr [ebp-C]1000162A |. 50 push eax ; /pOldProtect1000162B |. 6A 40 push 40 ; |NewProtect = PAGE_EXECUTE_READWRITE1000162D |. 68 00100000 push 1000 ; |Size = 1000 (4096.)10001632 |. FF75 F8 push dword ptr [ebp-8] ; |Address10001635 |. E8 C4100000 call <jmp.&kernel32.VirtualProtect> ; \VirtualProtect1000163A |. 68 AC560010 push 100056AC1000163F |. FF35 70500010 push dword ptr [10005070]10001645 |. E8 0E120000 call <AppendLen>1000164A |. FF35 70500010 push dword ptr [10005070]10001650 |. E8 CB110000 call <StrLen>10001655 |. 8B15 70500010 mov edx, dword ptr [10005070]1000165B |. 03D0 add edx, eax1000165D |. 42 inc edx1000165E |. 8915 14500010 mov dword ptr [10005014], edx10001664 |. E9 B0000000 jmp 1000171910001669 |> 803F 2B cmp byte ptr [edi], 2B1000166C |. 75 46 jnz short 100016B41000166E |. 8B45 F0 mov eax, dword ptr [ebp-10]10001671 |. 0345 EC add eax, dword ptr [ebp-14]10001674 |. 8945 F8 mov dword ptr [ebp-8], eax10001677 |. 8D4D F4 lea ecx, dword ptr [ebp-C]1000167A |. 51 push ecx ; /pOldProtect1000167B |. 6A 40 push 40 ; |NewProtect = PAGE_EXECUTE_READWRITE1000167D |. 68 00100000 push 1000 ; |Size = 1000 (4096.)10001682 |. 50 push eax ; |Address10001683 |. E8 76100000 call <jmp.&kernel32.VirtualProtect> ; \VirtualProtect10001688 |. 68 AC560010 push 100056AC1000168D |. FF35 70500010 push dword ptr [10005070]10001693 |. E8 C0110000 call <AppendLen>10001698 |. FF35 70500010 push dword ptr [10005070]1000169E |. E8 7D110000 call <StrLen>100016A3 |. 8B15 70500010 mov edx, dword ptr [10005070]100016A9 |. 03D0 add edx, eax100016AB |. 42 inc edx100016AC |. 8915 14500010 mov dword ptr [10005014], edx100016B2 |. EB 65 jmp short 10001719100016B4 |> 803F 23 cmp byte ptr [edi], 23100016B7 |. 75 60 jnz short 10001719100016B9 |. FF75 EC push dword ptr [ebp-14] ; /ProcNameOrOrdinal100016BC |. FF75 F0 push dword ptr [ebp-10] ; |hModule100016BF |. E8 F80F0000 call <jmp.&kernel32.GetProcAddress> ; \GetProcAddress100016C4 |. 0BC0 or eax, eax100016C6 |. 74 40 je short 10001708100016C8 |. 8945 F8 mov dword ptr [ebp-8], eax100016CB |. 8D4D F4 lea ecx, dword ptr [ebp-C]100016CE |. 51 push ecx ; /pOldProtect100016CF |. 6A 40 push 40 ; |NewProtect = PAGE_EXECUTE_READWRITE100016D1 |. 68 00100000 push 1000 ; |Size = 1000 (4096.)100016D6 |. 50 push eax ; |Address100016D7 |. E8 22100000 call <jmp.&kernel32.VirtualProtect> ; \VirtualProtect100016DC |. 68 AC560010 push 100056AC100016E1 |. FF35 70500010 push dword ptr [10005070]100016E7 |. E8 6C110000 call <AppendLen>100016EC |. FF35 70500010 push dword ptr [10005070]100016F2 |. E8 29110000 call <StrLen>100016F7 |. 8B15 70500010 mov edx, dword ptr [10005070]100016FD |. 03D0 add edx, eax100016FF |. 42 inc edx10001700 |. 8915 14500010 mov dword ptr [10005014], edx10001706 |. EB 11 jmp short 1000171910001708 |> 33C0 xor eax, eax1000170A |. 8945 F8 mov dword ptr [ebp-8], eax1000170D |. FF05 04500010 inc dword ptr [10005004]10001713 |. 57 push edi10001714 |. E8 F6050000 call 10001D0F10001719 |> 8B45 FC mov eax, dword ptr [ebp-4]1000171C |. E8 82000000 call <fnGetApiHookInfoPos> ; 计数10001721 |. 8B45 F8 mov eax, dword ptr [ebp-8]10001724 |. 8942 08 mov dword ptr [edx+8], eax10001727 |. 0BC0 or eax, eax10001729 |. 74 15 je short <L_FUN_API_HOOK_END>1000172B |. 8B45 FC mov eax, dword ptr [ebp-4] ; 函数不为空1000172E |. E8 82000000 call <fnApiCnt>10001733 |. 8B45 F8 mov eax, dword ptr [ebp-8]10001736 |. 8B08 mov ecx, dword ptr [eax] ; 读API实现头4个个OPCODE10001738 |. 890A mov dword ptr [edx], ecx ; 保存API实现头4个字节1000173A |. 8A48 04 mov cl, byte ptr [eax+4]1000173D |. 884A 04 mov byte ptr [edx+4], cl10001740 <ke_core.L_FUN_API_HOOK_END> |> 59 pop ecx ; 保存5个字节中的最后一个.10001741 |. 5F pop edi10001742 |. 5E pop esi10001743 |. C9 leave10001744 \. C3 retn
调试代码
在开始调试时, 由于HookDll崩溃退出, 需要加调试代码才能附加.
* 在HookDll’s DllMain入口处加0xcc, 会使HookDll崩溃,无法调试附加.
* 加了一段弹框代码, 附加修复完再去掉.
10001040 /$ 55 push ebp10001041 |. 8BEC mov ebp, esp10001043 |. 81C4 FCFEFFFF add esp, -10410001049 E9 B2220000 jmp 100033001000104E |. E8 D4100000 call 10002127 ; read cfg10001053 |. E8 40160000 call <jmp.&kernel32.GetCurrentProcess>; [GetCurrentProcessId
10003300 90 nop10003301 90 nop10003302 90 nop10003303 90 nop10003304 90 nop10003305 90 nop10003306 90 nop10003307 90 nop10003308 90 nop10003309 90 nop1000330A 90 nop1000330B 90 nop1000330C 90 nop1000330D E8 8AEAFFFF call 10001D9C10003312 ^ E9 37DDFFFF jmp 1000104E
之前的弹框代码
10003300 > \6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL10003302 . 6A 00 push 0 ; |Title = NULL10003304 . 6A 00 push 0 ; |Text = NULL10003306 . 6A 00 push 0 ; |hOwner = NULL10003308 . E8 6DF3FFFF call <jmp.&user32.MessageBoxA> ; \MessageBoxA1000330D . E8 8AEAFFFF call 10001D9C10003312 .^ E9 37DDFFFF jmp 1000104E
修复后程序记录的日志
kerberos API spy v1.13(C)2004-2007 Rustem FasihovThu Mar 2 2:47:58 2017DLL's : 2DLL's failed : 0Functions : 1310Functions failed: 0========================================================================================================================================================================================================test.exe | 00401013 | MessageBoxA(00000000, 00402042: "Run this program under other spyes", 00402036: "Spy testing", 00000000) returns: 00000001test.exe | 00401018 | IsDebuggerPresent() returns: 00000000test.exe | 0040102F | MessageBoxA(00000000, 00402023: "NOT under debugger", 00402023: "NOT under debugger", 00000000) returns: 00000001test.exe | 0040104B | ExitProcess(00000000) ========================================================================================================================================================================================================END OF REPORT