ptrace linux,【ptrace注入】linux下ptrace注入器的实现
[Asm] 纯文本查看 复制代码#include "iostream"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
class Utils
{
public:
static vector uint64ToByteList(uint64_t value)
{
vector 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 uint32ToByteList(uint32_t value, int number = 4)
{
vector 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 uint16ToByteList(uint32_t value)
{
vector 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 data)
{
for (const auto& item : data)
{
cout << std::hex << (int)item << " ";
}
cout << endl;
}
string static byteListToString(vector 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 memoryRead_bytes(void* addr, int number)
{
int i = 0;
uint32_t tempValue = 0;
vector reByteList;
vector 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 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 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 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 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 byteList{ (uint8_t)data };
return memoryWrite_bytes(addr, byteList);
}
bool memoryWrite_uint8(void* addr, uint8_t data)
{
vector 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 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 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[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(®s);
int state = 0;
ptrace_continue();
waitpid(targetPid, &state, WUNTRACED);
getRegs(®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] 返回说明
* -false fail
* -true succeed
*/
bool inject(const char* modulePath, const char *funcName=NULL,bool isRestore = true,int64_t* reValue=NULL)
{
bool isCallSucess = false;
vector 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;
}
ptrace linux,【ptrace注入】linux下ptrace注入器的实现相关推荐
- linux命令注入,Linux kernel本地命令注入漏洞
Linux kernel本地命令注入漏洞 2005-10-19 eNet&Ciweek Linux kernel 2.2.6 Linux kernel 2.2.5 Linux kernel 2 ...
- Linux ptrace 原理,从gdb原理学习ptrace调用
Linux的ptrace系统调用,是Android二进制hook框架adbi的核心.因此学习adbi之前,先学习一下ptrace()函数. ptrace介绍 ptrace可以拆开来,看作Process ...
- Linux ptrace系统调用详解:利用 ptrace 设置硬件断点
<GDB调试之ptrace实现原理> <C语言程序调用栈:backtrace+backtrace_symbols+backtrace_symbols_fd> <strac ...
- Linux中/proc目录下文件详解
Linux中/proc目录下文件详解(一) 声明:可以自由转载本文,但请务必保留本文的完整性. 作者:张子坚 email:zhangzijian@163.com 说明:本文所涉及示例均在fedora ...
- transmission Linux(debian)下的BT下载客户端安装
transmission Linux(debian)下的BT下载客户端安装 转载于:https://blog.51cto.com/2042617/1597540
- Linux(ubuntu)下安装anaconda(64位)并配置jupyter notebook远程访问
Linux(ubuntu)下安装anaconda(64位)并配置jupyter notebook远程访问 Anaconda指的是一个开源的Python发行版本,其包含了conda.Python等180 ...
- 蜗蜗 Linux内核芬妮下,Linux内核的整体架构
作者:蜗蜗 发布于:2014-2-21 13:23 分类:Linux内核分析 1. 前言 本文是"Linux内核分析"系列文章的第一篇,会以内核的核心功能为出发点,描述Linux内 ...
- linux es连接mysql_LINUX下使用elasticsearch-jdbc工具实现MySQL同步到ElasticSearch 以及linux 64位centos系统安装jdk1.8...
第一步:环境匹配 1)elasticsearch 2.3.3 成功安装部署 2)mysql安装成功,增删改查无误~~. 3)要保证elasticsearch-jdbc的版本要与elasticsearc ...
- windows命令行下访问linux,Windows支持直接访问Linux子系统文件:你的下一台Linux何必是Linux...
原标题:Windows支持直接访问Linux子系统文件:你的下一台Linux何必是Linux 晓查 发自 凹非寺 量子位 报道 | 公众号 QbitAI 微软,致力于做最好的Linux发行版. 今天, ...
- Linux快捷键-命令行下
LINUX中命令行下是没有鼠标的,所以所有的操作只能通过键盘来实现.确实,鼠标对于电脑而言感觉还是很重要的,相对与Windows,Linux在易操作性上差的很多.所以,对于我们技术人员来讲,刚开始学习 ...
最新文章
- WebStorm配置SVN
- 你的电池再充几次电就报废?机器学习帮你预测电池寿命
- 抖音数据统计_“彭十六elf”单条视频获赞200W+,荣登抖音TOP20丨红人榜
- allegro差分信号走线_浅谈硬件设计中的一些思路和方法(5)—信号系统,又学到了...
- 大学加权平均分计算器_英国排名前20的大学GPA要求
- 2019牛客暑期多校训练营(第三场)J - LRU management (模拟+list+unorder_map)
- 解决devenv.exe应用程序错误,应用程序发生异常
- 基于水色图像的水质评价
- 年底无心工作?给个摸鱼好去处。中国超级英雄【一方净土】,进来看看嘛
- Quest2有线串联steamVR
- 在Pycharm中,全文搜索、替换,以及单独文件搜索、替换!
- Windows笔记本-U盘无法完成格式化
- 三秒让你学会公私网地址转换(NAT)
- css大图切割,利用CSS切割图片技术来动态显示图片
- 微信小程序——设置tabBar
- 浏览器2014官方下载
- win10 python3.8.10下ipython无响应处理
- 网站历史博物馆来过反爬
- 【Java】变量的分类(作用域,初始值,生命周期)
- 小白怎样学习数据分析?
热门文章
- musescore源码_业余歌剧歌手如何使用MuseScore
- 为什么Qt会有 QT_BEGIN_NAMESPACE宏
- NepCTF2022 WP
- 绑定内联样式 :style
- 【转载】System.Data.ParameterDirection 参数的说明
- “全国十佳新锐领军程序员”出炉,小i机器人朱频频等获评
- tcpdump抓包分段
- 2022无线蓝牙耳机排行榜,2022最值得入手的蓝牙耳机品牌
- python判断用户名是否合法_Python校验用户名是否合法示例
- 全球及中国再生水行业十四五利用前景与运营布局规划报告2022版