HOOK API 函数跳转详解

什么是HOOK API:

       Windows下暴露的对开发人员的接口叫做应用程序编程接口,就是我们常说的API。我们在写应用层应用程序软件的时候都是通过调用各种API来实现的。有些时候,我们需要监控其他程序调用的API,也就是,当其他应用程序调用我们感兴趣的API的时候,我们在他调用前有一个机会做自己的处理,这就是HOOK API的涵义。

  

思路:

       我们知道Windows系统API函数都是被封装到DLL中,在某个应用程序要调用一个API函数的时候,如果这个函数所在的DLL没有被加载到本进程中则加载它,然后保存当前环境(各个寄存器和函数调用完后的返回地址等)。接着程序会跳转到这个API函数的入口地址去执行此处的指令。由此看来,我们想在调用真正的API之前先调用我们的函数,那么可以修改这个API函数的入口处的代码,使他先跳转到我们的函数地址,然后在我们的函数最后再调用原来的API函数。下面以拦截WS2_32.dll中的recv函数为例说明拦截的主要过程。首先把自己编写的DLL挂接到系统当前运行的所有进程中(要排除一些Windows系统自身的进程,否则会出现问题,影响系统正常工作),挂接的意思是,要我们的DLL运行在目标进程的地址空间中。可以使用列举系统进程然后用远程线程注入的方法,但是这种方法只适用于Win2000以上的操作系统。

 

       当我们的DLL被所有目标进程加载后,我们就可以进行真正的工作了。首先使用Tool Help库的相关函数列举目标进程加载的所有模块,看看是否有ws2_32.dll,如果没有,说明这个进程没有使用Winsock提供的函数,那么我们就不用再给这个进程添乱了。如果找到ws2_32.dll模块,那么OK,我们可以开工了。先是用GetProcAddress函数获得进程中ws2_32.dll模块的recv函数的入口地址,也就是函数的起始地址。刚才说过,我们想把recv函数起始位置加入一条跳转指令,让它先跳转到我们的函数中运行。跳转指令可以用0xE9来表示(0xE9是汇编语言中CALL指令的机器码)后面还有4个字节的我们函数的相对地址。也就是我们要修改recv函数前5个字节。这5个字节由1个字节的跳转指令和4个字节的地址组成。这样当程序运行到这里的时候,将会跳转到这4个字节表示的地址处去运行代码。还要注意的是这4个字节的地址是偏移地址,而偏移地址 = 我们函数的地址 - 原API函数的地址 - 5(我们这条指令的长度)好了,别忘了我们要先读取稍后要被覆盖的recv函数入口处的5个字节的内容,把它保存起来留着以后恢复时使用。因为在我们的函数中要想调用真正的recv的时候,必须把它前5个字节恢复了,他才能正常工作呢。

 

       通过上面的说明,我们可以整理出这样的一个流程:

 

1.  保存recv的前5个字节的内容

2.  把recv的前5个字节的内容改变成CALL xxxx(xxxx是我们的函数的偏移地址)

3.  在我们的函数中恢复recv的前5个字节的内容,并作处理。

4.  我们的函数返回后,再把recv的前5个字节的内容改变成CALL xxxx

慢着,你一定发现问题了吧?当我们为了调用原来的recv函数而刚刚把recv入口处的5个字节恢复,这时系统中的其他线程调用了recv函数,而这个调用将会成为漏网之鱼而不会进入到我们的函数中来。简单的解决办法是使用临界对象CriticalSection保证同时只能有一个线程对recv函数入口处5个字节进行读写操作。

 

最后记得在你想要停止拦截的时候恢复所有你修改过的进程和这些进程中被修改的API的前5个字节。其实原理讲着容易,在实现的时候会遇到各种各样的问题,如98下这些系统的DLL被加载到系统内存区供应用程序共享,所以这些内存是受保护的,不能随意修改,还有nt/2000下权限问题,还要考虑到不要拦截某些系统进程,否则会带来灾难性的后果。这些都是在实践当中遇到的实际问题。

 

下面结合代码给大家讲解一下吧,首先我们要实现HOOK模块,我们给它起个名字叫做MainHookDll.DLL。在此模块中,主要要实现一个CHookApi的类,这个类完成主要的拦截功能,也是整个项目的技术核心和难点,后面将具体介绍它。而且,MainHookDll模块就是将来要注入到系统其它进程的模块,而远程调用函数是非常困难的事情,所以我们设计此模块的时候应让其被加载后自动执行拦截的初始化等工作。这样,我们只需要让远程的进程加载HOOK,然后MainHookDll.dll就能够自动执行其它操作从而HOOK该进程的相关API。 

 

MainHookDll模块中的CHookApi类拥有2个向外部提供的主要的方法,HookAllAPI,表示拦截指定进程中的指定API和UnhookAllAPI,表示取消拦截指定进程中的指定API。进行具体设计的时候,会遇到一个问题。大家看到,上文所说的开始将原始API的前5个字节写成CALL XXXX,而在我们的替换函数中要恢复保存的API原始的5个字节,在调用完成后又要把API前5个字节改为CALL XXXX。如果我们拦截多个API要在每个替换函数中按照如上的方法进行设置,这样虽然我们自己明白,但是可能您只是实现HOOKAPI部分,而别人实现调用,这样会使代码看起来很难维护,在别人写的替换函数中加上这些莫名奇妙的语句看来不是一个好主意,当需要拦截多个感兴趣的API函数,那样的话将会在每一个要拦截的函数里都有这些莫名其妙的代码将会是件很恶心得事情。而且对于CALL XXXX中的地址,要对于不同的API设置不同的替换函数地址。那么能不能把这些所有的函数归纳为一个函数,所有的API函数前5字节都改为CALL到这个函数的地址,这个函数先恢复API的前5字节,然后调用用户真正的替换函数,然后再设置API函数的前5字节,这样可以使真正的替换函数只做自己应该做的事情,而跟HOOK API相关的操作都由我们的通用函数来干。 

 

这样的想法是好的,但是有一个突出问题,因为替换函数的函数声明与原API一致,所以对于要拦截的不同的API,它们的的参数和返回值是不一样的。那我们怎样通过一个函数获得用户传递给API的参数,然后使用这些参数调用替换函数,最后把替换函数的返回值再返回给调用API的客户?要想实现这个功能,我们需要了解一个知识,也就是C++究竟是怎样调用一个函数的。我们以ws2_32.dll中提供的recv函数为例进行说明,recv函数的声明如下:

 

        int recv(

            SOCKET s,

            char* buf,

        int len,

            int flags

            );

 

可以看出它具有4个参数,返回值类型是int。我们作如下调用:

        recv(s,buf,buflen,0);

 

    那么在调用recv前,这四个参数将按照从右向左的顺序压到栈中,然后用Call指令跳转到recv函数的地址继续执行。recv可以从栈中取出参数并执行其他功能,最后返回时返回值将被保存在寄存器EAX中。最后还要说明一点的是,在汇编语言看来这些参数和返回值都是以DWORD类型表示的,所以如果是大于4字节的值,就用这4个字节表示值所在的地址。

 

有了这些知识我们就可以想到,如果用户调用recv函数并被拦截跳转到我们的函数中运行,但是我们并不知道有多少个参数和返回值,那么我们可以从栈中取出参数,但是参数的个数需要提供,当然我们可以在前面为每个API函数指定相应的参数个数,然后运行真正的替换函数,最后在返回前把替换函数的返回值放到寄存器EAX中,这样就解决了不知道参数和返回值个数的问题。那么我们的函数应该是看起来无参数无返回值的。

        基本原理我们大家都清楚了,但是继续之前我还是想讲一讲几个汇编的知识,如果没有这些知识那么看下面的代码就好像天书一样。

 

 

 

关于参数

        我们讲过,在调用一个子函数前要把参数按顺序压栈,而子函数会从栈中取出参数。对于栈操作,我们一般使用EBP和ESP寄存器,而ESP是堆栈指针寄存器,所以多数情况下使用EBP寄存器对堆栈进行暂时操作。还是用调用recv函数为例,假设调用前ESP指向0x00000100处(程序运行时ESP是不可能为这个值的,此处只是为了举例说明问题)。先将参数一次压栈  

        push 0          // flags入栈 

        lea eax, [len]  

        push eax        // len入栈  

        lea eax, [buf]  

        push eax        // buf入栈 

        lea eax, [s]  

        push eax        // s入栈  

 

        下面使用call调用真正的recv函数,  

        call dword ptr [recv] // 调用recv 

 

        call指令先将返回地址压入栈中,返回地址就是CALL指令的下一条指令的地址,然后跳转到recv入口地址处继续执行。进入recv后,recv使用EBP临时访问堆栈之前,要保存EBP的当前内容,以便以后再使用(在 关于调用函数时保存各个寄存器的值 部分将详细讨论)。所以位于recv函数开始可能是这样的  

        push ebp    // 保存ebp的当前值 

        mov ebp,esp // 使把esp负给ebp 

 

堆栈指针

[ESP]

堆栈的内容

堆栈内容的含义

0x00000100

flags

参数

0x000000fc

len

参数

0x000000f8

buf

参数

0x000000f4

s

参数

0x000000f0

RetAddress

返回的地址

0x00000ec

OldEBP

保存EBP的当前值

  

     到此,我们可以知道,如果现在要想通过EBP获得最后一个入栈的参数,那么需要用EBP+8来获得,因为最后一个入栈的参数被保存在返回地址和EBP原始值的上面(一定记住,栈是由高地址到低地址的)。而返回地址被放在EBP+4处,EBP的原始值放在EBP+0处。

     关于调用函数时保存各个寄存器的值
        当我们要调用其它函数的时候,程序应该先保存各个寄存器的值,然后转去调用其它函数,最后会恢复各个寄存器的值使它们恢复成调用其它函数之前的状态。当然我们使用高级语言写程序的时候,编译器为我们做了这些事情。使用vc调试程序,打开反汇编窗口。运行一个简单的程序,该程序调用一个我们自己写的简单函数,在这个简单函数中设置断点,可以看到,编译器生成的汇编代码使用堆栈保存各个寄存器的值,上面提到当执行一个函数的时候,首先保存的是EBP的值,然后依次压入栈中保存的寄存器为EBX、ESI、EDI,我们在恢复这些寄存器的值的时候将逆向出栈来完成。

 


 

    关于函数调用的返回

 

        调用子函数前ESP指针会因为压栈参数而改变,然后压入返回地址等,子函数中会使用ret指令从栈中取出返回地址并跳转到返回地址,而在子函数返回到CALL的下一条指令时栈中还保存着参数,所以我们需要手工的将栈中的参数所占用的空间释放,如在调用完成一个4个参数的子函数后,我们应该将ESP指针上移4*4个字节,如 

        add esp,16 

 

    这个操作在调用API的时候是不需要的,因为,windows API在函数中自己将参数弹出堆栈了。所以这就有一个调用约定的问题,默认情况下调用约定是__cdecl,表示参数从右向左入栈,由调用者清理参数。而windows API使用的是__stdcall调用,表示参数从右向左入栈,由函数自己清理参数。我们的程序API的替换函数使用__stdcall调用约定。所以不用考虑清理栈中的参数的问题,由替换函数自己处理。

 

 

 

    有了上面的知识,让我们回顾一下先前讨论的问题,首先,用户调用API的recv函数,程序运行到recv的入口地址处,此时堆栈中拥有用户调用recv的参数和用户代码中CALL [recv]的下一条指令的地址。堆栈如下图:

 

堆栈指针

[ESP]

堆栈的内容

堆栈内容的含义

0x00000100

0

参数

0x000000fc

len

参数

0x000000f8

buf

参数

0x000000f4

S

参数

0x000000f0

RetUserAddress

用户调用recv的下一条指令的地址

 

