android 全局hook_Android so注入(inject)和Hook技术学习(二)——Got表hook之导入表hook...

全局符号表(GOT表)hook实际是通过解析SO文件,将待hook函数在got表的地址替换为自己函数的入口地址,这样目标进程每次调用待hook函数时,实际上是执行了我们自己的函数。

GOT表其实包含了导入表和导出表,导出表指将当前动态库的一些函数符号保留,供外部调用,导入表中的函数实际是在该动态库中调用外部的导出函数。

这里有几个关键点要说明一下:

(1) so文件的绝对路径和加载到内存中的基址是可以通过 /proc/[pid]/maps 获取到的。

(2) 修改导入表的函数地址的时候需要修改页的权限,增加写权限即可。

(3) 一般的导入表Hook是基于注入操作的,即把自己的代码注入到目标程序,本次实例重点讲述Hook的实现,注入代码采用上节所有代码inject.c。

导入表的hook有两种方法,以hook fopen函数为例。

方法一:

通过解析elf格式,分析Section header table找出静态的.got表的位置,并在内存中找到相应的.got表位置,这个时候内存中.got表保存着导入函数的地址,读取目标函数地址,与.got表每一项函数入口地址进行匹配,找到的话就直接替换新的函数地址,这样就完成了一次导入表的Hook操作了。

hook流程如下图所示:

af8ca50d2c2a7cf5cff6a939d7c0b780.png

图1 导入表Hook流程图

具体代码实现如下:

entry.c:

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10

11 #define LOG_TAG "INJECT"

12 #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)

13

14 //FILE *fopen(const char *filename, const char *modes)

15 FILE* (*old_fopen)(const char *filename, const char *modes);16 FILE* new_fopen(const char *filename, const char *modes){17 LOGD("[+] New call fopen.\n");18 if(old_fopen == -1){19 LOGD("error.\n");20 }21 returnold_fopen(filename, modes);22 }23

24 void* get_module_base(pid_t pid, const char*module_name){25 FILE*fp;26 long addr = 0;27 char*pch;28 char filename[32];29 char line[1024];30

31 //格式化字符串得到 "/proc/pid/maps"

32 if(pid < 0){33 snprintf(filename, sizeof(filename), "/proc/self/maps");34 }else{35 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);36 }37

38 //打开文件/proc/pid/maps,获取指定pid进程加载的内存模块信息

39 fp = fopen(filename, "r");40 if(fp !=NULL){41 //每次一行,读取文件 /proc/pid/maps中内容

42 while(fgets(line, sizeof(line), fp)){43 //查找指定的so模块

44 if(strstr(line, module_name)){45 //分割字符串

46 pch = strtok(line, "-");47 //字符串转长整形

48 addr = strtoul(pch, NULL, 16);49

50 //特殊内存地址的处理

51 if(addr == 0x8000){52 addr = 0;53 }54 break;55 }56 }57 }58 fclose(fp);59 return (void*)addr;60 }61

62 #define LIB_PATH "/data/app-lib/com.bbk.appstore-2/libvivosgmain.so"

