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
测试结果:
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,®); // 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
参考
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;
}
测试结果:
需要注意的是,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
参考
当然,如果要持久化运用到项目上,只是这样的话,还是不够的,参考: 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,®); // 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;
}
如果我们把写入地址改为不可写的内存块的时候,就会出现下面情况:
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;
}
就算是 process_vm_writev 也得在root的权限下才能完成读写进程。。。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结