【ptrace注入】linux下ptrace注入器的实现
KKPtrace是我写的ptrace注入器类的名称,注入器将会实现进程附加、内存读、内存写、寄存器读写等操作。目前已实现功能:
[*]进程
[*]进程附加
[*]取消附加
[*]继续运行
[*]内存读
[*]int32
[*]byteList(字节数组,Vector<uint8>)
[*]内存写
[*]int8
[*]int16
[*]int32
[*]int64
[*]byteList
[*]寄存器
[*]获取
[*]设置
[*]打印
[*]call
[*]计算远程libc中函数地址
[*]批量call
[*]得到call的返回值
[*]inject
远程CALL流程图
附C++代码:
#include "iostream"
#include <stdio.h>
#include <stdlib.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;
class Utils
{
public:
static vector<uint8_t> uint64ToByteList(uint64_t value)
{
vector<uint8_t> byteList;
for (size_t i = 0; i < 8; i++)
{
int tempValue = value;
tempValue = value << (8 * (7 - i));
tempValue = tempValue >> 8 * 8;
byteList.push_back(tempValue);
}
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)
{
cout << std::hex << (int)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("print regs\n");
printf("rax=0x%016" PRIx64 "\n", reg_addr->rax);
printf("rcx=0x%016" PRIx64 "\n", reg_addr->rcx);
printf("rdx=0x%016" PRIx64 "\n", reg_addr->rdx);
printf("rbx=0x%016" PRIx64 "\n", reg_addr->rbx);
printf("rsp=0x%016" PRIx64 "\n", reg_addr->rsp);
printf("rbp=0x%016" PRIx64 "\n", reg_addr->rbp);
printf("rsi=0x%016" PRIx64 "\n", reg_addr->rsi);
printf("rdi=0x%016" PRIx64 "\n", reg_addr->rdi);
printf("rip=0x%016" PRIx64 "\n", reg_addr->rip);
printf("--------------------------\n");
}
};
class KKptrace
{
private:
pid_t targetPid = 0;
const char localLibcPath = "/usr/lib/x86_64-linux-gnu/libc-2.32.so";
void* getLibcBaseAddr(pid_t pid, const char* localLibcPath) {
char filepath;
void* moduleBaseAddr = NULL;
snprintf(filepath, 512, "/proc/%d/maps", pid);
FILE* f = fopen(filepath, "r");
char line;
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_tremotePid = 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*)(uint64_t)localFuncAddr - (uint64_t)localLibcBaseAddr + (uint64_t)remoteLibcBaseAddr;
return remoteFuncAddr;
}
public:
// 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(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(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);
}
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 != 0; i++)
{
byteList.push_back(data);
}
byteList.push_back(0);
return memoryWrite_bytes(addr, byteList);
}
bool memoryWrite_bytes(void* addr, vector<uint8_t> data)
{
if (!isAttachSuccess)
{
return false;
}
uint64_t writeValue = 0;
void* writeAddr = addr;
size_t i;
for (i = 0; i < data.size() / 8; i++)
{
writeValue = 0;
for (size_t j = 0; j < 8; j++)
{
uint64_t tempValue = 0;
tempValue = data;
tempValue = tempValue << (8 * j);
writeValue = writeValue + tempValue;
}
writeAddr = addr + 8 * i;
if (ptrace(PTRACE_POKETEXT, targetPid, writeAddr, writeValue) < 0)
{
return false;
}
}
int yu = data.size() % 8;
if (yu)
{
writeValue = 0;
writeAddr = addr + 8 * i;
// 未对齐64bit的情况,需要先取值再覆盖。
vector<uint8_t> readByteList = memoryRead_bytes(writeAddr, 8);
for (size_t j = yu; j < 8; j++)
{
uint64_t tempValue = readByteList;
tempValue = tempValue << 8 * j;
writeValue = writeValue + tempValue;
}
for (size_t j = 0; j < yu; j++)
{
uint64_t tempValue = 0;
tempValue = data;
tempValue = tempValue << (8 * j);
writeValue = writeValue + tempValue;
}
if (ptrace(PTRACE_POKETEXT, targetPid, writeAddr, writeValue) < 0)
{
return false;
}
}
return true;
}
bool memoryWrite_int64(void* addr, int64_t value)
{
return memoryWrite_bytes(addr, Utils::uint64ToByteList(value));
}
bool memoryWrite_uint64(void* addr, uint64_t value)
{
return memoryWrite_bytes(addr, Utils::uint64ToByteList(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(bool isWaitToRun=false)
{
// 将寄存器恢复到call之前的状态
setRegs(&callBefore_regs);
int state = 0;
ptrace_continue();
if (isWaitToRun)
{
waitpid(targetPid, &state, WUNTRACED);
}
}
bool call(void* localFunc, vector<int64_t> paramList, int64_t* 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)
{
return false;
}
int64_t re = call_funcAddr(funcAddr, paramList);
if (reValue)
{
*reValue = re;
}
return true;
}
int64_t call_funcAddr(void* targetFuncAddr, vector<int64_t> paramList)
{
struct user_regs_struct regs_ori;
struct user_regs_struct regs;
getRegs(®s_ori);
memcpy(®s, ®s_ori, sizeof(regs_ori));
// 获取当前寄存器环境
// 多于6个参数通过栈传递
regs.rsp -= sizeof(void*);
size_t errRet = 0;
// 返回地址弄成0导致错误停止
memoryWrite_int64((void*)regs.rsp, 0);
// 前6个参数 通过寄存器传参
switch (paramList.size()) {
case 6:
regs.r9 = paramList;
case 5:
regs.r8 = paramList;
case 4:
regs.rcx = paramList;
case 3:
regs.rdx = paramList;
case 2:
regs.rsi = paramList;
case 1:
regs.rdi = paramList;
break;
}
// 参数>6个,后续参数需要压栈。
if (paramList.size() > 6) {
regs.rsp -= (paramList.size() - 6) * sizeof(long);
for (size_t i = 6; i < paramList.size(); i++)
{
memoryWrite_int64((void*)regs.rsp + i * 8, paramList);
}
}
// 通过修改RIP,修改CPU执行位置
regs.rax = 0;
regs.rip = (unsigned long long) targetFuncAddr;
setRegs(®s);
int state = 0;
ptrace_continue();
waitpid(targetPid, &state, WUNTRACED);
getRegs(®s);
uint64_t reValue = regs.rax;
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,int64_t* reValue=NULL)
{
bool isCallSucess = false;
vector<int64_t> 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);
int64_t remoteBuffer;
call((void*)mmap, paramList,&remoteBuffer);
if (remoteBuffer == -1)
{
printf("mmap() fail");
return false;
}
printf("mmap sucess addr=%p\n", remoteBuffer);
char realPath;
realpath(modulePath, 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);
int64_t moduleHandle;
isCallSucess = call((void*)dlopen, paramList, &moduleHandle, "libdl-2.32.so");
if (!isCallSucess)
{
return false;
}
printf("moduleHandle=%p\n", moduleHandle);
if (!moduleHandle)
{
paramList.clear();
int64_t dlerrorReAddr;
call((void*)dlerror, paramList, &dlerrorReAddr,"libdl-2.32.so");
printf("dlopen() error,text=");
paramList.push_back(dlerrorReAddr);
call((void*)puts, paramList);
return false;
}
// 如果函数名为空,则只load so 不执行函数;
if (funcName==NULL || string(funcName).size()==0)
{
return true;
}
memoryWrite_chars((void*)remoteBuffer, funcName);
// 获取函数地址
// libcAddr=dlsym(libcAddr,funcName)
paramList.clear();
paramList.push_back(moduleHandle);
paramList.push_back(remoteBuffer);
int64_t funcAddr;
isCallSucess = call((void*)dlsym, paramList,&funcAddr, "libdl-2.32.so");
if (!isCallSucess)
{
return false;
}
printf("func addr=%p\n", funcAddr);
if (!funcAddr)
{
printf("dlsym() error");
return false;
}
// 执行已经加载成功的模块中的函数
paramList.clear();
int64_t 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;
}
int64_t 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;
}
iOS能用吗 顶楼主,就是注释太少了...
页:
[1]