zhukai055 发表于 2021-3-4 21:16

【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;
}

qwe30245868913 发表于 2021-5-28 20:52

iOS能用吗

smartking 发表于 2022-3-23 12:21

顶楼主,就是注释太少了...
页: [1]
查看完整版本: 【ptrace注入】linux下ptrace注入器的实现