At first, I regret the length of this post, but I wanted to clearly explain the problem.
I am trying to write a small self-modification program in C , but I have some problems and I donβt know exactly why.
Plateform: Ubuntu / Linux 2.6.32-40 x86_64, prog built on x86 arch, gcc (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3, GNU ld (GNU Binutils for Ubuntu) 2.20.1-system.20100303
The purpose of the program is to create a memory read / write / execute block (with memalign (3) and mprotect (2) ), copy a small function called p()(defined in a segment .text) in this memory fragment, and then execute the copied function using the pointer. The function p()simply displays the message with printf(puts).
To get the start and end address of the code p()(in order to copy it), I use the address of the function itself, and it dummy()creates the address of the function immediately after p()c .text.
int p() { ... } <- address where the copy starts
int dummy() { ... } <- address where the copy stops
The creation and copying of the memory is completed successfully, but when the code in the block is executed, segfault is executed . Using gdb, it is clear that we are entering the block code (the body of the copied function), but the printf call failed . When disassembling a function p()and code in a piece, I see that the address used in the "call" does not match.
And I donβt know why the address is incorrect when the code is copied, it is displayed, and it is the same as objdump (or gdb) when I parse the function p().
A binary file is created using -staticto avoid a potential problem with got/pltor with the relocation process ld.so. It seems that the problem is not to run the code in heap, since the start of the copied function is executed (tick << 29>).
src :
<... skip include/checks ...>
#define newline() putchar('\n')
int p()
{
printf("hello world\n");
return 0;
}
int dummy() { return 0; }
int main()
{
char *s, *code, *chunk;
unsigned int pagesz, sz;
int (*ptr)(void);
pagesz = sysconf(_SC_PAGE_SIZE);
chunk = (char*)memalign(pagesz, 4 * pagesz);
mprotect(chunk, 4 * pagesz, PROT_WRITE|PROT_EXEC|PROT_READ);
sz = (char *)dummy - (char *)p;
printf("Copy between : %p - %p\n", (char *)p, (char *)dummy);
printf("Copy in chunk : %p - %p\n", chunk, chunk + sz, sz);
printf("Copied code : ");
for(s = (char *)p, code = chunk; \
s <= (char *)dummy; s++, code++) {
*code = *s;
printf("%02x ", *(unsigned char *)code);
}
newline();
ptr = p;
ptr();
ptr = (int (*)(void))chunk;
ptr();
newline();
free(chunk);
return 0;
}
p() objdump(1):
080483c3 <p>:
80482c0: 55 push %ebp
80482c1: 89 e5 mov %esp,%ebp
80482c3: 83 ec 18 sub $0x18,%esp
80482c6: c7 04 24 a8 d9 0a 08 movl $0x80ad9a8,(%esp)
80482cd: e8 7e 0c 00 00 call 8048f50 <_IO_puts>
80482d2: b8 00 00 00 00 mov $0x0,%eax
80482d7: c9 leave
80482d8: c3 ret
080483dc <dummy>:
....
gdb (1), ( ), objdump (1):
Reading symbols from /path/.../selfmodif_light...done.
(gdb) list 55
50 /* - run once orginal function */
51 ptr = p;
52 ptr();
53
54 /* - run copied function (in chunk) */
55 ptr = (int (*)(void))chunk;
<<< The problem is here >>>
56 ptr();
57
58 newline();
59 free(chunk);
(gdb) br 56
Breakpoint 1 at 0x8048413: file tmp.c, line 56.
(gdb) run
Starting program: /path/.../selfmodif_light
Copy between : 0x80482c0 - 0x80482d9
Copy in chunk : 0x80d2000 - 0x80d2019
Copied code : 55 89 e5 83 ec 18 c7 04 24 a8 d9 0a 08 e8 7e 0c 00 00 b8 00 00 00 00 c9 c3 55
hello world
Breakpoint 1, main () at tmp.c:56
56 ptr();
, :
(gdb) disas main
Dump of assembler code for function main:
0x080482e3 <+0>: push %ebp
... <skip> ...
=> 0x08048413 <+304>: mov 0x18(%esp),%eax
0x08048417 <+308>: call *%eax
... <skip> ...
0x08048437 <+340>: ret
End of assembler dump.
p() , call 0x8048f50 <puts>, p(), call 0x80d2c90? .
(gdb) disas p
Dump of assembler code for function p:
0x080482c0 <+0>: push %ebp
0x080482c1 <+1>: mov %esp,%ebp
0x080482c3 <+3>: sub $0x18,%esp
0x080482c6 <+6>: movl $0x80ad9a8,(%esp)
0x080482cd <+13>: call 0x8048f50 <puts> <<= it is not the same address
0x080482d2 <+18>: mov $0x0,%eax
0x080482d7 <+23>: leave
0x080482d8 <+24>: ret
End of assembler dump.
(gdb) disas 0x80d2000,0x80d2019
Dump of assembler code from 0x80d2000 to 0x80d2019:
0x080d2000: push %ebp
0x080d2001: mov %esp,%ebp
0x080d2003: sub $0x18,%esp
0x080d2006: movl $0x80ad9a8,(%esp)
0x080d200d: call 0x80d2c90 <<= than here (but it should be ??)
0x080d2012: mov $0x0,%eax
0x080d2017: leave
0x080d2018: ret
End of assembler dump.
, . , , ? gdb, ?
(gdb) x/25bx p // code of p in .text
0x80482c0 <p>: 0x55 0x89 0xe5 0x83 0xec 0x18 0xc7 0x04
0x80482c8 <p+8>: 0x24 0xa8 0xd9 0x0a 0x08 0xe8 0x7e 0x0c
0x80482d0 <p+16>: 0x00 0x00 0xb8 0x00 0x00 0x00 0x00 0xc9
0x80482d8 <p+24>: 0xc3
(gdb) x/25bx 0x80d2000 // code of copy in the chunk
0x80d2000: 0x55 0x89 0xe5 0x83 0xec 0x18 0xc7 0x04
0x80d2008: 0x24 0xa8 0xd9 0x0a 0x08 0xe8 0x7e 0x0c
0x80d2010: 0x00 0x00 0xb8 0x00 0x00 0x00 0x00 0xc9
0x80d2018: 0xc3
ββ , :
(gdb) br *0x080d200d
Breakpoint 2 at 0x80d200d
(gdb) cont
Continuing.
Breakpoint 2, 0x080d200d in ?? ()
(gdb) disas 0x80d2000,0x80d2019
Dump of assembler code from 0x80d2000 to 0x80d2019:
0x080d2000: push %ebp
0x080d2001: mov %esp,%ebp
0x080d2003: sub $0x18,%esp
0x080d2006: movl $0x80ad9a8,(%esp)
=> 0x080d200d: call 0x80d2c90
0x080d2012: mov $0x0,%eax
0x080d2017: leave
0x080d2018: ret
End of assembler dump.
(gdb) info reg eip
eip 0x80d200d 0x80d200d
(gdb) nexti
0x080d2c90 in ?? ()
(gdb) info reg eip
eip 0x80d2c90 0x80d2c90
(gdb) bt
, , segfault, $eip , .
(gdb) set $eip = 0x8048f50
(gdb) cont
Continuing.
hello world
Program exited normally.
(gdb)
, , . , , () ?