监视API调用的一个小程序

工作一段时间了,我喜欢工作,但是,工作确实很累,压里很大~所以我就得每天好好的学习,抓进一切时间学习,于是,我就APIHOOK这个主题进行了一番演练:监视API调用的一个小程序,原理是根据远程进程的导入目录和IAT,查找API的名字、所属的DLL和入口地址,然后让所有导入的API都指向同一个函数,这个函数由我的DLL导出,完成输出API调用的功能,我也说不清楚,反正核心就是APIHOOK。

/APIMON.C//
/*
首先,加载一个负责记录信息的DLL到远程进程并保存基址
接着读远程数据,根据所度读数据和远程DLL基址构造本地SwitchTable,同时修改远程IAT!
要读的数据类型有DWORD和IDT
所以实现ReadRemoteDWORD(hp,addr)和ReadRemoteIDT(HANDLE hp,void* addr,IDT* idt)这两个函数
*/

#include "windows.h"
#include "tlhelp32.h"
#include "stdio.h"

定义//

#define API    APIENTRY

typedef struct
{
 char** API_DEC;
 DWORD unknown1;
 DWORD unknown2;
 char* dllName;
 DWORD* IAT;
}IDT;

typedef struct
{
 char code[32];
}SwitchItem;

///声明///

const BYTE switchItem[32]=
{
 0x60,                       // PUSHAD
 0x54,                       // PUSH ESP
 0x68,0x00,0x00,0x00,0x00,               // PUSH ModuleName  @3
 0x68,0x00,0x00,0x00,0x00,                  // PUSH ApiName  @8
 0xB8,0x00,0x00,0x00,0x00,                  // MOV EAX,HOOKPROC @13
 0xFF,0xD0,                   // CALL EAX
 0x61,                    // POPAD
 0x68,0x00,0x00,0x00,0x00,                  // PUSH ApiEP   @21
 0xc3,                       // RET
 0x90,0x90,0x90,                  // NOPS
 0x90,0x90,0x90                     // NOPS
};

SwitchItem    *RemoteSIBase,*si;
BOOL     HookOver=FALSE;
DWORD     cPID;
CHAR                    outputHelper[]="OutputHelper.dll";
CHAR                    kernel32[]="kernel32.dll";

HANDLE     hModule,remoteProc;
DWORD     RemoteCallbackProc;

///定义///
void  API FillCodeAndChangeIAT(char* moduleName,char* apiName,DWORD* IAT);
void* API GetrRemoteBase();
void  API ConvertIDT(DWORD mzBase,IDT* Tidt);
void  API CreateSwitchTable(DWORD mzBase);
DWORD API ReadRemoteDWORD(void* address);
BOOL  API ReadRemoteIDT(void* address,IDT* idt);
BOOL  API EditRemoteDWORD(void* address,DWORD value);
BOOL  API EditeRemoteBlock(void* address,void* lpBuffer,DWORD size);
BOOL  API WriteRemoteSwitchItem(void* address,void* si);
char* API WriteRemoteString(char* str);
BOOL  API BeginHook(DWORD PID);
LPTHREAD_START_ROUTINE API LocateRemoteAPI(char* modName,char* apiName);

///实现///

void  API FillCodeAndChangeIAT(char* moduleName,char* apiName,DWORD* IAT)
{
    CopyMemory(si->code,&switchItem,sizeof(switchItem));
 *(DWORD*)(((char*)si->code)+3)=moduleName;
 *(DWORD*)(((char*)si->code)+8)=apiName;
 *(DWORD*)(((char*)si->code)+13)=RemoteCallbackProc;
 *(DWORD*)(((char*)si->code)+21)=ReadRemoteDWORD(IAT);
    WriteRemoteSwitchItem(RemoteSIBase,si);
    EditRemoteDWORD(IAT,RemoteSIBase);
}

void* API GetrRemoteBase()
{
 HANDLE hModuleSnap;
 MODULEENTRY32 me32={0};
 DWORD res=0;

 hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,cPID);
 me32.dwSize=sizeof(MODULEENTRY32);
 if(Module32First(hModuleSnap,&me32))
 {
  res=me32.modBaseAddr;
 }
 CloseHandle(hModuleSnap);
 return res;
}

void  API ConvertIDT(DWORD mzBase,IDT* Tidt)
{
 Tidt->API_DEC=(DWORD)Tidt->API_DEC+mzBase;
 Tidt->dllName+=mzBase;
 Tidt->IAT=(DWORD)Tidt->IAT+mzBase;
}

