//who.c這段代碼本身沒有什么意思,執(zhí)行"gcc who.c -o who -g -Wall"完成編譯并啟動who程序,每隔2s會向終端打印一句"who are you ?",但有意思的是,可能會出現(xiàn)一種"詭異"的現(xiàn)象,比如屏幕上突然冒出一句"it's me ~"。
#include <stdio.h>
#include <unistd.h>
int main()
{
while(1) {
printf("who are you ?\n");
sleep(2);
}
return0;
}
//isme32.c64位系統(tǒng),編譯如下代碼并在反匯編結(jié)果中提。
int main()
{
__asm__(
"jmp forward\n\t"
"backward: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:call backward\n\t"
".string \"it's me ~\\n\""
);
return0;
}
//isme64.c本篇文章的實驗環(huán)境是64位ubuntu系統(tǒng),所以執(zhí)行"gcc isme64.c -oisme64 -g -Wall"生成isme64可執(zhí)行文件,并通過反匯編isme64文件提取機器碼:
int main()
{
__asm__(
"jmp forward\n\t"
"backward:popq %rsi\n\t"
"movq $1, %rax\n\t"
"movq $2, %rdi\n\t"
"movq $12, %rdx\n\t"
"syscall\n\t"
"int3\n\t"
"forward:call backward\n\t"
".string \"it's me ~\\n\""
);
return0;
}
// inject.c
#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 <errno.h>
// 注入指令塊(打印"it's me ~")
#ifdef ENV_I386
#define 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\x69\x74\x27\x73"\
"\x20\x6d\x65\x20\x7e\x0a\x00"
#define REG_IP regs.eip
#else // X_64
#define CODE \
"\xeb\x19\x5e\x48\xc7\xc0\x01\x00"\
"\x00\x00\x48\xc7\xc7\x02\x00\x00"\
"\x00\x48\xc7\xc2\x0c\x00\x00\x00"\
"\x0f\x05\xcc\xe8\xe2\xff\xff\xff"\
"\x69\x74\x27\x73\x20\x6d\x65\x20"\
"\x7e\x0a\x00"
#define REG_IP regs.rip
#endif
#define CODE_SIZE (sizeof(CODE)-1)
/* 往pid進(jìn)程的addr地址處寫數(shù)據(jù) */
voidputdata(pid_t pid, unsigned longaddr, void*vptr, intlen)
{
intcount = 0;
longword;
while(count < len)
{
memcpy(&word, vptr+count, sizeof(word));
word = ptrace(PTRACE_POKEDATA, pid, addr+count, word);
count += sizeof(word);
if(errno!= 0)
printf("putdata failed: %p\n", (void*)(addr+count));
}
}
/* 讀pid進(jìn)程addr地址處的數(shù)據(jù) */
voidgetdata(pid_t pid, unsigned longaddr, void*vptr, intlen)
{
inti = 0, count = 0;
longword;
unsigned long*ptr = (unsigned long*)vptr;
while(count < len)
{
word = ptrace(PTRACE_PEEKDATA, pid, addr+count, NULL);
count += sizeof(word);
ptr[i++] = word;
if(errno!= 0)
printf("getdata failed: %p\n", (void*)(addr+count));
}
}
intmain(intargc, char*argv[])
{
pid_t pid;
structuser_regs_struct regs;
charbackup[CODE_SIZE+1];
if(argc != 2) {
printf("Usage: %s {pid}\n", argv[0]);
return-1;
}
// 通過啟動參數(shù),獲取被注入進(jìn)程號,并attach
pid = atoi(argv[1]);
ptrace(PTRACE_ATTACH, pid, NULL, NULL); // SIGTRAP
if(errno!= 0)
printf("attach failed: %s\n", strerror(errno));
wait(NULL); // 收到回復(fù)信號,保證后續(xù)過程在attach完成的情況下執(zhí)行
// 獲取被注入進(jìn)程當(dāng)前寄存器值
ptrace(PTRACE_GETREGS, pid, NULL, ®s);
// 備份*ip寄存器指向的指令塊
getdata(pid, REG_IP, backup, CODE_SIZE);
// 替換為CODE指令塊
putdata(pid, REG_IP, CODE, CODE_SIZE);
// 恢復(fù)被注入進(jìn)程的執(zhí)行
ptrace(PTRACE_CONT, pid, NULL, NULL); // SIGCONT
// 注入程序最后一條指令為int3,此為即為等待注入指令塊執(zhí)行完畢
wait(NULL);
// 等待用戶輸入,方便查看結(jié)果
printf("continue to execute the orginal process, press any key ..\n");
getchar();
// 將修改的指令塊恢復(fù)為備份內(nèi)容
putdata(pid, REG_IP, backup, CODE_SIZE);
// 恢復(fù)被注入進(jìn)程寄存器值
ptrace(PTRACE_SETREGS, pid, NULL, ®s);
// detach,被注入進(jìn)程恢復(fù)正常執(zhí)行
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return0;
}
歡迎光臨 資源共享吧|易語言論壇|逆向破解教程|輔助開發(fā)教程|網(wǎng)絡(luò)安全教程|m.rigasin.com|我的開發(fā)技術(shù)隨記 (http://m.rigasin.com/) | Powered by Discuz! X3.4 |