Linux & Android 下的内存注入手段

ptrace_inject_mem

long ptrace(enum __ptrace_request request, pid_t pid,
                   void *addr, void *data);
请求 (Request) 说明
PTRACE_TRACEME 0 使调用进程变为被跟踪进程。在子进程调用 ptrace(PTRACE_TRACEME, ...) 后,父进程可以使用 PTRACE_ATTACH 进行跟踪。
PTRACE_PEEKTEXT 1 从目标进程的内存中读取一个字
PTRACE_PEEKDATA 2 从目标进程的内存中读取一个字
PTRACE_PEEKUSER 3 从目标进程的用户区域读取一个字
PTRACE_POKETEXT 4 向目标进程的内存写入一个字
PTRACE_POKEDATA 5 向目标进程的内存写入一个字
PTRACE_POKEUSER 6 向目标进程的用户区域写入一个字
PTRACE_CONT 7 继续执行目标进程。
PTRACE_KILL 8 终止目标进程。
PTRACE_SINGLESTEP 9 使目标进程执行单步操作。
PTRACE_ATTACH 16 附加到目标进程。
PTRACE_DETACH 17 从目标进程分离。
PTRACE_SYSCALL 24 让目标继续运行,直到进入和退出系统调用的时候停止。
PTRACE_GETREGS 读通用寄存器,得到一个struct user_regs_struct结构体中,结构体的定义在<sys/user.h>
PTRACE_GETFPREGS 读浮点寄存器
PTRACE_SETREGS 将一个struct user_regs_struct类型的结构体变量的值,设置到被跟踪进程的用户寄存器中

linux下测试

test.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/auxv.h>
const char xxx[] = "tlsn_wheeler";


int main(){
    
    puts("nihao");
    while(1){
        puts(xxx);
        getchar();
    }


    return 0;
}
//gcc ./test.c -g -o test

Inject_mem.c:

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>

unsigned long long get_baseaddr(pid_t pid){
    char path[256] = {0};
    sprintf(path, "/proc/%d/maps", pid);
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }

    char line[256];
    unsigned long long start_addr =0; 
    while (fgets(line, sizeof(line), fp) != NULL) {
        unsigned long start, end;
        if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
            // printf("Program loaded at address range: %lx - %lx\n", start, end);
            start_addr = start;
            fclose(fp);
            return start_addr;
        }
    }    
}


unsigned char payload[] = "yohoooooooooo!!!!!!!";

int ptrace_attach(pid_t pid)    
{
    int status = 0;
    if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) {    
        printf("attach process error, pid:%d\n", pid);    
        return -1;    
    }    
  
  printf("attach process pid:%d\n", pid);          
    waitpid(pid, &status , WUNTRACED);        
    
    return 0;    
} 


int ptrace_detach(pid_t pid)    
{    
    if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) {    
        printf("detach process error, pid:%d\n", pid);     
        return -1;    
    }    
    
    printf("detach process pid:%d\n", pid);  
    return 0;    
}




void ptrace_read_mem(pid_t pid){
    if(ptrace_attach(pid)==-1){
        return ;
    }
    
    unsigned long long baseaddr = get_baseaddr(pid);
    // printf("baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000002008;
    unsigned long long target_addr = baseaddr + offset;

    

    unsigned char read_buff[100] = {0};
    for (size_t i = 0; i < 4; i+=8) 
    {
        *(unsigned long long int*)&read_buff[i] =  ptrace(PTRACE_PEEKTEXT , pid, target_addr + i,NULL);
    }

    read_buff[4] = 0;
    printf("[+]ptrace read: %s\n",read_buff);
    if(ptrace_detach(pid) == -1){
        return ;
    }
}

void ptrace_write_mem(pid_t pid){
    if(ptrace_attach(pid)==-1){
        return ;
    }
    
    unsigned long long baseaddr = get_baseaddr(pid);
    unsigned long long offset = 0x000000000002008;
    unsigned long long target_addr = baseaddr + offset;

    


    for (size_t i = 0; i < 0x10; i+=8) 
    {
        ptrace(PTRACE_POKETEXT , pid, target_addr + i,*(unsigned long long*)&payload[i]);       // 目前来看 PTRACE_POKETEXT / PTRACE_PEEKDATA 都可以
    }

    printf("[+]ptrace write finish.\n");
    if(ptrace_detach(pid) == -1){
        return ;
    }
}


