吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2664|回复: 2
收起左侧

[其他转载] 【ptrace注入】linux下ptrace注入器的实现

[复制链接]
zhukai055 发表于 2021-3-4 21:16
     KKPtrace是我写的ptrace注入器类的名称,注入器将会实现进程附加、内存读、内存写、寄存器读写等操作。


目前已实现功能:
  • 进程
    • 进程附加
    • 取消附加
    • 继续运行
  • 内存读
    • int32
    • byteList(字节数组,Vector<uint8>)
  • 内存写
    • int8
    • int16
    • int32
    • int64
    • byteList
  • 寄存器
    • 获取
    • 设置
    • 打印
  • call
    • 计算远程libc中函数地址
    • 批量call
    • 得到call的返回值
  • inject


远程CALL流程图 1.png
附C++代码:
[Asm] 纯文本查看 复制代码
#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[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*)(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[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)
	{
		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[i * 8 + j];
				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[j];
				tempValue = tempValue << 8 * j;
				writeValue = writeValue + tempValue;

			}
			for (size_t j = 0; j < yu; j++)
			{
				uint64_t tempValue = 0;
				tempValue = data[i * 8 + j];
				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(&#174;s);
		Utils::print_regs(&#174;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(&#174;s);
			Utils::print_regs(&#174;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(&#174;s_ori);
		memcpy(&#174;s, &#174;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[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;

		}

		// 参数>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[6 + i]);
			}
		}

		// 通过修改RIP,修改CPU执行位置
		regs.rax = 0;
		regs.rip = (unsigned long long) targetFuncAddr;


		setRegs(&#174;s);


		int state = 0;
		ptrace_continue();
		waitpid(targetPid, &state, WUNTRACED);
		getRegs(&#174;s);
		uint64_t reValue = regs.rax;

		return reValue;
	}

	/**
	 * [url=home.php?mod=space&uid=190858]@brief[/url] 将模块注入
	 * [url=home.php?mod=space&uid=952169]@Param[/url] modulePath 模块路径,例如./test.so
	 * @param funcName 函数名,默认为空,为空则只load so文件 不执行
	 * @param isRestore 注入后是否恢复程序正常运行,默认恢复;若设置不恢复,则需要手动调用call_end();
	 * @param isRestore 注入后是否恢复程序正常运行,默认恢复;若设置不恢复,则需要手动调用call_end();
	 *
	 * [url=home.php?mod=space&uid=155549]@Return[/url] 返回说明
	 *     -<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[500];
		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;
}

免费评分

参与人数 2吾爱币 +2 热心值 +2 收起 理由
plasd + 1 + 1 热心回复!
streaking + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

qwe30245868913 发表于 2021-5-28 20:52
iOS能用吗
smartking 发表于 2022-3-23 12:21
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 07:28

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表