void  API CreateSwitchTable(DWORD mzBase)
{
 DWORD                    size,peBase,itCount,index=0,apiCount=0;
 IDT                     *idt;
 IDT                      Tidt;
 DWORD                    temp;
 DWORD      *IATBase;
 HOOKPROC     RecordFunc;
 char*                    dllName,*apiName;

 //RecordFunc=(HOOKPROC)RecordApiCall;
 peBase=ReadRemoteDWORD(mzBase+0x3c)+mzBase;
 idt=ReadRemoteDWORD(peBase+0x80)+mzBase;
 itCount=ReadRemoteDWORD(peBase+0x84)/sizeof(IDT)-1;

 //Tidt为本地IDT
 //将远程IDT拷到本地是为了方便操作

 for(index=0;index<itCount;index++)
 {
  ReadRemoteIDT(idt,&Tidt);
  ConvertIDT(mzBase,&Tidt);
  apiName=ReadRemoteDWORD(Tidt.API_DEC)+mzBase+2;
  IATBase=Tidt.IAT;
  while(apiName!=mzBase+2)
  {
   //开始压参数
   //(char* moduleName,char* apiName,DWORD IAT);
   _asm
   {
    mov eax,IATBase
    push eax                          // IA
    mov eax,apiName
    push eax                          //apiName
   }
   temp=Tidt.dllName;
   _asm
   {
    mov eax,temp
    push eax                          //moduleName
   }
   apiCount++;
   Tidt.API_DEC++;
   IATBase++;
   apiName=ReadRemoteDWORD(Tidt.API_DEC)+mzBase+2;
  }
  //以上使用Tidt
  idt++;
 }
    //导入的所有API的信息压如堆栈完毕
 RemoteSIBase=(SwitchItem*)VirtualAllocEx(remoteProc,NULL,apiCount*sizeof(SwitchItem),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
    //根据API的数量分配内存
    RemoteCallbackProc=LocateRemoteAPI("OutputHelper.dll","_CallAPICallbackProc@12");
    //根据堆栈里的内容和apiCount生成switchTable
 si=VirtualAlloc(NULL,apiCount*sizeof(SwitchItem),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
 _asm
 {
  mov ecx,apiCount
loc1: 
  mov temp,ecx
  call FillCodeAndChangeIAT
 }
 si++;
    RemoteSIBase++;
 _asm
 {
  mov ecx,temp
  loop loc1
 }
    //连续调用FillCodeAndChangeIAT,参数已经压完
    //接着将被地构造好的SeitchTable拷贝到远程进程
     //WriteRemoteSwitchTable(RemoteSTBase,Lsi,apiCount);
}
BOOL  API WriteRemoteSwitchItem(void* address,void* si)
{
    return WriteProcessMemory(remoteProc,address,si,sizeof(SwitchItem),NULL);
}
DWORD API ReadRemoteDWORD(void* address)
{
 DWORD r;
 ReadProcessMemory(remoteProc,address,&r,4,NULL);
 return r;
}
BOOL  API ReadRemoteIDT(void* address,IDT* idt)
{
 ReadProcessMemory(remoteProc,address,idt,sizeof(IDT),NULL);
}
BOOL  API EditRemoteDWORD(void* address,DWORD value)
{
    return WriteProcessMemory(remoteProc,address,&value,4,NULL);
}
BOOL  API EditeRemoteBlock(void* address,void* lpBuffer,DWORD size)
{
    return WriteProcessMemory(remoteProc,address,lpBuffer,size,NULL);
}
char* API WriteRemoteString(char* str)
{
 void* lp;
 DWORD l;
 l=strlen(str);
 lp=VirtualAllocEx(remoteProc,NULL,l,MEM_COMMIT,PAGE_READWRITE);
 if(lp==NULL)
  return NULL;
 if(!WriteProcessMemory(remoteProc,lp,str,l,NULL))
  return NULL; 
 return lp;
}

BOOL  API BeginHook(DWORD PID)
{
 cPID=PID;
    remoteProc=OpenProcess(PROCESS_ALL_ACCESS,TRUE,PID);
    if(remoteProc!=NULL)
        return TRUE;
    return FALSE;
}
LPTHREAD_START_ROUTINE API LocateRemoteAPI(char* modName,char* apiName)
{
 DWORD offsetAPI;
 HMODULE thisDLL;
 HANDLE hModuleSnap;
 MODULEENTRY32 me32={0};

 thisDLL=LoadLibrary(modName);
 offsetAPI=(DWORD)GetProcAddress(thisDLL,apiName)-(DWORD)thisDLL;
 hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,cPID);
 me32.dwSize=sizeof(MODULEENTRY32);
 if(Module32First(hModuleSnap,&me32))
 {
  do
  {
   if(lstrcmp(me32.szModule,modName)==0)
   {
    return (DWORD)(me32.hModule)+offsetAPI;
   }
  }
  while(Module32Next(hModuleSnap,&me32));
  return 0;
 }
}

void main(int argc, char* argv[])
{
 DWORD PID;
    DWORD outputType;
 void* remoteStr;
    char buffer[1024];
 LPTHREAD_START_ROUTINE remoteLoadLibraryA;
    LPTHREAD_START_ROUTINE remoteSetOutputType;
 //PID=2216;
    if(argc<2)
 {
        printf("用法:ApiMon <PID> [f]/n switch [f] means to output to a file/n");
  return;
 }
 PID=atoi(argv[1]);
 BeginHook(PID);
    GetCurrentDirectory(1024,&buffer);
    remoteStr=strcat(strcat(&buffer,"//"),&outputHelper);
    printf("%s",remoteStr);
 remoteStr=WriteRemoteString(remoteStr);
 remoteLoadLibraryA=LocateRemoteAPI(&kernel32,"LoadLibraryA");
 if(CreateRemoteThread(remoteProc,NULL,0,remoteLoadLibraryA,remoteStr,0,NULL)!=NULL)
 {
  printf("Helper Inject OK/n");
 }
 else
 {
  printf("Fuck,What's wrong?!/n");
        return;
 }
    outputType=0;       //0=MessageBox
    if(argc>2)
    {
        if((char)argv[2]=="f") outputType=1;
    }
    remoteSetOutputType=LocateRemoteAPI(&outputHelper,"_SetOutputType@4");
 if(CreateRemoteThread(remoteProc,NULL,0,remoteSetOutputType,outputType,0,NULL)!=NULL)
 {
  printf("SetOutputType OK/n");
 }
 else
 {
  printf("Fuck,What's wrong?!/n");
        return;
 }
    CreateSwitchTable(GetrRemoteBase());
    return;
}
//重写OutputHelper.dll,其实写重复的代码没有什么意思
//但是也看到了用注入的DLL去控制进程出现了问题
//所以,我把写目标进程的代码都移到远程
//这样可能会成功,顺便写背背这些API和练练远程进程操纵
//明天得先写好OutputHelper.dll,先就只提供OutputToMessageBox@4RecordApiCall@c
//然后获得RecordApiCall@c的远程地址
//然后根据远程IDT在本地构造SwtichTable和改远程IAT
//这其中还要先分配远程虚拟空间,这样改远程IAT的时候才知道正确的地址
//最后把本地的SwitchTable拷贝到预先分配好的远程虚拟空间中
//HOOK结束!


/*改进:
由于现在只能监视已经存在的进程,这样一般不是很理想
我们需要从头到尾监视一个程序
所以有必要让APIMON具有创建监视进程的功能
使用CreateProcess创建一个进程并传递CREATE_SUSPENDED的属性以及lpProcessInformation来接受主线程句柄
被创建进程暂停后进行HOOK
然后在用ResumeThread恢复进程主线程运行就可以了
*/

/OutputHelper.c/
//DLL

#include "stdio.h"
#include "windows.h"

DWORD Type=1;
FILE* fp=NULL;

void _declspec(dllexport) APIENTRY OutputToFile(char* str);
void _declspec(dllexport) APIENTRY OutputToMessageBox(char* str);
void _declspec(dllexport) APIENTRY SetOutputType(DWORD t);
void _declspec(dllexport) APIENTRY CallAPICallbackProc(char* apiName,char *moduleName,DWORD* curESP);

BOOL APIENTRY DllMain(HANDLE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{
    switch (ul_reason_for_call)
 {
  case DLL_PROCESS_ATTACH:
  break;
  case DLL_THREAD_ATTACH:
  break;
  case DLL_THREAD_DETACH: 
  break;
  case DLL_PROCESS_DETACH: 
  break;
    }
    return TRUE;
}

void _declspec(dllexport) APIENTRY OutputToFile(char* str)
{
 if(fp)
 {
  fprintf(fp,"%s",str);
  fflush(fp);
 }
}
void _declspec(dllexport) APIENTRY OutputToMessageBox(char* str)
{
 MessageBox(0,str,"Message",0);
}

void _declspec(dllexport) APIENTRY SetOutputType(DWORD t)
{
 char buf[255];
 //Type=t;
 //if(t==0)
 //{
  sprintf(buf,"E://PID=%d.txt",GetCurrentProcessId());
        fp=fopen(&buf,"a+");
        MessageBox(0,"Starting Recording...","Message",0);
  //if(fp=fopen(&buf,"a+")==NULL)
  // Type=1;
 //}
 //if(Type==1)
 //{
 // MessageBox(0,"1",NULL,0);
 //}
 //if(Type==0)
 //{
 // MessageBox(0,"0",NULL,0);
 //}
}

void _declspec(dllexport) APIENTRY CallAPICallbackProc(char* apiName,char *moduleName,DWORD* curESP)
{
 char buf[511];
 DWORD caller;

  caller=*(curESP+8);
  sprintf(&buf,"%x : Call %s @ %s/n",caller,apiName,moduleName);
  //if(Type==1)
  //{
  OutputToFile(&buf);
  //}
  //else
  //{
  // OutputToMessageBox(&buf);
  //}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值