void ptrace_inject(pid_t pid){
    ptrace_read_mem(pid);
    ptrace_write_mem(pid);
}

int main(){


    // read_mem();
    // inject();
    // procfs_inject(13452);

    ptrace_inject(15431);
    

    return 0;
}

// gcc ./Inject_mem.c -g -o ./ptrace_inject

测试结果:

image-20250210191632908

Android下测试

test.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/auxv.h>
const char xxx[] = "tlsn_wheeler";


int main(){
    
    puts("nihao");
    while(1){
        puts(xxx);
        getchar();
    }


    return 0;
}

// '/home/tlsn/Btools/NDKXX/NDK24/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang' ./test.c -g -o ./test

Inject.c

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>

unsigned long long get_baseaddr(pid_t pid){
    char path[256] = {0};
    sprintf(path, "/proc/%d/maps", pid);
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }

    char line[256];
    unsigned long long start_addr =0; 
    while (fgets(line, sizeof(line), fp) != NULL) {
        unsigned long start, end;
        if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
            // printf("Program loaded at address range: %lx - %lx\n", start, end);
            start_addr = start;
            fclose(fp);
            return start_addr;
        }
    }    
}


unsigned char payload[] = "yohoooooooooo!!!!!!!";

int ptrace_attach(pid_t pid)    
{
    int status = 0;
    if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) {    
        printf("attach process error, pid:%d\n", pid);    
        return -1;    
    }    
  
  printf("attach process pid:%d\n", pid);          
    waitpid(pid, &status , WUNTRACED);        
    
    return 0;    
} 


int ptrace_detach(pid_t pid)    
{    
    if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) {    
        printf("detach process error, pid:%d\n", pid);     
        return -1;    
    }    
    
    printf("detach process pid:%d\n", pid);  
    return 0;    
}




void ptrace_read_mem(pid_t pid){

    
    unsigned long long baseaddr = get_baseaddr(pid);
    printf("baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000000560;
    unsigned long long int target_addr = baseaddr + offset;

    

    unsigned char read_buff[100] = {0};
    for (size_t i = 0; i < 4; i+=8) 
    {
        *(unsigned long long int*)&read_buff[i] =  ptrace(PTRACE_PEEKTEXT , pid, target_addr + i,NULL);
    }

    read_buff[4] = 0;
    printf("[+]ptrace read: %s\n",read_buff);
    for(int i=0;i<4;i++){
        printf("0x%x,",read_buff[i]);
    }
    puts("");


}

void ptrace_write_mem(pid_t pid){

    
    unsigned long long baseaddr = get_baseaddr(pid);
    unsigned long long offset = 0x000000000000560;
    unsigned long long target_addr = baseaddr + offset;

    


    for (size_t i = 0; i < 0x10; i+=8) 
    {
        ptrace(PTRACE_POKETEXT , pid, target_addr + i,*(unsigned long long*)&payload[i]);       // 目前来看 PTRACE_POKETEXT / PTRACE_PEEKDATA 都可以
    }

    printf("[+]ptrace write finish.\n");

}


void ptrace_read_regs(pid_t pid){
    
    
    
    unsigned long long int reg[100];
    ptrace(PTRACE_GETREGSET,pid,NULL,&reg);     // aarch64使用PTRACE_GETREGSET,arm使用 PTRACE_GETREGS
    printf("xx0: 0x%llx\n",reg[0]);
    printf("xx1: 0x%llx\n",reg[1]);
    printf("xx2: 0x%llx\n",reg[2]);
    printf("xx3: 0x%llx\n",reg[3]);


    

}

void ptrace_inject(pid_t pid){
    if(ptrace_attach(pid)==-1){
        return ;
    }

    // ptrace_read_regs(pid);
    ptrace_read_mem(pid);
    ptrace_write_mem(pid);

    if(ptrace_detach(pid) == -1){
        return ;
    }
    
}



int main(){


    ptrace_inject(30768);

    return 0;
}
// '/home/tlsn/Btools/NDKXX/NDK24/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang' ./Inject.c -g -fPIE -o ./Inject_mem_R

image-20250211131350916

参考

https://tomqunchao.github.io/2021/01/19/note/rev/game-1/

https://blog.csdn.net/ayang1986/article/details/79466717

procfs_inject_mem

linux 一切皆文件的思想,我们可以直接读/写 /proc/pid/mem 中的数据来直接修改内存。

Linux下测试

test.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/auxv.h>
const char xxx[] = "tlsn_wheeler";


int main(){
    
    puts("nihao");
    while(1){
        puts(xxx);
        getchar();
    }


    return 0;
}

// gcc ./test.c -g -o ./test 

Inject.c

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>


unsigned long long get_baseaddr(){
    FILE *fp = fopen("/proc/9816/maps", "r");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }

    char line[256];
    unsigned long long start_addr =0; 
    while (fgets(line, sizeof(line), fp) != NULL) {
        unsigned long start, end;
        if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
            // printf("Program loaded at address range: %lx - %lx\n", start, end);
            start_addr = start;
            fclose(fp);
            return start_addr;
        }
    }    
}


unsigned char payload[] = "yohoooooooooo!!!!!!!";
int inject_size = 0x10;
void inject(){
    unsigned long long baseaddr = get_baseaddr();
    printf("target baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000002008;
    unsigned long long target_addr = baseaddr + offset;
    FILE *file = fopen("/proc/9816/mem", "w");
    if (file == NULL){
        printf("fopen error\n");
        return ;
    }

    // Set the file index to our required offset, representing the memory address
    fseek(file, target_addr, SEEK_SET);
    fwrite(payload, sizeof(char), inject_size, file);

    printf("Inject finish\n");
}


void read_mem(){
    unsigned long long baseaddr = get_baseaddr();
    printf("target baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000002008;
    unsigned long long target_addr = baseaddr + offset;

    FILE *file = fopen("/proc/9816/mem", "r");
    if (file == NULL){
        printf("fopen error\n");
        return ;
    }
    


    fseek(file, target_addr, SEEK_SET);
    
    char buffer[0x10] = {0};
    fread(buffer,1,4,file);

    printf("read_mem: %s\n",buffer);
}

int main(){


    read_mem();
    inject();

    return 0;
}

测试结果:

image-20250210155149546

需要注意的是,Inject需要给 root权限

Android下测试

test.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/auxv.h>
const char xxx[] = "tlsn_wheeler";


int main(){
    
    puts("nihao");
    while(1){
        puts(xxx);
        getchar();
    }


    return 0;
}

// '/home/tlsn/Btools/NDKXX/NDK24/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang' ./test.c -g -o ./test

Inject.c

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>

unsigned long long get_baseaddr(pid_t pid){
    char path[256] = {0};
    sprintf(path, "/proc/%d/maps", pid);
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }

    char line[256];
    unsigned long long start_addr =0; 
    while (fgets(line, sizeof(line), fp) != NULL) {
        unsigned long start, end;
        if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
            // printf("Program loaded at address range: %lx - %lx\n", start, end);
            start_addr = start;
            fclose(fp);
            return start_addr;
        }
    }    
}


unsigned char payload[] = "yohoooooooooo!!!!!!!";
int inject_size = 0x10;
void procfs_write_mem(pid_t pid){

    
    unsigned long long baseaddr = get_baseaddr(pid);
    printf("target baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000000560;
    unsigned long long target_addr = baseaddr + offset;

    char path[256] = {0};
    sprintf(path, "/proc/%d/mem", pid);
    FILE *file = fopen(path, "w");
    if (file == NULL){
        printf("fopen error\n");
        return ;
    }

    // Set the file index to our required offset, representing the memory address
    fseek(file, target_addr, SEEK_SET);
    fwrite(payload, sizeof(char), inject_size, file);

    printf("Inject finish\n");
}


void procfs_read_mem(pid_t pid){
    unsigned long long baseaddr = get_baseaddr(pid);
    printf("target baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000000560;
    unsigned long long target_addr = baseaddr + offset;


    char path[256] = {0};
    sprintf(path, "/proc/%d/mem", pid);
    FILE *file = fopen(path, "r");
    if (file == NULL){
        printf("fopen error\n");
        return ;
    }
    


    fseek(file, target_addr, SEEK_SET);
    
    char buffer[0x10] = {0};
    fread(buffer,1,4,file);

    printf("read_mem: %s\n",buffer);
}





void procfs_inject(pid_t pid){
    procfs_read_mem(pid);
    procfs_write_mem(pid);
}




int main(){



    procfs_inject(31247);



    return 0;
}

// '/home/tlsn/Btools/NDKXX/NDK24/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang' ./Inject.c -g -fPIE -o ./Inject_mem_R

image-20250211131755451

参考

当然,如果要持久化运用到项目上,只是这样的话,还是不够的,参考: https://erfur.dev/blog/dev/code-injection-without-ptrace

参考: https://github.com/erfur/linjector-rs

process_vm_writev

process_vm_readv() , process_vm_writev() 是 Linux 3.2 新增的 syscall,用于在多个进程的地址空间之间,高效传输大块数据。

process_vm_writev 遵守内存访问权限规则,故其不能像 ptrace、procfs一样,无视内存规则,向不可写字段写入数据。

#include <sys/uio.h>
ssize_t process_vm_readv(pid_t pid,
                         const struct iovec *local_iov,
                         unsigned long liovcnt,
                         const struct iovec *remote_iov,
                         unsigned long riovcnt,
                         unsigned long flags);
ssize_t process_vm_writev(pid_t pid,
                          const struct iovec *local_iov,
                          unsigned long liovcnt,
                          const struct iovec *remote_iov,
                          unsigned long riovcnt,
                          unsigned long flags);
pid							进程pid号
struct iovec *local_iov		结构体local进程指向一个数组基地址
liovcnt						local进程数组大小
struct iovec *remote_iov	结构体remote进程指向一个数组基地址
riovcnt						remote进程数组大小
flags						默认0
<sys / uio.h>
   struct iovec {
               void  *iov_base;    /* 地址基址 */
               size_t iov_len;     /* 数据传输字节数 */
           };

process_vm_readv()从remote进程传送数据到local进程。

process_vm_writev()系统调用是process_vm_readv()的逆过程。它从local进程传送数据到remote进程。

linux 下测试

test.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/auxv.h>
const char xxx_r[] = "tlsn_wheeler_r";
char yyy_rw[] = "rw_1433223xxx!!!!"; 

int main(){
    
    puts("nihao");
    while(1){
        puts(xxx_r);
        puts(yyy_rw);
        getchar();
    }


    return 0;
}

// gcc ./test.c -g -o ./tess 


Inject_mem.c

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <sys/uio.h>


unsigned long long get_baseaddr(pid_t pid){
    char path[256] = {0};
    sprintf(path, "/proc/%d/maps", pid);
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }

    char line[256];
    unsigned long long start_addr =0; 
    while (fgets(line, sizeof(line), fp) != NULL) {
        unsigned long start, end;
        if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
            // printf("Program loaded at address range: %lx - %lx\n", start, end);
            start_addr = start;
            fclose(fp);
            return start_addr;
        }
    }    
}


