本人自己实现的一个向指定可执行文件注入函数的一个程序,代码注入以后,会回调事先已经
定义好的函数,在这个函数里可以实现所有的功能(代码会依次将将 模块基地址 LoadLibrary
GetProcAddress FreeLibrary GetModuleHandle 等函数,还有用户自定义的数据结构,和数据
结构的大小等东西传给指定的函数),有了这些数据,相信什么事情都可以干了,由于本人嘴
笨,只好贴上代码,我将在代码中给予仔细说明
(这样很好做壳)
//////////////////////////////
test.exe : #include "stdafx.h"
#include <windows.h>
///////////////////////////////////////////////////////////////////////////////////
//定义函数指针 不用我讲大家都应该知道吧
typedef HMODULE (_stdcall *PLOADLIBRARY)(LPCTSTR lpFileName);
typedef PVOID (_stdcall *PGETPROCADDRESS)( HMODULE hModule, // handle to DLL
module
LPCSTR lpProcName // function name
);
typedef HMODULE (_stdcall *PGETMODULEHANDLE)(
LPCTSTR lpModuleName // module name
);
typedef BOOL (_stdcall *PFREELIBRARY)(
HMODULE hModule // handle to DLL module
);
typedef int (_stdcall *PMESSAGEBOX)(
HWND hWnd, // handle to owner window
LPCTSTR lpText, // text in message box
LPCTSTR lpCaption, // message box title
UINT uType // message box style
);待会这个函数将会在回调函数调用以后,由用户动态加载,它不是回调函数必须的,我的作
用是用来显示一个消息,用来证明代码运行成功
///////////////////////////////////////////////////////////////////////////////////
/
///要传入目标文件的数据结构,这个结构是自定义的,等一下传入的时候是这个结构在目标加
载起来的时候所在的内存空间的指针
typedef struct _MYMSG{
HWND hWnd;
BYTE BUF1[30];
BYTE BUF2[30];
int Type;
BYTE ModuleName[30];
BYTE FunctionName[30];
}MYMSG,*PMYMSG;
void _stdcall MyEntryPoint(PVOID MapAddress,PLOADLIBRARY
pLoadLibrary,PGETPROCADDRESS pGetProcAddress,PGETMODULEHANDLE
pGetModuleHandle,PFREELIBRARY pFreeLibrary,PVOID UserData,DWORD UserDataSize);//要
写入目标的函数 typedef void (_stdcall *PENTRYPIONT)(PVOID MapAddress,PLOADLIBRARY
pLoadLibrary,PGETPROCADDRESS pGetProcAddress,PGETMODULEHANDLE
pGetModuleHandle,PFREELIBRARY pFreeLibrary,PVOID UserData,DWORD UserDataSize);//入
口指针
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
__declspec(dllimport)BOOL _stdcall FileIsPeFile(char *FileName);//验证目标是不是PE
文件
__declspec(dllimport)BOOL _stdcall AddFunctionToPeFile(char *FIleName,PENTRYPIONT
pEntryPoint,DWORD EntryPointSize ,PVOID Data,DWORD DataSize);//主要函数,由这个函数
提供向目标注入代码的功能
__declspec(naked)VOID _stdcall StartFun(PVOID MapAddress,PLOADLIBRARY
pLoadLibrary,PGETPROCADDRESS pGetProcAddress,PGETMODULEHANDLE
pGetModuleHandle,PFREELIBRARY pFreeLibrary,PVOID UserData,DWORD UserDataSize)//标示
回调函数开始
{
_asm jmp MyEntryPoint//跳回我们的回调函数 为什么要这样呢?以为等一下复制函
数的时候,会将我们的标示函数一起复制进去,从而导致标示函数的代码被执行,所以我们就
要一个跳转
//跳回到我们的函数
}
void _stdcall MyEntryPoint(PVOID MapAddress,PLOADLIBRARY
pLoadLibrary,PGETPROCADDRESS pGetProcAddress,PGETMODULEHANDLE
pGetModuleHandle,PFREELIBRARY pFreeLibrary,PVOID UserData,DWORD UserDataSize)//这个
就是我们要注入目标的函数,由于这个函数不是在本程序被执行,而是进入到目标程序执行,
所以这个函数不能使用任何的全局变量,静态变量,也不能调用任何API
//这个时候可能有人就问,不用API和一些变量,怎么来实现我的功能呢?
//这个就需要用到我传入的参数了,
//MapAddress 这个是这个模块的HANDLE,也就是模块的基地址,pLoadLibrary 是函数
LoadLibrary的指针,可以直接使用
///pGetProcAddress这个是函数GetProcAddress的指针,可以直接使用
///pGetModuleHandle这个是函数GetModuleHandle的指针,可以直接使用
///pFreeLibrary这个是函数FreeLibrary的指针,可以直接使用
//UserData这个指针很重要,指向的用户自定义的一个数据结构,是唯一可以使用的全局变量
,请大家在使用这个变量的时候,一定要使用能够容纳一定数据的结构,而不是指向数据结构
的一个指针
{
//以下是用户实现的功能
PMYMSG Msg = (PMYMSG)UserData;//取得用户数据结构
PMESSAGEBOX pMessageBox=NULL;
HMODULE hModule = NULL;
if(Msg==NULL)
return ;
hModule=pGetModuleHandle((char*)&Msg->ModuleName[0]);//加载DLL
if(hModule==NULL)
{
hModule = pLoadLibrary((char*)&Msg->ModuleName);//加载DLL
}
if(hModule==NULL)
return ;
pMessageBox=(PMESSAGEBOX)pGetProcAddress(hModule,(char*)&Msg-
>FunctionName);//取得MessageBoxA函数的地址
if(!pMessageBox)
return ;
pMessageBox(Msg->hWnd,(char*)&Msg->BUF1,(char*)&Msg->BUF2,Msg->Type);//显示
提示框
// _asm jmp pLoadLibrary
return ;
}
__declspec(naked)VOID _stdcall EndFun()//标示回调函数结束
{
}
int main(int argc, char* argv[])
{
DeleteFile("d:\\test.exe");
::CopyFile(argv[0],"d:\\test.exe",0);
MYMSG MyMsg={0};
strcpy((char*)&MyMsg.BUF1[0],"欢迎使用!");
strcpy((char*)&MyMsg.BUF2[0],"Welcome!");
strcpy((char*)&MyMsg.ModuleName[0],"User32.dll");
strcpy((char*)&MyMsg.FunctionName[0],"MessageBoxA");
MyMsg.Type=48;
MyMsg.hWnd=0;
if(AddFunctionToPeFile("d:\\test.exe",//目标文件地址
StartFun,//注入目标的函数在本进程的地址
((DWORD)&EndFun-(DWORD)&StartFun),要注入的代码的大小
&MyMsg,//用户自定义的数据结构,这个结构是唯一的全局变量,回调函数中的UserData指针指
向的就是这个变量在目标的指针
sizeof(MyMsg)))//用户自定义的数据结构的大小
//调用函数向目标添加函数
MessageBox(0,"添加成功!","添加函数",48);
else
MessageBox(0,"添加失败!","添加函数",48);
printf("Hello World!\n");
return 0;
} AddFunctionDll :
主要函数实现:
其余的请看传上来的代码
BOOL _stdcall AddFunctionToPeFile(char *FIleName,PENTRYPIONT pEntryPoint,DWORD
EntryPointSize ,PVOID Data,DWORD DataSize)
{
// DWORD Size = EntryPointSize+DataSize;
static char *buffer[]={
"Kernel32.dll",
"LoadLibraryA",
"GetProcAddress",
"GetModuleHandleA",
"FreeLibrary",
0,
0,
};
ULONG Rav = 0;
DWORD Size = (((DWORD)&End-(DWORD)&EntryPoint)+EntryPointSize);//计算一下传
入目标的代码的多少,包括用来回调用户函数的入口函数的大小
PIMAGE_SECTION_HEADER OldSectionHeader = NULL;
DWORD Address = 0;
KERNEL32DLL Kernel32={0};
PKERNEL32DLL pKernel32;//这个也是一个全局变量,也可以在目标进程使用,但是这
个是我们内部使用的,是不暴露给用户的,但是用户的结构的VA我们保存在这里,这样我们就
能够计算出
//用户的数据结构在目标的真实地址,以便我们传递给用户的回调函数
IMAGE_SECTION_HEADER pSectionHeader={0};
CLoadPeFile LoadPeFile;//自己写的一个类,主要是对映射文件用的API进行封装
CLoadFile LoadFile;//自己写的一个类,主要是对读取文件用的API进行封装
PVOID pFun = (PVOID)malloc(Size+DataSize);//申请缓冲区,用来临时保
存一些数据
if(pFun==NULL)
return 0;
if(!IsPeFile(FIleName))//验证一下是否是PE 文件
{
free(pFun);
return 0;
}
if(!AddImportDirectory(FIleName,buffer,&Address))//向目标的导入表添加指定的
函数,函数由buffer变量指定
{
free(pFun);
return 0;
}
//调用成功AddImportDirectory,这个时候Address保存的就是旧的导入表的VA
if(!AddNewSection
(FIleName,FIleName,".czc",Size+DataSize,&pSectionHeader))//向表添加新节
{
free(pFun);
return 0;
}
if(!LoadModuleFile(&LoadPeFile,&LoadFile,FIleName))//将目标读取进入
内存,我主要采用的映射方式读取进入内存的
{
free(pFun);
return 0;
}
OldSectionHeader=ImageRvaToSection(LoadPeFile.GetNtHeaders
(),LoadPeFile.GetMapAddress(),Address);//得到旧导入表所在的节
OldSectionHeader->Characteristics|=IMAGE_SCN_MEM_WRITE;//修改节属性
,加上写属性
CopyDataToPeFile
(&LoadPeFile,pSectionHeader.VirtualAddress,&EntryPoint,((DWORD)&End-(DWORD)
&EntryPoint));//将入口函数写入目标
Kernel32.EntryPoint=LoadPeFile.GetNtHeaders()-
>OptionalHeader.AddressOfEntryPoint;//保存目标的原入口函数的VA
Kernel32.MapAddress=pSectionHeader.VirtualAddress+15;//保存Kernel32结构在目标的VA
Kernel32.GetModuleHandle=GetImportDirectoryFunction
(&LoadPeFile,"GetModuleHandleA","Kernel32.dll");//取得导入表中指定函数所在的VA
Kernel32.GetProcAddress=GetImportDirectoryFunction
(&LoadPeFile,"GetProcAddress","Kernel32.dll");//同上
Kernel32.FreeLibrary=GetImportDirectoryFunction
(&LoadPeFile,"FreeLibrary","Kernel32.dll");//同上
Kernel32.UserData=pSectionHeader.VirtualAddress+Size;//计算用户结构所在的VA,用户的
数据结构应该在代码后面
Kernel32.UserDataSize=DataSize;//数据大小
CopyDataToPeFile
(&LoadPeFile,pSectionHeader.VirtualAddress+15,&Kernel32,sizeof(Kernel32));
pKernel32=(PKERNEL32DLL)LoadPeFile.ImageRvaToVa
(pSectionHeader.VirtualAddress+15);
CopyMemory(pKernel32,&Kernel32,sizeof(KERNEL32DLL));
pKernel32=(PKERNEL32DLL)LoadPeFile.ImageRvaToVa
(pSectionHeader.VirtualAddress+15);
//
//这里好像重复了,但是请原谅,看电脑久了,头晕了,不改了,不知道的自己调试
memcpy((PVOID)((DWORD)(pFun)+Size),Data,DataSize);
memcpy(pFun,&EntryPoint,((DWORD)&End-(DWORD)&EntryPoint));
memcpy((PVOID)((DWORD)(pFun)+((DWORD)&End-(DWORD)
&EntryPoint)),pEntryPoint,EntryPointSize);
Kernel32.LoadLibrary=GetImportDirectoryFunction
(&LoadPeFile,"LoadLibraryA","Kernel32.dll"); memcpy((PVOID)((DWORD)(pFun)+15),&Kernel32,sizeof
(Kernel32));
// _asm call pFun
makejmp((PVOID)((DWORD)pSectionHeader.VirtualAddress+5),(PVOID)
LoadPeFile.GetNtHeaders()->OptionalHeader.AddressOfEntryPoint,(PVOID)((DWORD)
pFun+5),
&Rav);//用来生成跳回原来入口点指令的函数
CopyDataToPeFile
(&LoadPeFile,pSectionHeader.VirtualAddress,pFun,Size+DataSize);//将所有代码写入文件
CopyDataToPeFile
(&LoadPeFile,pSectionHeader.VirtualAddress+Size,Data,DataSize);//将所有全局变量写入
文件
LoadPeFile.GetNtHeaders()-
>OptionalHeader.AddressOfEntryPoint=pSectionHeader.VirtualAddress;//修改入口点
pKernel32=(PKERNEL32DLL)LoadPeFile.ImageRvaToVa
(pSectionHeader.VirtualAddress+15);//测试用的,主要是看一下写入的数据结构是否正确,
前面我写数据的,时候,结构一直不正确,弄得我很头晕,所以我就加上了这个测试
LoadPeFile.CloseFile();//关闭映射,将内存中的未写入磁盘的内容写入磁盘
free(pFun);
return TRUE;
}
////////////////////////////////////////下面我讲一下入口函数的构成,其余的请看代码
__declspec(naked) void _stdcall EntryPoint()
{
_asm
{
call GetAddressAndCall //调用函数,取得Kernel32变量的指针
nop //这里用来容纳一个JMP指令
nop //这个指令是用来
nop //跳回原来入口点
nop //用的
nop //
nop
nop
nop
nop
nop
nop //Kernel32变量应该在这个位置,它在内
存中的位置为 EntryPoint + 15
nop
nop
nop
nop
nop
nop //这里为什么要写这么多的NOP指令呢?
主要是填充用的,确保能够容下Kernel32结构
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
}
}
__declspec(naked)void _stdcall CallEntryPoint(PVOID MapAddress,PLOADLIBRARY
pLoadLibrary,PGETPROCADDRESS pGetProcAddress,PGETMODULEHANDLE
pGetModuleHandle,PFREELIBRARY pFreeLibrary,PVOID UserData,DWORD UserDataSize)
{
_asm jmp End //跳到用户函数
}
PVOID _stdcall EntryPointFun(PKERNEL32DLL pKernel32Dll)//分发函数,用来取得必要的参
数以后,将其传入用户回调函数
{
PVOID MapAddress = 0;
PFREELIBRARY pFreeLibrary = NULL;
PLOADLIBRARY pLoadLibrary = NULL;
PGETPROCADDRESS pGetProcAddress = NULL;
PGETMODULEHANDLE pGetModuleHandle = NULL;
PVOID pUserData;
DWORD UserDataSize;
MapAddress=(PVOID)((DWORD)pKernel32Dll-pKernel32Dll->MapAddress);//取得
HANDLE ,其实模块的映射地址就是她的HANDLE,
// pKernel32Dll->UserData=1;
if(pKernel32Dll->UserData==0)//用户结构验证
{
UserDataSize = 0;
pUserData=NULL;
}else
{
//取得用户的数据结构所在地址,由于前面我们已经将用户数据结构的VA保存在Kernel32结构
中了,又因为我们已经计算出模块的映射地址,所以用户数据所在的地址就是
//pKernel32Dll + pKernel32Dll->UserData
pUserData=(PVOID)((DWORD)MapAddress+pKernel32Dll->UserData);
char *Buf = (char*)pUserData;
PMYMSG Msg = (PMYMSG)pUserData;
Buf=(char*)&Msg->ModuleName[0];
_asm MOV EAX,pUserData
UserDataSize=pKernel32Dll->UserDataSize;
}
pLoadLibrary=*(PLOADLIBRARY *)((DWORD)MapAddress+(DWORD)pKernel32Dll-
>LoadLibrary);//从导入表取得指定函数的地址,原理同取得用户数据结构一样
pGetProcAddress=*(PGETPROCADDRESS *)((DWORD)MapAddress+(DWORD)pKernel32Dll
->GetProcAddress);//同上
pGetModuleHandle=*(PGETMODULEHANDLE *)((DWORD)MapAddress+(DWORD)
pKernel32Dll->GetModuleHandle);//同上
pFreeLibrary=*(PFREELIBRARY*)((DWORD)MapAddress+(DWORD)pKernel32Dll-
>FreeLibrary);//同上
CallEntryPoint
(MapAddress,pLoadLibrary,pGetProcAddress,pGetModuleHandle,pFreeLibrary,pUserData,Us
erDataSize);//连同用户数据结构,和指定函数的的指针回调给用户,这个时候能//确保使用
的结构,以及指针已经可以使用了
_asm
{
mov esp,ebp
pop ebp
ret 4
}
return 0;
}
__declspec(naked)void _stdcall GetAddressAndCall()//用来取得Kernel32结构的函数,并
且这个函数还会将Kernel32结构的指针传递给EntryPointFun函数
{
_asm
{
mov edi,edi
push ebp //保存原来的值
mov ebp,esp //保存堆饯
mov ecx,[ebp+4]//取得EntryPoint函数中第二条指令的地址,它的地址是
EntryPoint+5 那么它再加10 就是Kernel32结构的地址了
add ecx,10//取得Kernel32结构的地址
push ecx //保存原来的值
push ecx //传入参数
call EntryPointFun //调用分发函数
pop ecx //弹出堆饯
mov esp,ebp //恢复堆饯
pop ebp //弹出堆饯得到原来ebp的值
ret //函数返回,返回以后,就通过EntryPoint+5处的JMP指令,跳回到原入
口点执行
}
}
__declspec(naked)void _stdcall End()//这个函数实际上其在写入目标以后接入的就是用户
的回调函数,所以从CallEntryPoint来到这里以后,就会陷入用户的回调函数中执行
{
_asm nop
}
///////////////////////////////////////////////////////////由于时间的关系,我只能写
到这里 我要睡觉了,有什么问题,请大家指出,欢迎大家修改代码,也欢迎大家批评
代码我上传了 我已经修正了代码中的BUG,发布在后面的帖子里面,向后找找就可以看到了
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: