您的位置:首页 > 移动开发 > 微信开发

监视API调用的一个小程序

2005-07-28 01:29 357 查看
工作一段时间了,我喜欢工作,但是,工作确实很累,压里很大~所以我就得每天好好的学习,抓进一切时间学习,于是,我就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);
//}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