63 inthook_fopen(){64

65 //获取目标pid进程中"/data/app-lib/com.bbk.appstore-2/libvivosgmain.so"模块的加载地址

66 void* base_addr =get_module_base(getpid(), LIB_PATH);67 LOGD("[+] libvivosgmain.so address = %p \n", base_addr);68

69 //保存被Hook的目标函数的原始调用地址

70 old_fopen =fopen;71 LOGD("[+] Orig fopen = %p\n", old_fopen);72

73 intfd;74 //打开内存模块文件"/data/app-lib/com.bbk.appstore-2/libvivosgmain.so"

75 fd =open(LIB_PATH, O_RDONLY);76 if(-1 ==fd){77 LOGD("error.\n");78 return -1;79 }80

81 //elf32文件的文件头结构体Elf32_Ehdr

82 Elf32_Ehdr ehdr;83 //读取elf32格式的文件"/data/app-lib/com.bbk.appstore-2/libvivosgmain.so"的文件头信息

84 read(fd, &ehdr, sizeof(Elf32_Ehdr));85

86 //elf32文件中节区表信息结构的文件偏移

87 unsigned long shdr_addr =ehdr.e_shoff;88 //elf32文件中节区表信息结构的数量

89 int shnum =ehdr.e_shnum;90 //elf32文件中每个节区表信息结构中的单个信息结构的大小(描述每个节区的信息的结构体的大小)

91 int shent_size =ehdr.e_shentsize;92

93 //elf32文件节区表中每个节区的名称存放的节区名称字符串表,在节区表中的序号index

94 unsigned long stridx =ehdr.e_shstrndx;95

96 //elf32文件中节区表的每个单元信息结构体(描述每个节区的信息的结构体)

97 Elf32_Shdr shdr;98 //elf32文件中定位到存放每个节区名称的字符串表的信息结构体位置.shstrtab

99 lseek(fd, shdr_addr + stridx *shent_size, SEEK_SET);100 //读取elf32文件中的描述每个节区的信息的结构体(这里是保存elf32文件的每个节区的名称字符串的)

101 read(fd, &shdr, shent_size);102 LOGD("[+] String table offset is %lu, size is %lu", shdr.sh_offset, shdr.sh_size); //41159, size is 254103

104 //为保存elf32文件的所有的节区的名称字符串申请内存空间

105 char * string_table = (char *)malloc(shdr.sh_size);106 //定位到具体存放elf32文件的所有的节区的名称字符串的文件偏移处

107 lseek(fd, shdr.sh_offset, SEEK_SET);108 //从elf32内存文件中读取所有的节区的名称字符串到申请的内存空间中

109 read(fd, string_table, shdr.sh_size);110

111 //重新设置elf32文件的文件偏移为节区信息结构的起始文件偏移处

112 lseek(fd, shdr_addr, SEEK_SET);113

114 inti;115 uint32_t out_addr = 0;116 uint32_t out_size = 0;117 uint32_t got_item = 0;118 int32_t got_found = 0;119

120 //循环遍历elf32文件的节区表(描述每个节区的信息的结构体)

121 for(i = 0; i

123 read(fd, &shdr, shent_size);124 //判断当前节区描述结构体描述的节区是否是SHT_PROGBITS类型125 //类型为SHT_PROGBITS的.got节区包含全局偏移表

126 if(shdr.sh_type ==SHT_PROGBITS){127 //获取节区的名称字符串在保存所有节区的名称字符串段.shstrtab中的序号

128 int name_idx =shdr.sh_name;129

130 //判断节区的名称是否为".got.plt"或者".got"

131 if(strcmp(&(string_table[name_idx]), ".got.plt") == 0

132 || strcmp(&(string_table[name_idx]), ".got") == 0){133 //获取节区".got"或者".got.plt"在内存中实际数据存放地址

134 out_addr = base_addr +shdr.sh_addr;135 //获取节区".got"或者".got.plt"的大小

136 out_size =shdr.sh_size;137 LOGD("[+] out_addr = %lx, out_size = %lx\n", out_addr, out_size);138 int j = 0;139 //遍历节区".got"或者".got.plt"获取保存的全局的函数调用地址

140 for(j = 0; j

142 got_item = *(uint32_t*)(out_addr +j);143 //判断节区".got"或者".got.plt"中函数调用地址是否是将要被Hook的目标函数地址

144 if(got_item ==old_fopen){145 LOGD("[+] Found fopen in got.\n");146 got_found = 1;147 //获取当前内存分页的大小

148 uint32_t page_size =getpagesize();149 //获取内存分页的起始地址(需要内存对齐)

150 uint32_t entry_page_start = (out_addr + j) & (~(page_size - 1));151 LOGD("[+] entry_page_start = %lx, page size = %lx\n", entry_page_start, page_size);152 //修改内存属性为可读可写可执行

153 if(mprotect((uint32_t*)entry_page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) == -1){154 LOGD("mprotect false.\n");155 return -1;156 }157 LOGD("[+] %s, old_fopen = %lx, new_fopen = %lx\n", "before hook function", got_item, new_fopen);158

159 //Hook函数为我们自己定义的函数

160 got_item =new_fopen;161 LOGD("[+] %s, old_fopen = %lx, new_fopen = %lx\n", "after hook function", got_item, new_fopen);162 //恢复内存属性为可读可执行

163 if(mprotect((uint32_t*)entry_page_start, page_size, PROT_READ | PROT_EXEC) == -1){164 LOGD("mprotect false.\n");165 return -1;166 }167 break;168 //此时,目标函数的调用地址已经被Hook了

169 }else if(got_item ==new_fopen){170 LOGD("[+] Already hooked.\n");171 break;172 }173 }174 //Hook目标函数成功,跳出循环

175 if(got_found)176 break;177 }178 }179 }180 free(string_table);181 close(fd);182 }183

184 int hook_entry(char*a){185 LOGD("[+] Start hooking.\n");186 hook_fopen();187 return 0;188 }

运行ndk-build编译,得到libentry.so,push到/data/local/tmp目录下,运行上节所得到的inject程序,得到如下结果,表明hook成功:

d273634ace1fb5c82db11a70e4563165.png

图2.

方法二

通过分析program header table查找got表。导入表对应在动态链接段.got.plt(DT_PLTGOT)指向处,但是每项的信息是和GOT表中的表项对应的,因此,在解析动态链接段时,需要解析DT_JMPREL、DT_SYMTAB,前者指向了每一个导入表表项的偏移地址和相关信息,包括在GOT表中偏移,后者为GOT表。

具体代码如下:

1 #include

2 #include

3 #include

4 #include

5 #include

6 #include

7 #include

8 #include

9 #include

10

11 #define LOG_TAG "INJECT"

12 #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)

13

14

15 //FILE *fopen(const char *filename, const char *modes)

16 FILE* (*old_fopen)(const char *filename, const char *modes);17 FILE* new_fopen(const char *filename, const char *modes){18 LOGD("[+] New call fopen.\n");19 if(old_fopen == -1){20 LOGD("error.\n");21 }22 returnold_fopen(filename, modes);23 }24

25 void* get_module_base(pid_t pid, const char*module_name){26 FILE*fp;27 long addr = 0;28 char*pch;29 char filename[32];30 char line[1024];31

32 //格式化字符串得到 "/proc/pid/maps"

33 if(pid < 0){34 snprintf(filename, sizeof(filename), "/proc/self/maps");35 }else{36 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);37 }38

39 //打开文件/proc/pid/maps,获取指定pid进程加载的内存模块信息

