将代码注入 ubuntu 64 位进程
Inject code into process in ubuntu 64bit
我正在通过文章 "playing with ptrace" 学习 ptrace。
现在我可以通过将tracee的指令替换为"syscall"来设置断点,但无法成功注入代码。
在 X86 中,打印可以使用 "int 80" 然后按 "int3" 暂停处理。
我如何注入具有指令 "syscall " 的代码并在 x64 中完成注入代码时停止进程 谢谢。
我注入的代码是这样的
section .text
global main
main:
mov rax, 1
mov rdi, 1
mov rsi, message
mov rdx, 13
syscall
int3
message:
db "Hello world", 10
我的密码是
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LONG_SIZE 8
void getdata(pid_t child, long addr,char *str,int len)
{
char *laddr = str;
int i = 0,j = len/LONG_SIZE;
union u{
long val;
char chars[LONG_SIZE];
} word;
while(i<j)
{
word.val = ptrace(PTRACE_PEEKDATA,child,addr + i*LONG_SIZE,NULL);
if(word.val == -1)
perror("trace error");
memcpy(laddr,word.chars,LONG_SIZE);
++i;
laddr += LONG_SIZE;
}
j = len %LONG_SIZE;
if(j!=0)
{
word.val == ptrace(PTRACE_PEEKDATA,child,addr + i*LONG_SIZE,NULL);
if(word.val == -1)
perror("trace error");
}
str[len] = '[=12=]';
}
void putdata(pid_t child,long addr,char *str,int len)
{
char *laddr = str;
int i = 0, j = len/LONG_SIZE;
union u{
long val;
char chars[LONG_SIZE];
}word;
while(i<j)
{
memcpy(word.chars,laddr,LONG_SIZE);
if(ptrace(PTRACE_POKEDATA,child,addr+i*LONG_SIZE,word.val) == -1)
perror("trace error");
++i;
laddr += LONG_SIZE;
}
j = len % LONG_SIZE;
if(j != 0)
{
word.val = 0;
memcpy(word.chars,laddr,j);
if(ptrace(PTRACE_POKEDATA,child,addr+i*LONG_SIZE,word.val) == -1)
perror("trace error");
}
}
void printBytes(const char* tip,char* codes,int len)
{
int i;
printf("%s :",tip);
for(i = 0;i<len;++i)
{
printf("%02x ",(unsigned char)codes[i]);
}
puts("");
}
#define CODE_SIZE 48
int main(int argc ,char *argv[])
{
if(argc != 2)
{
puts("no pid input");
exit(1);
}
pid_t traced_process;
struct user_regs_struct regs;
long ins;
char code[CODE_SIZE] = {0xb8,0x01,0x00,0x00,0x00,0xbf,0x01,0x00,0x00,0x00,0x48,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xba,0x0d,0x00,0x00,0x00,0x0f,0x05,0xcc,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x77,0x6f,0x72,0x6c,0x64,0x0a};
char backup[CODE_SIZE];
traced_process = atoi(argv[1]);
printf("try to attach pid:%u\n",traced_process);
if(ptrace(PTRACE_ATTACH,traced_process,NULL,NULL) == -1)
{
perror("trace attach error");
}
wait(NULL);
if(ptrace(PTRACE_GETREGS,traced_process,NULL,®s) == -1)
{
perror("trace get regs error");
}
//copy instructions into backup variable
getdata(traced_process,regs.rip,backup,CODE_SIZE);
printBytes("get tracee instuction",backup,CODE_SIZE);
puts("try to inject code");
putdata(traced_process,regs.rip,code,CODE_SIZE);
puts("inject success, tracee continue");
if(ptrace(PTRACE_CONT,traced_process,NULL,NULL) == -1)
{
perror("trace continue error");
}
//wait tracee to execute int3 to stop
wait(NULL);
puts("inject code finish, Press <Enter> to continue");
getchar();
printBytes("place inject instructions with backup instructions",backup,CODE_SIZE);
putdata(traced_process,regs.rip,backup,CODE_SIZE);
ptrace(PTRACE_SETREGS,traced_process,NULL,®s);
ptrace(PTRACE_DETACH,traced_process,NULL,NULL);
return 0;
}
没用,只能让tracee停止再恢复。它出什么问题了?
运行 它在 ubuntu 16.04 64 位中。
你自己说的。使用发出信号的命令。
调试器使用 int 3
,原因很简单。虽然您引发的每个软件中断都是几个字节长(一个用于 int
命令,另一个用于中断编号),但 int 3
是一个单字节指令。正因为如此,它可以很容易地被调试器注入(然后删除)。
总而言之,由于您在 x86_64
,请将 int 80
注入替换为 syscall
,但保持其他软件中断不变。
我知道原因。我post的asm代码不是PIC,注入tracee的内存时,字符串地址错误,所以失败。
正确的 asm 代码应该是
section .text
global main
main:
jmp forward
backward:
pop rsi
mov rax, 1
mov rdi, 1
mov rdx, 13
syscall
int3
forward:
call backward
db "Hello world",0xa
我正在通过文章 "playing with ptrace" 学习 ptrace。 现在我可以通过将tracee的指令替换为"syscall"来设置断点,但无法成功注入代码。
在 X86 中,打印可以使用 "int 80" 然后按 "int3" 暂停处理。 我如何注入具有指令 "syscall " 的代码并在 x64 中完成注入代码时停止进程 谢谢。
我注入的代码是这样的
section .text
global main
main:
mov rax, 1
mov rdi, 1
mov rsi, message
mov rdx, 13
syscall
int3
message:
db "Hello world", 10
我的密码是
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LONG_SIZE 8
void getdata(pid_t child, long addr,char *str,int len)
{
char *laddr = str;
int i = 0,j = len/LONG_SIZE;
union u{
long val;
char chars[LONG_SIZE];
} word;
while(i<j)
{
word.val = ptrace(PTRACE_PEEKDATA,child,addr + i*LONG_SIZE,NULL);
if(word.val == -1)
perror("trace error");
memcpy(laddr,word.chars,LONG_SIZE);
++i;
laddr += LONG_SIZE;
}
j = len %LONG_SIZE;
if(j!=0)
{
word.val == ptrace(PTRACE_PEEKDATA,child,addr + i*LONG_SIZE,NULL);
if(word.val == -1)
perror("trace error");
}
str[len] = '[=12=]';
}
void putdata(pid_t child,long addr,char *str,int len)
{
char *laddr = str;
int i = 0, j = len/LONG_SIZE;
union u{
long val;
char chars[LONG_SIZE];
}word;
while(i<j)
{
memcpy(word.chars,laddr,LONG_SIZE);
if(ptrace(PTRACE_POKEDATA,child,addr+i*LONG_SIZE,word.val) == -1)
perror("trace error");
++i;
laddr += LONG_SIZE;
}
j = len % LONG_SIZE;
if(j != 0)
{
word.val = 0;
memcpy(word.chars,laddr,j);
if(ptrace(PTRACE_POKEDATA,child,addr+i*LONG_SIZE,word.val) == -1)
perror("trace error");
}
}
void printBytes(const char* tip,char* codes,int len)
{
int i;
printf("%s :",tip);
for(i = 0;i<len;++i)
{
printf("%02x ",(unsigned char)codes[i]);
}
puts("");
}
#define CODE_SIZE 48
int main(int argc ,char *argv[])
{
if(argc != 2)
{
puts("no pid input");
exit(1);
}
pid_t traced_process;
struct user_regs_struct regs;
long ins;
char code[CODE_SIZE] = {0xb8,0x01,0x00,0x00,0x00,0xbf,0x01,0x00,0x00,0x00,0x48,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xba,0x0d,0x00,0x00,0x00,0x0f,0x05,0xcc,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x77,0x6f,0x72,0x6c,0x64,0x0a};
char backup[CODE_SIZE];
traced_process = atoi(argv[1]);
printf("try to attach pid:%u\n",traced_process);
if(ptrace(PTRACE_ATTACH,traced_process,NULL,NULL) == -1)
{
perror("trace attach error");
}
wait(NULL);
if(ptrace(PTRACE_GETREGS,traced_process,NULL,®s) == -1)
{
perror("trace get regs error");
}
//copy instructions into backup variable
getdata(traced_process,regs.rip,backup,CODE_SIZE);
printBytes("get tracee instuction",backup,CODE_SIZE);
puts("try to inject code");
putdata(traced_process,regs.rip,code,CODE_SIZE);
puts("inject success, tracee continue");
if(ptrace(PTRACE_CONT,traced_process,NULL,NULL) == -1)
{
perror("trace continue error");
}
//wait tracee to execute int3 to stop
wait(NULL);
puts("inject code finish, Press <Enter> to continue");
getchar();
printBytes("place inject instructions with backup instructions",backup,CODE_SIZE);
putdata(traced_process,regs.rip,backup,CODE_SIZE);
ptrace(PTRACE_SETREGS,traced_process,NULL,®s);
ptrace(PTRACE_DETACH,traced_process,NULL,NULL);
return 0;
}
没用,只能让tracee停止再恢复。它出什么问题了? 运行 它在 ubuntu 16.04 64 位中。
你自己说的。使用发出信号的命令。
调试器使用 int 3
,原因很简单。虽然您引发的每个软件中断都是几个字节长(一个用于 int
命令,另一个用于中断编号),但 int 3
是一个单字节指令。正因为如此,它可以很容易地被调试器注入(然后删除)。
总而言之,由于您在 x86_64
,请将 int 80
注入替换为 syscall
,但保持其他软件中断不变。
我知道原因。我post的asm代码不是PIC,注入tracee的内存时,字符串地址错误,所以失败。 正确的 asm 代码应该是
section .text
global main
main:
jmp forward
backward:
pop rsi
mov rax, 1
mov rdi, 1
mov rdx, 13
syscall
int3
forward:
call backward
db "Hello world",0xa