├── README.md └── code ├── injso ├── injso.c ├── libtarget.so ├── source ├── source.c └── target.c /README.md: -------------------------------------------------------------------------------- 1 | # linux-hotpatch 2 | 3 | ## 说明 4 | 5 | 实现Linux下程序运行时的函数替换 6 | 7 | ## 使用方法 8 | 9 | ``` 10 | sudo ./injso pid ./libtarget.so printf newmyprint 11 | ``` 12 | 13 | ## 参考 14 | 15 | * https://www.cnblogs.com/leo0000/p/5632642.html 16 | 17 | -------------------------------------------------------------------------------- /code/injso: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L1B0/linux-hotpatch/01676bf574745a2f11ba1b14c1f6c0311fe3d9af/code/injso -------------------------------------------------------------------------------- /code/injso.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define IMAGE_ADDR 0x08048000 16 | 17 | int mode = 2; 18 | 19 | struct user_regs_struct oldregs; 20 | Elf32_Addr phdr_addr; 21 | Elf32_Addr dyn_addr; 22 | Elf32_Addr map_addr; 23 | Elf32_Addr symtab; 24 | Elf32_Addr strtab; 25 | Elf32_Addr jmprel; 26 | Elf32_Addr reldyn; 27 | Elf32_Word reldynsz; 28 | Elf32_Word totalrelsize; 29 | Elf32_Word relsize; 30 | unsigned long link_addr; 31 | int nrels; 32 | int nreldyns; 33 | //int nchains; 34 | int modifyflag = 0; 35 | /*char libpath[128] = "/mnt/hgfs/svnroot/test/injectsov2/prj_linux/so.so";*/ 36 | 37 | 38 | /* 读进程寄存器 */ 39 | void ptrace_readreg(int pid, struct user_regs_struct *regs) 40 | { 41 | if(ptrace(PTRACE_GETREGS, pid, NULL, regs)) 42 | printf("*** ptrace_readreg error ***\n"); 43 | /*printf("ptrace_readreg\n"); 44 | printf("%x\n",regs->ebx); 45 | printf("%x\n",regs->ecx); 46 | printf("%x\n",regs->edx); 47 | printf("%x\n",regs->esi); 48 | printf("%x\n",regs->edi); 49 | printf("%x\n",regs->ebp); 50 | printf("%x\n",regs->eax); 51 | printf("%x\n",regs->xds); 52 | printf("%x\n",regs->xes); 53 | printf("%x\n",regs->xfs); 54 | printf("%x\n",regs->xgs); 55 | printf("%x\n",regs->orig_eax); 56 | printf("%x\n",regs->eip); 57 | printf("%x\n",regs->xcs); 58 | printf("%x\n",regs->eflags); 59 | printf("%x\n",regs->esp); 60 | printf("%x\n",regs->xss);*/ 61 | 62 | } 63 | 64 | /* 写进程寄存器 */ 65 | void ptrace_writereg(int pid, struct user_regs_struct *regs) 66 | { 67 | /*printf("ptrace_writereg\n"); 68 | printf("%x\n",regs->ebx); 69 | printf("%x\n",regs->ecx); 70 | printf("%x\n",regs->edx); 71 | printf("%x\n",regs->esi); 72 | printf("%x\n",regs->edi); 73 | printf("%x\n",regs->ebp); 74 | printf("%x\n",regs->eax); 75 | printf("%x\n",regs->xds); 76 | printf("%x\n",regs->xes); 77 | printf("%x\n",regs->xfs); 78 | printf("%x\n",regs->xgs); 79 | printf("%x\n",regs->orig_eax); 80 | printf("%x\n",regs->eip); 81 | printf("%x\n",regs->xcs); 82 | printf("%x\n",regs->eflags); 83 | printf("%x\n",regs->esp); 84 | printf("%x\n",regs->xss);*/ 85 | 86 | if(ptrace(PTRACE_SETREGS, pid, NULL, regs)) 87 | printf("*** ptrace_writereg error ***\n"); 88 | } 89 | 90 | /* 关联到进程 */ 91 | void ptrace_attach(int pid) 92 | { 93 | if(ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { 94 | perror("ptrace_attach"); 95 | exit(-1); 96 | } 97 | 98 | waitpid(pid, NULL, /*WUNTRACED*/0); 99 | 100 | ptrace_readreg(pid, &oldregs); 101 | } 102 | 103 | /* 进程继续 */ 104 | void ptrace_cont(int pid) 105 | { 106 | int stat; 107 | 108 | if(ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { 109 | perror("ptrace_cont"); 110 | exit(-1); 111 | } 112 | /*while(!WIFSTOPPED(stat)) 113 | waitpid(pid, &stat, WNOHANG);*/ 114 | } 115 | 116 | /* 脱离进程 */ 117 | void ptrace_detach(int pid) 118 | { 119 | ptrace_writereg(pid, &oldregs); 120 | 121 | if(ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) { 122 | perror("ptrace_detach"); 123 | exit(-1); 124 | } 125 | } 126 | 127 | /* 写指定进程地址 */ 128 | void ptrace_write(int pid, unsigned long addr, void *vptr, int len) 129 | { 130 | int count; 131 | long word; 132 | 133 | count = 0; 134 | 135 | while(count < len) { 136 | memcpy(&word, vptr + count, sizeof(word)); 137 | word = ptrace(PTRACE_POKETEXT, pid, addr + count, word); 138 | count += 4; 139 | 140 | if(errno != 0) 141 | printf("ptrace_write failed\t %ld\n", addr + count); 142 | } 143 | } 144 | 145 | /* 读指定进程 */ 146 | int ptrace_read(int pid, unsigned long addr, void *vptr, int len) 147 | { 148 | int i,count; 149 | long word; 150 | unsigned long *ptr = (unsigned long *)vptr; 151 | 152 | i = count = 0; 153 | //printf("ptrace_read addr = %x\n",addr); 154 | while (count < len) { 155 | //printf("ptrace_read addr+count = %x\n",addr + count); 156 | word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL); 157 | while(word < 0) 158 | { 159 | if(errno == 0) 160 | break; 161 | //printf("ptrace_read word = %x\n",word); 162 | perror("ptrace_read failed"); 163 | return 2; 164 | } 165 | count += 4; 166 | ptr[i++] = word; 167 | } 168 | return 0; 169 | } 170 | 171 | /* 172 | 在进程指定地址读一个字符串 173 | */ 174 | char * ptrace_readstr(int pid, unsigned long addr) 175 | { 176 | char *str = (char *) malloc(64); 177 | int i,count; 178 | long word; 179 | char *pa; 180 | 181 | i = count = 0; 182 | pa = (char *)&word; 183 | 184 | while(i <= 60) { 185 | word = ptrace(PTRACE_PEEKTEXT, pid, addr + count, NULL); 186 | count += 4; 187 | 188 | if (pa[0] == 0) { 189 | str[i] = 0; 190 | break; 191 | } 192 | else 193 | str[i++] = pa[0]; 194 | 195 | if (pa[1] == 0) { 196 | str[i] = 0; 197 | break; 198 | } 199 | else 200 | str[i++] = pa[1]; 201 | 202 | if (pa[2] ==0) { 203 | str[i] = 0; 204 | break; 205 | } 206 | else 207 | str[i++] = pa[2]; 208 | 209 | if (pa[3] ==0) { 210 | str[i] = 0; 211 | break; 212 | } 213 | else 214 | str[i++] = pa[3]; 215 | } 216 | 217 | return str; 218 | } 219 | 220 | 221 | 222 | 223 | /* 224 | 将指定数据压入进程堆栈并返回堆栈指针 225 | */ 226 | void * ptrace_push(int pid, void *paddr, int size) 227 | { 228 | unsigned long esp; 229 | struct user_regs_struct regs; 230 | 231 | ptrace_readreg(pid, ®s); 232 | esp = regs.esp; 233 | esp -= size; 234 | esp = esp - esp % 4; 235 | regs.esp = esp; 236 | 237 | ptrace_writereg(pid, ®s); 238 | 239 | ptrace_write(pid, esp, paddr, size); 240 | 241 | return (void *)esp; 242 | } 243 | 244 | /* 245 | 在进程内调用指定地址的函数 246 | */ 247 | void ptrace_call(int pid, unsigned long addr) 248 | { 249 | void *pc; 250 | struct user_regs_struct regs; 251 | int stat; 252 | void *pra; 253 | 254 | pc = (void *) 0x41414140; 255 | pra = ptrace_push(pid, &pc, sizeof(pc)); 256 | 257 | ptrace_readreg(pid, ®s); 258 | regs.eip = addr; 259 | ptrace_writereg(pid, ®s); 260 | 261 | ptrace_cont(pid); 262 | //while(WIFSIGNALED(stat)) 263 | // waitpid(pid, &stat, WNOHANG); 264 | } 265 | /* 266 | 因为应用程序可能不存在hash表,所以通过读取源文件的section header获取符号表的入口数, 267 | 其实是被误导了,但也学习了hash表的作用,用来快速查找符号表中的信息和字符串表中的信息 268 | */ 269 | /*int getnchains(int pid,unsigned long base_addr) 270 | { 271 | printf("getnchains enter \n"); 272 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *) malloc(sizeof(Elf32_Ehdr)); 273 | Elf32_Shdr *shdr = (Elf32_Shdr *)malloc(sizeof(Elf32_Shdr)); 274 | unsigned long shdr_addr; 275 | int i = 0; 276 | int fd; 277 | char filename[1024] = {0}; 278 | ptrace_read(pid, base_addr, ehdr, sizeof(Elf32_Ehdr)); 279 | shdr_addr = base_addr + ehdr->e_shoff; 280 | //printf("getnchains ehdr->e_shoff\t %p\n", ehdr->e_shoff); 281 | 282 | snprintf(filename, sizeof(filename), "/proc/%d/exe", pid); 283 | fd = open(filename, O_RDONLY); 284 | if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0) 285 | exit(-1); 286 | 287 | /*while(ie_shnum) 288 | { 289 | read(fd, shdr, ehdr->e_shentsize); 290 | printf("getnchains i = %d\n",i); 291 | printf("getnchains shdr->sh_type = %x\n",shdr->sh_type); 292 | printf("getnchains shdr->sh_name = %x\n",shdr->sh_name); 293 | printf("getnchains shdr->sh_size = %x\n",shdr->sh_size); 294 | printf("getnchains shdr->sh_entsize = %x\n",shdr->sh_entsize); 295 | i++; 296 | } 297 | 298 | while(shdr->sh_type != SHT_SYMTAB) 299 | read(fd, shdr, ehdr->e_shentsize); 300 | nchains = shdr->sh_size/shdr->sh_entsize; 301 | //printf("getnchains shdr->sh_type = %d\n",shdr->sh_type); 302 | //printf("getnchains shdr->sh_name = %d\n",shdr->sh_name); 303 | //printf("getnchains shdr->sh_size = %d\n",shdr->sh_size); 304 | //printf("getnchains shdr->sh_entsize = %d\n",shdr->sh_entsize); 305 | //printf("getnchains nchains = %x\n",nchains); 306 | close(fd); 307 | free(ehdr); 308 | free(shdr); 309 | printf("getnchains exit \n"); 310 | } 311 | */ 312 | 313 | 314 | /* 315 | 取得指向link_map链表首项的指针 316 | */ 317 | struct link_map * get_linkmap(int pid) 318 | { 319 | Elf32_Ehdr *ehdr = (Elf32_Ehdr *) malloc(sizeof(Elf32_Ehdr)); 320 | Elf32_Phdr *phdr = (Elf32_Phdr *) malloc(sizeof(Elf32_Phdr)); 321 | Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn)); 322 | Elf32_Word got; 323 | struct link_map *map = (struct link_map *)malloc(sizeof(struct link_map)); 324 | int i = 1; 325 | unsigned long tmpaddr; 326 | 327 | ptrace_read(pid, IMAGE_ADDR, ehdr, sizeof(Elf32_Ehdr)); 328 | phdr_addr = IMAGE_ADDR + ehdr->e_phoff; 329 | printf("phdr_addr\t %p\n", phdr_addr); 330 | 331 | ptrace_read(pid, phdr_addr, phdr, sizeof(Elf32_Phdr)); 332 | while(phdr->p_type != PT_DYNAMIC) 333 | ptrace_read(pid, phdr_addr += sizeof(Elf32_Phdr), phdr,sizeof(Elf32_Phdr)); 334 | dyn_addr = phdr->p_vaddr; 335 | printf("dyn_addr\t %p\n", dyn_addr); 336 | 337 | ptrace_read(pid, dyn_addr, dyn, sizeof(Elf32_Dyn)); 338 | while(dyn->d_tag != DT_PLTGOT) { 339 | tmpaddr = dyn_addr + i * sizeof(Elf32_Dyn); 340 | //printf("get_linkmap tmpaddr = %x\n",tmpaddr); 341 | ptrace_read(pid,tmpaddr, dyn, sizeof(Elf32_Dyn)); 342 | i++; 343 | } 344 | 345 | got = (Elf32_Word)dyn->d_un.d_ptr; 346 | got += 4; 347 | //printf("GOT\t\t %p\n", got); 348 | 349 | ptrace_read(pid, got, &map_addr, 4); 350 | printf("map_addr\t %p\n", map_addr); 351 | map = map_addr; 352 | //ptrace_read(pid, map_addr, map, sizeof(struct link_map)); 353 | 354 | free(ehdr); 355 | free(phdr); 356 | free(dyn); 357 | 358 | return map; 359 | } 360 | 361 | /* 362 | 取得给定link_map指向的SYMTAB、STRTAB、HASH、JMPREL、PLTRELSZ、RELAENT、RELENT信息 363 | 这些地址信息将被保存到全局变量中,以方便使用 364 | */ 365 | void get_sym_info(int pid, struct link_map *lm) 366 | { 367 | Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn)); 368 | unsigned long dyn_addr; 369 | //printf("get_sym_info lm = %x\n",lm); 370 | //printf("get_sym_info lm->l_ld's offset = %x\n",&((struct link_map *)0)->l_ld); 371 | //printf("get_sym_info &lm->l_ld = %x\n",&(lm->l_ld)); 372 | //dyn_addr = (unsigned long)&(lm->l_ld); 373 | //进入被跟踪进程获取动态节的地址 374 | ptrace_read(pid,&(lm->l_ld) , &dyn_addr, sizeof(dyn_addr)); 375 | ptrace_read(pid,&(lm->l_addr) , &link_addr, sizeof(dyn_addr)); 376 | ptrace_read(pid, dyn_addr, dyn, sizeof(Elf32_Dyn)); 377 | //if(link_addr == 0) 378 | // getnchains(pid,IMAGE_ADDR); 379 | /*else 380 | getnchains(pid,link_addr);*/ 381 | while(dyn->d_tag != DT_NULL){ 382 | //printf("get_sym_info dyn->d_tag = %x\n",dyn->d_tag); 383 | //printf("get_sym_info dyn->d_un.d_ptr = %x\n",dyn->d_un.d_ptr); 384 | switch(dyn->d_tag) 385 | { 386 | case DT_SYMTAB: 387 | symtab = dyn->d_un.d_ptr; 388 | 389 | break; 390 | case DT_STRTAB: 391 | strtab = dyn->d_un.d_ptr; 392 | break; 393 | /*case DT_HASH://可能不存在哈希表,此时nchains是错误的,这个值可以通过符号表得到 394 | //printf("get_sym_info hash table's addr = %x\n",dyn->d_un.d_ptr); 395 | //printf("get_sym_info symtbl's entry = %x\n",(dyn->d_un.d_ptr) + 4); 396 | ptrace_read(pid, (dyn->d_un.d_ptr) + 4,&nchains, sizeof(nchains)); 397 | break;*/ 398 | case DT_JMPREL: 399 | jmprel = dyn->d_un.d_ptr; 400 | break; 401 | case DT_PLTRELSZ: 402 | totalrelsize = dyn->d_un.d_val; 403 | break; 404 | case DT_RELAENT: 405 | relsize = dyn->d_un.d_val; 406 | break; 407 | case DT_RELENT: 408 | relsize = dyn->d_un.d_val; 409 | break; 410 | case DT_REL: 411 | reldyn = dyn->d_un.d_ptr; 412 | break; 413 | case DT_RELSZ: 414 | reldynsz = dyn->d_un.d_val; 415 | break; 416 | } 417 | ptrace_read(pid, dyn_addr += sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn)); 418 | } 419 | 420 | //printf("get_sym_info link_addr = %x\n",link_addr); 421 | //printf("get_sym_info symtab = %x\n",symtab); 422 | //printf("get_sym_info relsize = %x\n",relsize); 423 | //printf("get_sym_info reldyn = %x\n",reldyn); 424 | //printf("get_sym_info totalrelsize = %x\n",totalrelsize); 425 | //printf("get_sym_info jmprel = %x\n",jmprel); 426 | //printf("get_sym_info nchains = %x\n",nchains); 427 | //printf("get_sym_info strtab = %x\n",strtab); 428 | 429 | nrels = totalrelsize / relsize; 430 | nreldyns = reldynsz/relsize; 431 | 432 | //printf("get_sym_info nreldyns = %d\n",nreldyns); 433 | //printf("get_sym_info nrels = %d\n",nrels); 434 | 435 | free(dyn); 436 | printf("get_sym_info exit\n"); 437 | } 438 | /* 439 | 在指定的link_map指向的符号表查找符号,它仅仅是被上面的find_symbol使用 440 | */ 441 | unsigned long find_symbol_in_linkmap(int pid, struct link_map *lm, char *sym_name) 442 | { 443 | Elf32_Sym *sym = (Elf32_Sym *) malloc(sizeof(Elf32_Sym)); 444 | int i = 0; 445 | char *str; 446 | unsigned long ret; 447 | int flags = 0; 448 | 449 | get_sym_info(pid, lm); 450 | 451 | do{ 452 | if(ptrace_read(pid, symtab + i * sizeof(Elf32_Sym), sym, sizeof(Elf32_Sym))) 453 | return 0; 454 | i++; 455 | //printf("find_symbol_in_linkmap sym->st_name = %x\tsym->st_size = %x\tsym->st_value = %x\n",sym->st_name,sym->st_size,sym->st_value); 456 | //printf("find_symbol_in_linkmap Elf32_Sym's size = %d\n",sizeof(Elf32_Sym)); 457 | //printf("\nfind_symbol_in_linkmap sym->st_name = %x\n",sym->st_name); 458 | if (!sym->st_name && !sym->st_size && !sym->st_value)//全为0是符号表的第一项 459 | continue; 460 | //printf("\nfind_symbol_in_linkmap strtab = %x\n",strtab); 461 | str = (char *) ptrace_readstr(pid, strtab + sym->st_name); 462 | //printf("\nfind_symbol_in_linkmap str = %s\n",str); 463 | //printf("\nfind_symbol_in_linkmap sym->st_value = %x\n",sym->st_value); 464 | if (strcmp(str, sym_name) == 0) { 465 | printf("\nfind_symbol_in_linkmap str = %s\n",str); 466 | printf("\nfind_symbol_in_linkmap sym->st_value = %x\n",sym->st_value); 467 | free(str); 468 | if(sym->st_value == 0)//值为0代表这个符号本身就是重定向的内容 469 | continue; 470 | flags = 1; 471 | 472 | //str = ptrace_readstr(pid, (unsigned long)lm->l_name); 473 | //printf("find_symbol_in_linkmap lib name [%s]\n", str); 474 | //free(str); 475 | break; 476 | } 477 | 478 | free(str); 479 | }while(1); 480 | 481 | 482 | if (flags != 1) 483 | ret = 0; 484 | else 485 | ret = link_addr + sym->st_value; 486 | 487 | free(sym); 488 | 489 | return ret; 490 | } 491 | 492 | /* 493 | 解析指定符号 494 | */ 495 | unsigned long find_symbol(int pid, struct link_map *map, char *sym_name) 496 | { 497 | struct link_map *lm = map; 498 | unsigned long sym_addr; 499 | char *str; 500 | unsigned long tmp; 501 | 502 | //sym_addr = find_symbol_in_linkmap(pid, map, sym_name); 503 | //return 0; 504 | //if (sym_addr) 505 | // return sym_addr; 506 | //printf("\nfind_symbol map = %x\n",map); 507 | //ptrace_read(pid,(char *)map+12,&tmp,4); 508 | //lm = tmp; 509 | //printf("find_symbol lm = %x\n",lm); 510 | //ptrace_read(pid, (unsigned long)map->l_next, lm, sizeof(struct link_map)); 511 | sym_addr = find_symbol_in_linkmap(pid, lm, sym_name); 512 | while(!sym_addr ) { 513 | ptrace_read(pid, (char *)lm+12, &tmp, 4);//获取下一个库的link_map地址 514 | if(tmp == 0) 515 | return 0; 516 | lm = tmp; 517 | //printf("find_symbol lm = %x\n",lm); 518 | /*str = ptrace_readstr(pid, (unsigned long)lm->l_name); 519 | if(str[0] == '/0') 520 | continue; 521 | printf("[%s]\n", str); 522 | free(str);*/ 523 | 524 | if ((sym_addr = find_symbol_in_linkmap(pid, lm, sym_name))) 525 | break; 526 | } 527 | 528 | return sym_addr; 529 | } 530 | 531 | 532 | /* 查找符号的重定位地址 */ 533 | unsigned long find_sym_in_rel(int pid, char *sym_name) 534 | { 535 | Elf32_Rel *rel = (Elf32_Rel *) malloc(sizeof(Elf32_Rel)); 536 | Elf32_Sym *sym = (Elf32_Sym *) malloc(sizeof(Elf32_Sym)); 537 | int i; 538 | char *str; 539 | unsigned long ret; 540 | struct link_map *lm; 541 | lm = map_addr; 542 | 543 | //get_dyn_info(pid); 544 | do{ 545 | get_sym_info(pid,lm); 546 | ptrace_read(pid, (char *)lm+12, &lm, 4); 547 | //首先查找过程连接的重定位表 548 | for(i = 0; i< nrels ;i++) { 549 | ptrace_read(pid, (unsigned long)(jmprel + i * sizeof(Elf32_Rel)), 550 | rel, sizeof(Elf32_Rel)); 551 | if(ELF32_R_SYM(rel->r_info)) { 552 | ptrace_read(pid, symtab + ELF32_R_SYM(rel->r_info) * 553 | sizeof(Elf32_Sym), sym, sizeof(Elf32_Sym)); 554 | str = ptrace_readstr(pid, strtab + sym->st_name); 555 | if (strcmp(str, sym_name) == 0) { 556 | if(sym->st_value != 0){ 557 | free(str); 558 | continue; 559 | } 560 | modifyflag = 1; 561 | free(str); 562 | break; 563 | } 564 | free(str); 565 | } 566 | } 567 | 568 | if(modifyflag == 1) 569 | break; 570 | //没找到的话,再找在链接时就重定位的重定位表 571 | for(i = 0; i< nreldyns;i++) { 572 | ptrace_read(pid, (unsigned long)(reldyn+ i * sizeof(Elf32_Rel)), 573 | rel, sizeof(Elf32_Rel)); 574 | if(ELF32_R_SYM(rel->r_info)) { 575 | ptrace_read(pid, symtab + ELF32_R_SYM(rel->r_info) * 576 | sizeof(Elf32_Sym), sym, sizeof(Elf32_Sym)); 577 | str = ptrace_readstr(pid, strtab + sym->st_name); 578 | if (strcmp(str, sym_name) == 0) { 579 | if(sym->st_value != 0){ 580 | free(str); 581 | continue; 582 | } 583 | modifyflag = 2; 584 | free(str); 585 | break; 586 | } 587 | free(str); 588 | } 589 | } 590 | 591 | if(modifyflag == 2) 592 | break; 593 | 594 | }while(lm); 595 | //printf("find_sym_in_rel flags = %d\n",flags); 596 | if (modifyflag == 0) 597 | ret = 0; 598 | else 599 | ret = link_addr + rel->r_offset; 600 | //printf("find_sym_in_rel link_addr = %x\t sym->st_value = %x\n",link_addr , sym->st_value); 601 | free(rel); 602 | free(sym); 603 | 604 | return ret; 605 | } 606 | 607 | /* 608 | 在进程自身的映象中(即不包括动态共享库,无须遍历link_map链表)获得各种动态信息 609 | */ 610 | /*void get_dyn_info(int pid) 611 | { 612 | Elf32_Dyn *dyn = (Elf32_Dyn *) malloc(sizeof(Elf32_Dyn)); 613 | int i = 0; 614 | 615 | ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn)); 616 | i++; 617 | while(dyn->d_tag){ 618 | switch(dyn->d_tag) 619 | { 620 | case DT_SYMTAB: 621 | //puts("DT_SYMTAB"); 622 | symtab = dyn->d_un.d_ptr; 623 | break; 624 | case DT_STRTAB: 625 | strtab = dyn->d_un.d_ptr; 626 | //puts("DT_STRTAB"); 627 | break; 628 | case DT_JMPREL: 629 | jmprel = dyn->d_un.d_ptr; 630 | //puts("DT_JMPREL"); 631 | //printf("jmprel\t %p\n", jmprel); 632 | break; 633 | case DT_PLTRELSZ: 634 | totalrelsize = dyn->d_un.d_val; 635 | //puts("DT_PLTRELSZ"); 636 | break; 637 | case DT_RELAENT: 638 | relsize = dyn->d_un.d_val; 639 | //puts("DT_RELAENT"); 640 | break; 641 | case DT_RELENT: 642 | relsize = dyn->d_un.d_val; 643 | //puts("DT_RELENT"); 644 | break; 645 | } 646 | 647 | ptrace_read(pid, dyn_addr + i * sizeof(Elf32_Dyn), dyn, sizeof(Elf32_Dyn)); 648 | i++; 649 | } 650 | 651 | nrels = totalrelsize / relsize; 652 | 653 | free(dyn); 654 | }*/ 655 | 656 | /*void call_dl_open(int pid, unsigned long addr, char *libname) 657 | { 658 | void *pRLibName; 659 | struct user_regs_struct regs; 660 | 661 | /* 662 | 先找个空间存放要装载的共享库名,我们可以简单的把它放入堆栈 663 | 664 | pRLibName = ptrace_push(pid, libname, strlen(libname) + 1); 665 | 666 | /* 设置参数到寄存器 667 | ptrace_readreg(pid, ®s); 668 | regs.eax = (unsigned long) pRLibName; 669 | regs.ecx = 0x0; 670 | regs.edx = RTLD_LAZY; 671 | ptrace_writereg(pid, ®s); 672 | 673 | /* 调用_dl_open 674 | ptrace_call(pid, addr); 675 | puts("call _dl_open ok"); 676 | }*/ 677 | 678 | 679 | 680 | 681 | /*#define RTLD_LAZY 0x00001 682 | #define RTLD_NOW 0x00002 683 | #define RTLD_BINDING_MASK 0x3 684 | #define RTLD_NOLOAD 0x00004 685 | #define RTLD_DEEPBIND 0x00008 686 | 687 | #define RTLD_GLOBAL 0x00100 688 | 689 | #define RTLD_LOCAL 0 690 | 691 | #define RTLD_NODELETE 0x01000 */ 692 | 693 | void call__libc_dlopen_mode(int pid, unsigned long addr, char *libname) 694 | { 695 | void *plibnameaddr; 696 | 697 | //printf("call__libc_dlopen_mode libname = %s\n",libname); 698 | //printf("call__libc_dlopen_mode addr = %x\n",addr); 699 | //将需要加载的共享库地址压栈 700 | plibnameaddr = ptrace_push(pid, libname, strlen(libname) + 1); 701 | ptrace_push(pid,&mode,sizeof(int)); 702 | ptrace_push(pid,&plibnameaddr,sizeof(plibnameaddr)); 703 | 704 | /* 调用__libc_dlopen_mode */ 705 | ptrace_call(pid, addr); 706 | } 707 | void call_printf(int pid, unsigned long addr, char *string) 708 | { 709 | void *paddr; 710 | 711 | paddr = ptrace_push(pid, string, strlen(string) + 1); 712 | ptrace_push(pid,&paddr,sizeof(paddr)); 713 | 714 | ptrace_call(pid, addr); 715 | } 716 | 717 | int main(int argc, char *argv[]) 718 | { 719 | int pid; 720 | struct link_map *map; 721 | char sym_name[256]; 722 | unsigned long sym_addr; 723 | unsigned long new_addr,old_addr,rel_addr; 724 | int status = 0; 725 | char libpath[1024]; 726 | char oldfunname[128]; 727 | char newfunname[128]; 728 | //mode = atoi(argv[2]); 729 | if(argc < 5){ 730 | printf("usage : ./injso pid libpath oldfunname newfunname\n"); 731 | exit(-1); 732 | } 733 | /* 从命令行取得目标进程PID*/ 734 | pid = atoi(argv[1]); 735 | 736 | /* 从命令行取得新库名称*/ 737 | memset(libpath,0,sizeof(libpath)); 738 | memcpy(libpath,argv[2],strlen(argv[2])); 739 | 740 | /* 从命令行取得旧函数的名称*/ 741 | memset(oldfunname,0,sizeof(oldfunname)); 742 | memcpy(oldfunname,argv[3],strlen(argv[3])); 743 | 744 | /* 从命令行取得新函数的名称*/ 745 | memset(newfunname,0,sizeof(newfunname)); 746 | memcpy(newfunname,argv[4],strlen(argv[4])); 747 | 748 | printf("main pid = %d\n",pid); 749 | printf("main libpath : %s\n",libpath); 750 | printf("main oldfunname : %s\n",oldfunname); 751 | printf("main newfunname : %s\n",newfunname); 752 | /* 关联到目标进程*/ 753 | ptrace_attach(pid); 754 | 755 | /* 得到指向link_map链表的指针 */ 756 | map = get_linkmap(pid); /* get_linkmap */ 757 | 758 | 759 | sym_addr = find_symbol(pid, map, "printf"); 760 | printf("found printf at addr %p\n", sym_addr); 761 | if(sym_addr == 0) 762 | goto detach; 763 | call_printf(pid,sym_addr,"injso successed\n"); 764 | waitpid(pid,&status,0); 765 | printf("status = %x\n",status); 766 | 767 | /*ptrace_writereg(pid, &oldregs); 768 | ptrace_cont(pid); 769 | 770 | 771 | 772 | waitpid(pid,&status,0); 773 | //printf("status = %x\n",status); 774 | //ptrace_readreg(pid, &oldregs); 775 | //oldregs.eip = 0x8048414; 776 | //ptrace_writereg(pid, &oldregs); 777 | ptrace_cont(int pid)(pid); 778 | 779 | ptrace_detach(pid); 780 | 781 | exit(0);*/ 782 | 783 | /* 发现__libc_dlopen_mode,并调用它 */ 784 | sym_addr = find_symbol(pid, map, "__libc_dlopen_mode"); /* call _dl_open */ 785 | printf("found __libc_dlopen_mode at addr %p\n", sym_addr); 786 | if(sym_addr == 0) 787 | goto detach; 788 | call__libc_dlopen_mode(pid, sym_addr,libpath); /* 注意装载的库地址 */ 789 | //while(1); 790 | waitpid(pid,&status,0); 791 | /* 找到新函数的地址 */ 792 | strcpy(sym_name, newfunname); /* intercept */ 793 | sym_addr = find_symbol(pid, map, sym_name); 794 | printf("%s addr\t %p\n", sym_name, sym_addr); 795 | if(sym_addr == 0) 796 | goto detach; 797 | 798 | /* 找到旧函数在重定向表的地址 */ 799 | strcpy(sym_name, oldfunname); 800 | rel_addr = find_sym_in_rel(pid, sym_name); 801 | printf("%s rel addr\t %p\n", sym_name, rel_addr); 802 | if(rel_addr == 0) 803 | goto detach; 804 | 805 | /* 找到用于保存read地址的指针 */ 806 | //strcpy(sym_name, "oldread"); 807 | //old_addr = find_symbol(pid, map, sym_name); 808 | //printf("%s addr\t %p\n", sym_name, old_addr); 809 | 810 | /* 函数重定向 */ 811 | puts("intercept..."); /* intercept */ 812 | //ptrace_read(pid, rel_addr, &new_addr, sizeof(new_addr)); 813 | //ptrace_write(pid, old_addr, &new_addr, sizeof(new_addr)); 814 | //rel_addr = 0x8048497;如果是静态地址,也就是未导出该符号地址,那么只能通过反汇编先找到该函数被调用的地方,将这个地方的跳转地址修改 815 | 816 | if(modifyflag == 2) 817 | sym_addr = sym_addr - rel_addr - 4; 818 | printf("main modify sym_addr = %x\n",sym_addr); 819 | ptrace_write(pid, rel_addr, &sym_addr, sizeof(sym_addr)); 820 | 821 | puts("injectso ok"); 822 | detach: 823 | printf("prepare to detach\n"); 824 | ptrace_detach(pid); 825 | 826 | return 0; 827 | 828 | } 829 | -------------------------------------------------------------------------------- /code/libtarget.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L1B0/linux-hotpatch/01676bf574745a2f11ba1b14c1f6c0311fe3d9af/code/libtarget.so -------------------------------------------------------------------------------- /code/source: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L1B0/linux-hotpatch/01676bf574745a2f11ba1b14c1f6c0311fe3d9af/code/source -------------------------------------------------------------------------------- /code/source.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int main() 4 | { 5 | while(1){ 6 | sleep(10); 7 | printf("%d : original\n",time(0)); 8 | } 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /code/target.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int newmyprint() 4 | { 5 | write(1,"hahahahahahaha",14); 6 | return 0; 7 | } 8 | --------------------------------------------------------------------------------