inline hook的实现

思路

  对于目标运行中的EXE程序,如notepad.exe,使用inline hook劫持其kernel32.dll中的writefile函数:

  1. 找到notepad.exe的进程PID,通过进程PID获取进程模块,通过进程模块获取程序加载的imagebase。
  2. 在获得imagebase后,就可以像类似分析PE文件一样,先找PE头,然后到可选头,里面读取data directory的第2个成员,是IDT表的RVA和大小。
  3. 在IDT中找到对应的kernel32.dll,去kernel32.dll项的的INT中找到函数writefile,记录下标;拿下标在kernel32.dll项的IAT表中找到writefile在内存中的地址,记录下该地址。
  4. 把数据进行注入,之后对shellcode进行微调整,主要是最后一段调整。最后一段里面要包含writefile里面的前几个字节的内容,最后是跳转指令E9,跳转的偏移也要进行调整。
  5. 对wirtefile的地址处前几个字节进行改写,头5字节是一个跳转指令,跳转到shellcode。

系统结构

  包括inlinehook.exe、和notepad.exe(可以是其它的文件)。inlinehook.exe在notepad.exe执行时,注入shellcode,并进行inlinehook,hook掉目标函数如writefile。在操作notepad.exe时,如果按ctrl+s或者点击“文件->保存”,就会在notepad.exe中调用writefile函数,就会触发shellcode。系统结构如下图3-1所示。
在这里插入图片描述

shellcode

C语言版

#include <windows.h>
#include <stdio.h>
typedef void(*DLLWITHLIB)(void);
typedef HINSTANCE(*LOADP)(char*);
typedef LPTSTR(*GETP)(HINSTANCE,char*);
typedef void(*MSGBOX)(int,char*,char*,int);
int main()
{  
    //在inlinehook中执行,获得当时LoadLibraryA和GetProcAddress在内存中地址
	HINSTANCE LibHandle = LoadLibrary("KERNEL32.dll"); 
   //获取DLL中导出函数地址
    LPTSTR getaddr1 = (LPTSTR)GetProcAddress(LibHandle, "LoadLibraryA"); 
    //获取DLL中导出函数地址
    LPTSTR getaddr2 = (LPTSTR)GetProcAddress(LibHandle, "GetProcAddress"); 
    //加载user32.dll,里面有MessageBox
	HINSTANCE LibHandle1=(*(LOADP)getaddr1)("USER32.dll");
	
    //获取DLL中导出函数MessageBoxA的地址
    LPTSTR getaddr3 = (*(GETP)getaddr2)(LibHandle1, "MessageBoxA");
    //调用MessageBox弹框
	(*(MSGBOX)getaddr3)(0,"组员","组号",0);
    return 0;
}

  在inlinehook.exe中,执行LoadLibraryA()和GetProcAddress(),获取当时kernel32.dll里这两个函数的地址,然后就可以在shellcode中使用call来进行使用。使用它们,在目标函数中加载user32.dll,进而调用MessageBoxA函数,实现弹框。

汇编版

  shellcode包括一开始进行压栈,保存通用寄存器和EFLAGS;最后也要对它们的值进行恢复。调用LoadLibraryA加载user32.dll,调用GetProcAddress获取MessageBoxa的地址。然后调用MessageBoxA弹窗,最后将损伤了的目标函数的前几个字节,损伤了几个,就填入几个,剩下的空位用NOP填。接着E9进行跳转,每次到跳转到目标函数处的起始第5字节,但是起始第5字节后面可能会写入几个NOP。如损伤了7个字节,这7个字节的内容都写在shellcode里面了,执行过了,所以目标函数处的第6、7字节填为NOP,否则会执行失败。
  里面有几个地方是需要每次执行都要填写的,主要是B8、BB、68后的地址,有的是函数地址,有的是数据中的字符串的地址。以及指令填在NOP,E9跳转每次都不一样,也需要填写。
在这里插入图片描述

跳转关系图

在这里插入图片描述
  以inlinehook程序notepad.exe的WriteFile函数为例。如图3-3所示,当运行了inlinehook.exe后,当在notepad.exe中要调用WriteFile时,程序仍然会先运行到0x7C810E17处,但是在该地址处的指令不再是PUSH 18,而变成了JMP shellcode,程序跳转到shellcode处执行。shellcode中的内容在JMP前有7字节,之所以不是5字节,是因为7字节才是完整的两条指令,如果只在shellcode中留下5个字节,之后会发生执行错误。
  在shellcode中最后是跳转到0x7C810E1B处,也就是原先的函数的第6字节,而这里填写了2个NOP指令,因为原本在这里的指令,被放到shellcode中执行了。

