android hook 实例,代码实例分析android中inline hook

以下内容通过1、实现目标注入程序,2、实现主程序,3、实现注入函数,4、thumb指令集实现等4个方面详细分析了android中inline hook的用法,以下是全部内容:

最近终于沉下心来对着书把hook跟注入方面的代码敲了一遍,打算写几个博客把它们记录下来。

第一次介绍一下我感觉难度最大的inline hook,实现代码参考了腾讯GAD的游戏安全入门。

inline hook的大致流程如下:

829cded9904197737761952ee2537629.png

首先将目标指令替换为跳转指令,跳转地址为一段我们自己编写的汇编代码,这段汇编代码先是执行用户指定的代码,如修改寄存器的值,然后执行被替换掉的原指令2,最后再跳转回原指令3处,恢复程序的正常运行。

为了避开注入过程,我们通过hook自己进程加载的动态连接库进行演示。

1、实现目标注入程序

我们将这个程序编译为动态连接库,然后在主程序中加载,作为hook的目标。

target.h

#ifndef TARGET_H_INCLUDED

#define TARGET_H_INCLUDED

void target_foo();

#endif // TARGET_H_INCLUDED

target.c

#include "target.h"

#include

#include

#include

void target_foo()

{

int a = 3;

int b = 2;

while(a--) {

sleep(2);

b = a * b;

printf("[INFO] b is %d\n", b);

}

b = b + 2;

b = b - 1;

printf("[INFO] finally, b is %d\n", b);

}

Android.mk

include $(CLEAR_VARS)

LOCAL_ARM_MODE := arm

LOCAL_MODULE := target

LOCAL_CFLAGS += -pie -fPIE -std=c11

LOCAL_LDFLAGS += -pie -fPIE -shared -llog

APP_ABI := armeabi-v7a

LOCAL_SRC_FILES := target.c

include $(BUILD_SHARED_LIBRARY)

注意Android.mk中LOCAL_ARM_MODE := arm代表编译时使用4字节的arm指令集,而不是2字节的thumb指令集。

2、实现主程序

在主程序中我们首先加载之前编写的动态链接库,进行hook之后再对其中的函数target_foo进行调用。

main.c

#include

#include

#include

#include

#include

#include "hook_inline.h"

typedef void (*target_foo)(void);

void my_func(struct hook_reg *reg)

{

puts("here we go!");

}

void main()

{

void *handler = dlopen("/data/local/tmp/libtarget.so", RTLD_NOW);

target_foo foo = (target_foo)dlsym(handler, "target_foo");

hook_inline_make("/data/local/tmp/libtarget.so", 0xde2, my_func, true);

foo();

}

hook_inline.h

#ifndef HOOK_INLINE_H_INCLUDED

#define HOOK_INLINE_H_INCLUDED

#include

struct hook_reg {

long ARM_r0; long ARM_r1; long ARM_r2; long ARM_r3;

long ARM_r4; long ARM_r5; long ARM_r6; long ARM_r7;

long ARM_r8; long ARM_r9; long ARM_r10;long ARM_r11;

long ARM_r12;long ARM_sp; long ARM_lr; long ARM_cpsr;

};

typedef void (*hook_func)(struct hook_reg *reg);

bool hook_inline_make(const char *library, long address, hook_func func, bool isArm);

#endif // HOOK_INLINE_H_INCLUDED

这里我们hook功能的实现函数为hook_inline_make,4个参数分别为动态库路径,目标地址,用户函数,目标地址处指令集。

当程序执行到目标地址处时会回调我们传入的用户函数,可通过参数hook_reg来更改寄存器的值(不包括寄存器pc)。因为之前在动态链接库的Android.mk文件指定了使用arm指令集进行编译,所以此处指定最后一个参数为true。

3、实现注入函数

现在到了最为关键的地方,为了实现这个功能还需要了解几个知识。

(1)、获取内存中动态链接库的基址

Linux系统中各个进程的内存加载信息可以在/proc/pid/maps文件中到,通过它我们可以获取到动态链接库在内存中的加载基址。