40 fp = fopen(filename, "r");41 if(fp !=NULL){42 //每次一行,读取文件 /proc/pid/maps中内容

43 while(fgets(line, sizeof(line), fp)){44 //查找指定的so模块

45 if(strstr(line, module_name)){46 //分割字符串

47 pch = strtok(line, "-");48 //字符串转长整形

49 addr = strtoul(pch, NULL, 16);50

51 //特殊内存地址的处理

52 if(addr == 0x8000){53 addr = 0;54 }55 break;56 }57 }58 }59 fclose(fp);60 return (void*)addr;61 }62

63 #define LIB_PATH "/data/app-lib/com.bbk.appstore-2/libvivosgmain.so"

64 inthook_fopen(){65

66 //获取目标pid进程中"/data/app-lib/com.bbk.appstore-2/libvivosgmain.so"模块的加载地址

67 void* base_addr =get_module_base(getpid(), LIB_PATH);68 LOGD("[+] libvivosgmain.so address = %p \n", base_addr);69

70 //保存被Hook的目标函数的原始调用地址

71 old_fopen =fopen;72 LOGD("[+] Orig fopen = %p\n", old_fopen);73

74 //计算program header table实际地址

75 Elf32_Ehdr *header = (Elf32_Ehdr*)(base_addr);76 if (memcmp(header->e_ident, "\177ELF", 4) != 0) {77 return 0;78 }79

80 Elf32_Phdr* phdr_table = (Elf32_Phdr*)(base_addr + header->e_phoff);81 if (phdr_table == 0)82 {83 LOGD("[+] phdr_table address : 0");84 return 0;85 }86 size_t phdr_count = header->e_phnum;87 LOGD("[+] phdr_count : %d", phdr_count);88

89

90 //遍历program header table,ptype等于PT_DYNAMIC即为dynameic,获取到p_offset

91 unsigned long dynamicAddr = 0;92 unsigned int dynamicSize = 0;93 int j = 0;94 for (j = 0; j < phdr_count; j++)95 {96 if (phdr_table[j].p_type ==PT_DYNAMIC)97 {98 dynamicAddr = phdr_table[j].p_vaddr +base_addr;99 dynamicSize =phdr_table[j].p_memsz;100 break;101 }102 }103 LOGD("[+] Dynamic Addr : %x",dynamicAddr);104 LOGD("[+] Dynamic Size : %x",dynamicSize);105

106 /*

107 typedef struct dynamic {108 Elf32_Sword d_tag;109 union {110 Elf32_Sword d_val;111 Elf32_Addr d_ptr;112 } d_un;113 } Elf32_Dyn;114 */

115 Elf32_Dyn* dynamic_table = (Elf32_Dyn*)(dynamicAddr);116 unsigned long jmpRelOff = 0;117 unsigned long strTabOff = 0;118 unsigned long pltRelSz = 0;119 unsigned long symTabOff = 0;120 inti;121 for(i=0;i < dynamicSize / 8;i ++)122 {123 int val =dynamic_table[i].d_un.d_val;124 if (dynamic_table[i].d_tag ==DT_JMPREL)125 {126 jmpRelOff =val;127 }128 if (dynamic_table[i].d_tag ==DT_STRTAB)129 {130 strTabOff =val;131 }132 if (dynamic_table[i].d_tag ==DT_PLTRELSZ)133 {134 pltRelSz =val;135 }136 if (dynamic_table[i].d_tag ==DT_SYMTAB)137 {138 symTabOff =val;139 }140 }141

142 Elf32_Rel* rel_table = (Elf32_Rel*)(jmpRelOff +base_addr);143 LOGD("[+] jmpRelOff : %x",jmpRelOff);144 LOGD("[+] strTabOff : %x",strTabOff);145 LOGD("[+] symTabOff : %x",symTabOff);146 //遍历查找要hook的导入函数,这里以fopen做示例

147 for(i=0;i < pltRelSz / 8;i++)148 {149 int number = (rel_table[i].r_info >> 8) & 0xffffff;150 Elf32_Sym* symTableIndex = (Elf32_Sym*)(number*16 + symTabOff +base_addr);151 char* funcName = (char*)(symTableIndex->st_name + strTabOff +base_addr);152 //LOGD("[+] Func Name : %s",funcName);

153 if(memcmp(funcName, "fopen", 5) == 0)154 {155 //获取当前内存分页的大小

156 uint32_t page_size =getpagesize();157 //获取内存分页的起始地址(需要内存对齐)

158 uint32_t mem_page_start = (uint32_t)(((Elf32_Addr)rel_table[i].r_offset + base_addr)) & (~(page_size - 1));159 LOGD("[+] mem_page_start = %lx, page size = %lx\n", mem_page_start, page_size);160 //void* pstart = (void*)MEM_PAGE_START(((Elf32_Addr)rel_table[i].r_offset + base_addr));

161 mprotect((uint32_t)mem_page_start, page_size, PROT_READ | PROT_WRITE |PROT_EXEC);162 LOGD("[+] r_off : %x",rel_table[i].r_offset +base_addr);163 LOGD("[+] new_fopen : %x",new_fopen);164 *(unsigned int*)(rel_table[i].r_offset + base_addr) =new_fopen;165 }166 }167

168 return 0;169 }170

171 int hook_entry(char*a){172 LOGD("[+] Start hooking.\n");173 hook_fopen();174 return 0;175 }

运行后的结果为:

42d546b7fff9be65aceac065ae4c75ee.png

图3