函数调用关系

在这里插入图片描述
在这里插入图片描述

函数和对应需要“损伤”字节

在这里插入图片描述

源代码

#include <sys/stat.h>
#include <windows.h>
#include <Tlhelp32.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
//节表 
struct section_header{
	uint8_t name[8];//名字
	uint32_t virtualsize;
	uint32_t RVA;//内存中地址
	uint8_t size_of_raw_data[4];//节大小
	uint32_t file_address;//文件中地址,RVA-file_addr得到本节中delta
	uint8_t notimportant[12];
	uint8_t character[4]; 
};

//IDT项
struct IDT_entry{
	uint32_t INT_pointer;//指向INT表
	uint32_t timestamp;
	uint32_t forwarderchain;
	uint32_t dll_name_pointer;//指向DLL名字
	uint32_t IAT_pointer;//指向IAT表
};

//hint-name table
struct hint_name{
	uint16_t hint;//函数序号 
	char name[50];//函数名 
};

//地址和PID
struct PID_and_VA{
	uint32_t pid;
	uint32_t VA;
}; 

//获取文件字节数 
int file_size(char* filename)
{
    struct stat statbuf;
    stat(filename,&statbuf);
    int size=statbuf.st_size;
    return size;
}


uint32_t uint8to32(uint8_t fouruint8[4]) {
	return *(uint32_t*)fouruint8;	
}

uint16_t uint8to16(uint8_t fouruint8[2]) {
	return *(uint16_t*)fouruint8;	
}

//打印十六进制字符,小端序 
void printf_hex_buff(char * buff,int num){
	int i=0;
	for(i=0;i<num;i++)
		printf("%X ",(uint8_t)buff[i]);
	printf("\n");
}
void printf_hex_buff(uint8_t * buff,int num){
	int i=0;
	for(i=0;i<num;i++)
		printf("%X ",buff[i]);
	printf("\n");
}

//提升权限 
BOOL EnableDebugPrivilege()
{
	HANDLE hToken;
	LUID Luid;
	TOKEN_PRIVILEGES tp;
 
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))return FALSE;
 
	if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid))
	{
		CloseHandle(hToken);
		return FALSE;
	}
 
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Luid = Luid;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
 
	if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL))
	{
		CloseHandle(hToken);
		return FALSE;
	}
	CloseHandle(hToken);
	return TRUE;
}

int find_ID(char * PEname)
{
	char szStrTemp[50];
	PROCESSENTRY32 pe32;
	pe32.dwSize = sizeof(PROCESSENTRY32);
 	int PID=0;
	HANDLE hProcessShot,oneProcess;
	hProcessShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);	//获取进程列表,最后一个参数是0
	if (hProcessShot == INVALID_HANDLE_VALUE)
	{
		return 0;
	}
	// 创建系统当前进程快照
	if (Process32First(hProcessShot,&pe32))//获取下一个进程快照
	{
		for (int i = 0;Process32Next(hProcessShot, &pe32);i++)
		{
			if(!stricmp(PEname,pe32.szExeFile))
			{
				printf("PID: %d  %s\n",pe32.th32ProcessID,pe32.szExeFile);
				PID= pe32.th32ProcessID;
			}
			
		}
	}
	//遍历进程快照
	CloseHandle(hProcessShot);
	return PID;
}

PVOID GetProcessImageBase(DWORD dwProcessId)
{
    PVOID pProcessImageBase = NULL;
    MODULEENTRY32 me32 = { 0 };
    me32.dwSize = sizeof(MODULEENTRY32);
    // 获取指定进程全部模块的快照
    HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
    if (INVALID_HANDLE_VALUE == hModuleSnap)
    {
        return pProcessImageBase;
    }
    // 获取快照中第一条信息
    BOOL bRet = Module32First(hModuleSnap, &me32);
    if (bRet)
    {
        // 获取加载基址
        pProcessImageBase = (PVOID)me32.modBaseAddr;
    }
    // 关闭句柄
    CloseHandle(hModuleSnap);
    return pProcessImageBase;
}

