在看《加密与解密III》的时候,发现对OD attach进程有这么一个说法:进程将被中断在ntdll.DbgBreakPoint,并且调用ntdll.ZwContinue继续云云。
以下是本机函数相关内容(也许系统版本不一样,内容会有差别):
77F767CD ntdll.DbgBreakPoint /$ CC int3
77F767CE \. C3 retn
77F767CF ntdll.DbgUserBreakPoint CC int3
77F767D0 . C3 retn
77F75913 ntdll.ZwContinue /$ B8 20000000 mov eax, 20
77F75918 |. BA 0003FE7F mov edx, 7FFE0300
77F7591D |. FFD2 call edx
77F7591F \. C2 0800 retn 8
那么,我有想法:如果程序运行后修改相关代码,是否在OD加载的时候会出现异常情况呢?
先是网上搜索了一下,没找到相关介绍。那就自己实践吧。(代码参考了《0day安全》里的代码)
mem:
xor eax,eax ;这两行需要4 byte,考虑到ntdll.DbgBreakPoint后面确实有4 byte可以改写
mov [eax],eax
start:
dbg equ 1
@@:
invoke GetModuleHandle,NULL
mov hInstance,eax
ifdef dbg
pushad
cld
assume fs:nothing
xor eax,eax
mov ebx,dword ptr fs:[eax+30h]
mov eax,[ebx+0Ch]
mov eax,[eax+1Ch] ;链表开始
mov ebp,[eax+08h] ;ntdll.dll基址
mov eax,[ebp+3Ch] ;PE header
mov ecx,[ebp+eax+78h] ;offset export table
add ecx,ebp
mov ebx,[ecx+20h]
add ebx,ebp ;name table
mov eax,DbgBP ;DbgBP dd 0F52EB007h在数据段定义。是DbgBreakPoint的hash值。
push eax
xor edi,edi
@next:
inc edi
mov esi,[ebx+edi*4]
add esi,ebp
xor edx,edx
@@: movsx eax,byte ptr [esi]
cmp al,ah
jz @F
ror edx,7
add edx,eax
inc esi
jmp @B
@@:
cmp edx,[esp]
jnz @next
pop eax
mov ebx,[ecx+024h]
add ebx,ebp ;导出序号表(word值)
mov di,[ebx+2*edi] ;得到序号
mov ebx,[ecx+1Ch] ;导出指针表
add ebx,ebp
mov eax,[ebx+edi*4]
lea eax,[ebp+eax]
mov lpproc,eax
invoke WriteProcessMemory,-1,lpproc,offset mem,4,NULL
popad
endif
invoke MessageBox,0,0,0,MB_OK
@@: invoke ExitProcess,0
end start
OK,程序跑起来,MessageBox弹出来等待了,用OD加载吧。attach之,???OD中没有任何东西。。。成功了!OD附加看不到任何东西!
嗯嗯,蛮爽,那么,因地制宜,动动ntdll.ZwContinue吧。
sztmpstr db '发现调试',0
co:
invoke GetTopWindow,0
mov ebx,eax
invoke MessageBox,eax,offset sztmpstr,0,MB_OK
invoke ExitProcess,0
mem:
dd offset co
start:
dbg equ 1
@@:
invoke GetModuleHandle,NULL
mov hInstance,eax
ifdef dbg
pushad
cld
assume fs:nothing
xor eax,eax
mov ebx,dword ptr fs:[eax+30h]
mov eax,[ebx+0Ch]
mov eax,[eax+1Ch] ;链表开始
mov ebp,[eax+08h] ;ntdll.dll基址
mov eax,[ebp+3Ch] ;PE header
mov ecx,[ebp+eax+78h] ;offset export table
add ecx,ebp
mov ebx,[ecx+20h]
add ebx,ebp ;name table
mov eax,ZwCne ;ZwCne dd 0C79D4767h
push eax
xor edi,edi
@next:
inc edi
mov esi,[ebx+edi*4]
add esi,ebp
xor edx,edx
@@: movsx eax,byte ptr [esi]
cmp al,ah
jz @F
ror edx,7
add edx,eax
inc esi
jmp @B
@@:
cmp edx,[esp]
jnz @next
pop eax
mov ebx,[ecx+024h]
add ebx,ebp ;导出序号表(word值)
mov di,[ebx+2*edi] ;得到序号
mov ebx,[ecx+1Ch] ;导出指针表
add ebx,ebp
mov eax,[ebx+edi*4]
lea eax,[ebp+eax]
lea eax,[eax+6] 修改传递给edx的值
mov lpproc,eax
invoke WriteProcessMemory,-1,lpproc,offset mem,4,NULL
popad
endif
invoke MessageBox,0,0,0,MB_OK
@@: invoke ExitProcess,0
end start
运行并附加之,OD跳出了一个MessageBox,提示“发现调试”。确定,程序自动退出。嘿嘿,又成功了。
下面就可以任意发挥了。
当然,这个技巧无法阻止OD用加载方式运行程序。也不知道有没有通用性。而且,程序写得也不好,很多地方需要改善。比如WriteProcessMemory可能会在静态分析中暴露,考虑也用输入表寻找法。嘿嘿
本来我的code是这么写的:想把OD给结束掉,结果附加进去后,OD假死,机器假死,郁闷,屡试屡死,不知道为什么。按什么热键都没用,害得我电源键关机几次。不敢了。
co:
invoke GetTopWindow,0
mov ebx,eax
invoke MessageBox,eax,offset sztmpstr,0,MB_OK
invoke GetWindowThreadProcessId,ebx,addr hInstance
invoke OpenProcess,PROCESS_TERMINATE,0,hInstance
.if eax
invoke TerminateProcess,eax,0
.endif
invoke ExitProcess,0
不啰嗦了,献上。不知道算不算新发现。欢迎拍砖。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)