unsigned char payload[] = "yohoooooooooo!!!!!!!";
int inject_size = 0x10;
void procfs_write_mem(pid_t pid){

    
    unsigned long long baseaddr = get_baseaddr(pid);
    printf("target baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000000560;
    unsigned long long target_addr = baseaddr + offset;

    char path[256] = {0};
    sprintf(path, "/proc/%d/mem", pid);
    FILE *file = fopen(path, "w");
    if (file == NULL){
        printf("fopen error\n");
        return ;
    }

    // Set the file index to our required offset, representing the memory address
    fseek(file, target_addr, SEEK_SET);
    fwrite(payload, sizeof(char), inject_size, file);

    printf("Inject finish\n");
}


void procfs_read_mem(pid_t pid){
    unsigned long long baseaddr = get_baseaddr(pid);
    printf("target baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000000560;
    unsigned long long target_addr = baseaddr + offset;


    char path[256] = {0};
    sprintf(path, "/proc/%d/mem", pid);
    FILE *file = fopen(path, "r");
    if (file == NULL){
        printf("fopen error\n");
        return ;
    }
    


    fseek(file, target_addr, SEEK_SET);
    
    char buffer[0x10] = {0};
    fread(buffer,1,4,file);

    printf("read_mem: %s\n",buffer);
}





void procfs_inject(pid_t pid){
    procfs_read_mem(pid);
    procfs_write_mem(pid);
}




int ptrace_attach(pid_t pid)    
{
    int status = 0;
    if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) {    
        printf("attach process error, pid:%d\n", pid);    
        return -1;    
    }    
  
  printf("attach process pid:%d\n", pid);          
    waitpid(pid, &status , WUNTRACED);        
    
    return 0;    
} 


int ptrace_detach(pid_t pid)    
{    
    if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) {    
        printf("detach process error, pid:%d\n", pid);     
        return -1;    
    }    
    
    printf("detach process pid:%d\n", pid);  
    return 0;    
}




void ptrace_read_mem(pid_t pid){

    
    unsigned long long baseaddr = get_baseaddr(pid);
    printf("baseaddr is 0x%llx\n",baseaddr);
    unsigned long long offset = 0x000000000000560;
    unsigned long long int target_addr = baseaddr + offset;

    

    unsigned char read_buff[100] = {0};
    for (size_t i = 0; i < 4; i+=8) 
    {
        *(unsigned long long int*)&read_buff[i] =  ptrace(PTRACE_PEEKTEXT , pid, target_addr + i,NULL);
    }

    read_buff[4] = 0;
    printf("[+]ptrace read: %s\n",read_buff);
    for(int i=0;i<4;i++){
        printf("0x%x,",read_buff[i]);
    }
    puts("");


}

void ptrace_write_mem(pid_t pid){

    
    unsigned long long baseaddr = get_baseaddr(pid);
    unsigned long long offset = 0x000000000000560;
    unsigned long long target_addr = baseaddr + offset;

    


    for (size_t i = 0; i < 0x10; i+=8) 
    {
        ptrace(PTRACE_POKETEXT , pid, target_addr + i,*(unsigned long long*)&payload[i]);       // 目前来看 PTRACE_POKETEXT / PTRACE_PEEKDATA 都可以
    }

    printf("[+]ptrace write finish.\n");

}


void ptrace_read_regs(pid_t pid){
    
    
    
    unsigned long long int reg[100];
    ptrace(PTRACE_GETREGSET,pid,NULL,&reg);     // aarch64使用PTRACE_GETREGSET,arm使用 PTRACE_GETREGS
    printf("xx0: 0x%llx\n",reg[0]);
    printf("xx1: 0x%llx\n",reg[1]);
    printf("xx2: 0x%llx\n",reg[2]);
    printf("xx3: 0x%llx\n",reg[3]);


    

}

void ptrace_inject(pid_t pid){
    if(ptrace_attach(pid)==-1){
        return ;
    }

    // ptrace_read_regs(pid);
    ptrace_read_mem(pid);
    ptrace_write_mem(pid);

    if(ptrace_detach(pid) == -1){
        return ;
    }
    
}

void process_vm_read_mem(pid_t pid){

    struct iovec local[2];
    struct iovec remote[1];
    
    unsigned char read_buf1[10];
    unsigned char read_buf2[10];
    
    unsigned long long remote_read_addr = get_baseaddr(pid) + 0x000000000002008;


    local[0].iov_base =read_buf1;
    local[0].iov_len = 5;
    local[1].iov_base = read_buf2;
    local[1].iov_len = 5;

    
    remote[0].iov_base = remote_read_addr;
    remote[0].iov_len = 10;


    ssize_t nread = process_vm_readv(pid, local, 2, remote, 1, 0);
    
    
    read_buf1[5] = 0;
    read_buf2[5] = 0;
    printf("process_vm_read_mem1: %s\n",read_buf1);
    printf("process_vm_read_mem2: %s\n",read_buf2);


}

