目前该注入器只支持android 32bit。
KKPtrace是我写的ptrace注入器类的名称,注入器将会实现进程附加、内存读、内存写、寄存器读写等操作。
目前已实现功能:
- 进程
- 进程附加
- 取消附加
- 继续运行
- 内存读
- int32
- byteList(字节数组,Vector<uint8>)
- 内存写
- int8
- int16
- int32
- int64
- byteList
- 寄存器
- 获取
- 设置
- 打印
- call
- 计算远程libc中函数地址
- 批量call
- 得到call的返回值
- inject
#include "iostream"
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/user.h>
#include <asm/ptrace.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <elf.h>
#include "vector"
#include "sstream"
using namespace std;
#define CPSR_T_MASK ( 1u << 5 )
struct pt_regs_my {
long uregs[18];
};
#define ARM_ORIG_r0 uregs[17]
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
#define ARM_sp uregs[13]
#define ARM_ip uregs[12]
#define ARM_fp uregs[11]
#define ARM_r10 uregs[10]
#define ARM_r9 uregs[9]
#define ARM_r8 uregs[8]
#define ARM_r7 uregs[7]
#define ARM_r6 uregs[6]
#define ARM_r5 uregs[5]
#define ARM_r4 uregs[4]
#define ARM_r3 uregs[3]
#define ARM_r2 uregs[2]
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#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 pt_regs_my *reg_addr) {
printf("--------------------------\n");
printf("r0=%p\n", (void *) reg_addr->ARM_r0);
printf("r1=%p\n", (void *) reg_addr->ARM_r1);
printf("r2=%p\n", (void *) reg_addr->ARM_r2);
printf("r3=%p\n", (void *) reg_addr->ARM_r3);
printf("r4=%p\n", (void *) reg_addr->ARM_r4);
printf("r5=%p\n", (void *) reg_addr->ARM_r5);
printf("r6=%p\n", (void *) reg_addr->ARM_r6);
printf("r7=%p\n", (void *) reg_addr->ARM_r7);
printf("r8=%p\n", (void *) reg_addr->ARM_r8);
printf("r9=%p\n", (void *) reg_addr->ARM_r9);
printf("r10=%p\n", (void *) reg_addr->ARM_r10);
printf("rip=%p\n", (void *) reg_addr->ARM_ip);
printf("rsp=%p\n", (void *) reg_addr->ARM_sp);
printf("rlr=%p\n", (void *) reg_addr->ARM_lr);
printf("rpc=%p\n", (void *) reg_addr->ARM_pc);
printf("--------------------------\n");
}
static pid_t getPidByName(const char *process_name) {
int ProcessDirID = 0;
pid_t pid = -1;
FILE *fp = NULL;
char filename[PATH_MAX] = {0};
char cmdline[PATH_MAX] = {0};
struct dirent *entry = NULL;
if (process_name == NULL)
return -1;
DIR *dir = opendir("/proc");
if (dir == NULL)
return -1;
while ((entry = readdir(dir)) != NULL) {
ProcessDirID = atoi(entry->d_name);
if (ProcessDirID != 0) {
snprintf(filename, PATH_MAX, "/proc/%d/cmdline", ProcessDirID);
fp = fopen(filename, "r");
if (fp) {
fgets(cmdline, sizeof(cmdline), fp);
fclose(fp);
if (strncmp(process_name, cmdline, strlen(process_name)) == 0) {
pid = ProcessDirID;
break;
}
}
}
}
closedir(dir);
return pid;
}
};
class KKptrace {
private:
pid_t targetPid = 0;
struct pt_regs_my callBefore_regs;
void *getLibcBaseAddr(pid_t pid, const char *inLocalLibcPath) {
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("%s",line);
string lineStr = line;
if (lineStr.find(inLocalLibcPath) != -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=" << inLocalLibcPath << 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);
printf("localFuncAddr=%p,localLibcBaseAddr=%p,remoteLibcBaseAddr=%p\n",localFuncAddr,localLibcBaseAddr,remoteLibcBaseAddr);
return remoteFuncAddr;
}
public:
bool isExitAttch = false;
// attachment is premise of all opeartions
bool isAttachSuccess = false;
bool attach(pid_t pid) {
puts("attach begin");
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);
sleep(1);
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);
if (ptrace(17, 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(1, 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(4, 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(4, 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 pt_regs_my *regs_addr) {
if (ptrace(PTRACE_GETREGS, targetPid, NULL, regs_addr)< 0) {
printf("KKptrace->getRegs(): fail,pid=%d,errno=%d\n",targetPid,errno);
return false;
}
return true;
}
void regsPrint() {
struct pt_regs_my regs;
getRegs(®s);
Utils::print_regs(®s);
}
bool setRegs(struct pt_regs_my *regs_addr, bool isPrintSetBeforeAndAfter = false) {
struct pt_regs_my 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 *libcPath = NULL) {
string libcNameStr = "";
if (libcPath == NULL || string(libcPath).size() == 0) {
libcPath = libcNameStr.c_str();
}
void *funcAddr = getRemoteFuncAddr((void *) localFunc, libcPath);
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 pt_regs_my *regs, u_long value) {
regs->ARM_sp -= sizeof(void *);
memoryWrite_u_long((void *) regs->ARM_sp, value);
}
long call_funcAddr(void *targetFuncAddr, vector<long> paramList) {
struct pt_regs_my regs_ori;
struct pt_regs_my regs;
getRegs(®s_ori);
memcpy(®s, ®s_ori, sizeof(regs_ori));
for (size_t i = 0; i < 4 && paramList.size() > 0; i++)
{
regs.uregs[i] = paramList[i];
}
for (size_t i = 0; i < 4 && paramList.size() > 0; i++)
{
paramList.erase(std::begin(paramList));
}
// 参数>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]);
}
}
// 通过修改RIP,修改CPU执行位置
regs.ARM_pc = (u_long) targetFuncAddr;
if (regs.ARM_pc & 1)
{
/*Thumb*/
regs.ARM_pc &= (~1u);
regs.ARM_cpsr |= CPSR_T_MASK;
}
else
{
/* ARM*/
regs.ARM_cpsr &= ~CPSR_T_MASK;
}
regs.ARM_lr = 0;
puts("set before");
Utils::print_regs(®s);
setRegs(®s);
ptrace_continue();
int stat = 0;
waitpid(targetPid, &stat, WUNTRACED);
//0xb7f表示子进程进入暂停状态
while (stat != 0xb7f)
{
if (!ptrace_continue())
{
puts("ptrace call error");
return -1;
}
waitpid(targetPid, &stat, WUNTRACED);
}
struct pt_regs_my regs2;
getRegs(®s2);
puts("set after");
Utils::print_regs(®s2);
u_long reValue = regs2.ARM_r0;
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;
char libcPath_linker[] = "/system/lib/libdl.so";
const char libcPath_ori[39] ="/system/lib/libc.so";
vector<long> paramList;
call_begin();
// 分配内存地址
// mmap(0,0x100,可读可写可执行,…)
paramList.clear();
paramList.push_back(0);
paramList.push_back(0x200);
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,libcPath_ori);
if (remoteBuffer == -1) {
printf("mmap() fail\n");
return false;
}
printf("mmap sucess addr=%p\n", (void *) remoteBuffer);
char realPath[PATH_MAX];
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, libcPath_linker);
if (!isCallSucess) {
return false;
}
printf("moduleHandle=%p\n", (void *) moduleHandle);
if (!moduleHandle) {
paramList.clear();
u_long dlerrorReAddr;
call((void *) dlerror, paramList, &dlerrorReAddr, libcPath_linker);
printf("dlopen() error,text=");
vector<uint8_t> byteList_1 = memoryRead_bytes((void *) dlerrorReAddr, 300);
puts(Utils::byteListToString(byteList_1).c_str());
return false;
} else{
puts("dlopen success");
}
// 如果函数名为空,则只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, libcPath_linker);
if (!isCallSucess) {
return false;
}
printf("dlsym func addr=%p\n", (void *) funcAddr);
if (!funcAddr) {
printf("dlsym() error\n");
return false;
}
vector<uint8_t> byteList2 = memoryRead_bytes( (void *) funcAddr,100);
Utils::print_byteList_hexArray(byteList2);
// 执行已经加载成功的模块中的函数
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();
if (!kkptrace->attach(Utils::getPidByName("bin.mt.plus"))) {
return 0;
}
kkptrace->regsPrint();
long re;
//v/data/app/bin.mt.plus-TGrjPH_7IRiS9r-9mV2Nag==/lib/arm/
kkptrace->inject("/data/app/bin.mt.plus-TGrjPH_7IRiS9r-9mV2Nag==/lib/arm/libtestso.so", "Inject_entry",
true, &re);
cout << "injectAfterCall_re=" << re << endl;
puts("pls input any key exit");
getchar();
return 0;
}
注意事项:
1、“needed or dlopened by "(unknown)" is not accessible for the namespace "(anonymous)"”出现该提示,可能是我们没有把要注入的so放在app的私有目录下。私有目录一般是这样的“/data/app/bin.mt.plus-TGrjPH_7IRiS9r-9mV2Nag==/lib/arm/“
2、该注入器目前只支持32bit,因此在使用NDK编译时,请选择”armeabi-v7a“的编译参数。Application.mk中是“APP_ABI := armeabi-v7a”