2013-04-26 193 views
3

我正在編寫一個程序來替換另一個進程的內存中的字節字符串。它需要用C編寫,因爲我的目標平臺不支持任何更高級別的語言。最初,我不是直接跳到內存修改,而是直接嘗試將內存讀入緩衝區,以便我可以識別字符串所在的偏移量,以便我可以開始修改它。

我已經閱讀了每個堆棧溢出問題和代碼示例,我可以找到它們,以及手冊頁和一些常規試驗和錯誤。我的C有點生疏,所以這證明相當具有挑戰性。我讀過的例子似乎採取兩種不同的方法:

  • ptrace_attatch目標進程,使用多次調用ptrace_peekdata來讀取偏移的內存(INT)大小的塊。

  • ptrace_attatch,打開/ proc /進程/ MEM,和使用在/ proc/PID /地圖概述的偏移lseek的和read()出給定的字節數。

這是我的代碼。

程序attatch到:

#include <stdio.h> 

int main(int argc, char *argv[]){ 


printf("Spinning up....\n"); 
char changeme[6] = "AAAAA"; 
printf("ready for change....\n"); 

getchar(); 

printf("changeme is %s\n", changeme); 

    return 0; 
} 

程序用於轉儲存儲器:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/ptrace.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <sys/user.h> 
#include <sys/syscall.h> 
#include <unistd.h> 
#include <limits.h> 
#include <stdint.h> 
#include <fcntl.h> 
#include <wait.h> 
#include <errno.h> 


int main(int argc, char *argv[]){ 
char mempath[PATH_MAX]; 

uintptr_t const address = strtoul(argv[2], NULL, 0); 

int waitval = 0; 

    pid_t target_process = atoi(argv[1]); 
    struct user_regs_struct regs; 
    int readbytes = 0; 
    if (ptrace(PTRACE_ATTACH,target_process,NULL,NULL)) 
      perror("attach"); 
    printf("attatched!\n"); 

    waitpid(target_process, NULL, 0); 
    sprintf(mempath, "/proc/%s/mem", argv[1]); 
    printf("ready! opening %s\n", mempath); 

    int memfd = open(mempath, O_RDONLY); 
    printf("memfd = %d\n", memfd); 
    char *outbuf = malloc(_SC_PAGE_SIZE); 
    printf("trying to read %d bytes from offset %lu\n",_SC_PAGE_SIZE,address); 

    if (outbuf){ 
     lseek(memfd, address, SEEK_SET); 
     readbytes = read(memfd, outbuf, _SC_PAGE_SIZE); 
    if (_SC_PAGE_SIZE == readbytes) 
     printf("read success! - %s\n", outbuf); 
    else 
     printf("readfailed! read %d bytes: %s\n", readbytes, outbuf); 
     printf("oh noes! %s\n", strerror(errno)); 
    free(outbuf); 
    } 

    return 0; 
} 

和終端輸出:

終端1:

[10:59] [email protected]:~/research$ ./changeme 
Spinning up.... 
ready for change.... 

終端2:

[11:35] [email protected]:~/research$ ps aux | grep changeme 
tel0s  7763 0.0 0.0 4076 352 pts/2 S+ 10:59 0:00 ./changeme 
tel0s  8297 0.0 0.0 8948 928 pts/1 S+ 11:35 0:00 grep --colour=auto changeme 
[11:35] [email protected]:~/research$ cat /proc/7763/maps 
00400000-00401000 r-xp 00000000 fd:00 2260791       /home/tel0s/research/changeme 
00600000-00601000 r--p 00000000 fd:00 2260791       /home/tel0s/research/changeme 
00601000-00602000 rw-p 00001000 fd:00 2260791       /home/tel0s/research/changeme 
7fb2cfc56000-7fb2cfdf7000 r-xp 00000000 fd:00 4890420     /lib64/libc-2.17.so 
7fb2cfdf7000-7fb2cfff6000 ---p 001a1000 fd:00 4890420     /lib64/libc-2.17.so 
7fb2cfff6000-7fb2cfffa000 r--p 001a0000 fd:00 4890420     /lib64/libc-2.17.so 
7fb2cfffa000-7fb2cfffc000 rw-p 001a4000 fd:00 4890420     /lib64/libc-2.17.so 
7fb2cfffc000-7fb2d0000000 rw-p 00000000 00:00 0 
7fb2d0000000-7fb2d0022000 r-xp 00000000 fd:00 4888842     /lib64/ld-2.17.so 
7fb2d01f2000-7fb2d01f5000 rw-p 00000000 00:00 0 
7fb2d021e000-7fb2d0221000 rw-p 00000000 00:00 0 
7fb2d0221000-7fb2d0222000 r--p 00021000 fd:00 4888842     /lib64/ld-2.17.so 
7fb2d0222000-7fb2d0223000 rw-p 00022000 fd:00 4888842     /lib64/ld-2.17.so 
7fb2d0223000-7fb2d0224000 rw-p 00000000 00:00 0 
7fff03290000-7fff032b1000 rw-p 00000000 00:00 0       [stack] 
7fff03394000-7fff03395000 r-xp 00000000 00:00 0       [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0     [vsyscall] 

[11:36] [email protected]:~/research$ sudo ./writeprocmem 7763 400000 
attatched! 
ready! opening /proc/7763/mem 
memfd = 3 
trying to read 30 bytes from offset 400000 
readfailed! read -1 bytes: 
oh noes! Input/output error 

我瞭解可能的原因直接的想法是:

  • 我已經完全borked我的邏輯,和我沒有正確使用ptrace的。
  • 我changeme計劃是在一個陌生的國家,因爲gets()函數,這就是爲什麼即時通訊無法讀取(我用的bash的實例試過了,我只好然而相同的輸出)
  • 我不投/使用正確的類型爲我的偏移,這就是爲什麼讀取失敗的原因

任何幫助將是優秀的,我寧願回答概述了我所犯的錯誤,而不是直接給我工作代碼,作爲我想從根本上理解這一點,而不僅僅是讓我的代碼發揮作用。

回答

2

您應該檢查系統調用的返回狀態。如果它們失敗了,errno會被設置爲表明出了什麼問題,並且你可以用perror()來顯示相關的文本。

E.g.是這樣的:

if (lseek(memfd, address, SEEK_SET) < 0) { 
    perror("lseek"); 
} 
readbytes = read(memfd, outbuf, _SC_PAGE_SIZE); 
if (readbytes < 0) { 
    perror("read"); 
} 

羅伊山

0
uintptr_t const address = strtoul(argv[2], NULL, 0); 

[11:36] tel0s @狠話:〜/ $研究須藤./writeprocmem 7763 400000

printf("trying to read %d bytes from offset %lu\n",_SC_PAGE_SIZE,address); 

你'告訴strtoul該基地爲零,/ proc // maps的地址是十六進制的,你正在用十進制調試打印出來。不幸的是,你的地址恰好是一個十六進制和十進制有效的數字。

或者,在命令行中使用爲0x400000或告訴strtoul將使用基地爲0x10

你也想將sysconf(_SC_PAGESIZE)或爲getpagesize()。