然后程序指针EIP被修改为recv入口处的地址,而入口地址处有一条简单的CALL指令,它使程序将recv的第6个字节的地址压入栈中(因为CALL XXXX占用5个字节,第六个字节被认为为返回地址),然后跳转到我们的无参数无返回值的通用替换函数中去了,好了看看现在堆栈中都有些什么?如图:

 

堆栈指针

[ESP]

堆栈的内容

堆栈内容的含义

0x00000100

0

参数

0x000000fc

len

参数

0x000000f8

buf

参数

0x000000f4

s

参数

0x000000f0

RetUserAddress

用户调用recv的下一条指令的地址

0x00000ec

RetrecvAddress

recv的第六个字节的地址

 

 

首先是参数,其次是用户调用recv后的返回值,然后是recv调用我们的替换函数中的返回值,紧接着就像刚才提到的那样,程序将EBP当前内容压入栈中。如图

 

 

堆栈指针[ESP]

 

 

 

 

堆栈的内容

 

 

 

 

堆栈内容的含义

 

 

 

 

0x00000100

 

 

 

 

0

 

 

 

 

参数

 

 

 

 

0x000000fc

 

 

 

 

len

 

 

 

 

参数

 

 

 

 

0x000000f8

 

 

 

 

buf

 

 

 

 

参数

 

 

 

 

0x000000f4

 

 

 

 

S

 

 

 

 

参数

 

 

 

 

0x000000f0

 

 

 

 

RetUserAddress

 

 

 

 

用户调用recv的下一条指令的地址

 

 

 

 

0x00000ec

 

 

 

 

RetrecvAddress

 

 

 

 

recv的第六个字节的地址

 

 

 

 

0x000000e8

 

 

 

 

OldEBP

 

 

 

 

保存的旧的EBP的内容,然后[EBP]= 0x000000e8

 

 

 

 

0x000000e4

 

 

 

 

OldEBX

 

 

 

 

保存的旧的EBX的内容

 

 

 

 

0x000000e0

 

 

 

 

OldESI

 

 

 

 

保存的旧的ESI的内容

 

 

 

 

0x000000dc

 

 

 

 

OldEDI

 

 

 

 

保存的旧的EDI的内容,此时[ESP]=0x000000dc

 

 

 

 

 

 

 此时我们可以看到,[EBP]为保存的ebp的值,现在对我们没有用处,函数返回前用于恢复EBP的值,[EBP+4]是recv函数的CALL XXXX后面指令的地址(也就是第六个字节的地址),我们可以通过将此值减去5来得到recv的入口地址,这样在我们所有hook的api函数的列表中进行检索,就可以匹配出用户调用的是哪一个API函数,从而为后面恢复和再次改变该API的入口5字节做准备,因为调用任何我们需要HOOK的API程序都会进入到这个无返回值无参数的函数,所以通过这种方法找到当前HOOK的是哪一个API,从而可以区分不同的API进行特殊的处理。[EBP+8]保存的是用户调用recv后的返回地址,由于我们执行完替换函数后,应该返回到这个地址,而不应该返回到recv的第6个字节处执行,所以我们还是需要保存下这个值,以便在我们用ret返回前把它压栈从而使程序返回到用户调用recv的下一条指令处继续运行。


我们现在实现它,请注意参考上面堆栈表格。

void CHookApi::CommonFunc(void)
{
     DWORD* pdwCall;// 保存被调用前压在栈中的返回地址,也就是Call XXXX 的地址
     DWORD* pdwESP;// 保存ESP内容
     DWORD* pdwParam;       // 第一个参数的地址
     DWORD dwParamSize; // 所有参数所占用的大小应该=4* dwParamCount
     DWORD dwRt;        // 保存返回值
     DWORD dwRtAddr;        // 我们的函数真正要返回的地址
     PROCESS_INFORMATION *pPi;// 进程信息
    // 得到栈中第一个参数的位置
     _asm 
     { 
         mov EAX,[EBP+8] 
         mov [dwRtAddr],EAX 
         lea EAX,[EBP+4]        // call XXXX所在的地址 
         mov [pdwCall],EAX 
         lea EAX, [EBP+12]  // 第一个参数所在地址 
         mov [pdwParam],EAX 
     } 
     (*pdwCall) -= 5; 
     vector<APIINFO*>::iterator it; 
     APIINFO* pai = NULL; 
     for(it = m_vpApiInfo.begin(); it != m_vpApiInfo.end(); it++) 
     { 
         APIINFO* papiinfo = *it; 
         if((DWORD)papiinfo->lfOrgApiAddr == *pdwCall) 
         { 
              pai = *it; 
              break;   
         } 
     } 
     if(pai == NULL) 
         return; 
     BYTE* pbtapi = (BYTE*)pai->lfOrgApiAddr; 
     dwParamSize = 4*pai->ParamCount; 
     EnterCriticalSection(&pai->cs); 
     // 恢复被修改的5个字节 
     memcpy(pbtapi,pai->OrgApiBytes,5); 
     pai->bIsHooked = FALSE; 
     // 构造参数 
     _asm 
     { 
         sub esp,[dwParamSize] 
         mov [pdwESP],esp 
     } 
     memcpy(pdwESP, pdwParam, dwParamSize); 
     COMMONFUNC myapifunc = (COMMONFUNC)pai->lfMyApiAddr; 
     _asm 
     { 
         call myapifunc // 调用替换API的函数 
         mov [dwRt],eax // 保存返回值 
     } 
     // 如果是CreateProcess,那么继续hook它 
     pPi = (PROCESS_INFORMATION*)pdwParam[9]; 
     if(strcmpi(pai->szOrgApiName,"CreateProcessA") != 0 || strcmpi(pai->szOrgApiName,"CreateProcessW") != 0) 
     { 
         InjectDll(pPi->dwProcessId,m_szDllPathName); 
     } 
     // 再修改5字节 
     pbtapi[0] = CALLCODE;//jmp 
     DWORD* pdwapi = (DWORD*)&(pbtapi[1]); 
     pdwapi[0] = (DWORD)CommonFunc - (DWORD)pbtapi - 5;// 我的api的地址偏移 
     pai->bIsHooked = TRUE; 
     LeaveCriticalSection(&pai->cs); 
     // 下面准备返回的操作 
     _asm 
     { 
         mov EDX,[dwRtAddr] // 保存返回地址 
         mov EAX,dwRt  // 设置返回值 
         mov ECX,[dwParamSize]  // 获得参数的大小 
         // 下面弹出所有保存的寄存器值(按照入栈的逆顺序) 
         pop EDI  // 恢复EDI 
         pop ESI // 恢复ESI 
         pop EBX // 恢复EBX 
         // 我们没有改动过EBP的值,所以EBP指向堆栈中OldEBP的位置 
         mov ESP,EBP 
         pop EBP // 恢复EBP 
         // 由于堆栈中还剩下参数和两个返回地址(我们真正要返回的地址和原始API中的第6个字节的地址),所以我们把这些数据也清除出堆栈 
         add ESP,8 // 清除两个返回地址 
         add ESP,ECX // 清除参数 
         // 由于调用ret返回时,程序先从堆栈中取出返回地址,所以我们把要真正返回的地址压入堆栈中 
         push EDX 
         ret // 返回 
     } 
}


要说明的一点是,如果要执行得API函数是CreateProcess,那么应该把它新开启得进程也HOOK掉。以上我们了解了通用替换函数的原理,那么让我们深入的讨论CHookApi类,并且实现它。

前面提到过,我们的CHookApi类主要向外部提供2个方法,HookAllAPI方法和UnhookAllAPI方法。当调用HookAllAPI的时候,将拦截系统所有用户程序中我们感兴趣的API函数。当调用UnhookAllAPI的时候,将撤销拦截。当拦截启动之前,我们应该将所有我们感兴趣的,即需要拦截的API信息(如API名称,对应的替换函数名称、参数个数等)交给CHookApi,CHookApi类内部才能完成所有的拦截工作。以下是CHookApi类的声明
 

(HookApi.h)
 

#include "../include/CommonHeader.h"  

#include <Psapi.h>  

#include <tlhelp32.h>  

#pragma comment(lib,"Psapi.lib")  

// 通用替换函数指针声明  

typedef void(*COMMONFUNC)(void);  

/* 
     CHookApi类实现了Hook的核心功能 

*/ 

class CHookApi 

{  

public:  

     // 构造函数 

     CHookApi(void);  

     // 析构函数  

     ~CHookApi(void); 

private: 

     // 自身路径  

     static char m_szDllPathName[MAX_PATH];  

     // 此容器包含所有要Hook的API信息(在类中使用的有效信息)  

     static vector<APIINFO*> m_vpApiInfo;  

     // 此容器包含所有要Hook的API信息(用户填写的信息)  

     vector<HOOKAPIINFO*>* m_vpHookApiInfo;  

     // 防火墙策略模块句柄  

     HMODULE m_hFireWall;  

     // 加载防火墙策略模块 

     BOOL LoadFireWallModule(void);  

     // 卸载防火墙策略模块  

     BOOL UnloadFireWallModule(void); 

public:  

     // 使用远程线程注入的方法将我们的DLL注入到指定进程  

     static int WINAPI InjectDll(DWORD dwProcessId, LPTSTR lpDllName);  

     // 使用远程线程注入的方法将我们的DLL卸载  

     static int WINAPI EjectLib(DWORD dwProcessId, LPTSTR lpDllName); 

protected:  

     // 通用替换函数,这是技术核心部分  

     static void CommonFunc(void);  

private:  

     // 初始化函数  

     BOOL Init(void);  

     // 挂钩一个指定API的函数 

     BOOL HookOneApi(APIINFO* pai);  

     // 挂钩所有指定API的函数  

     BOOL HookAllApis(void);  

     // 取消挂钩一个指定API的函数  

     BOOL UnhookOneApi(APIINFO* pai); 

     // 取消挂钩所有指定API的函数 

     BOOL UnhookAllApis(void);  

     // 设置进程内存区域的存取权限 

     BOOL SetMemmoryAccess(APIINFO* pai,BOOL CanWritten);  

     // 修改/恢复指定API的前5个字节 

     BOOL SetCallMemmory(APIINFO* pai,BOOL bHook); 

};


    其中HOOKAPIINFO结构填写基本的拦截信息,在CHookApi内部将会把它转化为APIINFO结构。HOOKAPIINFO和APIINFO结构定义在CommonHeader.h文件中,CommonHeader.h文件如下: 

(CommonHeader.h) 

#define FIREWALLDLLNAME "ReplacelDll.Dll"                    // 实现被拦截的API替换函数的名字 

#define MAINHOOKDLLNAME "MainHookDll.Dll"                    // 拦截API主模块的名字 

#define GETHOOKINFOFUNCNAMEINREPLACEDLL "GetHookApiInfo"     // 替换模块导出函数,它返回要拦截的信息 

#define FREEHOOKINFOFUNCNAMEINREPLACEDLL "FreeHookApiInfo"   // 替换模块导出函数,它释放要拦截的信息

#define CALLCODE   0xE8

#ifndef COMMONHEADER_H 

#define COMMONHEADER_H

#include <vector> 

using namespace std; 

typedef void(*CMAPIFUNC)(void); 

// 关于API函数信息的结构 

typedef struct _APIINFO 