void process_vm_write_mem(pid_t pid){
    struct iovec local[1];
    struct iovec remote[1];

    
    unsigned char inject_data[] = "RW_rw_rw_RW_xxyyzz";
    local[0].iov_base = inject_data;
    local[0].iov_len = 10;

    unsigned long long remote_write_addr = get_baseaddr(pid) +  0x000000000004010;
    remote[0].iov_base = remote_write_addr;
    remote[0].iov_len =  10;


    process_vm_writev(pid, local, 1, remote, 1, 0);

}

void process_vm_inject(pid_t pid){
    process_vm_read_mem(pid);
    process_vm_write_mem(pid);
}


int main(){

    
    // procfs_inject(31247);
    // ptrace_inject(30768);
    process_vm_inject(23751);
    return 0;
}


image-20250211140339955

如果我们把写入地址改为不可写的内存块的时候,就会出现下面情况:

image-20250211140655087

Android 下测试

test.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/auxv.h>
const char xxx_r[] = "tlsn_wheeler_r";
char yyy_rw[] = "rw_1433223xxx!!!!"; 

int main(){
    
    puts("nihao");
    while(1){
        puts(xxx_r);
        puts(yyy_rw);
        getchar();
    }


    return 0;
}


// '/home/tlsn/Btools/NDKXX/NDK24/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android24-clang' ./test.c -g -o ./test

Inject_mem.c

#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <sys/uio.h>


unsigned long long get_baseaddr(pid_t pid){
    char path[256] = {0};
    sprintf(path, "/proc/%d/maps", pid);
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }

    char line[256];
    unsigned long long start_addr =0; 
    while (fgets(line, sizeof(line), fp) != NULL) {
        unsigned long start, end;
        if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
            // printf("Program loaded at address range: %lx - %lx\n", start, end);
            start_addr = start;
            fclose(fp);
            return start_addr;
        }
    }    
}



void process_vm_read_mem(pid_t pid){

    struct iovec local[2];
    struct iovec remote[1];
    
    unsigned char read_buf1[10];
    unsigned char read_buf2[10];
    
    unsigned long long remote_read_addr = get_baseaddr(pid) + 0x000000000000560;


    local[0].iov_base =read_buf1;
    local[0].iov_len = 5;
    local[1].iov_base = read_buf2;
    local[1].iov_len = 5;

    
    remote[0].iov_base = remote_read_addr;
    remote[0].iov_len = 10;


    ssize_t nread = process_vm_readv(pid, local, 2, remote, 1, 0);
    
    
    read_buf1[5] = 0;
    read_buf2[5] = 0;
    printf("process_vm_read_mem1: %s\n",read_buf1);
    printf("process_vm_read_mem2: %s\n",read_buf2);


}

void process_vm_write_mem(pid_t pid){
    struct iovec local[1];
    struct iovec remote[1];

    
    unsigned char inject_data[] = "RW_rw_rw_RW_xxyyzz";
    local[0].iov_base = inject_data;
    local[0].iov_len = 10;

    unsigned long long remote_write_addr = get_baseaddr(pid) +  0x0000000000039F0;
    remote[0].iov_base = remote_write_addr;
    remote[0].iov_len =  10;


    ssize_t nread = process_vm_writev(pid, local, 1, remote, 1, 0);
    printf("success Inject %d bytes\n",nread);
}

void process_vm_inject(pid_t pid){
    process_vm_read_mem(pid);
    process_vm_write_mem(pid);
}


int main(){

    
    // procfs_inject(31247);
    // ptrace_inject(30768);
    process_vm_inject(5472);
    return 0;
}


image-20250211141134890

就算是 process_vm_writev 也得在root的权限下才能完成读写进程。。。

posted @   TLSN  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结
点击右上角即可分享
微信分享提示