KKPtrace是我写的ptrace注入器类的名称,注入器将会实现进程附加、内存读、内存写、寄存器读写等操作。
目前已实现功能:
- 进程
- 进程附加
- 取消附加
- 继续运行
- 内存读
- int32
- byteList(字节数组,Vector<uint8>)
- 内存写
- int8
- int16
- int32
- int64
- byteList
- 寄存器
- 获取
- 设置
- 打印
- call
- 计算远程libc中函数地址
- 批量call
- 得到call的返回值
- inject
远程CALL流程图
附C++代码:
#include "iostream"
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <memory.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <dlfcn.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>
#include <vector>
#include <sstream>
using namespace std;
#if __WORDSIZE == 64
#define ax rax
#define cx rcx
#define dx rdx
#define bx rbx
#define sp rsp
#define bp rbp
#define si rsi
#define di rdi
#define ip rip
#endif
#if __WORDSIZE == 32
#define ax eax
#define cx ecx
#define dx edx
#define bx ebx
#define sp esp
#define bp ebp
#define si esi
#define di edi
#define ip eip
#endif
class Utils
{
public:
static vector<uint8_t> ulongToByteList(u_long value)
{
// printf("ulongToByteList,input=%x\n", value);
int longLen = sizeof(u_long);
vector<uint8_t> byteList;
for (size_t i = 0; i < longLen; i++)
{
int tempValue = value;
tempValue = value << (8 * ((longLen - 1) - i));
tempValue >>= (8 * (longLen - 1));
byteList.push_back(tempValue);
}
// Utils::print_byteList_hexArray(byteList);
return byteList;
}
static vector<uint8_t> uint32ToByteList(uint32_t value, int number = 4)
{
vector<uint8_t> byteList;
if (number <= 0 || number > 4)
{
return byteList;
}
for (size_t i = 0; i < number; i++)
{
int tempValue = value;
if (i == 0)
{
tempValue = value << 24;
}
if (i == 1)
{
tempValue = value << 16;
}
if (i == 2)
{
tempValue = value << 8;
}
tempValue = tempValue >> 24;
byteList.push_back(tempValue);
}
return byteList;
}
static vector<uint8_t> uint16ToByteList(uint32_t value)
{
vector<uint8_t> byteList;
int tempValue = 0;
tempValue = value << 8 >> 8;
byteList.push_back(tempValue);
tempValue = value >> 8;
byteList.push_back(tempValue);
return byteList;
}
void static print_byteList_hexArray(vector<uint8_t> data)
{
for (const auto &item : data)
{
printf("%02x ", item);
}
cout << endl;
}
string static byteListToString(vector<uint8_t> data)
{
std::string res;
res.insert(res.begin(), data.begin(), data.end());
return res;
}
void static print_regs(struct user_regs_struct *reg_addr)
{
printf("--------------------------\n");
printf("rax=%p\n", (void *)reg_addr->ax);
printf("rcx=%p\n", (void *)reg_addr->cx);
printf("rdx=%p\n", (void *)reg_addr->dx);
printf("rbx=%p\n", (void *)reg_addr->bx);
printf("rsp=%p\n", (void *)reg_addr->sp);
printf("rbp=%p\n", (void *)reg_addr->bp);
printf("rsi=%p\n", (void *)reg_addr->si);
printf("rdi=%p\n", (void *)reg_addr->di);
printf("rip=%p\n", (void *)reg_addr->ip);
printf("--------------------------\n");
}
};
class KKptrace
{
private:
pid_t targetPid = 0;
const char localLibcPath[39] = "/usr/lib/x86_64-linux-gnu/libc-2.32.so";
void *getLibcBaseAddr(pid_t pid, const char *localLibcPath)
{
char filepath[512];
void *moduleBaseAddr = NULL;
snprintf(filepath, 512, "/proc/%d/maps", pid);
FILE *f = fopen(filepath, "r");
char line[512];
while (!feof(f))
{
memset(line, 0, 512);
fgets(line, 512, f);
// printf(line);
string lineStr = line;
if (lineStr.find(localLibcPath) != -1)
{
int index = lineStr.find("-");
string addrStr = lineStr.substr(0, index);
stringstream ss;
// puts(lineStr.c_str());
ss << hex << addrStr.c_str();
ss >> moduleBaseAddr;
break;
}
}
if (moduleBaseAddr == NULL)
{
cout << "getLibcBaseAddr() error,moduleName=" << localLibcPath << endl;
}
fclose(f);
return moduleBaseAddr;
}
void *getRemoteFuncAddr(void *localFuncAddr, const char *libcName, pid_t remotePid = 0, void *remoteLibcBaseAddr = NULL)
{
void *remoteFuncAddr;
if (remotePid == 0)
{
remotePid = targetPid;
}
if (remoteLibcBaseAddr == NULL)
{
remoteLibcBaseAddr = getLibcBaseAddr(remotePid, libcName);
}
void *localLibcBaseAddr = getLibcBaseAddr(getpid(), libcName);
if (localLibcBaseAddr == NULL || remoteLibcBaseAddr == NULL)
{
return NULL;
}
remoteFuncAddr = (void *)((u_long)localFuncAddr - (u_long)localLibcBaseAddr + (u_long)remoteLibcBaseAddr);
return remoteFuncAddr;
}
public:
bool isExitAttch = false;
// attachment is premise of all opeartions
bool isAttachSuccess = false;
struct user_regs_struct callBefore_regs;
bool attach(pid_t pid)
{
targetPid = pid;
isAttachSuccess = false;
int status = 0;
if (ptrace(PTRACE_ATTACH, targetPid, NULL, 0) < 0)
{
printf("KKptrace->attach():attach process error, pid:%d\n", targetPid);
return false;
}
printf("KKptrace->attach(): process success pid:%d\n", targetPid);
waitpid(targetPid, &status, WUNTRACED);
isAttachSuccess = true;
return true;
}
bool ptrace_continue()
{
if (ptrace(PTRACE_CONT, targetPid, NULL, NULL) < 0)
{
printf("KKptrace->attach():ptrace continue error, pid:%d", targetPid);
return false;
}
return true;
}
bool detach()
{
//kill(targetPid, SIGSTOP);
//waitpid(targetPid, NULL, 0);
if (ptrace(PTRACE_DETACH, targetPid, NULL, 0) < 0)
{
printf("KKptrace->attach():detach process error, pid:%d\n", targetPid);
return false;
}
return true;
}
uint32_t memoryRead_uint32(void *addr)
{
if (!isAttachSuccess)
{
return 0;
}
uint32_t re = ptrace(PTRACE_PEEKTEXT, targetPid, addr, 0);
return re;
}
vector<uint8_t> memoryRead_bytes(void *addr, int number)
{
int i = 0;
uint32_t tempValue = 0;
vector<uint8_t> reByteList;
vector<uint8_t> tempByteList;
for (i = 0; i < number / 4; i++)
{
tempValue = memoryRead_uint32((void *)((u_long)addr + (i * 4)));
//cout << "readMemory_bytes.for->tempValue=" << std::hex << tempValue << endl;
tempByteList = Utils::uint32ToByteList(tempValue, 4);
reByteList.insert(reByteList.end(), tempByteList.begin(), tempByteList.end());
}
if (number % 4)
{
tempValue = memoryRead_uint32((void *)((u_long)addr + (i * 4)));
tempByteList = Utils::uint32ToByteList(tempValue, number % 4);
reByteList.insert(reByteList.end(), tempByteList.begin(), tempByteList.end());
}
return reByteList;
}
bool memoryWrite_string(void *addr, string data)
{
if (data.size() == 0)
{
return false;
}
vector<uint8_t> byteList;
for (size_t i = 0; i < data.size(); i++)
{
byteList.push_back(data[i]);
}
byteList.push_back(0);
return memoryWrite_bytes(addr, byteList);
}
bool memoryWrite_chars(void *addr, const char *data)
{
vector<uint8_t> byteList;
for (size_t i = 0; data[i] != 0; i++)
{
byteList.push_back(data[i]);
}
byteList.push_back(0);
return memoryWrite_bytes(addr, byteList);
}
bool memoryWrite_bytes(void *addr, vector<uint8_t> data)
{
// Utils::print_byteList_hexArray(data);
if (!isAttachSuccess)
{
return false;
}
int longLen = sizeof(u_long);
u_long writeValue = 0;
void *writeAddr = addr;
size_t i;
for (i = 0; i < data.size() / longLen; i++)
{
writeValue = 0;
for (size_t j = 0; j < longLen; j++)
{
u_long tempValue = 0;
tempValue = data[i * longLen + j];
tempValue = tempValue << (8 * j);
writeValue = writeValue + tempValue;
}
writeAddr = (void *)((u_long)addr + longLen * i);
// printf("PTRACE_POKETEXT,add=%p,value=%x\n", writeAddr, writeValue);
if (ptrace(PTRACE_POKETEXT, targetPid, writeAddr, writeValue) < 0)
{
return false;
}
}
int yu = data.size() % longLen;
if (yu)
{
writeValue = 0;
writeAddr = (void *)((u_long)addr + longLen * i);
// 未对齐64bit的情况,需要先取值再覆盖。
vector<uint8_t> readByteList = memoryRead_bytes(writeAddr, 8);
// puts("readByteList");
// Utils::print_byteList_hexArray(readByteList);
for (size_t j = yu; j < longLen; j++)
{
u_long tempValue = readByteList[j];
tempValue = tempValue << 8 * j;
writeValue = writeValue + tempValue;
}
for (size_t j = 0; j < yu; j++)
{
u_long tempValue = 0;
tempValue = data[i * longLen + j];
// printf("j < yu;tempValue=%x\n", tempValue);
tempValue = tempValue << (8 * j);
writeValue = writeValue + tempValue;
}
// printf("PTRACE_POKETEXT_yu,add=%p,value=%x\n", writeAddr, writeValue);
if (ptrace(PTRACE_POKETEXT, targetPid, writeAddr, writeValue) < 0)
{
return false;
}
}
return true;
}
bool memoryWrite_long(void *addr, long value)
{
return memoryWrite_bytes(addr, Utils::ulongToByteList(value));
}
bool memoryWrite_u_long(void *addr, u_long value)
{
return memoryWrite_bytes(addr, Utils::ulongToByteList(value));
}
bool memoryWrite_int32(void *addr, int32_t data)
{
return memoryWrite_bytes(addr, Utils::uint32ToByteList(data));
}
bool memoryWrite_uint32(void *addr, uint32_t data)
{
return memoryWrite_bytes(addr, Utils::uint32ToByteList(data));
}
bool memoryWrite_int16(void *addr, int16_t data)
{
return memoryWrite_bytes(addr, Utils::uint16ToByteList(data));
}
bool memoryWrite_uint16(void *addr, uint16_t data)
{
return memoryWrite_bytes(addr, Utils::uint16ToByteList(data));
}
bool memoryWrite_int8(void *addr, int8_t data)
{
vector<uint8_t> byteList{(uint8_t)data};
return memoryWrite_bytes(addr, byteList);
}
bool memoryWrite_uint8(void *addr, uint8_t data)
{
vector<uint8_t> byteList{data};
return memoryWrite_bytes(addr, byteList);
}
bool getRegs(struct user_regs_struct *regs_addr)
{
if (ptrace(PTRACE_GETREGS, targetPid, NULL, regs_addr) < 0)
{
printf("KKptrace->getRegs(): fail\n");
return false;
}
return true;
}
void regsPrint()
{
struct user_regs_struct regs;
getRegs(®s);
Utils::print_regs(®s);
}
bool setRegs(struct user_regs_struct *regs_addr, bool isPrintSetBeforeAndAfter = false)
{
struct user_regs_struct regs;
if (isPrintSetBeforeAndAfter)
{
puts("set before");
Utils::print_regs(regs_addr);
}
if (ptrace(PTRACE_SETREGS, targetPid, NULL, regs_addr) < 0)
{
printf("KKptrace->setRegs(): fail\n");
return false;
}
if (isPrintSetBeforeAndAfter)
{
puts("set before");
getRegs(®s);
Utils::print_regs(®s);
}
return true;
}
void call_begin()
{
// 1、获取并保留当前寄存器环境,以便函数执行完毕后恢复程序正常流程
getRegs(&callBefore_regs);
}
void call_end()
{
// 将寄存器恢复到call之前的状态
setRegs(&callBefore_regs);
int state = 0;
ptrace_continue();
//waitpid(targetPid, &state, WUNTRACED);
}
bool call(void *localFunc, vector<long> paramList, u_long *reValue = NULL, const char *libcName = NULL)
{
string libcNameStr = "libc-2.32.so";
if (libcName == NULL || string(libcName).size() == 0)
{
libcName = libcNameStr.c_str();
}
void *funcAddr = getRemoteFuncAddr((void *)localFunc, libcName);
if (funcAddr == NULL)
{
printf("call() fail,funcAddr=%p\n", (void *)funcAddr);
return false;
}
printf("call().begin,funcAddr=%p\n", (void *)funcAddr);
long re = call_funcAddr(funcAddr, paramList);
if (reValue)
{
*reValue = re;
}
return true;
}
void push(struct user_regs_struct *regs, u_long value)
{
regs->sp -= sizeof(void *);
memoryWrite_u_long((void *)regs->sp, value);
}
long call_funcAddr(void *targetFuncAddr, vector<long> paramList)
{
struct user_regs_struct regs_ori;
struct user_regs_struct regs;
getRegs(®s_ori);
memcpy(®s, ®s_ori, sizeof(regs_ori));
// 获取当前寄存器环境
// 多于6个参数通过栈传递
#if __WORDSIZE == 64
// 前6个参数 通过寄存器传参
switch (paramList.size())
{
case 6:
regs.r9 = paramList[5];
case 5:
regs.r8 = paramList[4];
case 4:
regs.rcx = paramList[3];
case 3:
regs.rdx = paramList[2];
case 2:
regs.rsi = paramList[1];
case 1:
regs.rdi = paramList[0];
break;
}
for (size_t i = 0; i < 6 && paramList.size() > 0; i++)
{
paramList.erase(std::begin(paramList));
}
#endif
// 参数>6个,后续参数需要压栈。
// i386
if (paramList.size() > 0)
{
// regs.sp -= paramList.size() * sizeof(u_long);
for (int i = paramList.size() - 1; i >= 0; i--)
{
push(®s, paramList[i]);
// printf(" paramList[i]=%x\n", paramList[i]);
// memoryWrite_u_long((void*)((u_long)regs.sp + i * sizeof(u_long)), paramList[i]);
}
}
push(®s, 0);
// 通过修改RIP,修改CPU执行位置
regs.ax = 0;
if (isExitAttch)
{
Utils::print_regs(®s);
regs.ip = 0;//(u_long)targetFuncAddr;
// setRegs(®s);
detach();
char temp[30];
sprintf(temp, "%d", targetPid);
string cmd = "sudo edb --attach " + string(temp);
puts(cmd.c_str());
system(cmd.c_str());
getchar();
getchar();
exit(0);
}
else
{
regs.ip = (u_long)targetFuncAddr;
setRegs(®s);
}
int state = 0;
ptrace_continue();
waitpid(targetPid, &state, WUNTRACED);
getRegs(®s);
u_long reValue = regs.ax;
return reValue;
}
/**
* @brief 将模块注入
* @param modulePath 模块路径,例如./test.so
* @param funcName 函数名,默认为空,为空则只load so文件 不执行
* @param isRestore 注入后是否恢复程序正常运行,默认恢复;若设置不恢复,则需要手动调用call_end();
* @param isRestore 注入后是否恢复程序正常运行,默认恢复;若设置不恢复,则需要手动调用call_end();
*
* @return 返回说明
* -<em>false</em> fail
* -<em>true</em> succeed
*/
bool inject(const char *modulePath, const char *funcName = NULL, bool isRestore = true, long *reValue = NULL)
{
bool isCallSucess = false;
vector<long> paramList;
call_begin();
// 分配内存地址
// mmap(0,0x100,可读可写可执行,…)
paramList.clear();
paramList.push_back(0);
paramList.push_back(0x100);
paramList.push_back(PROT_READ | PROT_WRITE | PROT_EXEC);
paramList.push_back(MAP_ANONYMOUS | MAP_PRIVATE);
paramList.push_back(0);
paramList.push_back(0);
u_long remoteBuffer;
call((void *)mmap, paramList, &remoteBuffer);
if (remoteBuffer == -1)
{
printf("mmap() fail\n");
return false;
}
printf("mmap sucess addr=%p\n", (void *)remoteBuffer);
char realPath[500];
realpath(modulePath, realPath);
puts(realPath);
memoryWrite_chars((void *)remoteBuffer, realPath);
// 动态加载so文件
// libcAddr=dlopen(realPath,RTLD_NOW|RTLD_GLOBAL)
paramList.clear();
paramList.push_back(remoteBuffer);
paramList.push_back(RTLD_NOW | RTLD_GLOBAL);
u_long moduleHandle;
isCallSucess = call((void *)dlopen, paramList, &moduleHandle, "libdl-2.32.so");
if (!isCallSucess)
{
return false;
}
printf("moduleHandle=%p\n", (void *)moduleHandle);
if (!moduleHandle)
{
paramList.clear();
u_long dlerrorReAddr;
call((void *)dlerror, paramList, &dlerrorReAddr, "libdl-2.32.so");
printf("dlopen() error,text=");
vector<uint8_t> byteList_1 = memoryRead_bytes((void *)dlerrorReAddr, 100);
puts(Utils::byteListToString(byteList_1).c_str());
return false;
}
// 如果函数名为空,则只load so 不执行函数;
if (funcName == NULL || string(funcName).size() == 0)
{
return true;
}
memoryWrite_chars((void *)remoteBuffer, funcName);
sleep(0.1);
// 获取函数地址
// libcAddr=dlsym(libcAddr,funcName)
paramList.clear();
paramList.push_back(moduleHandle);
paramList.push_back(remoteBuffer);
u_long funcAddr;
isCallSucess = call((void *)dlsym, paramList, &funcAddr, "libdl-2.32.so");
if (!isCallSucess)
{
return false;
}
printf("func addr=%p\n", (void *)funcAddr);
if (!funcAddr)
{
printf("dlsym() error\n");
return false;
}
// 执行已经加载成功的模块中的函数
paramList.clear();
long re = call_funcAddr((void *)funcAddr, paramList);
if (reValue)
{
*reValue = re;
}
if (isRestore)
{
call_end();
}
return true;
}
};
int main()
{
KKptrace *kkptrace = new KKptrace();
// pid_t forkPid = fork();
// if (forkPid == 0)
// {
// char *argv[] = {};
// execv("/home/ubuntu/Desktop/android_learningRoad/ptrace_reject/plsInjectMe", NULL);
// return 0;
// }
// sleep(1);
// cout << "childPid=" << forkPid << endl;
pid_t forkPid;
cin >> forkPid;
if (!kkptrace->attach(forkPid))
{
return 0;
}
long re;
kkptrace->inject("/home/ubuntu/Desktop/android_learningRoad/ptrace_reject/libtest.so", "testEntry", true, &re);
cout << "injectAfterCall_re=" << re << endl;
puts("pls input any key exit");
getchar();
return 0;
}