{

     // 要拦截的API函数名

     char szOrgApiName[100]; 

     // 要拦截的API的地址 

     CMAPIFUNC lfOrgApiAddr; 

     // 我们要替换原来API的地址 

     CMAPIFUNC lfMyApiAddr;

     // 要保存的原来API入口点的前5个字节 

     BYTE OrgApiBytes[5]; 

     // 对进程内存的保护状态,调用VirtualProtect来改变对内存访问权限时得到的。

     DWORD dwOldProtectFlag; 

     // 参数的个数 

     int ParamCount; 

     // 临界对象,为了互斥用,避免同时修改原始api的前5个字节 

     CRITICAL_SECTION cs; 

     // 是否已经HOOK了 

     BOOL bIsHooked; 

 

// 用户需要使用的结构,通过这个结构来了解用户需要拦截的API的信息 

typedef struct _HOOKAPIINFO

{

     union 

     {

         struct 

         { 

              // 我们要替换的API所在的DLL的名字 

              char szMyModuleName[100]; 

              // 我们要替换原来API的函数名字 

              char szMyApiName[50]; 

         } MyApi; 

         CMAPIFUNC lfMyApi; 

     }; 

     // 要拦截的API所在DLL的名字 

     char szOrgModuleName[100]; 

     // 要拦截的API的名字

     char szOrgApiName[50]; 

     // 参数的个数 

     int ParamCount;

     // 提供MyAPI的方式 

     BOOL bMyApiType;   // 如果是0代表提供地址,1代表使用模块名和函数名指定 

} HOOKAPIINFO;

 

// 获得要拦截的API的信息函数指针 

typedef vector<HOOKAPIINFO*>*(*GETHOOKAPIINFO)(void); 

// 释放要拦截的API的信息函数指针

typedef void(*FREEHOOKAPIINFO)(void); 

// 远程注入函数指针 

typedef int (*INJECTDLL)(DWORD dwProcessId, LPTSTR lpDllName);

#endif 
 

在这个头文件中,除了定义了HOOKAPIINFO和APIINFO结构还有一些其它定义,FIREWALLDLLNAME宏指定防火墙策略模块的文件名称,MAINHOOKDLLNAME宏指定本模块的文件名称,GETHOOKINFOFUNCNAMEINREPLACEDLL宏指定我们写的API替换函数所在的DLL(我们成为替换模块)中用来返回用户的HOOKAPIINFO结构容器指针的函数名称,程序将会自动加载替换模块并调用这个函数获得用户的HOOKAPIINFO结构容器的指针,根据后面的函数指针的定义不难看出,这个函数必须是一个返回值为vector<HOOKAPIINFO*>*,并且没有参数的导出函数。FREEHOOKINFOFUNCNAMEINREPLACEDLL 是释放返回的vector<HOOKAPIINFO*>*指针的导出函数名字。CALLCODE宏指定要替换的跳转指令,这里只用CALL指令,他的机器码是E8。

 

在构造函数中调用Init函数和HookAllApis函数,这样使该类被构造的时候就能够自动进行初始化和hook工作。Init函数的主要工作是将用户提供的HOOKAPIINFO结构转化成APIINFO结构。HookAllApis函数内部循环调用HookOneApi函数进行真正的Hook操作。详见源代码中的注释。 
 

CHookApi类完成了Hook的核心工作后,我们需要让系统所有的进程加载我们的MainHookDll.Dll,从而对系统所有进程中的指定API进行拦截。我们的想法是,MainHookDll模块提供2个导出函数,HookAllProcesses和UnhookAllProcesses函数完成这个功能,当UserUI调用HookAllProcesses函数的时候,系统所有的进程将加载MainHookDll.Dll,在加载的同时让CHookApi类开始工作,对目标进程中的所有指定API的前5个字节进行替换。当调用UnhookAllProcesses函数的时候,系统所有的进程将卸载MainHookDll.Dll,从而取消对指定API的拦截。在HookAllProcesses和UnhookAllProcesses函数中实际上是列举当前系统的所有进程,并对所有进程进行相同的操作。所以我们可以再实现两个函数,用CHookApi类的静态成员InjectDll和EjectLib函数完成真正的功能,而HookAllProcesses和UnhookAllProcesses中实现列举系统进程并对所有进程调用InjectDll或EjectLib函数。我们使用远程线程来实现InjectDll和EjectLib函数。远程线程是指在当前进程中使目标进程启动一个线程。可以通过以下方法完成远程线程的调用。首先使用OpenProcess打开目标进程得到进程句柄,要启动远程线程最少需要用PROCESS_CREATE_THREAD,PROCESS_QUERY_INFORMATION,PROCESS_VM_OPERATION,PROCESS_VM_WRITE, and PROCESS_VM_READ权限打开目标进程(我们使用PROCESS_ALL_ACCESS)。然后调用VirtualAllocEx函数在目标进程中分配内存,使用WriteProcessMemory函数将当前进程中的线程函数的参数写入在目标进程分配的内存中,最后调用CreateRemoteThread函数使目标进程执行线程函数。(实现过程请参考源代码中的注释)。下面给出InjectDll函数的代码,该函数将指定的Dll文件注入到指定ID号的进程中。

 

int WINAPI CHookApi::InjectDll(DWORD dwProcessId, LPTSTR lpDllName)

     PTHREAD_START_ROUTINE pfnRemote =(PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA"); 

     if(pfnRemote ==NULL) 

         return -1;

     HANDLE hProcess =OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); 

     if(hProcess ==NULL) 

     { 

         return -1; 

     } 

     int iMemSize = (int)strlen(lpDllName)+1; 

     void *pRemoteMem =VirtualAllocEx(hProcess, NULL, iMemSize, MEM_COMMIT, PAGE_READWRITE); 

     if(pRemoteMem ==NULL) 

     { 

         CloseHandle(hProcess); 

         return -1; 

     } 

     if (!WriteProcessMemory(hProcess, pRemoteMem, lpDllName, iMemSize,NULL)) 

     { 

         VirtualFreeEx(hProcess, pRemoteMem, 0, MEM_RELEASE); 

         CloseHandle(hProcess); 

         return -1; 

     } 

     HANDLE hThread =CreateRemoteThread(hProcess, NULL, 0, pfnRemote, pRemoteMem, 0, NULL); 

     if(hThread ==NULL) 

     { 

         VirtualFreeEx(hProcess, pRemoteMem, 0, MEM_RELEASE); 

         CloseHandle(hProcess); 

         return -1; 

     } 

     WaitForSingleObject(hThread, INFINITE); 

     VirtualFreeEx(hProcess, pRemoteMem, 0, MEM_RELEASE); 

     CloseHandle(hProcess); 

     CloseHandle(hThread); 

     return 0; 

}

 

函数一开始,指定了要被注入的线程函数的位置,在这里,我们的线程函数就是LoadLibraryA函数,远程线程中的线程函数应该是PTHREAD_START_ROUTINE类型的函数指针,该函数指针的声明如下: 

 

typedef DWORD (*PTHREAD_START_ROUTINE)(LPVOID)

 

由声明可知,该函数是一个只有一个参数的,且返回值是DWORD类型的函数,而LoadLibraryA函数符合要求的,所以它可以直接作为远程线程的线程函数。当远程进程调用LoadLibraryA把我们的MainHookDll.Dll加载后,拦截工作就会自动进行。紧接着,用VirtualAllocEx函数在远程进程中开辟一块内存,开辟的内存的大小是MainHookDll的全路径名(注意最后的’/0’)。接着使用WriteProcessMemory函数将参数(即MainHookDll的全路径名)写入到刚刚开辟的远程进程中的地址空间。最后调用CreateRemoteThread函数启动远程线程。要注意的是,当线程结束后,要用VirtualFreeEx函数释放在远程进程内开辟的内存。

 

下面的代码列出了EjectLib函数,它是使系统当前进程卸载我们的MainHookDll文件:

 

int WINAPI CHookApi::EjectLib(DWORD dwProcessId, LPTSTR lpDllName) 

     // open the process 

     HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId); 

     if(hProcess == NULL) 

         return -1; 

     // 枚举进程中的模块 

     HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId); 

     if(hModuleSnap == INVALID_HANDLE_VALUE) 

     { 

         CloseHandle(hProcess); 

         return -1; 

     } 

     MODULEENTRY32 me32; 

     me32.dwSize = sizeof(MODULEENTRY32); 

     BOOL bFound = FALSE; 

     HMODULE hmod = NULL; 

     if(Module32First(hModuleSnap, &me32)) 

     { 

         do 

         { 

              if(strcmpi(me32.szModule,lpDllName) == 0) 

              { 

                   hmod = me32.hModule; 

                   bFound = TRUE; 

              } 

         }while(!bFound && Module32Next(hModuleSnap, &me32)); 

     } 

     CloseHandle(hModuleSnap); 

     if(hmod == NULL) 

     { 

         // 没有指定的模块 

         CloseHandle(hProcess); 

         return 0; 

     } 

     // 创建远程线程 

     PTHREAD_START_ROUTINE pfnRemote =(PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle("Kernel32"),"FreeLibrary"); 

     if(pfnRemote ==NULL) 

     { 

         CloseHandle(hProcess); 

         return -1; 

     } 

     HANDLE hThread =CreateRemoteThread(hProcess,NULL,0,pfnRemote,hmod,0,NULL); 

     if(hThread ==NULL) 

     { 

         CloseHandle(hProcess); 

         return -1; 

     }  
     WaitForSingleObject(hThread, INFINITE); 

     CloseHandle(hProcess); 

     CloseHandle(hThread); 

     return 0; 


 

我们在函数中使用了Psapi中定义的函数列举指定进程中加载的模块,看看是否加载了我们的MainHookDll文件,如果加载了,那么使用FreeLibrary函数卸载它。


    我们写一个要被测试的程序叫test.exe,在里面调用要被拦截的API,比如是MessageBox。我们的主程序是MainApp.exe。HOOK模块是MainHookDll.dll,所有要替换的函数都在Replace.dll里面导出。当MainApp.exe运行起来后,他先加载MainHookDll.dll,并且调用MainHookDll.dll的InjectDll方法把MainHookDll.dll注入到目标进程。MainHookDll.dll被加载后,先主动加载Replace.dll并调用Replace.dll的GETHOOKINFOFUNCNAMEINREPLACEDLL方法获得要HOOK的信息。然后就按照刚才分析的机制对目标进程进行拦截了。由此可见,我们在写程序的时候,拦截某个API的处理函数都在Replace.dll中,其他部分的代码都是固定的。