long get_module_addr(pid_t pid, const char *module_name)

{

char file_path[256];

char file_line[512];

if (pid < 0) {

snprintf(file_path, sizeof(file_path), "/proc/self/maps");

} else {

snprintf(file_path, sizeof(file_path), "/proc/%d/maps", pid);

}

FILE *fp = fopen(file_path, "r");

if (fp == NULL) {

return -1;

}

long addr_start = -1, addr_end = 0;

while (fgets(file_line, sizeof(file_line), fp)) {

if (strstr(file_line, module_name)) {

if (2 == sscanf(file_line, "%8lx-%8lx", &addr_start, &addr_end)) {

break;

}

}

}

fclose(fp);

printf("library :%s %lx-%lx, pid : %d\n", module_name, addr_start, addr_end, pid);

return addr_start;

}

(2)、更改内存中的二进制代码

现在的计算机系统中一般对内存进行分段式管理,不同的段有不同的读、写、执行的属性。一般来讲代码段只有读和执行的属性,不允许对代码段进行写操作。Linux系统中通过函数mprotect对内存的属性进行更改,需要注意的一点是需要以内存页的大小进行对齐。

bool change_addr_writable(long address, bool writable) {

long page_size = sysconf(_SC_PAGESIZE);

//align address by page size

long page_start = (address) & (~(page_size - 1));

//change memory attribute

if (writable == true) {

return mprotect((void*)page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) != -1;

} else {

return mprotect((void*)page_start, page_size, PROT_READ | PROT_EXEC) != -1;

}

}

接下来就可以着手实现功能了,inline hook跟指令集密切相关,此处我们先演示arm指令集的情况,之后对thumb指令集进行讨论。这里实现的功能是用户可在自己注册的回调函数中对hook点寄存器的值进行修改。

d1c117e71f424f82cb7a1884ce22e382.png

