2016-11-04 7 views
0

"ptraceで遊ぶ"という記事でptraceを学んでいます。 これで、traceeの命令を "syscall"に置き換えてブレークポイントを設定できますが、コードを正常に注入することはできません。ubuntu 64bitのプロセスにコードを注入する

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 

私のコードでは、それは、動作しないだけでtracee停止と再開を行うことができます

#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] = '\0'; 
} 


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,&regs) == -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,&regs); 
    ptrace(PTRACE_DETACH,traced_process,NULL,NULL); 
    return 0; 
} 

されています。どうしたの? ubuntu 16.04 64bitで実行してください。

答えて

0

私はその理由を知っています。私が投稿するasmコードは、トレースのメモリに注入されたときにPICではなく、文字列アドレスが間違っているため、失敗しました。 正しい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 
0

あなたは自分でそれを言った。シグナルを発生させるコマンドを使用します。

デバッガは非常に簡単な理由からint 3を使用します。発生するすべての単一ソフトウェア割り込みは、長さが2,3バイトです(intコマンド用と割り込み番号用)。int 3は1バイト命令です。デバッガで簡単に注入(そして除去)することができます。

要約すると、x86_64にあるので、int 80注入をsyscallに置き換えますが、他のソフトウェア割り込みはそのままにしておきます。

+0

です。命令 "int3"はトレース自体を停止させ、トレーサはwait()を直接使用して信号を待つことができます。ありがとう。ちなみに、命令は "int 3"ではなく "int 3"であり、他者を混乱させる可能性があります。 – mmmmar

+0

この回答があなたの質問に対する答えだと思うなら、それを受け入れてください(その隣の "V"をクリックしてください)。 –

+0

私は理由を知っています。 asmからの指示はPICではないので、トレースに注入すると文字列アドレスは使用できません。 – mmmmar

関連する問題