参考文章:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hook API Lib 0.5.rar Hook API Lib 0.51.rar /* ////////////////////////////////////////////////////////////////////////// HookApi 0.5 thanks to xIkUg ,sucsor by 海风月影[RCT] , eIcn#live.cn 2008.04.15 ////////////////////////////////////////////////////////////////////////// //更新内容 2008.04.15 0.5 1,重新写了Stub,换了一种模式,使hook更加自由,将hookbefore和hookafter合并 HookProc的定义方式与以前有所不同: HookProc的函数类型和原来的api一样,只是参数比原API多2个 DWORD WINAPI HookProc(DWORD RetAddr ,__pfnXXXX pfnXXXX, ...); //参数比原始的API多2个参数 RetAddr //调用api的返回地址 pfnXXX //类型为__pfnXXXX,待hook的api的声明类型,用于调用未被hook的api 详见My_LoadLibraryA 原始的LoadLibraryA的声明是: HMODULE WINAPI LoadLibraryA( LPCSTR lpLibFileName ); 那么首先定义一下hook的WINAPI的类型 typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR lpFileName); 然后hookproc的函数声明如下: HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr, __pfnLoadLibraryA pfnLoadLibraryA, LPCTSTR lpFileName ); 比原来的多了2个参数,参数位置不能颠倒,在My_LoadLibraryA中可以自由的调用未被hook的pfnLoadLibraryA 也可以调用系统的LoadLibraryA,不过要自己在hookproc中处理好重入问题 另外,也可以在My_LoadLibraryA中使用UnInstallHookApi()函数来卸载hook,用法如下: 将第个参数__pfnLoadLibraryA pfnLoadLibraryA强制转换成PHOOKENVIRONMENT类型,使用UnInstallHookApi来卸载 例如: UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA); 至于以前版本的HookBefore和HookAfter,完全可以在自己的HookProc里面灵活使用了 2,支持卸载hook InstallHookApi()调用后会返回一个PHOOKENVIRONMENT类型的指针 需要卸载的时候可以使用UnInstallHookApi(PHOOKENVIRONMENT pHookEnv)来卸载 在HookProc中也可以使用UnInstallHookApi来卸载,参数传入HookProc中的第个参数 ★★注意: 1,如果在HookProc中自己不调用API(pfnXXXXX()),那么返回后,Stub是不会调用的,切记! 2,当HookProc中使用UnInstallHookApi卸载完后就不能用第个参数来调用API了(pfnXXXX()),切记! 2008.04.15 0.41 1,前面的deroko的LdeX86 有BUG,678b803412 会算错 换了一个LDX32,代码更少,更容易理解 2,修复了VirtualProtect的一个小BUG 0.4以前 改动太大了,前面的就不写了 */ #include <windows.h> #include <stdio.h> #include "HookApi.h" BYTE JMPGate[5] = { 0xE9, 0x00, 0x00, 0x00, 0x00 // JMP XXXXXXXX }; ////////////////////////////////////////////////////////////////////////// //另一个LDX32 #define C_ERROR 0xFFFFFFFF #define C_PREFIX 0x00000001 #define C_66 0x00000002 #define C_67 0x00000004 #define C_DATA66 0x00000008 #define C_DATA1 0x00000010 #define C_DATA2 0x00000020 #define C_DATA4 0x00000040 #define C_MEM67 0x00000080 #define C_MEM1 0x00000100 #define C_MEM2 0x00000200 #define C_MEM4 0x00000400 #define C_MODRM 0x00000800 #define C_DATAW0 0x00001000 #define C_FUCKINGTEST 0x00002000 #define C_TABLE_0F 0x00004000 DWORD table_1[256] = { /* 00 */ C_MODRM /* 01 */, C_MODRM /* 02 */, C_MODRM /* 03 */, C_MODRM /* 04 */, C_DATAW0 /* 05 */, C_DATAW0 /* 06 */, 0 /* 07 */, 0 /* 08 */, C_MODRM /* 09 */, C_MODRM /* 0A */, C_MODRM /* 0B */, C_MODRM /* 0C */, C_DATAW0 /* 0D */, C_DATAW0 /* 0E */, 0 /* 0F */, C_TABLE_0F /* 10 */, C_MODRM /* 11 */, C_MODRM /* 12 */, C_MODRM /* 13 */, C_MODRM /* 14 */, C_DATAW0 /* 15 */, C_DATAW0 /* 16 */, 0 /* 17 */, 0 /* 18 */, C_MODRM /* 19 */, C_MODRM /* 1A */, C_MODRM /* 1B */, C_MODRM /* 1C */, C_DATAW0 /* 1D */, C_DATAW0 /* 1E */, 0 /* 1F */, 0 /* 20 */, C_MODRM /* 21 */, C_MODRM /* 22 */, C_MODRM /* 23 */, C_MODRM /* 24 */, C_DATAW0 /* 25 */, C_DATAW0 /* 26 */, C_PREFIX /* 27 */, 0 /* 28 */, C_MODRM /* 29 */, C_MODRM /* 2A */, C_MODRM /* 2B */, C_MODRM /* 2C */, C_DATAW0 /* 2D */, C_DATAW0 /* 2E */, C_PREFIX /* 2F */, 0 /* 30 */, C_MODRM /* 31 */, C_MODRM /* 32 */, C_MODRM /* 33 */, C_MODRM /* 34 */, C_DATAW0 /* 35 */, C_DATAW0 /* 36 */, C_PREFIX /* 37 */, 0 /* 38 */, C_MODRM /* 39 */, C_MODRM /* 3A */, C_MODRM /* 3B */, C_MODRM /* 3C */, C_DATAW0 /* 3D */, C_DATAW0 /* 3E */, C_PREFIX /* 3F */, 0 /* 40 */, 0 /* 41 */, 0 /* 42 */, 0 /* 43 */, 0 /* 44 */, 0 /* 45 */, 0 /* 46 */, 0 /* 47 */, 0 /* 48 */, 0 /* 49 */, 0 /* 4A */, 0 /* 4B */, 0 /* 4C */, 0 /* 4D */, 0 /* 4E */, 0 /* 4F */, 0 /* 50 */, 0 /* 51 */, 0 /* 52 */, 0 /* 53 */, 0 /* 54 */, 0 /* 55 */, 0 /* 56 */, 0 /* 57 */, 0 /* 58 */, 0 /* 59 */, 0 /* 5A */, 0 /* 5B */, 0 /* 5C */, 0 /* 5D */, 0 /* 5E */, 0 /* 5F */, 0 /* 60 */, 0 /* 61 */, 0 /* 62 */, C_MODRM /* 63 */, C_MODRM /* 64 */, C_PREFIX /* 65 */, C_PREFIX /* 66 */, C_PREFIX+C_66 /* 67 */, C_PREFIX+C_67 /* 68 */, C_DATA66 /* 69 */, C_MODRM+C_DATA66 /* 6A */, C_DATA1 /* 6B */, C_MODRM+C_DATA1 /* 6C */, 0 /* 6D */, 0 /* 6E */, 0 /* 6F */, 0 /* 70 */, C_DATA1 /* 71 */, C_DATA1 /* 72 */, C_DATA1 /* 73 */, C_DATA1 /* 74 */, C_DATA1 /* 75 */, C_DATA1 /* 76 */, C_DATA1 /* 77 */, C_DATA1 /* 78 */, C_DATA1 /* 79 */, C_DATA1 /* 7A */, C_DATA1 /* 7B */, C_DATA1 /* 7C */, C_DATA1 /* 7D */, C_DATA1 /* 7E */, C_DATA1 /* 7F */, C_DATA1 /* 80 */, C_MODRM+C_DATA1 /* 81 */, C_MODRM+C_DATA66 /* 82 */, C_MODRM+C_DATA1 /* 83 */, C_MODRM+C_DATA1 /* 84 */, C_MODRM /* 85 */, C_MODRM /* 86 */, C_MODRM /* 87 */, C_MODRM /* 88 */, C_MODRM /* 89 */, C_MODRM /* 8A */, C_MODRM /* 8B */, C_MODRM /* 8C */, C_MODRM /* 8D */, C_MODRM /* 8E */, C_MODRM /* 8F */, C_MODRM /* 90 */, 0 /* 91 */, 0 /* 92 */, 0 /* 93 */, 0 /* 94 */, 0 /* 95 */, 0 /* 96 */, 0 /* 97 */, 0 /* 98 */, 0 /* 99 */, 0 /* 9A */, C_DATA66+C_MEM2 /* 9B */, 0 /* 9C */, 0 /* 9D */, 0 /* 9E */, 0 /* 9F */, 0 /* A0 */, C_MEM67 /* A1 */, C_MEM67 /* A2 */, C_MEM67 /* A3 */, C_MEM67 /* A4 */, 0 /* A5 */, 0 /* A6 */, 0 /* A7 */, 0 /* A8 */, C_DATA1 /* A9 */, C_DATA66 /* AA */, 0 /* AB */, 0 /* AC */, 0 /* AD */, 0 /* AE */, 0 /* AF */, 0 /* B0 */, C_DATA1 /* B1 */, C_DATA1 /* B2 */, C_DATA1 /* B3 */, C_DATA1 /* B4 */, C_DATA1 /* B5 */, C_DATA1 /* B6 */, C_DATA1 /* B7 */, C_DATA1 /* B8 */, C_DATA66 /* B9 */, C_DATA66 /* BA */, C_DATA66 /* BB */, C_DATA66 /* BC */, C_DATA66 /* BD */, C_DATA66 /* BE */, C_DATA66 /* BF */, C_DATA66 /* C0 */, C_MODRM+C_DATA1 /* C1 */, C_MODRM+C_DATA1 /* C2 */, C_DATA2 /* C3 */, 0 /* C4 */, C_MODRM /* C5 */, C_MODRM /* C6 */, C_MODRM+C_DATA66 /* C7 */, C_MODRM+C_DATA66 /* C8 */, C_DATA2+C_DATA1 /* C9 */, 0 /* CA */, C_DATA2 /* CB */, 0 /* CC */, 0 /* CD */, C_DATA1+C_DATA4 /* CE */, 0 /* CF */, 0 /* D0 */, C_MODRM /* D1 */, C_MODRM /* D2 */, C_MODRM /* D3 */, C_MODRM /* D4 */, 0 /* D5 */, 0 /* D6 */, 0 /* D7 */, 0 /* D8 */, C_MODRM /* D9 */, C_MODRM /* DA */, C_MODRM /* DB */, C_MODRM /* DC */, C_MODRM /* DD */, C_MODRM /* DE */, C_MODRM /* DF */, C_MODRM /* E0 */, C_DATA1 /* E1 */, C_DATA1 /* E2 */, C_DATA1 /* E3 */, C_DATA1 /* E4 */, C_DATA1 /* E5 */, C_DATA1 /* E6 */, C_DATA1 /* E7 */, C_DATA1 /* E8 */, C_DATA66 /* E9 */, C_DATA66 /* EA */, C_DATA66+C_MEM2 /* EB */, C_DATA1 /* EC */, 0 /* ED */, 0 /* EE */, 0 /* EF */, 0 /* F0 */, C_PREFIX /* F1 */, 0 // 0xF1 /* F2 */, C_PREFIX /* F3 */, C_PREFIX /* F4 */, 0 /* F5 */, 0 /* F6 */, C_FUCKINGTEST /* F7 */, C_FUCKINGTEST /* F8 */, 0 /* F9 */, 0 /* FA */, 0 /* FB */, 0 /* FC */, 0 /* FD */, 0 /* FE */, C_MODRM /* FF */, C_MODRM }; // table_1 DWORD table_0F[256] = { /* 00 */ C_MODRM /* 01 */, C_MODRM /* 02 */, C_MODRM /* 03 */, C_MODRM /* 04 */, -1 /* 05 */, -1 /* 06 */, 0 /* 07 */, -1 /* 08 */, 0 /* 09 */, 0 /* 0A */, 0 /* 0B */, 0 /* 0C */, -1 /* 0D */, -1 /* 0E */, -1 /* 0F */, -1 /* 10 */, -1 /* 11 */, -1 /* 12 */, -1 /* 13 */, -1 /* 14 */, -1 /* 15 */, -1 /* 16 */, -1 /* 17 */, -1 /* 18 */, -1 /* 19 */, -1 /* 1A */, -1 /* 1B */, -1 /* 1C */, -1 /* 1D */, -1 /* 1E */, -1 /* 1F */, -1 /* 20 */, -1 /* 21 */, -1 /* 22 */, -1 /* 23 */, -1 /* 24 */, -1 /* 25 */, -1 /* 26 */, -1 /* 27 */, -1 /* 28 */, -1 /* 29 */, -1 /* 2A */, -1 /* 2B */, -1 /* 2C */, -1 /* 2D */, -1 /* 2E */, -1 /* 2F */, -1 /* 30 */, -1 /* 31 */, -1 /* 32 */, -1 /* 33 */, -1 /* 34 */, -1 /* 35 */, -1 /* 36 */, -1 /* 37 */, -1 /* 38 */, -1 /* 39 */, -1 /* 3A */, -1 /* 3B */, -1 /* 3C */, -1 /* 3D */, -1 /* 3E */, -1 /* 3F */, -1 /* 40 */, -1 /* 41 */, -1 /* 42 */, -1 /* 43 */, -1 /* 44 */, -1 /* 45 */, -1 /* 46 */, -1 /* 47 */, -1 /* 48 */, -1 /* 49 */, -1 /* 4A */, -1 /* 4B */, -1 /* 4C */, -1 /* 4D */, -1 /* 4E */, -1 /* 4F */, -1 /* 50 */, -1 /* 51 */, -1 /* 52 */, -1 /* 53 */, -1 /* 54 */, -1 /* 55 */, -1 /* 56 */, -1 /* 57 */, -1 /* 58 */, -1 /* 59 */, -1 /* 5A */, -1 /* 5B */, -1 /* 5C */, -1 /* 5D */, -1 /* 5E */, -1 /* 5F */, -1 /* 60 */, -1 /* 61 */, -1 /* 62 */, -1 /* 63 */, -1 /* 64 */, -1 /* 65 */, -1 /* 66 */, -1 /* 67 */, -1 /* 68 */, -1 /* 69 */, -1 /* 6A */, -1 /* 6B */, -1 /* 6C */, -1 /* 6D */, -1 /* 6E */, -1 /* 6F */, -1 /* 70 */, -1 /* 71 */, -1 /* 72 */, -1 /* 73 */, -1 /* 74 */, -1 /* 75 */, -1 /* 76 */, -1 /* 77 */, -1 /* 78 */, -1 /* 79 */, -1 /* 7A */, -1 /* 7B */, -1 /* 7C */, -1 /* 7D */, -1 /* 7E */, -1 /* 7F */, -1 /* 80 */, C_DATA66 /* 81 */, C_DATA66 /* 82 */, C_DATA66 /* 83 */, C_DATA66 /* 84 */, C_DATA66 /* 85 */, C_DATA66 /* 86 */, C_DATA66 /* 87 */, C_DATA66 /* 88 */, C_DATA66 /* 89 */, C_DATA66 /* 8A */, C_DATA66 /* 8B */, C_DATA66 /* 8C */, C_DATA66 /* 8D */, C_DATA66 /* 8E */, C_DATA66 /* 8F */, C_DATA66 /* 90 */, C_MODRM /* 91 */, C_MODRM /* 92 */, C_MODRM /* 93 */, C_MODRM /* 94 */, C_MODRM /* 95 */, C_MODRM /* 96 */, C_MODRM /* 97 */, C_MODRM /* 98 */, C_MODRM /* 99 */, C_MODRM /* 9A */, C_MODRM /* 9B */, C_MODRM /* 9C */, C_MODRM /* 9D */, C_MODRM /* 9E */, C_MODRM /* 9F */, C_MODRM /* A0 */, 0 /* A1 */, 0 /* A2 */, 0 /* A3 */, C_MODRM /* A4 */, C_MODRM+C_DATA1 /* A5 */, C_MODRM /* A6 */, -1 /* A7 */, -1 /* A8 */, 0 /* A9 */, 0 /* AA */, 0 /* AB */, C_MODRM /* AC */, C_MODRM+C_DATA1 /* AD */, C_MODRM /* AE */, -1 /* AF */, C_MODRM /* B0 */, C_MODRM /* B1 */, C_MODRM /* B2 */, C_MODRM /* B3 */, C_MODRM /* B4 */, C_MODRM /* B5 */, C_MODRM /* B6 */, C_MODRM /* B7 */, C_MODRM /* B8 */, -1 /* B9 */, -1 /* BA */, C_MODRM+C_DATA1 /* BB */, C_MODRM /* BC */, C_MODRM /* BD */, C_MODRM /* BE */, C_MODRM /* BF */, C_MODRM /* C0 */, C_MODRM /* C1 */, C_MODRM /* C2 */, -1 /* C3 */, -1 /* C4 */, -1 /* C5 */, -1 /* C6 */, -1 /* C7 */, -1 /* C8 */, 0 /* C9 */, 0 /* CA */, 0 /* CB */, 0 /* CC */, 0 /* CD */, 0 /* CE */, 0 /* CF */, 0 /* D0 */, -1 /* D1 */, -1 /* D2 */, -1 /* D3 */, -1 /* D4 */, -1 /* D5 */, -1 /* D6 */, -1 /* D7 */, -1 /* D8 */, -1 /* D9 */, -1 /* DA */, -1 /* DB */, -1 /* DC */, -1 /* DD */, -1 /* DE */, -1 /* DF */, -1 /* E0 */, -1 /* E1 */, -1 /* E2 */, -1 /* E3 */, -1 /* E4 */, -1 /* E5 */, -1 /* E6 */, -1 /* E7 */, -1 /* E8 */, -1 /* E9 */, -1 /* EA */, -1 /* EB */, -1 /* EC */, -1 /* ED */, -1 /* EE */, -1 /* EF */, -1 /* F0 */, -1 /* F1 */, -1 /* F2 */, -1 /* F3 */, -1 /* F4 */, -1 /* F5 */, -1 /* F6 */, -1 /* F7 */, -1 /* F8 */, -1 /* F9 */, -1 /* FA */, -1 /* FB */, -1 /* FC */, -1 /* FD */, -1 /* FE */, -1 /* FF */, -1 }; // table_0F #pragma comment(linker, "/SECTION:HookStub,RW") #define NAKED __declspec(naked) #define ALLOCATE(x1) __declspec(allocate(#x1)) #define ALLOCATE_HookStub ALLOCATE(HookStub) #define ReloCationForADDR(x1,delta) ((DWORD(&x1) + delta)) #define ReloCationForDWORD(x1,delta) (*(LPDWORD(DWORD(&x1) + delta))) #define ReloCataonForTCHAR(x1,delta) (LPCTSTR(DWORD(&x1) + delta)) #define ReloCationForLP(x1,delta) (__##x1(ReloCationForDWORD(x1,delta))) #pragma code_seg("HookStub") #pragma optimize("",off) ALLOCATE_HookStub HOOKENVIRONMENT pEnv={0}; NAKED DWORD GetDelta() { __asm { call next next: pop eax sub eax,offset next ret } } NAKED void NewStub() { __asm { jmp next back: _emit 0xE9 NOP NOP NOP NOP next: push [esp] push [esp] push eax //保存一下Stub中唯一使用到的EAX call GetDelta lea eax,[eax+pEnv] mov dword ptr [esp+0xC],eax pop eax //恢复EAX jmp back } } NAKED DWORD GetEndAddr() { __asm { call next next: pop eax sub eax,5 ret } } #pragma optimize("",off) #pragma code_seg() DWORD __stdcall GetOpCodeSize(BYTE* iptr0) { BYTE* iptr = iptr0; DWORD f = 0; prefix: BYTE b = *iptr++; f |= table_1[b]; if (f&C_FUCKINGTEST) if (((*iptr)&0x38)==0x00) // ttt f=C_MODRM+C_DATAW0; // TEST else f=C_MODRM; // NOT,NEG,MUL,IMUL,DIV,IDIV if (f&C_TABLE_0F) { b = *iptr++; f = table_0F[b]; } if (f==C_ERROR) { //printf("error in X\n",b); return C_ERROR; } if (f&C_PREFIX) { f&=~C_PREFIX; goto prefix; } if (f&C_DATAW0) if (b&0x01) f|=C_DATA66; else f|=C_DATA1; if (f&C_MODRM) { b = *iptr++; BYTE mod = b & 0xC0; BYTE rm = b & 0x07; if (mod!=0xC0) { if (f&C_67) // modrm16 { if ((mod==0x00)&&(rm==0x06)) f|=C_MEM2; if (mod==0x40) f|=C_MEM1; if (mod==0x80) f|=C_MEM2; } else // modrm32 { if (mod==0x40) f|=C_MEM1; if (mod==0x80) f|=C_MEM4; if (rm==0x04) rm = (*iptr++) & 0x07; // rm<-sib.base if ((rm==0x05)&&(mod==0x00)) f|=C_MEM4; } } } // C_MODRM if (f&C_MEM67) if (f&C_67) f|=C_MEM2; else f|=C_MEM4; if (f&C_DATA66) if (f&C_66) f|=C_DATA2; else f|=C_DATA4; if (f&C_MEM1) iptr++; if (f&C_MEM2) iptr+=2; if (f&C_MEM4) iptr+=4; if (f&C_DATA1) iptr++; if (f&C_DATA2) iptr+=2; if (f&C_DATA4) iptr+=4; return iptr - iptr0; } PHOOKENVIRONMENT __stdcall InstallHookApi(PCHAR DllName,PCHAR ApiName,PVOID HookProc) { HMODULE DllHandle; PVOID ApiEntry; int ReplaceCodeSize; DWORD oldpro; DWORD SizeOfStub; DWORD delta; DWORD RetSize =0; PHOOKENVIRONMENT pHookEnv; if (HookProc == NULL) { return NULL; } DllHandle = GetModuleHandle(DllName); if (DllHandle == NULL) DllHandle = LoadLibrary(DllName); if (DllHandle == NULL) return NULL; ApiEntry = GetProcAddress(DllHandle,ApiName); if (ApiEntry == NULL) return NULL; ReplaceCodeSize = GetOpCodeSize((BYTE*)ApiEntry); while (ReplaceCodeSize < 5) ReplaceCodeSize += GetOpCodeSize((BYTE*)((DWORD)ApiEntry + (DWORD)ReplaceCodeSize)); if (ReplaceCodeSize > 16) return NULL; SizeOfStub = GetEndAddr()-(DWORD)&pEnv; pHookEnv = (PHOOKENVIRONMENT)VirtualAlloc(NULL,SizeOfStub,MEM_COMMIT,PAGE_READWRITE); memset((void*)&pEnv,0x90,sizeof(pEnv)); CopyMemory(pHookEnv,(PVOID)&pEnv,SizeOfStub); CopyMemory((void*)pHookEnv,(void*)&pEnv,sizeof(pEnv.savebytes)); CopyMemory(pHookEnv->savebytes,ApiEntry,ReplaceCodeSize); pHookEnv->OrgApiAddr = ApiEntry; pHookEnv->SizeOfReplaceCode = ReplaceCodeSize; pHookEnv->jmptoapi[0]=0xE9; *(DWORD*)(&pHookEnv->jmptoapi[1]) = (DWORD)ApiEntry + ReplaceCodeSize - ((DWORD)pHookEnv->jmptoapi + 5); //patch api if (!VirtualProtect(ApiEntry,ReplaceCodeSize,PAGE_EXECUTE_READWRITE,&oldpro)) return FALSE; delta = (DWORD)pHookEnv - (DWORD)&pEnv; *(DWORD*)(&JMPGate[1]) = ((DWORD)NewStub + delta) - ((DWORD)ApiEntry + 5); WriteProcessMemory(GetCurrentProcess(), ApiEntry, JMPGate, sizeof(JMPGate),&RetSize); if (!VirtualProtect(ApiEntry,ReplaceCodeSize,oldpro,&oldpro)) return FALSE; //写入变量 *(DWORD*)((DWORD)NewStub + delta + 3) = (DWORD)HookProc - ((DWORD)NewStub + delta + 3 + 4); return pHookEnv; } BOOL __stdcall UnInstallHookApi(PHOOKENVIRONMENT pHookEnv) { DWORD oldpro; DWORD RetSize; //如果内存不存在了,则退出 if(IsBadReadPtr((const void*)pHookEnv,sizeof(HOOKENVIRONMENT))) return FALSE; if(!VirtualProtect(pHookEnv->OrgApiAddr,pHookEnv->SizeOfReplaceCode,PAGE_EXECUTE_READWRITE,&oldpro)) return FALSE; WriteProcessMemory(GetCurrentProcess(),pHookEnv->OrgApiAddr,pHookEnv->savebytes,pHookEnv->SizeOfReplaceCode,&RetSize); if(!VirtualProtect(pHookEnv->OrgApiAddr,pHookEnv->SizeOfReplaceCode,oldpro,&oldpro)) return FALSE; VirtualFree((LPVOID)pHookEnv,0,MEM_RELEASE); return TRUE; } //定义下面这行可以作为演示使用 //#define TEST_MAIN #ifdef TEST_MAIN BOOL IsMe = FALSE; //先定义一下要hook的WINAPI typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR lpFileName); HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr, __pfnLoadLibraryA pfnLoadLibraryA, LPCTSTR lpFileName ) { HMODULE hLib; //需要自己处理重入和线程安全问题 if (!IsMe) { IsMe = TRUE; MessageBoxA(NULL,lpFileName,"test",MB_ICONINFORMATION); hLib = LoadLibrary(lpFileName);//这里调用的是系统的,已经被hook过的 IsMe = FALSE; //这里是卸载Hook,这里卸载完就不能用pfnLoadLibraryA来调用了 UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA); return hLib; } return pfnLoadLibraryA(lpFileName);//这里调用非hook的 } int main() { DWORD RetSize =0; DWORD dwThreadId; HANDLE hThread; PHOOKENVIRONMENT pHookEnv; pHookEnv = InstallHookApi("Kernel32.dll", "LoadLibraryA", My_LoadLibraryA); LoadLibrary("InjectDll.dll"); MessageBoxA(NULL,"Safe Here!!!","Very Good!!",MB_ICONINFORMATION); UnInstallHookApi(pHookEnv);//由于HookProc中卸载过了,所以这里的卸载就无效了 MessageBoxA(NULL,"UnInstall Success!!!","Good!!",MB_ICONINFORMATION); return 0; } #endif

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值