适合游戏外挂的开发
- 通过 ptrace 注入游戏进程
- 通过 libsubstrate.so inline hook 替换游戏方法。
注入进程方法
/*************************************************
Description: 使用ptrace远程call函数
Input: pid表示远程进程的ID,ExecuteAddr为远程进程函数的地址
parameters为函数参数的地址,regs为远程进程call函数前的寄存器环境
Output: 无
Return: 返回0表示call函数成功,返回-1表示失败
Others: 无
*************************************************
int ptrace_call(pid_t pid, uint32_t ExecuteAddr, long *parameters, long num_params, struct pt_regs* regs)
{
int i = 0;
if (ExecuteAddr == 0 || (parameters == NULL && num_params != 0) || regs == NULL)
return -1;
// ARM处理器,函数传递参数,将前四个参数放到r0-r3,剩下的参数压入栈中
for (i = 0; i < num_params && i < 4; i ++) {
regs->uregs[i] = parameters[i];
}
if (i < num_params) {
regs->ARM_sp -= (num_params - i) * sizeof(long) ; // 分配栈空间,栈的方向是从高地址到低地址
if (ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)¶meters[i], (num_params - i) * sizeof(long)) == -1)
return -1;
}
regs->ARM_pc = ExecuteAddr; //设置ARM_pc寄存器为需要调用的函数地址
// 与BX跳转指令类似,判断跳转的地址位[0]是否为1,如果为1,则将CPST寄存器的标志T置位,解释为Thumb代码
// 若为0,则将CPSR寄存器的标志T复位,解释为ARM代码
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;
if (ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1) {
LOGD("ptrace set regs or continue error, pid:%d", pid);
return -1;
}
int stat = 0;
// 对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。
// 参数WUNTRACED表示当进程进入暂停状态后,立即返回
// 将ARM_lr(存放返回地址)设置为0,会导致子进程执行发生错误,则子进程进入暂停状态
waitpid(pid, &stat, WUNTRACED);
// 判断是否成功执行函数
LOGD("ptrace call ret status is %d\n", stat);
while (stat != 0xb7f) {
if (ptrace_continue(pid) == -1) {
LOGD("ptrace call error");
return -1;
}
waitpid(pid, &stat, WUNTRACED);
}
// 获取远程进程的寄存器值,方便获取返回值
if (ptrace_getregs(pid, regs) == -1)
{
LOGD("After call getregs error");
return -1;
}
return 0;
}
inline hook
/*************************************************
Description: 程序注入到游戏进程后马上执行的入口函数
Input: 无
Output: 无
Return: 返回0表示成功,返回-1表示失败
Others: 无
*************************************************/
int Inject_entry()
{
LOGD("Inject_entry Func is called\n");
void *handle = NULL;
handle = dlopen("/data/local/tmp/main/libsubstrate.so", RTLD_NOW);
if(!handle)
{
LOGD("dlopen libsubstrate.so fail.\n");
return -1;
}
pfnMSHookFunction MSHookFunction = dlsym(handle, "MSHookFunction");
handle = NULL;
handle = dlopen("libcocos2dcpp.so", RTLD_NOW);
if(!handle)
{
LOGD("dlopen libcocos2dcpp.so fail.\n");
return -1;
}
void* uiAddrOfaddBoxAtIndexWithLevel = dlsym(handle,
"_ZN10Playground22addBoxAtIndexWithLevelEiib");
//InlineHook操作
MSHookFunction((void *)uiAddrOfaddBoxAtIndexWithLevel,
(void *)replaced_addBoxAtIndexWithLevel,
(void **)&old_addBoxAtIndexWithLevel);
return 0;
}
``
网友评论