【ptrace】android下ptrace注入器的实现

2 篇文章 0 订阅
1 篇文章 0 订阅

目前该注入器只支持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(&regs);
        Utils::print_regs(&regs);
    }

    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(&regs);
            Utils::print_regs(&regs);
        }
        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(&regs_ori);
        memcpy(&regs, &regs_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(&regs, 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(&regs);
        setRegs(&regs);

        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(&regs2);
        puts("set after");
        Utils::print_regs(&regs2);

        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”

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值