元始天尊 发表于 2014-2-19 19:51:40

qq空间老文章转载-api-hook探索

这两天仔细研究了下hook api,很难得,我电脑win7 64位,经过3天各种调试、终于有了眉目了,虽然还是有未知小bug,不过应该都能解决。。。先在网上遍搜api hook相关信息和文档和代码,最后把一些看起来比较正常的代码整合到一起,写到我的代码里,同时把我逆向过的一部分Unlocker代码也弄进去了。遇到的第一个难题:无论如何注入的代码总也运行不起来,就连xp都不行。。。后来加入各种调试输出语句,排了一些错,还是不行。。看网上有人说想在win7 64位成功必须用Unicode字符串,于是我把一些地方改了,包括Process32FirstW,然而本来很好用的Process32First改了以后,不知道为什么总获取不到信息了,最后仔细在msdn里找了一下,原来第二个参数要对一个成员初始化。。。网上的代码很不正规,图省事就直接贴上去了。。。第二个问题困扰了我2天:注入进程后总是是目标程序崩溃。。。百思不得其解,网上的代码也是都有问题的,没发现有能用的(64位win7),xp我没装,于是没管。网上的解决办法也不对。第一天晚上,突然发现release版的居然可以用了,注入到目标程序可以显示出对话框,但是点了以后还是程序崩溃。。网上全是求助帖,没看到有真正解决的!!!好水。可是第二天早上,我才发现只有release可以,debug居然不行!!!最后最后我实在没招了用ida看了一下,原来如此啊,,debug里为了调试程序,每一个自己写的函数都是由2个函数实现的,其中一个调用另一个,我把一个函数代码写到另一个进程中后,只是把最外层那个函数调用了,而注入的目标进程肯定是没有里面那个函数的,因为我没法写到进程里,而且极难实现。。连函数在哪里都无法得知的,微软弄得很复杂的。release版由于优化了,只有一个调用函数,所以能正常注入。。。最后我的解决办法是:利用外壳函数一个性质,外壳函数的内部汇编实现是jmp+偏移地址,这里暂且将外壳函数用func1表示,真正的函数用func2表示。那么有func1() {func2();}汇编写法就是jmp addr   其中addr为func2函数位置相对于jmp的下一条指令的偏移;这个指令长度5字节,这条指令本身占5字节(jmp1字节),因此只需要读取func1这个函数指针偏移位置为1的地方,读取4字节即可,然后把结果加上func1所在地址,就是func2的绝对地址了。此时把func2写入即可。做了这些以后,本以为万无一失了,谁知道还是不行,目标进程还是挂掉了。。于是我把写入到内存的那些func2函数代码看了一下,居然和直接汇编得到的(文件中的)不一样。。。,(很茫然,我觉得应该是用来调试的指令吧),总有字节被硬生生替换为0xcc...这是个特权指令,一运行程序就崩了。。。而且程序运行的时候内存里的函数居然也是这个。。。无解。最后想到的办法就是把func2硬编码了,直接编译出来,取得汇编代码相对应的16进制机器码,作为数组直接写到进程中,在执行,这样总不会弄什么猫腻了吧,结果真的可以,对话框有了。。。只有几个烦人的bug都被我调好了,现在仍然有bug,不过可以通过func2让目标进程加载dll了。
func2由于是注入函数,不能有任何直接的东西,比如这个程序自身的指针,字符串,api统统不能用,想用都要传到参数中才行。而且下断点发现func2无法被断下来,,,估计微软没考虑到要为注入程序提供调试了,这个函数里外来的东西都不能直接用,现在仍有一处崩溃,还在查,不过release版倒是可以随便运行了。。呵呵
相关代码:
DWORD RemoteInject(PROCESSENTRY32W* pInfo,DWORD len)
{
HMODULE hMod=GetModuleHandle("kernel32.dll");
ASSERT(hMod != NULL);
HANDLE hRemoteProcess=OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_VM_OPERATION |
PROCESS_CREATE_THREAD,FALSE,pInfo->th32ProcessID);
#ifdef _DEBUG
TRACE("hRemoteProcess=%d\n",hRemoteProcess);
#endif
if(hRemoteProcess)
{
#ifdef _DEBUG
unsigned char codedata[] = //Debug版FuncToInject的字节码,随着FuncToInject函数变化而变化
{
   0x55, 0x8B, 0xEC, 0x81, 0xEC, 0xC0, 0x00, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x8B, 0xE5,
   0x5D, 0xC2, 0x04, 0x00
};LPVOID pfnStartAddr=VirtualAllocEx(hRemoteProcess,NULL,sizeof(codedata),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
TRACE("pfnStartAddr=%d\n",pfnStartAddr);
#else
LPVOID pfnStartAddr=VirtualAllocEx(hRemoteProcess,NULL,len,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
#endifif(pfnStartAddr)
{
   SIZE_T NumberOfBytesWritten=0;#ifdef _DEBUG
   WriteProcessMemory(hRemoteProcess,pfnStartAddr,(LPVOID)codedata,sizeof(codedata),&NumberOfBytesWritten);
#else
   WriteProcessMemory(hRemoteProcess,pfnStartAddr,(LPVOID)&FuncToInject,len,&NumberOfBytesWritten);
#endif
   LPVOID ParamBuffer=VirtualAllocEx(hRemoteProcess,NULL,sizeof(InjectStruct),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
#ifdef _DEBUG
   TRACE("ParamBuffer=%d\n",ParamBuffer);
#endif
   if(ParamBuffer && hMod)
   {
    InjectStruct RemoteFunc;
    RemoteFunc.MyLoadLibraryW=(MYLOADLIBRARYW)GetProcAddress(hMod,"LoadLibraryW");
    RemoteFunc.MyGetModuleHandleW=(MYGETMODULEHANDLEW)GetProcAddress(hMod,"GetModuleHandleW");
    RemoteFunc.MyGetProcAddress=(MYGETPROCADDRESS)GetProcAddress(hMod,"GetProcAddress");
#ifdef TEST1
   HMODULE userhandle=GetModuleHandleA("user32.dll");
   RemoteFunc.MyMessageBoxW=(MYMESSAGEBOXW)GetProcAddress(userhandle,"MessageBoxW");
   ASSERT(RemoteFunc.MyMessageBoxW != NULL);
#endif
    memcpy(&RemoteFunc.ProcInfo,pInfo,sizeof(PROCESSENTRY32W));
    ASSERT(RemoteFunc.MyLoadLibraryW != NULL);
    ASSERT(RemoteFunc.MyGetModuleHandleW != NULL);
    ASSERT(RemoteFunc.MyGetProcAddress != NULL);
    lstrcpyW(RemoteFunc.DllFullPath,L"C:\\Users\\Administrator\\Desktop\\TransParentEnDeSrc\\Debug\\TransParentEnDeSrc.dll");//打算做成软件包,路径写到注册表中    WriteProcessMemory(hRemoteProcess,ParamBuffer,(LPVOID)&RemoteFunc,sizeof(InjectStruct),&NumberOfBytesWritten);    //HANDLE NewThread=CreateRemoteThread(hRemoteProcess,NULL,1024,(LPTHREAD_START_ROUTINE)pfnStartAddr,ParamBuffer,0,NULL);
    HANDLE NewThread=MyCreateRemoteThread(hRemoteProcess,(LPTHREAD_START_ROUTINE)pfnStartAddr,ParamBuffer);
#ifdef _DEBUG
//    TRACE("%S CreateRemoteThread:Getlasterror:%d\n",pInfo->szExeFile,GetLastError());
#endif
    if(NewThread)
   WaitForSingleObject(NewThread,INFINITE);
    VirtualFreeEx(hRemoteProcess,ParamBuffer,0,MEM_RELEASE);
    CloseHandle(NewThread);
   }
   VirtualFreeEx(hRemoteProcess,pfnStartAddr,0,MEM_RELEASE);
}
#ifdef _DEBUG
else
{
   TRACE("失败:%d\n",GetLastError());
}
#endifCloseHandle(hRemoteProcess);
}
return 0;
}

BOOL WINAPI FuncToInject(InjectStruct* INJECT)//此代码在拦截createprocess时也要用到
{//注入函数中不能有任何内部指针,字符串,函数也最好作为指针存到参数中   注入函数无法调试。。。。
if(INJECT->MyGetModuleHandleW(INJECT->DllFullPath)) return TRUE;//DLL已经加载直接返回
HMODULE hMod=INJECT->MyLoadLibraryW(INJECT->DllFullPath);
if(hMod == NULL)
   return FALSE;
SETINFO setinfo=(SETINFO)INJECT->MyGetProcAddress(hMod,(const char*)MAKELONG(1,0));//获取第一个函数
setinfo(&INJECT->ProcInfo);
return TRUE;
}

页: [1]
查看完整版本: qq空间老文章转载-api-hook探索