如果不知道注入是怎么回事儿,转战android inject(一)ptrace基础,本篇由第一篇转变而来。
本篇提供两个demo,一是进程demo,二是注入demo
一 进程demo
/*
* 被注入到进程demo
* */
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int i=0;
while(1){
printf("Hello,ptrace! [pid:%d]! num is %d\n",getpid(),i++);
sleep(2);
}
return 0;
}
二 注入demo
/*
* PTRACE_ATTACH: 注入到其他进程
* ptrace(PTRACE_SETREGS): 设置寄存器到值
* */
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define long_size sizeof(long)
//获取child进程 addr地址到内容到str里面,长度是len
void getdata(pid_t child, long addr ,char * str,int len){
char * laddr =str;
int i,j;
union u{
long val;
char chars [long_size] ;
} data;
i=0;
j=len/long_size;
while(i<j){
data.val=ptrace(PTRACE_PEEKDATA,child,addr + long_size*i,NULL);
if(data.val==-1){
if(errno){
printf("READ error: %s\n",strerror(errno));
}
}
memcpy(laddr,data.chars,long_size);
++i;
laddr=laddr+long_size;
}
j= len %long_size;
if(j!=0){
data.val=ptrace(PTRACE_PEEKDATA,child,addr + long_size*i,NULL);
if(data.val==-1){
if(errno){
printf("READ error: %s\n",strerror(errno));
}
}
memcpy(laddr,data.chars,j);
}
str[len]='\0';
}
//替换child进程addr内存的内容,替换内容是str,长度是len
void putdata(pid_t child , long addr,char * str,int len){
char * laddr =str;
int i,j;
j=len/long_size;
i=0;
union u{
long val;
char chars [long_size] ;
} data;
while(i<j){
memcpy(data.chars,laddr,long_size);
ptrace(PTRACE_POKEDATA,child,addr + long_size*i,data.val);
++i;
laddr=laddr+long_size;
}
j=len%long_size;
if(j!=0){
data.val= ptrace(PTRACE_PEEKDATA,child,addr + long_size*i,NULL);
if(data.val==-1){
if(errno){
printf("READ error: %s\n",strerror(errno));
}
}
memcpy(data.chars,laddr,j);
ptrace(PTRACE_POKEDATA,child,addr + long_size*i,data.val);
}
}
void reverse(char * str)
{
int i,j;
char temp;
for(i=0,j=strlen(str)-2;i<=j;++i,--j){
temp=str[i];
str[i]=str[j];
str[j]=temp;
}
}
int main(int argc,char * argv[]){
if(argc!=2){
printf("Usage: %s pid\n",argv[0]);
}
//获取输入到pid值,如果用于adnroidinject, 那么这里其所可以通过其他方式直接过去, 只需传递进来pack便可,这个以后再说
pid_t tracee = atoi(argv[1]);
printf("pid: %d \n",tracee);
//创建寄存器到变量
struct user_regs_struct regs;
/*int 80(系统调用) int 3(断点)*/
unsigned char code[]={0xcd,0x80,0xcc,0x00,0,0,0,0}; //八个字节,等于long 型的长度
char backup[8]; //备份读取的指令
//附加到pid进程.
ptrace(PTRACE_ATTACH,tracee,NULL,NULL);
long inst; //用于保存指令寄存器所指向的下一条将要执行的指令的内存地址
//等待他一个指令运行完毕
wait(NULL);
//获取tracee进程寄存器到regs
ptrace(PTRACE_GETREGS,tracee,NULL,®s);
//读取tracee进程的指令寄存器(rip)到inst
inst=ptrace(PTRACE_PEEKTEXT,tracee,regs.rip,NULL);
printf("tracee:RIP:0x%llx INST: 0x%lx\n",regs.rip,inst);
//读取子进程将要执行的 7 bytes指令并备份
//参数说明: pid 指令寄存器地址 str 长度
getdata(tracee,regs.rip,backup,7);
//设置断点
putdata(tracee,regs.rip,(char*)code,7);
//让子进程继续执行并执行“int 3”断点指令停止,同时在执行下次系统调用的时候tracee线程停止,以激活下面wait后面的代码
ptrace(PTRACE_CONT,tracee,NULL,NULL);
wait(NULL);
long rip=ptrace(PTRACE_PEEKUSER,tracee,8*RIP,NULL);//获取子进程停止时,rip的值
long inst2=ptrace(PTRACE_PEEKTEXT,tracee,rip,NULL);
printf("tracee:RIP:0x%lx INST: 0x%lx\n",rip,inst2);
printf("Press Enter to continue tracee process\n");
getchar();
putdata(tracee,regs.rip,backup,7); //重新将备份的指令写回寄存器
ptrace(PTRACE_SETREGS,tracee,NULL,®s);//设置会原来的寄存器值
//ptrace(PTRACE_CONT,tracee,NULL,NULL); //激活附加进程
ptrace(PTRACE_SYSCALL,tracee,NULL,NULL); //激活附加进程,但如果她依旧由执行系统调用,继续停止并激活wait
//ptrace(PTRACE_DETACH,tracee,NULL,NULL); //停止附加
//以下代码参考前一篇记录
int status;
char* str;
long orig_eax;
int toggle =0;
while(1){
wait(&status);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,tracee,8*ORIG_RAX,NULL);
if(orig_eax == SYS_write){
printf("reverse\n");
if(toggle == 0){
toggle =1;
ptrace(PTRACE_GETREGS,tracee,NULL,®s);
str=(char * )calloc((regs.rdx+1),sizeof(char));
getdata(tracee,regs.rsi,str,regs.rdx);
reverse(str);
putdata(tracee,regs.rsi,str,regs.rdx);
}else{
toggle =0;
}
}
ptrace(PTRACE_SYSCALL,tracee,NULL,NULL);
}
return 0;
}
先运行进程demo,无限输出
Hello,ptrace! [pid:6419]! num is 262
Hello,ptrace! [pid:6419]! num is 263
Hello,ptrace! [pid:6419]! num is 264
Hello,ptrace! [pid:6419]! num is 265
Hello,ptrace! [pid:6419]! num is 266
然后运行注入demo,打印到数据被颠倒过来
131 si mun !]9146:dip[ !ecartp,olleH
231 si mun !]9146:dip[ !ecartp,olleH
331 si mun !]9146:dip[ !ecartp,olleH
431 si mun !]9146:dip[ !ecartp,olleH
创建了一个qq群,主要研究android逆向 安全 系统开发(逆向android系统)方面,欢迎各位加入。群号:492788365