GetCurrentProcess返回0xffffffff是什么意思?

cugblue 2006-07-21 09:17:18
rt
...全文
636 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
louifox 2006-07-23
  • 打赏
  • 举报
回复
伪句柄,值都是-1
XiangDong 2006-07-22
  • 打赏
  • 举报
回复
This function only returns a pseudo handle. That means you can't make it inheriatable and pass it to other process. you can use it normally in current process.

---sorry I can't switch to chinese right now...
realorg 2006-07-22
  • 打赏
  • 举报
回复
获得的进程句柄无效!
有多种可能导致这个结果:
1 可能是由于函数调用失败,如多线程同步访问此 API函数。
2 可能是由于参数传递错误,如进程ID无效。

可以结贴了!
snowbirdfly 2006-07-21
  • 打赏
  • 举报
回复
GetCurrentProcess返回0xffffffff是什么意思? ~~~
A pseudo handle is a special constant, currently (HANDLE)-1, that is interpreted as the current process handle~~
表示的意思是当前进程的句柄~~因为-1表示刚好是0xffffffff`~~
Windows用户层下拦截api的原理与实现(附源码) (2008-03-29 16:15:07)转载▼ 标签: computer 杂谈 声明:本页所发布的技术文章及其附件,供自由技术传播,拒绝商业使用。本页文章及其附件的所有权归属本文作者,任何使用文档中所介绍技术者对其后果自行负责,本文作者不对其承担任何责任。 Email:redcoder163.com 目录 1 摘要 2 win2000和xp的内存结构和进程地址空间 3 函数堆栈的一些知识 4 关于拦截的整体思路 5 附件代码下载以及说明 一:摘要 拦截api的技术有很多种,大体分为用户层和内核层的拦截.这里只说说用户层的拦截(内核层也可以用,关键是让你的拦截程序获得ring0特权).而用户层也分为许多种:修改PE文件导入表,直接修改要拦截的api的内存(从开始到最后,使程序跳转到指定的地址执行).不过大部分原理都是修改程序流程,使之跳转到你要执行的地方,然后再返回到原地址.原来api的功能必须还能实现.否则拦截就失去作用了.修改文件导入表的方法的缺点是如果用户程序动态加载(使用LoadLibrary和GetProcAddress函数),拦截将变得复杂一些.所以这里介绍一下第二种方法,直接修改api,当然不是全局的.(后面会说到)   需要了解的一些知识:   1.windows内存的结构属性和进程地址空间   2.函数堆栈的一些知识 二:win2000和xp的内存结构和进程地址空间 windows采用4GB平坦虚拟地址空间的做法。即每个进程单独拥有4GB的地址空间。每个进程只能访问自己的这4GB的虚拟空间,而对于其他进程的地址空间则是不可见的。这样保证了进程的安全性和稳定性。但是,这4GB的空间是一个虚拟空间,在使用之前,我们必须先保留一段虚拟地址,然后再为这段虚拟地址提交物理存储器。可是我们的内存大部分都还没有1GB,那么这4GB的地址空间是如何实现的呢?事实上windows采用的内存映射这种方法,即把物理磁盘当作内存来使用,比如我们打开一个可执行文件的时候,操作系统会为我们开辟这个4GB的地址空间:0x00000000--0xffffffff。其中0x00000000--0x7fffffff是属于用户层的空间.0x80000000--0xffffffff则属于共享内核方式分区,主要是操作系统的线程调度,内存管理,文件系统支持,网络支持和所有设备驱动程序。对于用户层的进程,这些地址空间是不可访问的。任何访问都将导致一个错误。开辟这4GB的虚拟地址空间之后,系统会把磁盘上的执行文件映射到进程的地址空间中去(一般是在地址0x00400000,可以通过修改编译选项来修改这个地址)而一个进程运行所需要的动态库文件则一般从0x10000000开始加载。但是如果所有的动态库都加载到这个位置肯定会引起冲突。因此必须对一些可能引起冲突的dll编译时重新修改基地址。但是对于所有的操作系统所提供的动态库windows已经定义好了映射在指定的位置。这个位置会随着版本的不同而会有所改变,不过对于同一台机器上的映射地址来说都是一样的。即在a进程里映射的kernel32.dll的地址和在进程b里的kernel32.dll的地址是一样的。对于文件映射是一种特殊的方式,使得程序不需要进行磁盘i/o就能对磁盘文件进行操作,而且支持多种保护属性。对于一个被映射的文件,主要是使用CreateFileMapping函数,利用他我们可以设定一些读写属性:PAGE_READONLY,PAGE_READWRITE,PAGE_WRITECOPY.第一参数指定只能对该映射文件进行读操作。任何写操作将导致内存访问错误。第二个参数则指明可以对映射文件进行读写。这时候,任何对文件的读写都是直接操作文件的。而对于第三个参数PAGE_WRITECOPY顾名思义就是写入时拷贝,任何向这段内存写入的操作(因为文件是映射到进程地址空间的,对这段空间的读写就相当于对文件进行的直接读写)都将被系统捕获,并重新在你的虚拟地址空间重新保留并分配一段内存,你所写入的一切东西都将在这里,而且你原先的指向映射文件的内存地址也会实际指向这段重新分配的内存,于是在进程结束后,映射文件内容并没有改变,只是在运行期间在那段私有拷贝的内存里面存在着你修改的内容。windows进程运行所需要映射的一些系统dll就是以这种方式映射的,比如常用的ntdll.dll,kernel32.dll,gdi32.dll.几乎所有的进程都会加载这三个动态库。如果你在一个进程里修改这个映射文件的内容,并不会影响到其他的进程使用他们。你所修改的只是在本进程的地址空间之内的。事实上原始文件并没有被改变。 这样,在后面的修改系统api的时候,实际就是修改这些动态库地址内的内容。前面说到这不是修改全局api就是这个原因,因为他们都是以写入时拷贝的方式来映射的。不过这已经足够了,windows提供了2个强大的内存操作函数ReadProcessMemory和WriteProcessMemory.利用这两个函数我们就可以随便对任意进程的任意用户地址空间进行读写了。但是,现在有一个问题,我们该写什么,说了半天,怎么实现跳转呢?现在来看一个简单的例子: MessageBox(NULL, "World", "Hello", 0); 我们在执行这条语句的时候,调用了系统api MessageBox,实际上在程序中我没有定义UNICODE宏,系统调用的是MessageBox的ANSI版本MessageBoxA,这个函数是由user32.dll导出的。下面是执行这条语句的汇编代码: 0040102A push 0 0040102C push offset string "Hello" (0041f024) 00401031 push offset string "World" (0041f01c) 00401036 push 0 00401038 call dword ptr [__imp__MessageBoxA@16 (0042428c)] 前面四条指令分别为参数压栈,因为MessageBoxA是__stdcall调用约定,所以参数是从右往左压栈的。最后再CALL 0x0042428c 看看0042428c这段内存的值: 0042428C 0B 05 D5 77 00 00 00 可以看到这个值0x77d5050b,正是user32.dll导出函数MessageBoxA的入口地址。 这是0x77D5050B处的内容, 77D5050B 8B FF mov edi,edi 77D5050D 55 push ebp 77D5050E 8B EC mov ebp,esp 理论上只要改变api入口和出口的任何机器码,都可以拦截该api。这里我选择最简单的修改方法,直接修改qpi入口的前十个字节来实现跳转。为什么是十字节呢?其实修改多少字节都没有关系,只要实现了函数的跳转之后,你能把他们恢复并让他继续运行才是最重要的。在CPU的指令里,有几条指令可以改变程序的流程:JMP,CALL,INT,RET,RETF,IRET等指令。这里我选择CALL指令,因为他是以函数调用的方式来实现跳转的,这样可以带一些你需要的参数。到这里,我该说说函数的堆栈了。 总结:windows进程所需要的动态库文件都是以写入时拷贝的方式映射到进程地址空间中的。这样,我们只能拦截指定的进程。修改目标进程地址空间中的指定api的入口和出口地址之间的任意数据,使之跳转到我们的拦截代码中去,然后再恢复这些字节,使之能顺利工作。 三:函数堆栈的一些知识 正如前面所看到MessageBoxA函数执行之前的汇编代码,首先将四个参数压栈,然后CALL MessageBoxA,这时候我们的线程堆栈看起来应该是这样的: | | <---ESP |返回地址| |参数1| |参数2| |参数3| |参数4| |.. | 我们再看MessageBoxA的汇编代码, 77D5050B 8B FF mov edi,edi 77D5050D 55 push ebp 77D5050E 8B EC mov ebp,esp 注意到堆栈的操作有PUSH ebp,这是保存当前的基址指针,以便一会儿恢复堆栈后返回调用线程时使用,然后再有mov ebp,esp就是把当前esp的值赋给ebp,这时候我们就可以使用 ebp+偏移 来表示堆栈中的数据,比如参数1就可以表示成[ebp+8],返回地址就可以表示成[ebp+4]..如果我们在拦截的时候要对这些参数和返回地址做任何处理,就可以使用这种方法。如果这个时候函数有局部变量的话,就通过减小ESP的值的方式来为之分配空间。接下来就是保存一些寄存器:EDI,ESI,EBX.要注意的是,函数堆栈是反方向生长的。这时候堆栈的样子: |....| |EDI| <---ESP |ESI| |EBX| |局部变量| |EBP | |返回地址| |参数1| |参数2| |参数3| |参数4| |.. | 在函数返回的时候,由函数自身来进行堆栈的清理,这时候清理的顺序和开始入栈的顺序恰恰相反,类似的汇编代码可能是这样的: pop edi pop esi pop ebx add esp, 4 pop ebp ret 0010 先恢复那些寄存器的值,然后通过增加ESP的值的方式来释放局部变量。这里可以用mov esp, ebp来实现清空所有局部变量和其他一些空闲分配空间。接着函数会恢复EBP的值,利用指令POP EBP来恢复该寄存器的值。接着函数运行ret 0010这个指令。该指令的意思是,函数把控制权交给当前栈顶的地址的指令,同时清理堆栈的16字节的参数。如果函数有返回值的话,那在EAX寄存器中保存着当前函数的返回值。如果是__cdecl调用方式,则执行ret指令,对于堆栈参数的处理交给调用线程去做。如wsprintf函数。 这个时候堆栈又恢复了原来的样子。线程得以继续往下执行... 在拦截api的过程之中一个重要的任务就是保证堆栈的正确性。你要理清每一步堆栈中发生了什么。 四:形成思路 呵呵,不知道你现在脑海是不是有什么想法。怎么去实现拦截一个api? 这里给出一个思路,事实上拦截的方法真的很多,理清了一个,其他的也就容易了。而且上面所说的2个关键知识,也可以以另外的形式来利用。 我以拦截CreateFile这个api为例子来简单说下这个思路吧: 首先,既然我们要拦截这个api就应该知道这个函数在内存中的位置吧,至少需要知道从哪儿入口。CreateFile这个函数是由kernel32.dll这个动态库导出的。我们可以使用下面的方法来获取他映射到内存中的地址: HMODULE hkernel32 = LoadLibrary("Kernel32.dll"); PVOID dwCreateFile = GetProcAddress(hkernei32, "CreateFileA"); 这就可以得到createfile的地址了,注意这里是获取的createfile的ansic版本。对于UNICODE版本的则获取CreateFileW。这时dwCreateFile的值就是他的地址了。对于其他进程中的createfile函数也是这个地址,前面说过windows指定了他提供的所有的dll文件的加载地址。 接下来,我们该想办法实现跳转了。最简单的方法就是修改这个api入口处的代码了。但是我们该修改多少呢?修改的内容为什么呢?前面说过我们可以使用CALL的方式来实现跳转,这种方法的好处是可以为你的拦截函数提供一个或者多个参数。这里只要一个参数就足够了。带参数的函数调用的汇编代码是什么样子呢,前面也已经说了,类似与调用MessageBoxA时的代码: PUSH 参数地址 CALL 函数入口地址(这里为一个偏移地址) 执行这2条指令就能跳转到你要拦截的函数了,但是我们该修改成什么呢。首先,我们需要知道这2条指令的长度和具体的机器代码的值。其中PUSH对应0x68,而CALL指令对应的机器码为0xE8,而后面的则分别对应拦截函数的参数地址和函数的地址。注意第一个是一个直接的地址,而第二个则是一个相对地址。当然你也可以使用0xFF0x15这个CALL指令来进行直接地址的跳转。 下面就是计算这2个地址的值了, 对于参数和函数体的地址,要分情况而定,对于对本进程中api的拦截,则直接取地址就可以了。对于参数,可以先定义一个参数变量,然后取变量地址就ok了。 如果是想拦截其他进程中的api,则必须使用其他一些方法,最典型的方法是利用VirtualAllocEx函数来在其他进程中申请和提交内存空间。然后用WriteProcessMemory来分别把函数体和参数分别写入申请和分配的内存空间中去。然后再生成要修改的数据,最后用WriteProcessMemory来修改api入口,把入口的前10字节修改为刚刚生成的跳转数据。比如在远程进程中你写入的参数和函数体的内存地址分别为0x00010000和0x00011000,则生成的跳转数据为 68 00 00 01 00 E8 00 10 01 00(PUSH 00010000 CALL 00011000),这样程序运行createfile函数的时候将会先运行PUSH 00010000 CALL 00011000,这样就达到了跳转的目的。此刻我们应该时刻注意堆栈的状态,对于CreateFile有 HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); 可以看到其有7个参数,于是在调用之前,堆栈应该已经被压入了这7个参数,堆栈的样子: |....| <---ESP |createfile执行后的下一条指令地址| |参数1| |参数2| |参数3| |参数4| |参数5| |参数6| |参数7| |..| 这是执行到我们的跳转语句:PUSH 00010000,于是堆栈又变了: |....| <---ESP |00010000| |createfile执行后的下一条指令地址| |参数1| |参数2| |参数3| |参数4| |参数5| |参数6| |参数7| |..| 接着执行CALL 00011000,堆栈变为: |...| <---ESP |api入口之后的第六个字节的指令的地址| |00010000| |createfile执行后的下一条指令地址| |参数1| |参数2| |参数3| |参数4| |参数5| |参数6| |参数7| |..| 接下来就到了我们的拦截函数中拉,当然,函数肯定也会做一些类似动作,把EBP压栈,为局部变量分配空间等。这时候堆栈的样子又变了: |EDI| <---ESP |ESI| |EBX| |局部变量| |EBP| dwMessageBox; pfnMessageBox(NULL, PFileName, PFileName, MB_ICONINFORMATION |MB_OK); //输出要打开的文件的路径..... } 对于你要使用的其他函数,都是使用同样的方式,利用这个参数来传递我们要传递的函数的绝对地址,然后定义这个函数指针,就可以使用了。 好了,接下来我们该让被拦截的api正常工作了,这个不难,把他原来的数据恢复一下就可以了。那入口的10个字节。我们在改写他们的时候应该保存一下,然后也把他放在参数中传递给拦截函数,呵呵,参数的作用可多了。接着我们就可以用WriteProcessMemory函数来恢复这个api的入口了,代码如下: PFN_GETCURRENTPROCESS pfnGetCurrentProcess = (PFN_GETCURRENTPROCESS)pRP->dwGetCurrentProcess; PFN_WRITEPROCESSMEMORY pfnWriteProcessMemory = (PFN_WRITEPROCESSMEMORY)pRP->dwWriteProcessMemory; if(!pfnWriteProcessMemory(pfnGetCurrentProcess(), (LPVOID)pfnConnect, (LPCVOID)pRP->szOldCode, 10, NULL)) pfnMessageBox(NULL, pRP->szModuleName1, pRP->szModuleName2, MB_ICONINFORMATION | MB_OK); 其中这些函数指针的定义和上面的类似。 而参数中的szoldcode则是在源程序中在修改api之前保存好,然后传给拦截函数,在源程序中是用ReadProcessMemory函数来获取他的前10个字节的: ReadProcessMemory(GetCurrentProcess(), (LPCVOID)RParam.dwCreateFile, oldcode, 10, &dwPid) strcat((char*)RParam.szOldCode, (char*)oldcode); 接下来如果你还继续保持对该api的拦截,则又该用WriteProcessMemory 来修改入口了,跟前面的恢复入口是一样的,只不过把szOldCode换成了szNewCode了而已。这样你又能对CreateFile继续拦截了。 好了,接下来该进行堆栈的清理了,也许你还要做点其他事情,尽管做去。但是清理堆栈是必须要做的,在函数结束的时候,因为在我们放任api恢复执行之后,他又return 到我们的函数中来了,这个时候的堆栈是什么样子呢? |EDI| <---ESP |ESI| |EBX| |局部变量| |EBP| <---EBP |api入口之后的第六个字节的指令的地址| |00010000| |createfile执行后的下一条指令地址| |参数1| |参数2| |参数3| |参数4| |参数5| |参数6| |参数7| |..| 我们的目标是把返回值记录下来放到EAX寄存器中去,把返回地址记录下来,同时把堆栈恢复成原来的样子。 首先我们恢复那些寄存器的值,接着释放局部变量,可以用mov esp, ebp.因为我们不清楚具体的局部变量分配了多少空间。所以使用这个方法。 __asm {POP EDI POP ESI POP EBX //恢复那些寄存器 MOV EDX, [NextIpAddr]//把返回地址放到EDX中,因为待会儿 //EBP被恢复后,线程中的所有局部变量就不能正常使用了。 MOV EAX, [RetValue]//返回值放到EAX中,当然也可以修改这个返回值 MOV ESP, EBP//清理局部变量 POP EBP//恢复EBP的值 ADD ESP, 28H //清理参数和返回地址,注意一共(7+1+1+1)*4 PUSH EDX //把返回地址压栈,这样栈中就只有这一个返回地址了,返回之后栈就空了 RET } 这样,一切就完成了,堆栈恢复了应该有的状态,而你想拦截的也拦截到了。 五:后记 拦截的方式多种多样,不过大体的思路却都相同。要时刻注意你要拦截的函数的堆栈状态以及在拦截函数中的对数据的引用和函数的调用(地址问题)。
Hook API Lib 0.5.rar Hook API Lib 0.51.rar /* ////////////////////////////////////////////////////////////////////////// HookApi 0.5 thanks to xIkUg ,sucsor by 海风月影[RCT] , eIcn#live.cn 2008.04.15 ////////////////////////////////////////////////////////////////////////// //更新内容 2008.04.15 0.5 1,重新写了Stub,换了一种模式,使hook更加自由,将hookbefore和hookafter合并 HookProc的定义方式与以前有所不同: HookProc的函数类型和原来的api一样,只是参数比原API多2个 DWORD WINAPI HookProc(DWORD RetAddr ,__pfnXXXX pfnXXXX, ...); //参数比原始的API多2个参数 RetAddr //调用api的返回地址 pfnXXX //类型为__pfnXXXX,待hook的api的声明类型,用于调用未被hook的api 详见My_LoadLibraryA 原始的LoadLibraryA的声明是: HMODULE WINAPI LoadLibraryA( LPCSTR lpLibFileName ); 那么首先定义一下hook的WINAPI的类型 typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR lpFileName); 然后hookproc的函数声明如下: HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr, __pfnLoadLibraryA pfnLoadLibraryA, LPCTSTR lpFileName ); 比原来的多了2个参数,参数位置不能颠倒,在My_LoadLibraryA中可以自由的调用未被hook的pfnLoadLibraryA 也可以调用系统的LoadLibraryA,不过要自己在hookproc中处理好重入问题 另外,也可以在My_LoadLibraryA中使用UnInstallHookApi()函数来卸载hook,用法如下: 将第二个参数__pfnLoadLibraryA pfnLoadLibraryA强制转换成PHOOKENVIRONMENT类型,使用UnInstallHookApi来卸载 例如: UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA); 至于以前版本的HookBefore和HookAfter,完全可以在自己的HookProc里面灵活使用了 2,支持卸载hook InstallHookApi()调用后会返回一个PHOOKENVIRONMENT类型的指针 需要卸载的时候可以使用UnInstallHookApi(PHOOKENVIRONMENT pHookEnv)来卸载 在HookProc中也可以使用UnInstallHookApi来卸载,参数传入HookProc中的第二个参数 ★★注意: 1,如果在HookProc中自己不调用API(pfnXXXXX()),那么返回后,Stub是不会调用的,切记! 2,当HookProc中使用UnInstallHookApi卸载完后就不能用第二个参数来调用API了(pfnXXXX()),切记! 2008.04.15 0.41 1,前面的deroko的LdeX86 有BUG,678b803412 会算错 换了一个LDX32,代码更少,更容易理解 2,修复了VirtualProtect的一个小BUG 0.4以前 改动太大了,前面的就不写了 */ #include #include #include "HookApi.h" BYTE JMPGate[5] = { 0xE9, 0x00, 0x00, 0x00, 0x00 // JMP XXXXXXXX }; ////////////////////////////////////////////////////////////////////////// //另一个LDX32 #define C_ERROR 0xFFFFFFFF #define C_PREFIX 0x00000001 #define C_66 0x00000002 #define C_67 0x00000004 #define C_DATA66 0x00000008 #define C_DATA1 0x00000010 #define C_DATA2 0x00000020 #define C_DATA4 0x00000040 #define C_MEM67 0x00000080 #define C_MEM1 0x00000100 #define C_MEM2 0x00000200 #define C_MEM4 0x00000400 #define C_MODRM 0x00000800 #define C_DATAW0 0x00001000 #define C_FUCKINGTEST 0x00002000 #define C_TABLE_0F 0x00004000 DWORD table_1[256] = { /* 00 */ C_MODRM /* 01 */, C_MODRM /* 02 */, C_MODRM /* 03 */, C_MODRM /* 04 */, C_DATAW0 /* 05 */, C_DATAW0 /* 06 */, 0 /* 07 */, 0 /* 08 */, C_MODRM /* 09 */, C_MODRM /* 0A */, C_MODRM /* 0B */, C_MODRM /* 0C */, C_DATAW0 /* 0D */, C_DATAW0 /* 0E */, 0 /* 0F */, C_TABLE_0F /* 10 */, C_MODRM /* 11 */, C_MODRM /* 12 */, C_MODRM /* 13 */, C_MODRM /* 14 */, C_DATAW0 /* 15 */, C_DATAW0 /* 16 */, 0 /* 17 */, 0 /* 18 */, C_MODRM /* 19 */, C_MODRM /* 1A */, C_MODRM /* 1B */, C_MODRM /* 1C */, C_DATAW0 /* 1D */, C_DATAW0 /* 1E */, 0 /* 1F */, 0 /* 20 */, C_MODRM /* 21 */, C_MODRM /* 22 */, C_MODRM /* 23 */, C_MODRM /* 24 */, C_DATAW0 /* 25 */, C_DATAW0 /* 26 */, C_PREFIX /* 27 */, 0 /* 28 */, C_MODRM /* 29 */, C_MODRM /* 2A */, C_MODRM /* 2B */, C_MODRM /* 2C */, C_DATAW0 /* 2D */, C_DATAW0 /* 2E */, C_PREFIX /* 2F */, 0 /* 30 */, C_MODRM /* 31 */, C_MODRM /* 32 */, C_MODRM /* 33 */, C_MODRM /* 34 */, C_DATAW0 /* 35 */, C_DATAW0 /* 36 */, C_PREFIX /* 37 */, 0 /* 38 */, C_MODRM /* 39 */, C_MODRM /* 3A */, C_MODRM /* 3B */, C_MODRM /* 3C */, C_DATAW0 /* 3D */, C_DATAW0 /* 3E */, C_PREFIX /* 3F */, 0 /* 40 */, 0 /* 41 */, 0 /* 42 */, 0 /* 43 */, 0 /* 44 */, 0 /* 45 */, 0 /* 46 */, 0 /* 47 */, 0 /* 48 */, 0 /* 49 */, 0 /* 4A */, 0 /* 4B */, 0 /* 4C */, 0 /* 4D */, 0 /* 4E */, 0 /* 4F */, 0 /* 50 */, 0 /* 51 */, 0 /* 52 */, 0 /* 53 */, 0 /* 54 */, 0 /* 55 */, 0 /* 56 */, 0 /* 57 */, 0 /* 58 */, 0 /* 59 */, 0 /* 5A */, 0 /* 5B */, 0 /* 5C */, 0 /* 5D */, 0 /* 5E */, 0 /* 5F */, 0 /* 60 */, 0 /* 61 */, 0 /* 62 */, C_MODRM /* 63 */, C_MODRM /* 64 */, C_PREFIX /* 65 */, C_PREFIX /* 66 */, C_PREFIX+C_66 /* 67 */, C_PREFIX+C_67 /* 68 */, C_DATA66 /* 69 */, C_MODRM+C_DATA66 /* 6A */, C_DATA1 /* 6B */, C_MODRM+C_DATA1 /* 6C */, 0 /* 6D */, 0 /* 6E */, 0 /* 6F */, 0 /* 70 */, C_DATA1 /* 71 */, C_DATA1 /* 72 */, C_DATA1 /* 73 */, C_DATA1 /* 74 */, C_DATA1 /* 75 */, C_DATA1 /* 76 */, C_DATA1 /* 77 */, C_DATA1 /* 78 */, C_DATA1 /* 79 */, C_DATA1 /* 7A */, C_DATA1 /* 7B */, C_DATA1 /* 7C */, C_DATA1 /* 7D */, C_DATA1 /* 7E */, C_DATA1 /* 7F */, C_DATA1 /* 80 */, C_MODRM+C_DATA1 /* 81 */, C_MODRM+C_DATA66 /* 82 */, C_MODRM+C_DATA1 /* 83 */, C_MODRM+C_DATA1 /* 84 */, C_MODRM /* 85 */, C_MODRM /* 86 */, C_MODRM /* 87 */, C_MODRM /* 88 */, C_MODRM /* 89 */, C_MODRM /* 8A */, C_MODRM /* 8B */, C_MODRM /* 8C */, C_MODRM /* 8D */, C_MODRM /* 8E */, C_MODRM /* 8F */, C_MODRM /* 90 */, 0 /* 91 */, 0 /* 92 */, 0 /* 93 */, 0 /* 94 */, 0 /* 95 */, 0 /* 96 */, 0 /* 97 */, 0 /* 98 */, 0 /* 99 */, 0 /* 9A */, C_DATA66+C_MEM2 /* 9B */, 0 /* 9C */, 0 /* 9D */, 0 /* 9E */, 0 /* 9F */, 0 /* A0 */, C_MEM67 /* A1 */, C_MEM67 /* A2 */, C_MEM67 /* A3 */, C_MEM67 /* A4 */, 0 /* A5 */, 0 /* A6 */, 0 /* A7 */, 0 /* A8 */, C_DATA1 /* A9 */, C_DATA66 /* AA */, 0 /* AB */, 0 /* AC */, 0 /* AD */, 0 /* AE */, 0 /* AF */, 0 /* B0 */, C_DATA1 /* B1 */, C_DATA1 /* B2 */, C_DATA1 /* B3 */, C_DATA1 /* B4 */, C_DATA1 /* B5 */, C_DATA1 /* B6 */, C_DATA1 /* B7 */, C_DATA1 /* B8 */, C_DATA66 /* B9 */, C_DATA66 /* BA */, C_DATA66 /* BB */, C_DATA66 /* BC */, C_DATA66 /* BD */, C_DATA66 /* BE */, C_DATA66 /* BF */, C_DATA66 /* C0 */, C_MODRM+C_DATA1 /* C1 */, C_MODRM+C_DATA1 /* C2 */, C_DATA2 /* C3 */, 0 /* C4 */, C_MODRM /* C5 */, C_MODRM /* C6 */, C_MODRM+C_DATA66 /* C7 */, C_MODRM+C_DATA66 /* C8 */, C_DATA2+C_DATA1 /* C9 */, 0 /* CA */, C_DATA2 /* CB */, 0 /* CC */, 0 /* CD */, C_DATA1+C_DATA4 /* CE */, 0 /* CF */, 0 /* D0 */, C_MODRM /* D1 */, C_MODRM /* D2 */, C_MODRM /* D3 */, C_MODRM /* D4 */, 0 /* D5 */, 0 /* D6 */, 0 /* D7 */, 0 /* D8 */, C_MODRM /* D9 */, C_MODRM /* DA */, C_MODRM /* DB */, C_MODRM /* DC */, C_MODRM /* DD */, C_MODRM /* DE */, C_MODRM /* DF */, C_MODRM /* E0 */, C_DATA1 /* E1 */, C_DATA1 /* E2 */, C_DATA1 /* E3 */, C_DATA1 /* E4 */, C_DATA1 /* E5 */, C_DATA1 /* E6 */, C_DATA1 /* E7 */, C_DATA1 /* E8 */, C_DATA66 /* E9 */, C_DATA66 /* EA */, C_DATA66+C_MEM2 /* EB */, C_DATA1 /* EC */, 0 /* ED */, 0 /* EE */, 0 /* EF */, 0 /* F0 */, C_PREFIX /* F1 */, 0 // 0xF1 /* F2 */, C_PREFIX /* F3 */, C_PREFIX /* F4 */, 0 /* F5 */, 0 /* F6 */, C_FUCKINGTEST /* F7 */, C_FUCKINGTEST /* F8 */, 0 /* F9 */, 0 /* FA */, 0 /* FB */, 0 /* FC */, 0 /* FD */, 0 /* FE */, C_MODRM /* FF */, C_MODRM }; // table_1 DWORD table_0F[256] = { /* 00 */ C_MODRM /* 01 */, C_MODRM /* 02 */, C_MODRM /* 03 */, C_MODRM /* 04 */, -1 /* 05 */, -1 /* 06 */, 0 /* 07 */, -1 /* 08 */, 0 /* 09 */, 0 /* 0A */, 0 /* 0B */, 0 /* 0C */, -1 /* 0D */, -1 /* 0E */, -1 /* 0F */, -1 /* 10 */, -1 /* 11 */, -1 /* 12 */, -1 /* 13 */, -1 /* 14 */, -1 /* 15 */, -1 /* 16 */, -1 /* 17 */, -1 /* 18 */, -1 /* 19 */, -1 /* 1A */, -1 /* 1B */, -1 /* 1C */, -1 /* 1D */, -1 /* 1E */, -1 /* 1F */, -1 /* 20 */, -1 /* 21 */, -1 /* 22 */, -1 /* 23 */, -1 /* 24 */, -1 /* 25 */, -1 /* 26 */, -1 /* 27 */, -1 /* 28 */, -1 /* 29 */, -1 /* 2A */, -1 /* 2B */, -1 /* 2C */, -1 /* 2D */, -1 /* 2E */, -1 /* 2F */, -1 /* 30 */, -1 /* 31 */, -1 /* 32 */, -1 /* 33 */, -1 /* 34 */, -1 /* 35 */, -1 /* 36 */, -1 /* 37 */, -1 /* 38 */, -1 /* 39 */, -1 /* 3A */, -1 /* 3B */, -1 /* 3C */, -1 /* 3D */, -1 /* 3E */, -1 /* 3F */, -1 /* 40 */, -1 /* 41 */, -1 /* 42 */, -1 /* 43 */, -1 /* 44 */, -1 /* 45 */, -1 /* 46 */, -1 /* 47 */, -1 /* 48 */, -1 /* 49 */, -1 /* 4A */, -1 /* 4B */, -1 /* 4C */, -1 /* 4D */, -1 /* 4E */, -1 /* 4F */, -1 /* 50 */, -1 /* 51 */, -1 /* 52 */, -1 /* 53 */, -1 /* 54 */, -1 /* 55 */, -1 /* 56 */, -1 /* 57 */, -1 /* 58 */, -1 /* 59 */, -1 /* 5A */, -1 /* 5B */, -1 /* 5C */, -1 /* 5D */, -1 /* 5E */, -1 /* 5F */, -1 /* 60 */, -1 /* 61 */, -1 /* 62 */, -1 /* 63 */, -1 /* 64 */, -1 /* 65 */, -1 /* 66 */, -1 /* 67 */, -1 /* 68 */, -1 /* 69 */, -1 /* 6A */, -1 /* 6B */, -1 /* 6C */, -1 /* 6D */, -1 /* 6E */, -1 /* 6F */, -1 /* 70 */, -1 /* 71 */, -1 /* 72 */, -1 /* 73 */, -1 /* 74 */, -1 /* 75 */, -1 /* 76 */, -1 /* 77 */, -1 /* 78 */, -1 /* 79 */, -1 /* 7A */, -1 /* 7B */, -1 /* 7C */, -1 /* 7D */, -1 /* 7E */, -1 /* 7F */, -1 /* 80 */, C_DATA66 /* 81 */, C_DATA66 /* 82 */, C_DATA66 /* 83 */, C_DATA66 /* 84 */, C_DATA66 /* 85 */, C_DATA66 /* 86 */, C_DATA66 /* 87 */, C_DATA66 /* 88 */, C_DATA66 /* 89 */, C_DATA66 /* 8A */, C_DATA66 /* 8B */, C_DATA66 /* 8C */, C_DATA66 /* 8D */, C_DATA66 /* 8E */, C_DATA66 /* 8F */, C_DATA66 /* 90 */, C_MODRM /* 91 */, C_MODRM /* 92 */, C_MODRM /* 93 */, C_MODRM /* 94 */, C_MODRM /* 95 */, C_MODRM /* 96 */, C_MODRM /* 97 */, C_MODRM /* 98 */, C_MODRM /* 99 */, C_MODRM /* 9A */, C_MODRM /* 9B */, C_MODRM /* 9C */, C_MODRM /* 9D */, C_MODRM /* 9E */, C_MODRM /* 9F */, C_MODRM /* A0 */, 0 /* A1 */, 0 /* A2 */, 0 /* A3 */, C_MODRM /* A4 */, C_MODRM+C_DATA1 /* A5 */, C_MODRM /* A6 */, -1 /* A7 */, -1 /* A8 */, 0 /* A9 */, 0 /* AA */, 0 /* AB */, C_MODRM /* AC */, C_MODRM+C_DATA1 /* AD */, C_MODRM /* AE */, -1 /* AF */, C_MODRM /* B0 */, C_MODRM /* B1 */, C_MODRM /* B2 */, C_MODRM /* B3 */, C_MODRM /* B4 */, C_MODRM /* B5 */, C_MODRM /* B6 */, C_MODRM /* B7 */, C_MODRM /* B8 */, -1 /* B9 */, -1 /* BA */, C_MODRM+C_DATA1 /* BB */, C_MODRM /* BC */, C_MODRM /* BD */, C_MODRM /* BE */, C_MODRM /* BF */, C_MODRM /* C0 */, C_MODRM /* C1 */, C_MODRM /* C2 */, -1 /* C3 */, -1 /* C4 */, -1 /* C5 */, -1 /* C6 */, -1 /* C7 */, -1 /* C8 */, 0 /* C9 */, 0 /* CA */, 0 /* CB */, 0 /* CC */, 0 /* CD */, 0 /* CE */, 0 /* CF */, 0 /* D0 */, -1 /* D1 */, -1 /* D2 */, -1 /* D3 */, -1 /* D4 */, -1 /* D5 */, -1 /* D6 */, -1 /* D7 */, -1 /* D8 */, -1 /* D9 */, -1 /* DA */, -1 /* DB */, -1 /* DC */, -1 /* DD */, -1 /* DE */, -1 /* DF */, -1 /* E0 */, -1 /* E1 */, -1 /* E2 */, -1 /* E3 */, -1 /* E4 */, -1 /* E5 */, -1 /* E6 */, -1 /* E7 */, -1 /* E8 */, -1 /* E9 */, -1 /* EA */, -1 /* EB */, -1 /* EC */, -1 /* ED */, -1 /* EE */, -1 /* EF */, -1 /* F0 */, -1 /* F1 */, -1 /* F2 */, -1 /* F3 */, -1 /* F4 */, -1 /* F5 */, -1 /* F6 */, -1 /* F7 */, -1 /* F8 */, -1 /* F9 */, -1 /* FA */, -1 /* FB */, -1 /* FC */, -1 /* FD */, -1 /* FE */, -1 /* FF */, -1 }; // table_0F #pragma comment(linker, "/SECTION:HookStub,RW") #define NAKED __declspec(naked) #define ALLOCATE(x1) __declspec(allocate(#x1)) #define ALLOCATE_HookStub ALLOCATE(HookStub) #define ReloCationForADDR(x1,delta) ((DWORD(&x1) + delta)) #define ReloCationForDWORD(x1,delta) (*(LPDWORD(DWORD(&x1) + delta))) #define ReloCataonForTCHAR(x1,delta) (LPCTSTR(DWORD(&x1) + delta)) #define ReloCationForLP(x1,delta) (__##x1(ReloCationForDWORD(x1,delta))) #pragma code_seg("HookStub") #pragma optimize("",off) ALLOCATE_HookStub HOOKENVIRONMENT pEnv={0}; NAKED DWORD GetDelta() { __asm { call next next: pop eax sub eax,offset next ret } } NAKED void NewStub() { __asm { jmp next back: _emit 0xE9 NOP NOP NOP NOP next: push [esp] push [esp] push eax //保存一下Stub中唯一使用到的EAX call GetDelta lea eax,[eax+pEnv] mov dword ptr [esp+0xC],eax pop eax //恢复EAX jmp back } } NAKED DWORD GetEndAddr() { __asm { call next next: pop eax sub eax,5 ret } } #pragma optimize("",off) #pragma code_seg() DWORD __stdcall GetOpCodeSize(BYTE* iptr0) { BYTE* iptr = iptr0; DWORD f = 0; prefix: BYTE b = *iptr++; f |= table_1[b]; if (f&C_FUCKINGTEST) if (((*iptr)&0x38)==0x00) // ttt f=C_MODRM+C_DATAW0; // TEST else f=C_MODRM; // NOT,NEG,MUL,IMUL,DIV,IDIV if (f&C_TABLE_0F) { b = *iptr++; f = table_0F[b]; } if (f==C_ERROR) { //printf("error in X\n",b); return C_ERROR; } if (f&C_PREFIX) { f&=~C_PREFIX; goto prefix; } if (f&C_DATAW0) if (b&0x01) f|=C_DATA66; else f|=C_DATA1; if (f&C_MODRM) { b = *iptr++; BYTE mod = b & 0xC0; BYTE rm = b & 0x07; if (mod!=0xC0) { if (f&C_67) // modrm16 { if ((mod==0x00)&&(rm==0x06)) f|=C_MEM2; if (mod==0x40) f|=C_MEM1; if (mod==0x80) f|=C_MEM2; } else // modrm32 { if (mod==0x40) f|=C_MEM1; if (mod==0x80) f|=C_MEM4; if (rm==0x04) rm = (*iptr++) & 0x07; // rm<-sib.base if ((rm==0x05)&&(mod==0x00)) f|=C_MEM4; } } } // C_MODRM if (f&C_MEM67) if (f&C_67) f|=C_MEM2; else f|=C_MEM4; if (f&C_DATA66) if (f&C_66) f|=C_DATA2; else f|=C_DATA4; if (f&C_MEM1) iptr++; if (f&C_MEM2) iptr+=2; if (f&C_MEM4) iptr+=4; if (f&C_DATA1) iptr++; if (f&C_DATA2) iptr+=2; if (f&C_DATA4) iptr+=4; return iptr - iptr0; } PHOOKENVIRONMENT __stdcall InstallHookApi(PCHAR DllName,PCHAR ApiName,PVOID HookProc) { HMODULE DllHandle; PVOID ApiEntry; int ReplaceCodeSize; DWORD oldpro; DWORD SizeOfStub; DWORD delta; DWORD RetSize =0; PHOOKENVIRONMENT pHookEnv; if (HookProc == NULL) { return NULL; } DllHandle = GetModuleHandle(DllName); if (DllHandle == NULL) DllHandle = LoadLibrary(DllName); if (DllHandle == NULL) return NULL; ApiEntry = GetProcAddress(DllHandle,ApiName); if (ApiEntry == NULL) return NULL; ReplaceCodeSize = GetOpCodeSize((BYTE*)ApiEntry); while (ReplaceCodeSize < 5) ReplaceCodeSize += GetOpCodeSize((BYTE*)((DWORD)ApiEntry + (DWORD)ReplaceCodeSize)); if (ReplaceCodeSize > 16) return NULL; SizeOfStub = GetEndAddr()-(DWORD)&pEnv; pHookEnv = (PHOOKENVIRONMENT)VirtualAlloc(NULL,SizeOfStub,MEM_COMMIT,PAGE_READWRITE); memset((void*)&pEnv,0x90,sizeof(pEnv)); CopyMemory(pHookEnv,(PVOID)&pEnv,SizeOfStub); CopyMemory((void*)pHookEnv,(void*)&pEnv,sizeof(pEnv.savebytes)); CopyMemory(pHookEnv->savebytes,ApiEntry,ReplaceCodeSize); pHookEnv->OrgApiAddr = ApiEntry; pHookEnv->SizeOfReplaceCode = ReplaceCodeSize; pHookEnv->jmptoapi[0]=0xE9; *(DWORD*)(&pHookEnv->jmptoapi[1]) = (DWORD)ApiEntry + ReplaceCodeSize - ((DWORD)pHookEnv->jmptoapi + 5); //patch api if (!VirtualProtect(ApiEntry,ReplaceCodeSize,PAGE_EXECUTE_READWRITE,&oldpro)) return FALSE; delta = (DWORD)pHookEnv - (DWORD)&pEnv; *(DWORD*)(&JMPGate[1]) = ((DWORD)NewStub + delta) - ((DWORD)ApiEntry + 5); WriteProcessMemory(GetCurrentProcess(), ApiEntry, JMPGate, sizeof(JMPGate),&RetSize); if (!VirtualProtect(ApiEntry,ReplaceCodeSize,oldpro,&oldpro)) return FALSE; //写入变量 *(DWORD*)((DWORD)NewStub + delta + 3) = (DWORD)HookProc - ((DWORD)NewStub + delta + 3 + 4); return pHookEnv; } BOOL __stdcall UnInstallHookApi(PHOOKENVIRONMENT pHookEnv) { DWORD oldpro; DWORD RetSize; //如果内存不存在了,则退出 if(IsBadReadPtr((const void*)pHookEnv,sizeof(HOOKENVIRONMENT))) return FALSE; if(!VirtualProtect(pHookEnv->OrgApiAddr,pHookEnv->SizeOfReplaceCode,PAGE_EXECUTE_READWRITE,&oldpro)) return FALSE; WriteProcessMemory(GetCurrentProcess(),pHookEnv->OrgApiAddr,pHookEnv->savebytes,pHookEnv->SizeOfReplaceCode,&RetSize); if(!VirtualProtect(pHookEnv->OrgApiAddr,pHookEnv->SizeOfReplaceCode,oldpro,&oldpro)) return FALSE; VirtualFree((LPVOID)pHookEnv,0,MEM_RELEASE); return TRUE; } //定义下面这行可以作为演示使用 //#define TEST_MAIN #ifdef TEST_MAIN BOOL IsMe = FALSE; //先定义一下要hook的WINAPI typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR lpFileName); HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr, __pfnLoadLibraryA pfnLoadLibraryA, LPCTSTR lpFileName ) { HMODULE hLib; //需要自己处理重入和线程安全问题 if (!IsMe) { IsMe = TRUE; MessageBoxA(NULL,lpFileName,"test",MB_ICONINFORMATION); hLib = LoadLibrary(lpFileName);//这里调用的是系统的,已经被hook过的 IsMe = FALSE; //这里是卸载Hook,这里卸载完就不能用pfnLoadLibraryA来调用了 UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA); return hLib; } return pfnLoadLibraryA(lpFileName);//这里调用非hook的 } int main() { DWORD RetSize =0; DWORD dwThreadId; HANDLE hThread; PHOOKENVIRONMENT pHookEnv; pHookEnv = InstallHookApi("Kernel32.dll", "LoadLibraryA", My_LoadLibraryA); LoadLibrary("InjectDll.dll"); MessageBoxA(NULL,"Safe Here!!!","Very Good!!",MB_ICONINFORMATION); UnInstallHookApi(pHookEnv);//由于HookProc中卸载过了,所以这里的卸载就无效了 MessageBoxA(NULL,"UnInstall Success!!!","Good!!",MB_ICONINFORMATION); return 0; } #endif

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