int find_function_VA(char * PEname,char *hook_dll_name,char*hook_function_name,struct PID_and_VA* the_PID_and_VA)
{
	//char *hook_dll_name="KERNEL32.DLL";//要hook的函数在哪个DLL里面
	//char *hook_function_name="WriteFile";//要hook的函数名 
	//char * PEname="notepad.exe";
	PVOID  pProcessImageBase;
	int pid=find_ID(PEname);//PID
	uint32_t imagebase=(uint32_t)GetProcessImageBase(pid);//image base
	HANDLE hProcess;//handle for process
	uint8_t tempbuff[1024];//临时存放的
	memset(tempbuff,0,1024);
	DWORD bufnum;//每次读写的实际大小
	 
	uint32_t IDT_directory[2];//[0]表示RVA,[1]表示size 
	uint32_t pindex=0;//文件偏移
	uint32_t RVA=0;//RVA 
	uint32_t EXEheader_offset=0;
	
	int IDT_entry_num=0;
	char dll_name[50];//读取dll名字 
	char function_name[50];//读取函数名字 
	uint32_t dll_name_addr=0;
	uint32_t function_name_addr=0;
	struct IDT_entry* the_IDT_entry=NULL;
	int dll_index=0;//是第几个index是要找的DLL? 
	uint32_t INT_addr=0;
	struct hint_name the_hint_name={0};//hint_name table
	uint32_t hint_name_addr;//hint_name_addr
	uint32_t IAT_seri_num=0;//目标函数在IAT中的下标号 
	
	
	uint32_t hook_function_VA=0;//hook函数内存地址 
	uint32_t hook_function_IAT=0; 
	
	if(pid!=0)
		printf("\n\nfind %s! It's PID is %d\n",PEname,pid);
	else{
		printf("no %s running or find failed!",PEname);
	}
	the_PID_and_VA->pid=pid;
	printf("image base is 0x%X\n",imagebase);
	
    //"打开"进程 
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    if(hProcess == NULL) 
    { 
        fprintf(stderr,"\nOpen process error : %d",GetLastError()); 
        goto bad;
    }

	
	//读取第一部分PE头
	if(ReadProcessMemory(hProcess, imagebase, tempbuff, 1024, &bufnum)){
		if(bufnum != 1024) 
        { 
			printf("\nRead PE failed!\n"); 
            goto bad;
        } 
	} 
	
	//对于tempbuff是文件偏移!注意RVA和index偏移
	EXEheader_offset=*(uint32_t*)&tempbuff[0x3C];
	printf("EXE header offset at %X\n",EXEheader_offset);
	
	//加上0x18到达可选头,这里有文件大小,全部复制, EXEheader_offse+0x50是文件大小 
	//imagesize=*(uint32_t*)&tempbuff[EXEheader_offset+0x50];
	//printf("imagesize is %X\n",imagesize);
	//读取IAT目录成员 
	if(ReadProcessMemory(hProcess, imagebase+EXEheader_offset+0x80, IDT_directory, 8, &bufnum)){
		if(bufnum != 8) 
        { 
			printf("\nRead IAT directory failed!\n"); 
            goto bad;
        } 
	}
	//printf("RVA address : IDT at %X, it size is %X\n",IDT_directory[0],IDT_directory[1]);
	//uint8_t *imagebuffer =(uint8_t*)malloc(sizeof(imagesize));
	//free(imagebuffer);
	IDT_entry_num=IDT_directory[1]/20;//计算需要多少个IDT项
	
	//读取IDT表项 
	the_IDT_entry = (struct IDT_entry*)malloc(IDT_directory[1]);
	
	if(ReadProcessMemory(hProcess, imagebase+IDT_directory[0], the_IDT_entry, IDT_directory[1], &bufnum)){
		if(bufnum != IDT_directory[1]) 
        { 
			printf("\nRead IDT directory failed!\n"); 
            goto bad;
        } 
	}
	//列出DLL名字 
	for(int i=0;i<IDT_entry_num;i++){
		dll_name_addr=the_IDT_entry[i].dll_name_pointer;
		//printf("dll_name_addr is %X\n",dll_name_addr);
		memset(dll_name,0,sizeof(dll_name));
		if(dll_name_addr!=0)//如果的确有这一项,为0表示为空
		{
			if(ReadProcessMemory(hProcess, imagebase+dll_name_addr, dll_name, sizeof(dll_name), &bufnum)){
				if(bufnum != sizeof(dll_name)) 
		        { 
					printf("\nRead dll_name failed!\n"); 
		            goto bad;
		        } 
		        //printf("%s\n",dll_name);
		        //如果找到了要hook的函数所在的DLL,结束
		        if(!stricmp(dll_name,hook_dll_name))
				{
					//printf("found target dll!\n"); 
					dll_index=i;
					break;
				}
			}
		} 
	}
	
	//在INT中找函数名,INT内存基址是这里 
	INT_addr=imagebase+the_IDT_entry[dll_index].INT_pointer;
	//只要没有读到末尾,都得读 
	for(int i=0;;i++)
	{
		if(ReadProcessMemory(hProcess, INT_addr+4*i, &hint_name_addr, 4, &bufnum))
		{
			if(bufnum != 4) 
		    { 
				printf("\nRead hint_name_addr failed!\n"); 
		        goto bad;
		    }
		    //printf("hint_name_addr is %X\n",hint_name_addr);
		    if(hint_name_addr==0)//读完了
			{
				printf("can not found %s in %s!\n",hook_dll_name,hook_function_name);
				break;
			}
				 
		    memset(&the_hint_name,0,sizeof(the_hint_name));
			 if(ReadProcessMemory(hProcess, imagebase+hint_name_addr, &the_hint_name, sizeof(the_hint_name), &bufnum))
			 {
				if(bufnum != sizeof(the_hint_name)) 
			    { 
					printf("\nRead hint_name failed!\n"); 
			        goto bad;
			    }
			     //如果找到了  
				if(!stricmp(hook_function_name,the_hint_name.name))
				{
					//printf("%X %s\n",the_hint_name.hint,the_hint_name.name);
					IAT_seri_num=i;
				 	break;
				}
			}
		}
	}
	
	//在IAT中获得目标函数在内存中的地址
	if(ReadProcessMemory(hProcess, imagebase+the_IDT_entry[dll_index].IAT_pointer+4*IAT_seri_num, &hook_function_VA, 4, &bufnum))
	{
		if(bufnum != 4) 
		{ 
			printf("\nRead hook_function_addr failed!\n"); 
		    goto bad;
		}
	}
	printf("target function address is at %X\n",hook_function_VA);
	the_PID_and_VA->VA=hook_function_VA;
	
good:	
		free(the_IDT_entry);
		CloseHandle(hProcess); 
		//system("pause");	
		return 0;
bad:    
		free(the_IDT_entry);
		CloseHandle(hProcess); 
		//system("pause");
		return -1;
}
 
 
 int main(){
	
	char bigbuff[4096]={0};//用来临时读取的 
	int pid=0;
	char exepath[100]={0};
	HANDLE hProcess;
	DWORD dwHasWrite;
    LPVOID lpRemoteBuf;
    //uint8_t buff[7] = {0};
    uint8_t find_inst[20]={0};//观察目标位置有什么 
    char addr[4]={0};
    struct PID_and_VA the_PID_and_VA={0};	
	uint32_t tempaddr=0;
	uint32_t function_addr=0;//目标函数在内存中位置 
	
	char string_data[]=
	"\x55\x53\x45\x52\x33\x32\x2E\x64"
	"\x6C\x6C\x00\x4D\x65\x73\x73\x61"
	"\x67\x65\x42\x6F\x78\x41\x00\xB5"
	"\xDA\x31\x34\xD7\xE9\x00\x32\x30"
	"\x31\x36";

	
	char shellcode1[]=
	    "\x9C\x60\x90\x90\xB8\x7B\x1D\x80"
		"\x7C\xBB\x00\x94\x00\x01\x53\x90"
		"\xFF\xD0\x90\x90\x90\xBB\x10\x94"
		"\x00\x01\x53\x50\x90\xB8\x30\xAE"
		"\x80\x7C\xFF\xD0\x90\x90\x90\x90"
		"\x90\x90\x6A\x00\x90\x90\x90\x68"
		"\x30\x94\x00\x01\x90\x90\x90\x68"
		"\x20\x94\x00\x01\x90\x90\x90\x90"
		"\x90\x6A\x00\xFF\xD0\x61\x9D\x90"
		"\x90\x90\x90\x90\x90\x90\x90\x90"
		"\x90\x90\x90\xE9\x12\x34\x56\x78";//大小为84 		
	
	char exename[30]={0};
	char dllname[30]={0};
	char function_name[30]={0};
	int buffsize=0;
	printf("\nplease enter exe name: ");
	scanf("%s",exename);
	printf("\nplease enter dll name: ");
	scanf("%s",dllname);
	printf("\nplease enter function name: ");
	scanf("%s",function_name);
	printf("\nplease enter buffsize[destory buffsize bytes,5/7bytes maybe]: ");
	scanf("%d",&buffsize);
	
	uint8_t *buff=(uint8_t *)malloc(buffsize);
	
	
	HINSTANCE LibHandle = LoadLibrary("KERNEL32.dll"); 
    printf("LERNEL32 Address = 0x%x \n",LibHandle);
    LPTSTR getaddr1 = (LPTSTR)GetProcAddress(LibHandle, "LoadLibraryA"); //获取加载函数的地址在getaddr1 
    printf("LoadLibraryA Address = 0x%x \n",getaddr1);
    LPTSTR getaddr2 = (LPTSTR)GetProcAddress(LibHandle, "GetProcAddress"); //GetProcAddress的在getaddr2
    printf("GetProcAddress Address = 0x%x \n",getaddr2);
	
	 if (!EnableDebugPrivilege())
    {
        fprintf(stderr,"Add Privilege error\n");
        goto bad;
    }
    else{
    	printf("Add Privilege success!\n");
	}

	
	//要hook的函数在IAT中的地址 
	//if(!find_function_VA("notepad.exe","kernel32.dll","writefile",&the_PID_and_VA))
	if(!find_function_VA(exename,dllname,function_name,&the_PID_and_VA))	
		function_addr=the_PID_and_VA.VA;
	else{
		printf("no such exe!");
	}
	
	 //"打开"进程 
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, the_PID_and_VA.pid);
    if(hProcess == NULL) 
    { 
        fprintf(stderr,"\nOpen process error : %d",GetLastError()); 
        goto bad;
    }

	dwHasWrite=0;
	//读取要hook的函数的前5个字节 
	if(ReadProcessMemory(hProcess,  function_addr, find_inst, sizeof(find_inst), &dwHasWrite)) 
    { 
        if(dwHasWrite != sizeof(find_inst)) 
        { 
			printf("\nOpen hook target function failed,length failed\n"); 
            goto bad;
        } 
        printf("first 20 bytes of the target function is : ");
		printf_hex_buff(find_inst, sizeof(find_inst));
    }else 
    { 
        printf("\nOpen hook target function failed :%d",GetLastError()); 
        goto bad;
    }
	
	
	if(ReadProcessMemory(hProcess, function_addr, buff, buffsize, &dwHasWrite)) 
    { 
        if(dwHasWrite != buffsize) 
        { 
			printf("\nOpen hook target function failed,length failed\n"); 
            goto bad;
        } 
        printf("first %d bytes of the target function is : ",buffsize);
		printf_hex_buff(buff,sizeof(buff));
    }else 
    { 
        printf("\nOpen hook target function failed :%d",GetLastError()); 
        goto bad;
    }
    dwHasWrite=0;
    //写入字符串数据,起始地址是lpRemoteBuf
	lpRemoteBuf = VirtualAllocEx(hProcess, NULL, sizeof(string_data), MEM_COMMIT, PAGE_READWRITE);
    if(WriteProcessMemory(hProcess, lpRemoteBuf, string_data, sizeof(string_data), &dwHasWrite)) 
    { 
    	//printf("write size is %d\n",dwHasWrite);
        if(dwHasWrite != sizeof(string_data)) 
        { 
            VirtualFreeEx(hProcess,lpRemoteBuf,sizeof(string_data), MEM_RELEASE);
            printf("\nwrite data length wrong!\n");
            goto bad;
        } 
		 
    }else 
    { 
        printf("\nwrite data falied : %d",GetLastError()); 
        goto bad;
    } 
    
    tempaddr = (uint32_t)lpRemoteBuf;  //数据区首地址是lpRemoteBuf 
    addr[0]=((char*)&tempaddr)[0];
    addr[1]=((char*)&tempaddr)[1];
    addr[2]=((char*)&tempaddr)[2];
    addr[3]=((char*)&tempaddr)[3];
    printf("data block first addr: ");
    printf_hex_buff((uint8_t*)&lpRemoteBuf,4);
    
    //printf_hex_buff((uint8_t*)&shellcode2,sizeof(shellcode2));
    //填入字符串的 VA 地址 
    *(uint32_t*)&shellcode1[5] = (uint32_t)getaddr1;//LoadlibraryA的地址填入
	*(uint32_t*)&shellcode1[10] = (uint32_t)((lpRemoteBuf)+0);//填入user32.dll的地址
	*(uint32_t*)&shellcode1[22] = (uint32_t)((lpRemoteBuf)+11);//填入messagebox的地址 
	*(uint32_t*)&shellcode1[30] = (uint32_t)getaddr2;//填入GetProAddress地址
	
	*(uint32_t*)&shellcode1[48] = (uint32_t)((lpRemoteBuf)+23);//标题
	*(uint32_t*)&shellcode1[56] = (uint32_t)((lpRemoteBuf)+30);//内容
	
	//填那5字节的目标对象  71--82  12个 
	for(int i=0;i<12;i++)
	{
		if(i<buffsize)
			shellcode1[71+i]=buff[i];
		else
			shellcode1[71+i]=0x90;
	}
	
	//写入shellcode 
	lpRemoteBuf = VirtualAllocEx(hProcess, NULL, sizeof(shellcode1), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
	tempaddr = ((uint32_t)lpRemoteBuf)+83;//E9的位置 
	tempaddr = function_addr+ 5 - (tempaddr + 5 ); 

	*(uint32_t *)&shellcode1[84]=tempaddr;
	printf("shellcode at %X, E9 at %X, target at %X, jump distance tmp is %X\n",(uint32_t)lpRemoteBuf,((uint32_t)lpRemoteBuf)+83,function_addr,tempaddr);
		
	printf("shellcode is : \n");
	printf_hex_buff(shellcode1,sizeof(shellcode1));
	
	dwHasWrite=0;
	
    if(WriteProcessMemory(hProcess, lpRemoteBuf, shellcode1, sizeof(shellcode1), &dwHasWrite)) 
    { 
        if(dwHasWrite != sizeof(shellcode1)) 
        { 
            VirtualFreeEx(hProcess,lpRemoteBuf,sizeof(shellcode1),MEM_COMMIT); 
            printf("WriteProcessMemory failed\n");
            goto bad;
        } 

    }else 
    { 
        printf("\nWriteProcessMemory failed: %d",GetLastError()); 
        goto bad; 
    }
	
	
	//实现Inline hook
	tempaddr = (uint32_t)lpRemoteBuf;       
    tempaddr = tempaddr - (function_addr + 5 );
    buff[0] = 0xe9;
    *(uint32_t*)&buff[1] = (uint32_t)tempaddr;
    if(buffsize>5){
    	for(int i=5;i<buffsize;i++)
    		buff[i]=0x90;
	}
    dwHasWrite=0;
    if(WriteProcessMemory(hProcess,  function_addr, buff, buffsize, &dwHasWrite))
    { 
    	if(dwHasWrite!=buffsize)
   		{
        printf("\nWriteProcessMemory failed: %d",GetLastError());
        goto bad;
		}
		printf("Hook success!\n");
    } 
	else{
		printf("\nWriteProcessMemory failed: %d",GetLastError());
	}

good:	
		free(buff);
		CloseHandle(hProcess); 
		system("pause");	
		return 0;
bad:    
		free(buff);
		CloseHandle(hProcess); 
		system("pause");
		return -1;
}
 
 
 
 

结果

测试记事本的writefile函数【kernel32.dll中】

  先在桌面新建一个txt文件,然后用notepad.exe打开它。运行inlinehook.exe程序,hook掉kernel32.dll里的WriteFile函数。接着,按ctrl+s,可以看到弹出了消息框,如图4-5(a)所示,点击确定,关闭记事本。再次打开文件,发现文件内容被保存,如图4-5(b)所示。说明hook并没有干扰记事本原有的功能。
在这里插入图片描述

后记

  1. 可以不用提升权限
  2. 如果目标函数前几个字节,本来是一个通过相对寻址的指令,比如E8/E9这些跳转指令,上面的代码需要更改,把E8后面四字节调整成在shellcode中的内存地址访问的偏移。
  3. 可以通过一些自动化的方法,调一些库,判断应该替换几个字节,每次多取一个字节,判断是不是一个完整的汇编指令。
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值