为了实现32位地址空间的长跳转,我们需要两条指令的长度(8个字节)来实现。一般手机上的arm处理器为3级流水,所以pc寄存器的值总是指向当前执行指令后的第二条指令,因而使用ldr pc, [pc, #-4]来加载该指令之后的跳转地址。当程序跳转到shellcode后,首先对寄存器组进行备份,然后调用用户注册的回调函数,用户可在回调函数中修改备份中各个寄存器(pc寄存器除外)的值,然后从备份中恢复寄存器组再跳转到stubcode,stubcode的功能是执行被hook点的跳转指令替换掉的两条指令,最后跳回原程序。

ellcode.S 1 .global _shellcode_start_s

.global _shellcode_end_s

.global _hook_func_addr_s

.global _stub_func_addr_s

.data

_shellcode_start_s:

@ 备份各个寄存器

push  {r0, r1, r2, r3}

mrs   r0, cpsr

str   r0, [sp, #0xc]

str   r14, [sp, #0x8]

add   r14, sp, #0x10

str   r14, [sp, #0x4]

pop   {r0}

push  {r0-r12}

@ 此时寄存器被备份在栈中,将栈顶地址作为回调函数的参数(struct hook_reg)

mov   r0, sp

ldr   r3, _hook_func_addr_s

blx   r3

@ 恢复寄存器值

ldr   r0, [sp, #0x3c]

msr   cpsr, r0

ldmfd sp!, {r0-r12}

ldr   r14, [sp, #0x4]

ldr   sp, [r13]

ldr   pc, _stub_func_addr_s

_hook_func_addr_s:

.word 0x0

_stub_func_addr_s:

.word 0x0

_shellcode_end_s:

.end

shellcode使用汇编实现,在使用时需要对里边的两个地址进行修复,用户回调函数地址(_hook_func_addr_s)跟stubcode地址(_stub_func_addr_s)。

接下来我们可以看一下函数hook_inline_make的具体实现了

void hook_inline_make(const char *library, long address, hook_func func)

{

//获取hook点在内存中的地址

long base_addr = get_module_addr(-1, library);

long hook_addr = base_addr + address;

//获取shellcode中的符号地址

extern long _shellcode_start_s;

extern long _shellcode_end_s;

extern long _hook_func_addr_s;

extern long _stub_func_addr_s;

void *p_shellcode_start = &_shellcode_start_s;

void *p_shellcdoe_end = &_shellcode_end_s;

void *p_hook_func = &_hook_func_addr_s;

void *p_stub_func = &_stub_func_addr_s;

//计算shellcode大小

int shellcode_size = (int)(p_shellcdoe_end - p_shellcode_start);

//新建shellcode

void *shellcode = malloc(shellcode_size);

memcpy(shellcode, p_shellcode_start, shellcode_size);

//添加执行属性

change_addr_writable((long)shellcode, true);

//在32bit的arm指令集中,stubcode中的4条指令占用16个字节的空间

//前两条指令为hook点被替换的两条指令

//后两条指令跳转回原程序

void *stubcode = malloc(16);

memcpy(stubcode, (void*)hook_addr, 8);

//ldr pc, [pc, #-4]

//[address]

//手动填充stubcode

char jump_ins[8] = {0x04, 0xF0, 0x1F, 0xE5};

uint32_t jmp_address = hook_addr + 8;

memcpy(jump_ins + 4, &jmp_address, 4);

memcpy(stubcode + 8, jump_ins, 8);

//添加执行属性

change_addr_writable((long)stubcode, true);

//修复shellcode中的两个地址值

uint32_t *shell_hook = shellcode + (p_hook_func - p_shellcode_start);

*shell_hook = (uint32_t)func;

uint32_t *shell_stub = shellcode + (p_stub_func - p_shellcode_start);

*shell_stub = (uint32_t)stubcode;

//为hook点添加写属性

change_addr_writable(hook_addr, true);

//替换hook点指令为跳转指令,跳转至shellcode

jmp_address = (uint32_t)shellcode;

memcpy(jump_ins + 4, &jmp_address, 4);

memcpy((void*)hook_addr, jump_ins, 8);

change_addr_writable(hook_addr, false);

//刷新cache

cacheflush(hook_addr, 8, 0);

}

注意这里的change_addr_writable函数无论传入false还是true对应地址都会添加上执行属性。由于处理器采用流水线跟多级缓存,在更改代码后我们需要手动刷新cache,即函数cacheflush(第三个参数无意义)。

4、thumb指令集实现

由于thumb指令集的功能受到限制,虽然思路上跟arm指令集一致,但在实现上需要用更多条指令,下面是我自己想的一种实现方式,欢迎交流。

963016a09ff75b01cdf23e14b1ef3e3b.png

需要注意的是由于每条thumb指令为16bit,所以32位的跳转地址需要占用两条指令的空间,而且跳转时会污染r0寄存器所以要对其进行保护。我在实现程序时将shellcode编译为了arm指令集,所以在原程序、shellcode、stubcode之间相互跳转时需要使用bx指令进行处理器状态切换(需要跳转的地址代码为thumb指令集时,需要将地址的第1个bit位置位)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/566573.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dax 筛选 包含某个字_筛选状态(ALL与REMOVEFILTERS)

这一章比较绕&#xff0c;但是帮助我们理清切片器的筛选状态以及主要函数对于公式筛选上下文的改变。1.切片器的筛选状态切片器的全选与全不选的状态的区别&#xff0c;我们可以看下图&#xff1a;全不选全选多个点击筛选逐个点击至全部结论初始状态&#xff0c;没有选择任何元…

山东鲁能轨道智能巡检机器人_温湿度传感器在轨道巡检机器人中的应用

▲地下综合管廊智慧管廊建设&#xff0c;是智慧城市在地下的一个缩影&#xff0c;有助于缓解“大城市病”&#xff0c;实现精细化和动态管理。与此同时&#xff0c;各种传感器技术也将被运用到地下综合管廊运维的每一环&#xff0c;这其中&#xff0c;地下管廊巡检机器人便是其…

android显示网络图片控件,Android控件之ImageView(二)

前言在上一篇文章中&#xff0c;我们讲解了如何加载本地图片&#xff0c;那么在实际项目中 ImageView 大多数使用场景是加载网络图片&#xff0c;网络图片其实就是存储在服务器上的文件&#xff0c;我们需要从服务器获取到文件的二进制输入流 Inpustream &#xff0c;然后将其转…

坯子库曲面推拉教程_一招曲面流动,搞定99%异形建模

曲面流动可以建什么模型&#xff1f;这样的▼这样的▼还有这样的▼那究竟如何使用曲面流动呢?本文告诉你!曲面流动是什么&#xff1f;曲面流动功能相当于Rhino(犀牛)中的“沿曲面流动”命令&#xff0c;可以使来源几何体群组或组件&#xff0c;根据基准平面为参照&#xff0c;…

android o 结构光流程,惊艳亮相!一分钟看懂OPPO Find X 3D结构光技术是什么鬼,太牛了...

法国时间6月19日&#xff0c;OPPO在巴黎卢浮宫正式举办未来旗舰Find X发布会。此次亮相的Find X新机&#xff0c;既有充满艺术感的3D玻璃机身设计&#xff0c;又有3D结构光、曲面全景屏、双轨潜望结构等多项黑科技。众多黑科技中&#xff0c;以3D结构光O-face最受数目。据悉&am…

jframe运行和预览大小不一样_同一款车型,为什么配的轮胎大小还会不一样?【内含福利】...

小编又来给大家送福利啦~阅读完文章之后 戳文章底部阅读原文 岁末巨献 国货好胎&#xff01;免费体验价值1999元国产轮胎&#xff01;相信有不少朋友&#xff0c;买车的时候一定会有类似的经历。选车、试驾的时候&#xff0c;看到试驾车配置相当漂亮&#xff0c;尤其搭配的轮圈…

java设计按月每天签到_活动攻略|新同学新签到,欢乐福利全都要!

12月03日【每日一题答案】— 枫叶书签答对问题即有机会获得金币、道具、积分&#xff0c;还有宠物好奇星噢~12月来了&#xff0c;和12月一起来的是我们的新同学——花轮&#xff01;谁不喜欢浪漫体贴的小少爷呢&#xff01;喵星星感觉自己爱消除【最受欢迎男性角色】的地位正岌…

bs cs架构区别_软件架构设计分层模型和构图思考

今天谈下架构设计中的分层思维和分层模型以及基于分层思维下的架构构图逻辑。架构思维概述对于架构思维本身仍然是类似系统思维&#xff0c;结构化思维&#xff0c;编程思维等诸多思维模式的一个合集。由于架构的核心作用是在业务现实世界和抽象的IT实现之间建立起一道桥梁&…

pin码计算器网页版_AP微积分Excel简便计算+网页工具指南

今年的AP考试既然是开卷&#xff0c;允许大家使用各种资源。今天一个学生提了一个不(zhe)错(mo)的(wo)想(de)法(shi)。于是给大家写了一个Excel的公式表格照例老规矩&#xff1a;点个”在看“再走呗先说明一下使用指南&#xff1a;文末有下载表格包含&#xff1a;(目前的功能&a…

HTML文本下划线效果,聊聊CSS中文本下划线_CSS, SVG, masking, clip-path, 会员专栏, text-decoration 教程_W3cplus...

在Web中给文本添加下划线常常出现在链接的文本上&#xff0c;早期一般使用text-decoration属性给文本添加下划线、删除线等。除了text-decoration之外&#xff0c;CSS还有很多技术方案可以给文本添加下划线效果&#xff0c;比如border-bottom、box-shadow、background-image等。…

学员感言html效果图,学员感言丨非计算机专业学员 开始学HTML5的点点滴滴

学员感言丨非计算机专业学员 开始学HTML5的点点滴滴来源&#xff1a;奇酷教育 发表于&#xff1a;2017-08-03 12:09:25在奇酷学员学习HTML5的这段时间里&#xff0c;让我学习到了实用的技能和知识。我是一个非计算机类学生&#xff0c;可以说是对编程一窍不通&#xff0c;在选择…

请领导批阅文件怎么说_请领导吃饭,不要对外说,职场员工为何如此保密?

前一段时间公司员工晋升&#xff0c;因为小王在公司的表现非常不错&#xff0c;所以成为了公司领导的秘书。其实按理来说&#xff0c;成为公司领导的秘书与否&#xff0c;往往只需要看这个员工有没有眼力&#xff0c;看她的办事能力如何&#xff0c;能不能提高公司的整体效率&a…

幼儿使用计算机需要注意事项,儿童玩电脑注意事项

相信现在的家庭里面很多小孩子爱玩电脑&#xff0c;但是电脑玩多了&#xff0c;对孩子眼睛、身体都不好&#xff0c;那么应该怎么才能科学玩电脑呢&#xff1f;妈网百科给大家总结了一些其他家长的经验&#xff0c;希望能够帮得到各位有需要的家长。【与电脑保持距离】孩子与电…

c++实现卷积码编码和维特比译码_鑫艾勒维特家用别墅电梯:安全至上,无可替代...

近年来&#xff0c;随着房地产行业的兴起&#xff0c;家用别墅电梯作为房地产配套产业也逐渐走进了平常家庭别墅中&#xff0c;如今一句俗语“无梯不成墅”将电梯在别墅中的重要地位彰显的淋漓尽致。艾勒维特家用液压小电梯因其适用于私人住宅&#xff0c;适用场景多样等特点&a…

某个元素的距离页面的左边距_如何提高办公写作效率?先设置好页面上的这4类数据,准没错...

有人说&#xff0c;在体制内混的好&#xff0c;首先要文笔好。这里要说的是&#xff0c;一个文笔好的人&#xff0c;可能在哪里都能混的好。#直言职场#因为很多表达形式都需要以文字做雏形&#xff0c;进而进行各种形式的变换和转化。就拿当下很热门的自媒体行业来说&#xff0…

地线与接地螺丝_电气接地的规范要求及接地的各项参数,收藏!

申请加入微信群&#xff1a;加微信好友&#xff0c;diangong1968申请格式&#xff1a;城市-公司简称(电气工程师职称)点此去资料库下载本篇资料为了主要目的是保护人身和设备的安全&#xff0c;减少公司电气事故发生&#xff0c;控制公司人员和财产不受损失&#xff0c;所有电气…

ai怎么渐变颜色_Ai渐变插画怎么丰富细节

此次教程只需小伙伴对AI软件有基本的操作了解就可以完成&#xff0c;易上手容易理解。止疼药瓶子1.新建画布800X600&#xff0c;绘制止疼药瓶子轮廓用矩形工具(W)绘制止疼药瓶子轮廓&#xff0c;圆角处用直接选择工具(A)选择矩形2个锚点&#xff0c;拉成自己想要的圆角。2.给止…

axure8.0发布html,Axure 8.0 beta最后一批新增和改进功能的介绍

之前一直想翻译Axure官方博客的这篇介绍&#xff0c;但一直没抽出时间&#xff0c;今天偶然发现ShunzUX翻译了这篇文章。阅读后觉得翻译得很准确&#xff0c;特别转来分享给大家。特别是On-Premises Axure Share&#xff0c;我之前都是翻译成『本地部署Axure Share』&#xff0…

实现option上下移动_Django实战2-自动化运维之配置管理-05:字典管理功能实现

本节内容主要实现CMDB基础数据管理功能的实现&#xff0c;文档中会介绍到datatables后端分页实现和过滤查询功能的实现。在Django实战1中已经自定义了 添加、修改等自定义类视图&#xff0c;本节中可以直接使用。1、字典管理页面实现首先来实现字段管理的基础管理页面&#xff…

用计算机对话的小品,爆笑小品剧本台词《作弊记》

小品深入生活&#xff0c;贴近生活&#xff0c;体验生活&#xff0c;从生活中找灵感。要用艺术的眼光去发现题材&#xff0c;挖掘题材。人物&#xff1a; 学生甲 学生乙 监考教师(教室门前)(甲乙边走边聊&#xff0c;乙背着书包&#xff0c;甲两手空空&#xff0c;只在上衣贴胸…