引自: http://blog.csdn.net/liutaoxwl/archive/2006/05/15/729448.aspx

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面这个模块是我使用易语言时写补丁最常用的一个模块(当然很多也是抄的),一开始我觉得bug肯定会很多,放出去肯定又会坑很多人,后来我发现坑坑更健康,当你明白一个东西的优缺点之后,你才会更好的选择你所需要的。所以呢,现在模块开源了,希望对某些朋友有参考意义或者说使用价值吧。 声明:大家使用过程中发现任何问题都不要来问我,请自己想办法解决。我现在已经完全放弃易语言了,改用VC++了。 以下是全部接口: 模块名称:sunflover.ec 作者:by sunflover 版本:2015.2 自己收集的一些常用函数,方便写补丁。 @备注: 自己收集的一些常用函数 ------------------------------ .版本 2 .子程序 Ansi2Unicode, 字节集, 公开, 将Ansi码转换为Unicode码 (返回转换后的字节集) .参数 Ansi, 文本型, , 欲转换的Ansi文本 .子程序 AntiDebug, 逻辑型, 公开, 这个没啥用,效果差;可放在程序运行的第一个函数 被调试返回真 .子程序 AntiODMenu, 逻辑型, 公开, 这个效果较好,推荐用这个;找到OD相关句柄返回真, 此函数枚举窗口通过菜单名来 判定是否OD窗口。 .子程序 AntiStrongOD, 逻辑型, 公开, 这个效果还行,检测带有驱动的 OD调试器 此函数专门对付 StrongOD 插件 .参数 判断OD运行状态, 逻辑型, 可空, 此参数作用: 发现OD驱动时 —是否检测OD运行状态作为返回值基础 ,默认判断运行状态 .子程序 Bin2Dec, 整数型, 公开, 字节集到整数 .参数 Bin, 字节集 .子程序 Bin2Hex, 文本型, 公开, 字节集到十六进制文本 .参数 字节集, 字节集 .子程序 Bin2Hex1, 文本型, 公开, 文本型->文本型 .参数 Bin, 文本型 .子程序 BinXor, 字节集, 公开, 字节集异或 .参数 需异或的字节集, 字节集, , 返回的字节集 .参数 参与异或的字节集, 字节集 .子程序 Dec2Hex, 文本型, 公开, 十到十六 .参数 十进制转换数据, 长整数型 .子程序 GetAPIAddress, 整数型, 公开, 失败返回0 .参数 模块名, 文本型, , 如"user32.dll","kernel32.dll" .参数 API, 文本型, , 如“CreateWindowExA” .子程序 Hex2Bin, 字节集, 公开, 十六进制文本到字节集 .参数 原文, 文本型 .子程序 Hex2Bin1, 文本型, 公开, 文本型->文本型 .参数 Hex, 文本型 .子程序 Hex2Dec, 整数型, 公开, 十六到十 .参数 十六进制转换数据, 文本型 .子程序 InjectDll, 逻辑型, 公开, 向目标进程中注入一个指定 Dll 模块文件;注入成功返回 true, 注入失败则返回 false,CreateRemoteThread法 .参数 进程ID, 整数型, , 进程PID .参数 DLL文件名, 文本型, , 欲注入的DLL名称 .子程序 InjectDLL1, 逻辑型, 公开, SuspendThread,shellcode,SetEip .参数 PID, 整数型 .参数 DLL路径, 文本型 .子程序 InjectDLL2, 逻辑型, 公开, code cave,与InjectDLL1同 .参数 进程ID, 整数型 .参数 DLL文件名, 文本型 .子程序 inline_patch, 逻辑型, 公开, 失败返回假,成功返回真;适合patch尚未运行的加壳或不加壳的可执行文件 .参数 文件名, 文本型, , 文件全路径 .参数 模块名, 文本型, , 如"user32.dll" .参数 API, 文本型, , 如“CreateWindowExA” .参数 地址, 整数型, , 如Hex2Dec (“00401000”) .参数 数据, 字节集, , 如 Hex2Bin (“90909090”) .子程序 inline_patch_Pro, 逻辑型, 公开, 失败返回假,成功返回真;适合patch尚未运行的加壳不加壳的可执行文件,需要补丁的数据较多时建议使用这个,在子程序中打补丁 .参数 文件名, 文本型, , 文件全路径 .参数 模块名, 文本型, , 如"user32.dll" .参数 API, 文本型, , 如“CreateWindowExA” .参数 子程序指针, 子程序指针, , 如&子程序1 .子程序 inline_patch_Pro1, 逻辑型, 公开, 失败返回假,成功返回真;适合patch尚未运行的加壳或不加壳的可执行文件,解码时机判断是选用VirtualProtect;如果壳检测到了,自行换用inline_patch或inline_patch_Pro .参数 文件名, 文本型, , 文件全路径 .参数 子程序指针, 子程序指针, , 如&子程序1 .参数 地址, 整数型, 可空, 如Hex2Dec (“00401000”),用来判断是否解码完成;如果没壳,就空着 .子程序 inline_patch1, 逻辑型, 公开, patch尚未运行的,没加壳的程序,并运行它 .参数 文件名, 文本型, , 文件全路径 .参数 地址, 整数型, , 如Hex2Dec (“00401000”) .参数 数据, 字节集, , 如 Hex2Bin (“90909090”) .子程序 InlinePatch, 逻辑型, 公开, 失败返回假,成功返回真;适合patch尚未运行的加壳不加壳的可执行文件,需要补丁的数据较多时建议使用这个,在子程序中打补丁 .参数 文件名, 文本型, , 文件全路径,如"D:\test.exe" .参数 运行参数, 文本型, 可空, 可空,没有参数则留空,大多数情况没有参数;有参数时填写,如"-s" .参数 模块名, 文本型, , 如"user32.dll" .参数 API, 文本型, , 如“CreateWindowExA” .参数 API中断次数, 整数型, 可空, 可空,有些时候需要计次,根据需要填写;一般留空即可,留空表示中断第一次,就开始补丁 .参数 补丁子程序, 子程序指针, , 如&子程序1 .参数 寄存器结构体, context_, 参考 可空, 可空,CONTEXT,返回寄存器结构体,方便写补丁函数;这个属于高级功能,看不懂的话就留空吧 .参数 进程信息结构体, PROCESS_INFORMATION, 参考 可空, 可空,PROCESS_INFORMATION,返回进程信息结构体,方便写补丁函数;这个属于高级功能,看不懂的话就留空吧 .子程序 OpenProcessPro, 整数型, 公开, 返回句柄权限是完全访问 .参数 PID, 整数型 .子程序 OpenThreadPro, 整数型, 公开, 返回句柄权限是完全访问 .参数 进程ID, 整数型 .子程序 Unicode2Ansi, 文本型, 公开, 将Unicode码转换为Ansi码 (返回转换后的文本) .参数 Unicode, 字节集, , 欲转换的Unicode字节集 .子程序 UnInjectDLL1, 逻辑型, 公开, SuspendThread,shellcode,SetEip .参数 PID, 整数型 .参数 DLL路径, 文本型 .子程序 UnInjectDLL2, 逻辑型, 公开, 远程时钟卸载dll .参数 参数_窗口句柄, 整数型, , FindWindow(字符 (0),“计算器”) .参数 参数_DLL路径, 文本型, , '可以是DLL全路径也可以只是DLL名称 .子程序 超级延时, , 公开, 高精度延时,cpu占用低,窗口不卡死,一次最大可延时几年 (无返回值) .参数 延时间隔, 整数型, , 1000微秒 = 1毫秒 ; 1000毫秒 = 1秒 .参数 延时单位, 整数型, 可空, 可空:毫秒 0 毫秒 1 微秒 2 秒 3 分 4 小时 5 天 .子程序 打开保存文件对话框, 文本型, 公开, 未提示 是否有重复的文件存在 自己注意一下 .参数 窗口句柄, 整数型, 可空, 调用处窗口句柄 .参数 窗口标题, 文本型, 可空, 对话框窗口标题 .参数 过滤器, 文本型, 可空, 格式:“MP3文件(*.mp3)|*.mp3|媒体文件(*.mpg)|*.mpg” .参数 初始路径, 文本型, 可空, 可以被省略。如果本参数被省略,默认从“我的文档”开始。否则,请给出盘符,如“d:” .子程序 打开多文件对话框, 文本型, 公开, 如果多选文件,返回文件路径以“;”(半角分号)分隔。失败或取消返回空文本。 .参数 窗口句柄, 整数型, 可空, 调用处窗口句柄 .参数 窗口标题, 文本型, 可空, 对话框窗口标题 .参数 过滤器, 文本型, 可空, 格式:“MP3文件(*.mp3)|*.mp3|媒体文件(*.mpg)|*.mpg” .参数 初始路径, 文本型, 可空, 可以被省略。如果本参数被省略,默认从“我的文档”开始。否则,请给出盘符,如“d:” .参数 窗口风格, 整数型, 可空, 可以被省略。如果本参数被省略,默认为 0 。位置值从 0 开始。从0-11之间,可以设置多种窗口风格。0.工具栏、只读选择框-未选中;1.工具栏、只读选择框-选中;2.工具栏;3.工具栏、只读选择框-未选中,帮助按钮;4.工具栏、只读选择框-选中,帮助按钮;5.工具栏,帮助按钮;6.普通风格、只读选择框-未选中;7.普通风格、只读选择框-选中;8.普通风格;9.普通风格、只读选择框-未选中,帮助按钮;10.普通风格、只读选择框-选中,帮助按钮;11.普通风格、帮助按钮。 .子程序 读内存字节集, 字节集, 公开, 从内存中读取字节集数据(返回字节集,失败返回0字节长度的空字节集) .参数 进程ID, 整数型, , 进程ID .参数 地址, 整数型, , 内存地址 .参数 长度, 整数型, , 欲读取内存数据的长度 .子程序 复制文件夹, 逻辑型, 公开, 可复制文件,也可复制目录。成功返回真,失败返回假。 .参数 被复制的文件或目录, 文本型 .参数 复制到的位置, 文本型 .子程序 恢复进程, 逻辑型, 公开 .参数 PID, 整数型 .子程序 结束进程, 逻辑型, 公开 .参数 进程ID, 整数型 .子程序 进程取ID, 整数型, 公开, 取指定进程的进程ID(返回第一个进程ID,失败返回空信息) .参数 进程名, 文本型, , 程序进程名(不区分大小写!) .子程序 进程是否存在1, 逻辑型, 公开 .参数 进程ID, 整数型 .子程序 进程是否存在2, 逻辑型, 公开 .参数 进程名, 文本型 .子程序 蓝屏, , 公开, 惩罚破解者函数 。 在确定当前程序被调试后 可使用此函数让系统蓝屏。 慎重使用! .子程序 内存补丁, 逻辑型, 公开, 根据进程名补丁内存,patch已经运行的可执行文件 .参数 进程名, 文本型, , '完整的文件名,注意大小写 .参数 地址, 文本型, , 需patch地址,如“00401000” .参数 代码, 文本型, , 被替换的代码,如“90909090” .子程序 内存补丁1, 逻辑型, 公开, 根据进程ID补丁内存,patch已经运行的可执行文件 .参数 进程ID, 整数型, , 要补丁的进程ID .参数 地址, 文本型, , 需patch地址,如“00401000” .参数 代码, 文本型, , 被替换的代码,如“90909090” .子程序 内存搜索, 整数型, 公开, 某些情况,需提升权限(返回结果数目,失败返回0),返回搜索到的数目 .参数 进程ID, 整数型, , 进程ID .参数 搜索内容, 字节集, , 欲搜索的内容 其他类型-需自行转换为字节集类型 .参数 结果数组, 整数型, 参考 数组, 用来保存搜索的结果 .子程序 取汇编指令长度, 整数型, 公开, 返回指定进程指定地址处的首条汇编指令的长度。注:计算方法使用的是LDX32 .参数 进程ID, 整数型, , 进程ID .参数 地址, 整数型, , 指令地址,如Hex2Dec("00401000") .子程序 取寄存器值, 文本型, 公开, 适用于明码读码,运行到地址处读真码;如 取寄存器值(文件名,"user32.dll",“CreateWindowExA”,Hex2Dec (“00401000”),“Eax”) .参数 文件名, 文本型, , 文件全路径 .参数 模块名, 文本型, , 如"user32.dll" .参数 API, 文本型, , 如“CreateWindowExA”,这里主要为了解码时机 .参数 地址, 整数型, , 如Hex2Dec (“00401000”) .参数 寄存器, 文本型, , 可选Dr0-Dr7,Eax,Ecx,Ebx,Edx,Ebp,Esp,Eip,Edi,Esi,SegGs,SegFs,SegEs,SegDs,SegCs,EFlags,Esp,SegSs .子程序 取进程主线程, 整数型, 公开, 失败返回0 .参数 进程ID, 整数型 .子程序 取路径目录, 文本型, 公开, 返回一个文件所在目录,如"C:\Program Files\WinRAR\WinRAR.exe",返回"C:\Program Files\WinRAR" .参数 路径, 文本型, , 如"C:\Program Files\WinRAR\WinRAR.exe" .子程序 取路径文件名, 文本型, 公开, 根据文件路径获取文件名 .参数 路径, 文本型, , 文件完整路径 .子程序 取线程起始地址, 整数型, 公开, 失败返回0 .参数 参数_dwThreadId, 整数型 .子程序 去除空格, 文本型, 公开 .参数 文本, 文本型 .子程序 设置颜色对话框, 逻辑型, 公开, 例如:如果真 (设置颜色对话框 (取窗口句柄 (), j));编辑框1.文本颜色 = 到整数 (j)。 .参数 窗口句柄, 整数型 .参数 返回_颜色, 文本型, , 返回的颜色~~需要传回整数 .子程序 申请内存Pro, 整数型, 公开, 成功返回申请的首地址,失败返回0;申请的内存可读可写可执行 .参数 进程ID, 整数型, , .参数 申请内存大小, 整数型 .子程序 释放内存Pro, 逻辑型, 公开 .参数 进程ID, 整数型, , .参数 内存地址, 整数型 .子程序 特征码模糊搜索, 整数型, 公开, 最多支持三段通配符如“68 00 00 00 40 ?? ?? ?? ?? ?? ?? ?? ?? 50 E8 ?? ?? ?? ?? 12 34 ?? ?? ?? ?? 85 69” .参数 进程ID, 整数型, , 进程ID .参数 特征码, 文本型, , 十六进制文本,如“68 00 00 00 40 ?? ?? ?? ?? ?? ?? ?? ?? 50 E8” .参数 结果数组, 整数型, 参考 数组, 用来保存搜索的结果 .参数 偏移, 整数型, 可空, 默认为0 .参数 起始地址, 文本型, 可空, 默认为“00400000” .参数 结束地址, 文本型, 可空, 默认为“00800000” .子程序 提升进程权限, 逻辑型, 公开 .参数 目标进程, 整数型, 可空 .参数 权限类别, 文本型, 可空, 默认为“SeDebugPrivilege”;可选“SeDebugPrivilege”,“SeShutdownPrivilege”,“SeRestorePrivilege”,“SeBackupPrivilege” .子程序 写内存字节集, 逻辑型, 公开, 往内存中写入字节集数据(成功返回真,失败返回假);注:内部有VirtualProtectEx处理 .参数 进程ID, 整数型, , 进程ID .参数 地址, 整数型, , 内存地址 .参数 数据, 字节集, , 写入数据 如果为其它数据类型,可以用 到字节集() 将数据转换为字节集 .参数 写入长度, 整数型, 可空, 默认为全部数据,(参考: 1字节型 2短整数型 4长整数型,小数型,指针 8长整数型,双精度小数型,日期时间型) .子程序 移动文件夹, 逻辑型, 公开, 可移动文件,也可移动目录。成功返回真,失败返回假。 .参数 被移动的文件或目录, 文本型 .参数 移动到的位置, 文本型 .子程序 隐藏进程, 逻辑型, 公开, hide.dll,会被误报,大家看着处理 .参数 进程ID, 整数型 .子程序 暂停进程, 逻辑型, 公开 .参数 PID, 整数型 .子程序 终止进程Pro, , 公开, 终止进程,终止所有指定进程 .参数 进程名, 文本型, , 程序进程名(不区分大小写!) .子程序 终止线程, 逻辑型, 公开, 成功返回真 失败返回假 .参数 参数_线程ID, 整数型 .数据类型 context_, 公开, 公开 .成员 ContextFlags, 整数型 .成员 Dr0, 整数型 .成员 Dr1, 整数型 .成员 Dr2, 整数型 .成员 Dr3, 整数型 .成员 Dr4, 整数型 .成员 Dr5, 整数型 .成员 Dr6, 整数型 .成员 Dr7, 整数型 .成员 ControlWord, 整数型 .成员 StatusWord, 整数型 .成员 TagWord, 整数型 .成员 ErrorOffset, 整数型 .成员 ErrorSelector, 整数型 .成员 DataOffset, 整数型 .成员 DataSelector, 整数型 .成员 RegisterArea, 字节型, , "72" .成员 Cr0NpxState, 整数型 .成员 SegGs, 整数型 .成员 SegFs, 整数型 .成员 SegEs, 整数型 .成员 SegDs, 整数型 .成员 Edi, 整数型 .成员 Esi, 整数型 .成员 Ebx, 整数型 .成员 Edx, 整数型 .成员 Ecx, 整数型 .成员 Eax, 整数型 .成员 Ebp, 整数型 .成员 Eip, 整数型 .成员 SegCs, 整数型 .成员 EFlags, 整数型 .成员 Esp, 整数型 .成员 SegSs, 整数型 .成员 reserve, 字节型, , "512" .数据类型 FLOATING_SAVE_AREA, 公开 .成员 ControlWord, 整数型 .成员 StatusWord, 整数型 .成员 TagWord, 整数型 .成员 ErrorOffset, 整数型 .成员 ErrorSelector, 整数型 .成员 DataOffset, 整数型, , , ; .成员 DataSelector, 整数型 .成员 RegisterArea, 字节型, , "80" .成员 Cr0NpxState, 整数型 .数据类型 LuID, 公开 .成员 lowpart, 整数型 .成员 highpart, 整数型 .数据类型 MEMORY_BASIC_INFORMATION, 公开 .成员 BaseAddress, 整数型 .成员 AllocationBase, 整数型 .成员 AllocattionProtect, 整数型 .成员 RegionSize, 整数型 .成员 State, 整数型 .成员 Protect, 整数型 .成员 Type, 整数型 .数据类型 MODULEENTRY32, 公开, MODULEENTRY32 .成员 dwSize, 整数型, , , dwSize .成员 th32ModuleID, 整数型, , , th32ModuleID .成员 th32ProcessID, 整数型, , , th32ProcessID .成员 GlblcntUsage, 整数型, , , GlblcntUsage .成员 ProccntUsage, 整数型, , , ProccntUsage .成员 modBaseAddr, 整数型, , , modBaseAddr .成员 modBaseSize, 整数型, , , modBaseSize .成员 hModule, 整数型, , , hModule .成员 szModule, 字节型, , "256", 模块名称 .成员 szExePath, 字节型, , "260", 文件路径 .数据类型 PROCESS_BASIC_INFORMATION, 公开 .成员 ExitStatus, 整数型 .成员 PebBaseAddress, 整数型 .成员 AffinityMask, 整数型 .成员 BasePriority, 整数型 .成员 UniqueProcessId, 整数型 .成员 InheritedFromUniqueProcessId, 整数型 .数据类型 PROCESS_INFORMATION, 公开 .成员 hProcess, 整数型 .成员 hThread, 整数型 .成员 dwProcessId, 整数型 .成员 dwThreadId, 整数型 .数据类型 SECURITY_ATTRIBUTES, 公开, , SECURITY_ATTRIBUTES .成员 nLength, 整数型 .成员 lpSecurityDescriptor, 整数型 .成员 bInheritHandle, 整数型 .数据类型 SHFILEOPSTRUCT, 公开 .成员 句柄, 整数型 .成员 wFunc, 整数型 .成员 pFrom, 字节集 .成员 pTo, 字节集 .成员 fFlags, 短整数型 .成员 fAnyOperationsAborted, 整数型 .成员 hNameMappings, 整数型 .成员 lpszProgressTitle, 文本型 .数据类型 STARTUPINFO, 公开 .成员 cb, 整数型 .成员 lpReserved, 文本型 .成员 lpDesktop, 文本型 .成员 lpTitle, 文本型 .成员 dwX, 整数型 .成员 dwY, 整数型 .成员 dwXSize, 整数型 .成员 dwYSize, 整数型 .成员 dwXCountChars, 整数型 .成员 dwYCountChars, 整数型 .成员 dwFillAttribute, 整数型 .成员 dwFlags, 整数型 .成员 wShowWindow, 短整数型 .成员 cbReserved2, 短整数型 .成员 lpReserved2, 整数型 .成员 hStdInput, 整数型 .成员 hStdOutput, 整数型 .成员 hStdError, 整数型 .数据类型 STARTUPINFO1, 公开 .成员 cb, 整数型 .成员 lpReserved, 整数型 .成员 lpDesktop, 整数型 .成员 lpTitle, 整数型 .成员 dwX, 整数型 .成员 dwY, 整数型 .成员 dwXSize, 整数型 .成员 dwYSize, 整数型 .成员 dwXCountChars, 整数型 .成员 dwYCountChars, 整数型 .成员 dwFillAttribute, 整数型 .成员 dwFlags, 整数型 .成员 wShowWindow, 短整数型 .成员 cbReserved2, 短整数型 .成员 lpReserved2, 字节型 .成员 hStdInput, 整数型 .成员 hStdOutput, 整数型 .成员 hStdError, 整数型 .数据类型 THREADENTRY32, 公开 .成员 dwsize, 整数型 .成员 cntUsage, 整数型 .成员 th32ThreadID, 整数型 .成员 th32OwnerProcessID, 整数型 .成员 tpBasePri, 长整数型 .成员 tpDeltaPri, 长整数型 .成员 dwFlags, 整数型 .数据类型 窗口句柄类, 公开 .成员 句柄, 整数型 .成员 标题, 文本型 .成员 类名, 文本型 .数据类型 打开文件名, 公开, OPENFILENAME .成员 结构大小, 整数型, , , lStructSize .成员 窗口句柄, 整数型, , , hwndOwner .成员 实例句柄, 整数型, , , hInstance .成员 过滤器, 字节集, , , lpstrFilter .成员 自定义过滤器, 文本型, , , lpstrCustomFilter .成员 自定义过滤器最大长度, 整数型, , , nMaxCustFilter .成员 过滤器索引, 整数型, , , nFilterIndex .成员 文件名, 字节集, , , lpstrFile .成员 文件名最大长度, 整数型, , , nMaxFile .成员 文件标题, 文本型, , , lpstrFileTitle .成员 文件标题最大长度, 整数型, , , nMaxFileTitle .成员 初始目录, 文本型, , , lpstrInitialDir .成员 标题, 文本型, , , lpstrTitle .成员 标志, 整数型, , , flags .成员 文件偏移量, 整数型, , , nFileOffset .成员 文件扩展名, 整数型, , , nFileExtension .成员 默认扩展名, 文本型, , , lpstrDefExt .成员 自定义数据, 整数型, , , lCustData .成员 回调函数地址, 整数型, , , lpfnHook .成员 模板名, 文本型, , , lpTemplateName .数据类型 函数信息, 公开 .成员 模块索引, 整数型 .成员 ThunkRav, 文本型 .成员 Thunk偏移, 文本型 .成员 Thunk值, 文本型 .成员 序数, 文本型 .成员 名称, 文本型 .数据类型 寄存器, 公开 .成员 标记, 整数型 .成员 dr0, 整数型 .成员 dr1, 整数型 .成员 dr2, 整数型 .成员 dr3, 整数型 .成员 dr6, 整数型 .成员 dr7, 整数型 .成员 FloatSave, FLOATING_SAVE_AREA .成员 seggs, 整数型 .成员 segfs, 整数型 .成员 seges, 整数型 .成员 segds, 整数型 .成员 edi, 整数型 .成员 esi, 整数型 .成员 ebx, 整数型 .成员 edx, 整数型 .成员 ecx, 整数型 .成员 eax, 整数型 .成员 ebp, 整数型 .成员 eip, 整数型 .成员 SegCs, 整数型 .成员 eflags, 整数型 .成员 esp, 整数型 .成员 SegSs, 整数型 .数据类型 进程信息, 公开, 进程信息 .成员 dwSize, 整数型 .成员 cntUsage, 整数型 .成员 进程ID, 整数型 .成员 th32DefaultHeapID, 整数型 .成员 th32ModuleID, 整数型 .成员 cntThreads, 整数型 .成员 th32ParentProcessID, 整数型 .成员 pcPriClassBase, 整数型 .成员 dwFlags, 整数型 .成员 进程名称, 字节型, , "256" .数据类型 逻辑字体, 公开, $(a)LOGFONT .成员 高度, 整数型, , , lfHeight .成员 宽度, 整数型, , , lfWidth .成员 控制摆, 整数型, , , lfEscapement .成员 定方位, 整数型, , , lfOrientation .成员 加粗, 整数型, , , lfWeight .成员 斜体, 字节型, , , lfItalic .成员 下划线, 字节型, , , lfUnderline .成员 删除线, 字节型, , , lfStrikeOut .成员 零碎工作组合, 字节型, , , lfCharSet .成员 出自精确, 字节型, , , lfOutPrecision .成员 修剪精确, 字节型, , , lfClipPrecision .成员 性质, 字节型, , , lfQuality .成员 间距, 字节型, , , lfPitchAndFamily .成员 字体名称, 字节型, , "32", 用LF_FACESIZE,lfFaceName? .数据类型 色盒, 公开 .成员 lStructsize, 整数型 .成员 hwndOwner, 整数型 .成员 hInstance, 整数型 .成员 rgbResult, 整数型 .成员 lpCustColors, 文本型, , , 可以指定16个数组,也可以不用指定,但无论用否,必须传址 .成员 flags, 整数型 .成员 lCustData, 整数型 .成员 lpfnHook, 子程序指针 .成员 lpTemplateName, 文本型 .数据类型 设定执行文件信息, 公开, SHELLEXECUTEINFO .成员 结构大小, 整数型, , , cbSize .成员 标志, 整数型, , , fMask .成员 窗口句柄, 整数型, , , hwnd .成员 操作命令, 文本型, , , lpVerb .成员 文件名, 文本型, , , lpFile .成员 应用程序参数, 文本型, , , lpParameters .成员 目录, 文本型, , , lpDirectory .成员 显示标志, 整数型, , , nShow .成员 实例句柄, 整数型, , , hInstApp .成员 项目标识符列表结构指针, 整数型, , , lpIDList .成员 文件类别, 文本型, , , lpClass .成员 热键句柄, 整数型, , , hkeyClass .成员 热键, 整数型, , , dwHotKey .成员 图标句柄, 整数型, , , hIcon .成员 进程句柄, 整数型, , , hProcess .数据类型 文件夹信息, 公开, BROWSEINFO .成员 窗口句柄, 整数型, , , hOwner .成员 根目录, 整数型, , , pidlRoot .成员 显示名称, 文本型, , , pszDisplayName .成员 标题, 文本型, , , lpszTitle .成员 标志, 整数型, , , ulFlags .成员 回调函数地址, 整数型, , , lpfn .成员 回调函数参数, 整数型, , , lParam .成员 图像索引, 整数型, , , iImage .数据类型 项目标识符列表, 公开, ITEMIDLIST .成员 结构大小, 整数型, , , cb .成员 标识符长度, 字节型, , "255", abID .数据类型 选择字体, 公开, CHOOSEFONT .成员 结构大小, 整数型, , , lStructSize .成员 窗口句柄, 整数型, , , hwndOwner,caller's window handle .成员 设备场景句柄, 整数型, , , hDC,printer DC/IC or NULL .成员 字体结构指针, 整数型, , , lpLogFont‘ptr. to a LOGFONT struct .成员 点大小, 整数型, , , iPointSize,10 * size in points of selected font .成员 标志, 整数型, , , flags,enum. type flags .成员 颜色值, 整数型, , , rgbColors,returned text color .成员 自定义数据, 整数型, , , lCustData,data passed to hook fn. .成员 回调函数地址, 整数型, , , lpfnHook,ptr. to hook function .成员 模板名称, 文本型, , , lpTemplateName,custom template name .成员 实例句柄, 整数型, , , hInstance,instance handle of.EXE that contains cust. dlg. template .成员 字体风格, 文本型, , , lpszStyle,return the style field here must be LF_FACESIZE(32) or bigger .成员 字体类型, 短整数型, , , nFontType,same value reported to the EnumFonts,call back with the extra FONTTYPE_ bits added .成员 空白队列, 短整数型 .成员 最小尺寸, 整数型 .成员 最大尺寸, 整数型 .数据类型 字体信息, 公开 .成员 名称, 文本型 .成员 大小, 整数型 .成员 颜色, 整数型 .成员 类型, 整数型 .成员 斜体, 整数型 .成员 下划线, 整数型 .程序集 IATHOOK类, , 公开 .子程序 APIAddr, 整数型, 公开, '此方法放在IATHOOK后调用方可成功,失败返回0 .子程序 IATHook, 逻辑型, 公开, 完事后注意调用IATUnHook .参数 进程ID, 整数型, 可空, '为空表示自身进程 .参数 模块名, 文本型, , 需加后缀,如“user32.dll” .参数 函数名, 文本型, , 注意大小写,如“MessageBoxA” .参数 新地址, 整数型, , 到整数 (&HookCallBack) .子程序 IATUnHook, 逻辑型, 公开, 与IATHOOK参数完全相同 .参数 进程ID, 整数型, 可空, 为空表示本进程 .参数 模块名, 文本型, , 需加后缀,如“user32.dll” .参数 函数名, 文本型, , 注意大小写,如“MessageBoxA” .参数 地址, 整数型, , 与IATHOOK最后一个参数相同 .程序集 PE类, , 公开, 获取可执行程序入口点,附加数据; .子程序 GetEntryPoint, 整数型, 公开, 获取的是OEP,即EP+imagebase .参数 全文件路径, 文本型, , 要处理的文件全路径 .子程序 overlay, 字节集, 公开, 获取PE文件的附加数据 .参数 全文件路径, 文本型, , 要处理的文件全路径 .程序集 超级解压类, , 公开, 调用7z解压文件,支持7z,zip,rar等压缩文件的带密码解压 .子程序 超级解压, 逻辑型, 公开, 解压压缩文件,支持rar,zip,7z等等压缩文件的解压,支持带密码解压 .参数 待解压文件, 文本型, , 欲解压的文件的全路径 .参数 解压到的目录, 文本型, , 欲解压到的路径 .参数 解压密码, 文本型, 可空, 解压所用密码,没有密码就不填 .程序集 汇编类, , 公开, 用于辅助生成shellcode,返回值都是字节集 .子程序 add_eax_char, 字节集, 公开, 占用3个字节,char值在0-127之间,返回汇编指令对应的字节集 .参数 char, 字节型, , add eax,1,参数为1,注意进制;16进制,请用Hex2Dec(Hex)转换 .子程序 add_eax_Num, 字节集, 公开, 占用5个字节,返回汇编指令对应的字节集 .参数 Num, 整数型, , add eax,8,参数为8,注意进制;16进制,请用Hex2Dec(Hex)转换 .子程序 add_esp_char, 字节集, 公开, 占用3个字节,char值在0-127之间,返回汇编指令对应的字节集 .参数 char, 字节型, , add esp,8,参数为8,注意进制;16进制,请用Hex2Dec(Hex)转换 .子程序 call, 字节集, 公开, 占用5个字节,call转换,返回汇编指令对应的字节集,此处为十进制,想用16进制,请自行转换;示例:call (Hex2Dec (“402000”), Hex2Dec (“401000”)) .参数 call到的地址, 整数型, , 00401000 call 00402000,参数为00402000 .参数 call所在的地址, 整数型, , 00401000 call 00402000,参数为00401000 .子程序 call_API, 字节集, 公开, 占用5个字节,如00401000 call MessageBoxA .参数 call所在地址, 整数型, , 自行转换,Hex2Dec("00401000") .参数 lpProcName, 文本型, , 如MessageBoxA .参数 hModule, 文本型, , 如user32.dll .子程序 call_API_FF15, 字节集, 公开, 占用6个字节,如00401000 call MessageBoxA .参数 lpProcName, 文本型, , 如MessageBoxA .参数 hModule, 文本型, , 如user32.dll .子程序 call_eax, 字节集, 公开, 占用2个字节,返回汇编指令对应的字节集 .子程序 call_FF15, 字节集, 公开, 占用6个字节,call转换,返回汇编指令对应的字节集,此处为十进制,想用16进制,请自行转换;示例:call (Hex2Dec (“402000”)) .参数 call到的地址, 整数型, , 00401000 call 00402000,参数为00402000 .子程序 jmp, 字节集, 公开, 占用5个字节,jmp转换,返回汇编指令对应的字节集,此处为十进制,想用16进制,请自行转换;jmp (Hex2Dec (“402000”), Hex2Dec (“401000”)) .参数 jmp_to, 整数型, , 00401000 jmp 00402000,参数为00402000 .参数 jmp_from, 整数型, , 00401000 jmp 00402000,参数为00401000 .子程序 jmp_FF25, 字节集, 公开, 占用6个字节,jmp转换,返回汇编指令对应的字节集,此处为十进制,想用16进制,请自行转换;jmp (Hex2Dec (“402000”)) .参数 jmp_to, 整数型, , 00401000 jmp 00402000,参数为00402000 .子程序 mov_eax_Num, 字节集, 公开, 占用5个字节,返回汇编指令对应的字节集 .参数 Num, 整数型, , 自己注意进制,mov eax,401000,参数为Hex2Dec(“401000”) .子程序 nop, 字节集, 公开, 占用个字节,返回汇编指令对应的字节集 .子程序 popad, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 popfd, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_char, 字节集, 公开, 占用2个字节,char值在0-127之间,返回汇编指令对应的字节集 .参数 char, 字节型, , push 8,参数为8,注意进制;16进制,请用Hex2Dec(Hex)转换 .子程序 push_eax, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_ebp, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_ebx, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_ecx, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_edi, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_edx, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_esi, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_esp, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 push_Num, 字节集, 公开, 占用5个字节,返回汇编指令对应的字节集 .参数 Num, 整数型, , push 401000,参数为Hex2Dec(401000),注意进制;16进制,请用Hex2Dec(Hex)转换 .子程序 pushad, 字节集, 公开, 占用1个字节,将通用寄存器的内容压入堆栈;返回汇编指令对应的字节集 .子程序 pushfd, 字节集, 公开, 占用1个字节,本指令可以把标志寄存器的内容保存到堆栈中去;返回汇编指令对应的字节集 .子程序 retn, 字节集, 公开, 占用1个字节,返回汇编指令对应的字节集 .子程序 retn_n, 字节集, 公开, 占用3个字节,返回汇编指令对应的字节集 .参数 n, 短整数型, , retn 3,参数填3,注意进制;16进制,请用Hex2Dec(Hex)转换 .子程序 xor_eax_eax, 字节集, 公开, 占用2个字节,返回汇编指令对应的字节集 .子程序 xor_ebx_ebx, 字节集, 公开, 占用2个字节,返回汇编指令对应的字节集 .子程序 xor_ecx_ecx, 字节集, 公开, 占用2个字节,返回汇编指令对应的字节集 .子程序 xor_edi_edi, 字节集, 公开, 占用2个字节,返回汇编指令对应的字节集 .子程序 xor_edx_edx, 字节集, 公开, 占用2个字节,返回汇编指令对应的字节集 .子程序 xor_esi_esi, 字节集, 公开, 占用2个字节,返回汇编指令对应的字节集 .程序集 内存DLL注入类, , 公开, 可能还有点问题 .子程序 取DLL函数地址, 整数型, 公开, 返回已经注入到指定进程内的DLL函数地址。失败返回0。 .参数 DLL函数名, 文本型, , 区分大小写。 .子程序 是否已注入, 逻辑型, 公开, 已注入返回真,未注入返回假。 .子程序 卸载DLL, 逻辑型, 公开, 卸载已经注入的内存中的DLL,成功返回真,失败返回假.(最好不要卸载,卸载的话被注入的进程很容易崩溃) .子程序 执行DLL函数, 整数型, 公开, 执行已经注入到指定进程内的DLL函数,成功返回所执行的函数的地址,失败返回0。 .参数 DLL函数名, 文本型, , 区分大小写。 .参数 等待函数执行完毕, 逻辑型, 可空, 默认为假,为真则函数执行完毕后本函数才返回。 .参数 返回值, 整数型, 参考 可空, 如果上一个参数为真,则可提供一个变量保存被执行的DLL函数的返回值。 .参数 线程句柄, 整数型, 参考 可空, 可提供变量保存函数执行线程的句柄,不需要请留空.接收了句柄记得不用时要关闭. .参数 参数1, 整数型, 可空, 可提供给被执行函数最多10个参数(理论上支持无限个,自己看着改吧)不需要的请留空。 .参数 参数2, 整数型, 可空, 非整数型参数需传递变量的内存数据指针,该指针必须是在目标进程内的。 .参数 参数3, 整数型, 可空, 提供的参数请与所执行的函数的参数个数一致,否则被注入的进程绝对会崩溃! .参数 参数4, 整数型, 可空 .参数 参数5, 整数型, 可空 .参数 参数6, 整数型, 可空 .参数 参数7, 整数型, 可空 .参数 参数8, 整数型, 可空 .参数 参数9, 整数型, 可空 .参数 参数10, 整数型, 可空 .子程序 注入DLL, 整数型, 公开, 成功返回DLL的模块句柄,失败或已注入返回0。 .参数 进程句柄, 整数型, , 句柄必须拥有对被注入进程的完全操作权限。注入后如果没有其他用处可以关闭该句柄。 .参数 DLL数据, 字节集 .程序集 取机器码类, , 公开, 获取硬件信息,硬盘等等 .子程序 取3段机器码, 文本型, 公开, 获取3段32位机器码,如1111111111-2222222222-3333333333 .参数 bios, 逻辑型, 可空, 填 假 表示此段全为0,可空,默认为真 .参数 HardDisk, 逻辑型, 可空, 填 假 表示此段全为0,可空,默认为真 .参数 MAC, 逻辑型, 可空, 填 假 表示此段全为0,可空,默认为真 .子程序 取4段机器码, 文本型, 公开, 获取4段23位机器码,如11111-22222-33333-44444 .参数 bios, 逻辑型, 可空, 填 假 表示此段全为0,可空,默认为真 .参数 HardDisk, 逻辑型, 可空, 填 假 表示此段全为0,可空,默认为真 .参数 Video, 逻辑型, 可空, 填 假 表示此段全为0,可空,默认为真 .参数 MAC, 逻辑型, 可空, 填 假 表示此段全为0,可空,默认为真 .DLL命令 _窗口是否可见, 整数型, "user32", "IsWindowVisible", 公开, 判断窗口是否可见 如窗口可见则返回TRUE(非零) .参数 窗口句柄, 整数型, , 要测试的那个窗口的句柄 .DLL命令 AdjustTokenPrivileges, 逻辑型, "advapi32.dll", "AdjustTokenPrivileges", 公开 .参数 TokenHandle, 整数型 .参数 DisableAllPrivileges, 整数型 .参数 NewState, , 传址 .参数 BufferLength, 整数型 .参数 PreviousState, , 传址 .参数 ReturnLength, 整数型, 传址 .DLL命令 API_IsDebuggerPresent, 整数型, "kernel32.dll", "IsDebuggerPresent", 公开 .DLL命令 CallNextHookEx, 整数型, "user32.dll", "CallNextHookEx", 公开 .参数 hhk, 整数型, , 钩子句柄 .参数 nCode, 整数型, , 钩子类型 .参数 wParam, 整数型 .参数 LPARAM, 整数型 .DLL命令 CloseHandle, 整数型, "kernel32.dll", "CloseHandle", 公开, 关闭一个内核对象。其中包括文件、文件映射、进程、线程、安全和同步对象等。涉及文件处理时,这个函数通常与vb的close命令相似。应尽可能的使用close,因为它支持vb的差错控制。注意这个函数使用的文件句柄与vb的文件编号是完全不同的 非零表示成功,零表示失败。会设置GetLastError .参数 对象句柄, 整数型, , 欲关闭的一个对象的句柄; .DLL命令 CreateFileA, 整数型, "kernel32.dll", "CreateFileA", 公开, , 成功返回文件句柄,失败返回0 .参数 打开文件名, 文本型, , lpFileName,要打开的文件的名字 .参数 访问权限, 整数型, , dwDesiredAccess,访问权限 .参数 共享方式, 整数型, , dwShareMode,共享方式 .参数 安全特性, SECURITY_ATTRIBUTES, 传址, lpSecurityAttributes,安全特性信息 .参数 创建方式, 整数型, , dwCreationDisposition,创建方式 .参数 文件属性, 整数型, , dwFlagsAndAttributes,参见相关帮助 .参数 从文件复制文件属性, 整数型, , hTemplateFile,参见相关帮助 .DLL命令 CreateProcess, 整数型, "kernel32.dll", "CreateProcessA", 公开, CreateProcess(编辑框1.内容, “”, 0, 0, 0, 4, 0, 取运行目录(), si, pi) .参数 lpApplicationName, 文本型 .参数 lpCommandLine, 文本型 .参数 lpProcessAttributes, 整数型 .参数 lpThreadAttributes, 整数型 .参数 bInheritHandles, 整数型 .参数 dwCreationFlags, 整数型, , 0正常,4挂起,3调试,6调试挂起 .参数 lpEnvironment, 整数型 .参数 lpCurrentDriectory, 文本型 .参数 lpStartupInfo, STARTUPINFO, 传址 .参数 lpProcessInformation, PROCESS_INFORMATION, 传址 .DLL命令 CreateRemoteThread, 整数型, "kernel32", "CreateRemoteThread", 公开, 在另一进程中建立线索 .参数 hProcess, 整数型 .参数 lpThreadAttributes, 整数型 .参数 dwStackSize, 整数型 .参数 lpStartAddress, 整数型 .参数 lpParameter, 整数型 .参数 dwCreationFlags, 整数型 .参数 lpThreadId, 整数型, 传址 .DLL命令 CreateToolhelp32Snapshot, 整数型, "kernel32.dll", "CreateToolhelp32Snapshot", 公开, 返回快照后的句柄 .参数 快照标志, 整数型, , 进程=15,线程=4,DLL=8,堆= .参数 进程标识符, 整数型, , lProcessID 欲照快照的进程标识符 .DLL命令 DuplicateHandle, 整数型, "kernel32", "DuplicateHandle", 公开, 复制对象句柄 .参数 hSourceProcessHandle, 整数型 .参数 hSourceHandle, 整数型 .参数 hTargetProcessHandle, 整数型 .参数 lpTargetHandle, 整数型, 传址 .参数 dwDesiredAccess, 整数型 .参数 bInheritHandle, 整数型 .参数 dwOptions, 整数型 .DLL命令 ExitProcess, 整数型, "kernel32.dll", "ExitProcess", 公开, , .参数 进程句柄, 整数型, , 填0即可 .DLL命令 FindWindow, 整数型, "user32.dll", "FindWindowA", 公开, FindWindow,寻找窗口列表中第一个符合指定条件的顶级窗口 .参数 窗口类名, 文本型, , lpClassName,参见相关帮助,字符 (0) .参数 窗口文本, 文本型, , lpWindowName,参见相关帮助 .DLL命令 GetClassName, 整数型, "user32.dll", "GetClassNameA", 公开, 为指定的窗口取得类名 以字节数表示的类名长度;排除最后的空中止字符。零表示出错。会设置GetLastError .参数 句柄, 整数型, , 欲获得类名的那个窗口的句柄 .参数 文本, 文本型, , 随同类名载入的缓冲区。预先至少必须分配nMaxCount+1个字符 .参数 文本长度, 整数型, , 由lpClassName提供的缓冲区长度; .DLL命令 GetCurrentProcess, 整数型, "kernel32.dll", "GetCurrentProcess", 公开 .DLL命令 GetCurrentProcessId, 整数型, "kernel32.dll", "GetCurrentProcessId", 公开 .DLL命令 GetExitCodeThread, 整数型, , "GetExitCodeThread", 公开, 取线程返回值 .参数 hThread, 整数型 .参数 lpExitCode, 整数型, 传址 .DLL命令 GetModuleHandleA, 整数型, "kernel32.dll", "GetModuleHandleA", 公开, , 获取一个应用程序或动态链接库的模块句柄 如执行成功成功,则返回模块句柄。零表示失败。会设置GetLastError .参数 lpModuleName, 文本型, , lpModuleName,指定模块名,这通常是与模块的文件名相同的一个名字。例如,NOTEPAD.EXE程序的模块文件名就叫作NOTEPAD .DLL命令 GetProcAddress, 整数型, "kernel32.dll", "GetProcAddress", 公开, , .参数 hModule, 整数型, , hModule .参数 lpProcName, 文本型, , lpProcName .DLL命令 GetThreadContext, 逻辑型, "kernel32", "GetThreadContext", 公开 .参数 hThreadId, 整数型 .参数 线程环境, context_ .DLL命令 GetThreadContext1, 逻辑型, "kernel32", "GetThreadContext", 公开 .参数 线程句柄, 整数型 .参数 寄存器, 寄存器 .DLL命令 GetWindow, 整数型, "user32", "GetWindow", 公开, 获得一个窗口的句柄,该窗口与某源窗口有特定的关系 由wCmd决定的一个窗口的句柄。如没有找到相符窗口,或者遇到错误,则返回零值。会设置GetLastError .参数 源窗口, 整数型, , 源窗口 .参数 关系, 整数型, , 指定结果窗口与源窗口的关系,它们建立在下述常数基础上:;GW_CHILD:寻找源窗口的第一个子窗口;GW_HWNDFIRST:为一个源子窗口寻找第一个兄弟(同级)窗口,或寻找第一个顶级窗口;GW_HWNDLAST:为一个源子窗口寻找最后一个兄弟(同级)窗口,或寻找最后一个顶级窗口;GW_HWNDNEXT:为源窗口寻找下一个兄弟窗口;GW_HWNDPREV:为源窗口寻找前一个兄弟窗口;GW_OWNER:寻找窗口的所有者; .DLL命令 GetWindowText, 整数型, "user32.dll", "GetWindowTextA", 公开, 取得一个窗体的标题(caption)文字,或者一个控件的内容(在vb里使用:使用vb窗体或控件的caption或text属性) 复制到lpString的字串长度;不包括空中止字符。会设置GetLastError .参数 句柄, 整数型, , 欲获取文字的那个窗口的句柄 .参数 文本, 文本型, , 预定义的一个缓冲区,至少有cch+1个字符大小;随同窗口文字载入 .参数 文本长度, 整数型, , lp缓冲区的长度; .DLL命令 GetWindowTextLength, 整数型, "user32", "GetWindowTextLengthA", 公开, 调查窗口标题文字或控件内容的长短(在vb里使用:直接使用vb窗体或控件的caption或text属性) 字串长度,不包括空中止字符 .参数 hwnd, 整数型, , 想调查文字长度的窗口的句柄; .DLL命令 GetWindowThreadProcessId, 整数型, "user32.dll", "GetWindowThreadProcessId", 公开, GetWindowThreadProcessId,获取与指定窗口关联在一起的一个线程和进程标识符 .参数 窗口句柄, 整数型, , hwnd,指定窗口句柄 .参数 进程标识符, 整数型, 传址, lpdwProcessId,指定一个变量,用于装载拥有那个窗口的一个进程的标识符 .DLL命令 KillTimer, 整数型, "user32.dll", "KillTimer", 公开 .参数 窗口句柄, 整数型, , hwnd .参数 事件标识符, 整数型, , nIDEvent .DLL命令 LoadLibraryA, 整数型, "kernel32.dll", "LoadLibraryA", 公开, , 载入指定的动态链接库,并将它映射到当前进程使用的地址空间 .参数 动态链接库名称, 文本型, , lpLibFileName,指定要载入的动态链接库的名称 .DLL命令 LookupPrivilegeValueA, 逻辑型, "advapi32.dll", "LookupPrivilegeValueA", 公开 .参数 lpSystemName, 文本型 .参数 lpName, 文本型 .参数 lpLuid, LuID, 传址 .DLL命令 Module32First, 整数型, "kernel32.dll", "Module32First", 公开 .参数 hSnapshot, 整数型, , hSnapshot .参数 模块进程结构, MODULEENTRY32, 传址 .DLL命令 Module32Next, 整数型, "kernel32.dll", "Module32Next", 公开 .参数 hSnapshot, 整数型, , hSnapshot .参数 模块进程结构, MODULEENTRY32, 传址 .DLL命令 OpenProcess, 整数型, "kernel32.dll", "OpenProcess", 公开, kernel32.dll .参数 访问级别, 整数型, , 2035711完全访问 .参数 子进程继承, 逻辑型, , 0为子进程继承 .参数 进程ID, 整数型, , 要打开的进程标识 .DLL命令 OpenProcessToken, 整数型, "advapi32.dll", "OpenProcessToken", 公开 .参数 ProcessHandle, 整数型 .参数 DesiredAccess, 整数型 .参数 TokenHandle, 整数型, 传址 .DLL命令 OpenThread, 整数型, "kernel32.dll", "OpenThread", 公开 .参数 dwDesiredAccess, 整数型 .参数 bInheritHandle, 逻辑型 .参数 dwThreadId, 整数型 .DLL命令 Process32First, 整数型, "kernel32.dll", "Process32First", 公开, 取进程快照第一个进程信息返回内存指针 .参数 快照句柄, 整数型 .参数 进程信息, 进程信息 .DLL命令 Process32Next, 整数型, "kernel32.dll", "Process32Next", 公开 .参数 快照句柄, 整数型 .参数 进程信息, 进程信息 .DLL命令 ReadProcessMemory, 整数型, "kernel32.dll", "ReadProcessMemory", 公开, 在进程中读内存数据 地址1048576 .参数 进程句柄, 整数型, , 欲读取的进程句柄(可用OpenProcess函数得到) .参数 地址, 整数型, , 读取的起始地址 .参数 返回内容, 字节集, 传址, 返回的数据,其类型可设为整数、文本和字节集 .参数 长度, 整数型, , 一次读取的字节长度(读取的字节数4) .参数 实际长度, 整数型, 传址, 实际读取的字节长度 .DLL命令 RegOpenKeyExA, 整数型, , "RegOpenKeyExA", 公开, 打开注册表项 .参数 hKey, 整数型 .参数 lpSubKey, 文本型 .参数 ulOptions, 整数型 .参数 samDesired, 整数型 .参数 phkResult, 整数型, 传址 .DLL命令 ResumeThread, 整数型, "kernel32.dll", "ResumeThread", 公开, 开始暂停的线程 .参数 线程句柄, 整数型 .DLL命令 RtlMoveMemory, 整数型, , "RtlMoveMemory", 公开 .参数 lpvDest, 整数型, 传址 .参数 lpvSource, 整数型 .参数 cbCopy, 整数型 .DLL命令 SetThreadContext, 逻辑型, "kernel32", "SetThreadContext", 公开 .参数 hThreadId, 整数型 .参数 线程环境, context_ .DLL命令 SetThreadContext1, 逻辑型, "kernel32", "SetThreadContext", 公开 .参数 线程句柄, 整数型 .参数 寄存器, 寄存器 .DLL命令 SetTimer, 整数型, "user32.dll", "SetTimer", 公开 .参数 窗口句柄, 整数型, , hwnd .参数 事件标识符, 整数型, , nIDEvent .参数 时钟周期, 整数型, , uElapse .参数 回调函数地址, 整数型, , lpTimerFunc .DLL命令 SetWindowsHookEx, 整数型, "user32.dll", "SetWindowsHookExA", 公开 .参数 钩子类型, 整数型 .参数 处理函数入口, 整数型 .参数 函数所在模块, 整数型 .参数 目标线程ID, 整数型 .DLL命令 SHFileOperation, 整数型, "Shell32.dll", "SHFileOperationA", 公开 .参数 文件参数, SHFILEOPSTRUCT .DLL命令 SuspendThread, 整数型, , "SuspendThread", 公开 .参数 线程句柄, 整数型 .DLL命令 TerminateProcess, 整数型, "kernel32.dll", "TerminateProcess", 公开, 成功返回非零 .参数 进程句柄, 整数型 .参数 退出代码, 整数型, , 传入0 .DLL命令 TerminateThread, 逻辑型, "kernel32", "TerminateThread", 公开 .参数 hThread, 整数型 .参数 dwExitCode, 整数型 .DLL命令 Thread32First, 逻辑型, "kernel32.dll", "Thread32First", 公开 .参数 hSnapshot, 整数型 .参数 lpte, THREADENTRY32, 传址 .DLL命令 Thread32Next, 逻辑型, "kernel32.dll", "Thread32Next", 公开 .参数 hSnapshot, 整数型 .参数 lpte, THREADENTRY32, 传址 .DLL命令 VirtualAllocEx, 整数型, "kernel32.dll", "VirtualAllocEx", 公开, 成功返回分配内存的首地址,失败返回0 .参数 hProcess, 整数型, , 申请内存所在的进程句柄 .参数 lpAddress, 整数型, , 填0 .参数 dwSize, 整数型, , 欲分配的内存大小 .参数 flAllocationType, 整数型, , 填4096,MEM_COMMI .参数 flProtect, 整数型, , 填64,可读可写,可执行 .DLL命令 VirtualFreeEx, 整数型, "kernel32.dll", "VirtualFreeEx", 公开 .参数 hProcess, 整数型 .参数 lpAddress, 整数型 .参数 dwSize, 整数型, , 填0 .参数 dwFreeType, 整数型, , 填32768 .DLL命令 VirtualProtect, 整数型, "kernel32.dll", "VirtualProtect", 公开, 成功返回非0,失败返回0 .参数 起始地址, 整数型, , lpAddress .参数 长度, 整数型, , dwSize .参数 新保护权限, 整数型, , 可读写权限(PAGE_READWRITE)=4;PAGE_EXECUTE_READWRITE=64 .参数 旧保护权限, 整数型, 传址, 保存旧属性的结构变量地址 .DLL命令 VirtualProtectEx, 整数型, "kernel32.dll", "VirtualProtectEx", 公开, 成功返回非0,失败返回0 .参数 hprocess, 整数型, , 要修改内存的进程句柄 .参数 起始地址, 整数型, , lpAddress .参数 长度, 整数型, , dwSize .参数 新保护权限, 整数型, , 可读写权限(PAGE_READWRITE)=4 .参数 旧保护权限, 整数型, 传址, 保存旧属性的结构变量地址 .DLL命令 VirtualQueryEx, 整数型, "kernel32.dll", "VirtualQueryEx", 公开 .参数 hProcess, 整数型 .参数 lpAddress, 整数型 .参数 info, MEMORY_BASIC_INFORMATION, 传址 .参数 dwLength, 整数型 .DLL命令 VMProtectBegin, , "VMProtectSDK32.lib", "_VMProtectBegin@4", 公开, 功能:设置开始标记 .参数 MarkerName, 文本型, 传址, 标记名 .DLL命令 VMProtectBeginMutation, , "VMProtectSDK32.lib", "_VMProtectBeginMutation@4", 公开, 功能:设置[变异]标记 .参数 MarkerName, 文本型, 传址, 标记名 .DLL命令 VMProtectBeginUltra, , "VMProtectSDK32.lib", "_VMProtectBeginUltra@4", 公开, 功能:设置[虚拟+变异]标记 .参数 MarkerName, 文本型, 传址 .DLL命令 VMProtectBeginUltraLockByKey, , "VMProtectSDK32.lib", "_VMProtectBeginUltraLockByKey@4", 公开 .参数 MarkerName, 文本型, 传址, 标记名 .DLL命令 VMProtectBeginVirtualization, , "VMProtectSDK32.lib", "_VMProtectBeginVirtualization@4", 公开, 功能:设置[虚拟]标记 .参数 MarkerName, 文本型, 传址, 标记名 .DLL命令 VMProtectBeginVirtualizationLockByKey, , "VMProtectSDK32.lib", "_VMProtectBeginVirtualizationLockByKey@4", 公开 .参数 MarkerName, 文本型, 传址 .DLL命令 VMProtectDecryptStringA, 整数型, "VMProtectSDK32.lib", "_VMProtectDecryptStringA@4", 公开, 功能:加密Ansi字符串常量,返回加密后的字符串指针 .参数 char, 文本型, 传址, 提供Ansi字符串常量 .DLL命令 VMProtectDecryptStringW, 整数型, "VMProtectSDK32.lib", "_VMProtectDecryptStringW@4", 公开, 功能:加Unicode字符串,返回加密后的字符串指针 .参数 wchar_t, 文本型, 传址, 提供Unicode字符串常量 .DLL命令 VMProtectEnd, , "VMProtectSDK32.lib", "_VMProtectEnd@0", 公开, 功能:设置与虚拟/变异等功能配对的结束标记 .DLL命令 VMProtectIsDebuggerPresent, 逻辑型, "VMProtectSDK32.lib", "_VMProtectIsDebuggerPresent@4", 公开, 功能:检测调试器是否存在 .参数 CheckKernelMode, 逻辑型, , 是否检测KernelMode调试器.为假,则检测user-mode调试器,例如OllyDBG, WinDBG等..为真,则同时检测user-mode和KernelMode(包括SoftICE, Syser等...)调试器, .DLL命令 VMProtectIsValidImageCRC, 逻辑型, "VMProtectSDK32.lib", "_VMProtectIsValidImageCRC@0", 公开, 功能:检测程序内存没有没有被改变 .DLL命令 VMProtectIsVirtualMachinePresent, 逻辑型, "VMProtectSDK32.lib", "_VMProtectIsVirtualMachinePresent@0", 公开, 功能:检测程序是否运行在虚拟机,比如VMware, Virtual PC, VirtualBox, Sandboxie等... .DLL命令 WaitForSingleObject, 整数型, "kernel32.dll", "WaitForSingleObject", 公开 .参数 hHandle, 整数型 .参数 dwMilliseconds, 整数型, , 填-1 .DLL命令 WriteProcessMemory, 逻辑型, "kernel32.dll", "WriteProcessMemory", 公开 .参数 进程句柄, 整数型 .参数 开始写入进址, 整数型, , 内存地址 .参数 写入数值数据, 字节集, 传址, 数据指针 .参数 写入长度, 整数型, , 长度 .参数 实际写入长度, 整数型, , 实际写出长度0 .DLL命令 取文本指针, 整数型, "kernel32", "lstrcpyn", 公开, 感谢海洋老师的例程 .参数 变量, , 传址, 一定要传址 .参数 变量, , 传址, 一定要传址.重复一次,骗骗Windows:) .参数 保留, 整数型, , 0 .图片 SE_PROTECT_END, 公开, 置入代码 (#SE_PROTECT_END)'结束标记 .图片 SE_PROTECT_START, 公开, 置入代码 (#SE_PROTECT_START)'默认保护 .图片 SE_PROTECT_START_MUTATION, 公开, 置入代码 (#SE_PROTECT_START_MUTATION)'乱序变形 .图片 SE_PROTECT_START_ULTRA, 公开, 置入代码 (#SE_PROTECT_START_ULTRA)'乱序+虚拟 .图片 SE_PROTECT_START_VIRTUALIZATION, 公开, 置入代码 (#SE_PROTECT_START_VIRTUALIZATION)'虚拟 .图片 SE_UNPROTECT_END, 公开, 置入代码 (#SE_UNPROTECT_END)'屏蔽特定代码的乱序和混淆 .图片 SE_UNPROTECT_START, 公开, 置入代码 (#SE_UNPROTECT_START)'屏蔽特定代码的乱序和混淆 .图片 VMProtect_Begin, 公开, 置入代码 (#VMProtect_Begin) 'VMP保护开始标志 .图片 VMProtect_End, 公开, 置入代码 (#VMProtect_End) 'VMP保护结束标志
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值