逆向CodeInjectEx发现“直接代码注入”中未曾考虑过的“retn 4”

今天在看一个WG教程中,作者提到了两个工具:CE和CodeInjectEx。CE算是老朋友了,CodeInjectEx虽然我以前没有用过,不过其原理多少知道一些。

下载CodeInjectEx(郁金香代码注入工具)后我简单想了一下:代码注入包括两类,DLL和ASM CODE直接代码注入。DLL注入的代码网上到处都是,一般常用办法是CreateRemoteThread,在远程进程中启动线程执行LoadLibrary加载dll。

CreateRemoteThread函数原型如下:

WINBASEAPI
HANDLE
WINAPI
CreateRemoteThread(
    HANDLE hProcess,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    DWORD dwStackSize,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    DWORD dwCreationFlags,
    LPDWORD lpThreadId
    );

 我们在注入DLL使用时候是这样:

__try
{
    hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, (PVOID)pszDllPathRemote, 0, NULL);        
}
__except(EXCEPTION_EXECUTE_HANDLER )
{
    OutputDebugStringA("Load the Dll Exception Error!");
}

其中pfnThreadRtn是函数LoadLibraryA的地址,pszDllPathRemote是写入到远程进程的作为参数的地址。反正“简单点”就是看成在远程进程启动一个线程调用函数形式:pfnThreadRtn(pszDllPathRemote)

 

有关直接代码注入我以前看过一个DEMO,提到就是将需要注入的ASM转为机器码之后(这里说明CodeInjectEx里面有个内置的汇编引擎),将代码通过WriteProcessMemory写入远程进程新申请的(VirtualAllocEx)内存,之后将其在远程进程中申请的内存起始地址作为CreateRemoteThread函数的lpStartAddress参数。以前运行这个DEMO的时候,发现该DEMO某些时候会导致被注入的进程崩溃,但是错误原因不清楚。当时也是初步学习而且现象只是偶然出现,并没有真正在意。不过我在这次逆向分析CodeInjectEx的时候,发现了其在输入的用于注入的汇编代码后面加入了5个字节:33 C0 C2 04 00,即:

xor eax,eax
retn 4

这不就是“return 0”吗?

等于说,如果我在CodeInjectEx代码注入的时候:

其实际是在pid=13160的进程0x00150000处写入了如下汇编指令:

push 0
push 00421d3c
call 7639edae
xor  eax,eax
retn 4

被注入进程(pid=13160)是我自己写的一个测试程序,7639edae是函数WinExec的地址,而00421d3c是“calc.exe”的偏移地址。等于说远程注入执行:WinExec("calc.exe",0),会启动一个计算器进程。

 

不过我还是没搞懂return 0从何而来,怎么会有一个返回值呢,那一个传入的参数又是怎么回事?

 

后来我想到在创建线程的时候,OD可以断在函数kernel32!BaseThreadInitThunk,它是由ntdll!RtlUserThreadStart函数所调用。BaseThreadInitThunk的实现如下所示:

这里从RtlUserThreadStart->BaseThreadInitThunk的调用过程中,ecx=0,edx正好就是CreateRemoteThread函数lpStartAddress参数值,push [ebp+8]就是CreateRemoteThread函数lpParameter参数值。这么一来正好就是lpStartAddress(lpParameter)的一个调用过程,这里就解释了那一个传入参数的来历,和之前阅读DLL注入代码逻辑吻合。结合我们注入的代码以及申请到的内存值(调用VirtualAllocEx获得)综合看就是:

typedef DWORD (WINAPI *STARTADDRESS)(LPVOID lpParameter);

STARTADDRESS m_pfnlpStartAddress;

m_pfnlpStartAddress = (STARTADDRESS)0x00150000;

DWORD m_pfnlpBaseAddress(0)
{
    WinExec("calc.exe",0);
    return 0;
}


我想,这也解释了为啥以前玩直接代码注入的时候,会出现时而崩溃注入进程,时而没事的现象。这太偶然了,当时还以为和调试版或者发布版有关呢,其实我想八成是漏了这个“retn 4”造成了栈平衡被破坏触发的!

 

posted on 2013-08-30 03:04  堕落华为人  阅读(781)  评论(0编辑  收藏  举报

导航