在上一节中完成了B程序对A程序的执行控制实例,在此基础上,本节将int80/ int3替换成简单的shellcode,使代码注入过程更加直观。
【环境】
CentOS 6.6 (Final)
Linux version 2.6.32-504.el6.i686
Gcc version 4.4.7 20120313
【A程序:counter.c】
#include
#include
long long timeum(){
struct timeval tim;
gettimeofday (&tim , NULL);
return (long long)tim.tv_sec*1000000+tim.tv_usec;
}
int main()
{
int i;
long long start,tmp;
start = timeum();
for(i = 0; i < 60; ++i){
printf("My Counter: %d\n", i);
sleep(1);
tmp = timeum();
printf("Time Interval: %lld\n",tmp-start);
start = tmp;
}
return 0;
}
gcc -o counter counter.c
【C程序:asmhello.c】
void main()
{
__asm__(
"jmp forward\n\t"
"backward:\n\t"
"popl %esi\n\t"
"movl $4, %eax\n\t"
"movl $2, %ebx\n\t"
"movl %esi, %ecx\n\t"
"movl $12, %edx\n\t"
"int $0x80\n\t"
"int3\n\t"
"forward:\n\t"
"call backward\n\t"
".string \"Hello World\\n\"\n\t"
);
}
gcc -o asmhello asmhello.c
在backward和forward之间的跳转是为了使程序能够找到”hello world” 字符串的地址。 获取二进制代码过程如下:
gdb asmhello
(gdb) disas main
Dump of assembler code for function main:
0x08048394 <+0 >: push %ebp
0x08048395 <+1 >: mov %esp,%ebp
0x08048397 <+3 >: jmp 0x80483ae
0x08048399 <+5 >: pop %esi
0x0804839a <+6 >: mov $0x4,%eax
0x0804839f <+11>: mov $0x2,%ebx
0x080483a4 <+16>: mov %esi,%ecx
0x080483a6 <+18>: mov $0xc,%edx
0x080483ab <+23>: int $0x80
0x080483ad <+25>: int3
0x080483ae <+0 >: call 0x8048399 5>
0x080483b3 <+5 >: dec %eax
0x080483b4 <+6 >: gs
0x080483b5 <+7 >: insb (%dx),%es:(%edi)
0x080483b6 <+8 >: insb (%dx),%es:(%edi)
0x080483b7 <+9 >: outsl %ds:(%esi),(%dx)
0x080483b8 <+10>: and %dl,0x6f(%edi)
0x080483bb <+13>: jb 0x8048429 <__libc_csu_init+73>
0x080483bd <+15>: or %fs:(%eax),%al
0x080483c0 <+18>: pop %ebp
0x080483c1 <+19>: ret
End of assembler dump.
(gdb) x /50bx main+3
0x8048397 <main+3>: 0xeb 0x15 0x5e 0xb8 0x04 0x00 0x00 0x00
0x804839f <main+11>: 0xbb 0x02 0x00 0x00 0x00 0x89 0xf1 0xba
0x80483a7 <main+19>: 0x0c 0x00 0x00 0x00 0xcd 0x80 0xcc 0xe8
0x80483af <forward+1>: 0xe6 0xff 0xff 0xff 0x48 0x65 0x6c 0x6c
0x80483b7 <forward+9>: 0x6f 0x20 0x57 0x6f 0x72 0x6c 0x64 0x0a
0x80483bf <forward+17>: 0x00 0x5d 0xc3 0x90 0x90 0x90 0x90 0x90
0x80483c7 <forward+25>: 0x90 0x90
shellcode实际位置为main+3到forward+17,共41个字节,所以最终shellcode如下:
char code[] =
"\xeb\x15\x5e\xb8\x04\x00\x00\x00"
"\xbb\x02\x00\x00\x00\x89\xf1\xba"
"\x0c\x00\x00\x00\xcd\x80\xcc\xe8"
"\xe6\xff\xff\xff\x48\x65\x6c\x6c"
"\x6f\x20\x57\x6f\x72\x6c\x64\x0a\x00";
【B程序:injecthello.c】
#include
#include
#include
#include
#include
#include
const int long_size = sizeof(long);
void getdata(pid_t child, long addr, char *str, int len)
{
char *laddr;
int i,j;
union u{
long val;
char chars[long_size];
}data;
i = 0;
j = len / long_size;
laddr = str;
while(i < j){
data.val = ptrace(PTRACE_PEEKDATA, child, addr + i*4, NULL);
memcpy(laddr, data.chars, long_size);
++i;
laddr += long_size;
}
j = len % long_size;
if(j != 0){
data.val = ptrace(PTRACE_PEEKDATA, child, addr + i*4, NULL);
memcpy(laddr, data.chars, j);
}
str[len] = ' ';
}
void putdata(pid_t child, long addr, char *str, int len)
{
char *laddr;
int i,j;
union u{
long val;
char chars[long_size];
}data;
long rst;
i = 0;
j = len / long_size;
laddr = str;
while(i < j){
memcpy(data.chars, laddr, long_size);
rst = ptrace(PTRACE_POKEDATA, child, addr + i*4, data.val);
if (rst < 0) {
printf("Putdata Failed! \n");
return;
}
++i;
laddr += long_size;
}
j = len % long_size;
if(j != 0){
memcpy(data.chars, laddr, j);
rst = ptrace(PTRACE_POKEDATA, child, addr + i*4, data.val);
if (rst < 0) {
printf("Putdata Failed! \n");
return;
}
}
}
int main(int argc, char *argv[])
{
pid_t traced_process;
struct user_regs_struct regs, newregs;
int len = 41;
/* hello world */
char code[] =
"\xeb\x15\x5e\xb8\x04\x00\x00\x00"
"\xbb\x02\x00\x00\x00\x89\xf1\xba"
"\x0c\x00\x00\x00\xcd\x80\xcc\xe8"
"\xe6\xff\xff\xff\x48\x65\x6c\x6c"
"\x6f\x20\x57\x6f\x72\x6c\x64\x0a\x00";
//char code[] = {0xcd,0x80,0xcc,0};
char backup[len+1];
if(argc != 2) {
printf("PID?\n");
return 1;
}
traced_process = atoi(argv[1]);
ptrace(PTRACE_ATTACH, traced_process, NULL, NULL);
int pid = wait(NULL);
printf("Attach Pid: %d\n",pid);
ptrace(PTRACE_GETREGS, traced_process, NULL, ®s);
/* Copy instructions into a backup variable */
getdata(traced_process, regs.eip, backup, len);
/* Put the breakpoint */
putdata(traced_process, regs.eip, code, len);
/* Let the process continue and execute
the int 3 instruction */
ptrace(PTRACE_CONT, traced_process, NULL, NULL);
wait(NULL);
putdata(traced_process, regs.eip, backup, len);
/* Setting the eip back to the original
instruction to let the process continue */
ptrace(PTRACE_SETREGS, traced_process, NULL, ®s);
ptrace(PTRACE_DETACH, traced_process, NULL, NULL);
return 0;
}
gcc -o injecthello injecthello.c
【执行】
1. run counter
./counter
2. find pid of counter
ps aux | grep counter
3. run injecthello(root)
./injecthello %pid%
【结果】
A进程部分输出如下,输出helloworld证明B进程代码注入成功。
My Counter: 0
1000429
My Counter: 1
1000207
My Counter: 2
1000513
My Counter: 3
1000581
My Counter: 4
1000143
My Counter: 5
1000624
My Counter: 6
Hello World
1000680
My Counter: 7
1000546
My Counter: 8
Hello World
1000652
…
【参考】
http://www.cnblogs.com/wangkangluo1/archive/2012/06/05/2535484.html