最近在应聘某大厂的安全岗位时,面试官问到了一些有关hook的知识, 在简单分析了下F8和ele7enxxh大牛的开源代码之后, 有了这篇文章.
本文引用了f8left和ele7enxxh两位大牛项目中的一些代码.还有部分代码引用自substrate项目.
文章:
项目:
MainActivity:
我们会将会测试Hook 这个"stringFromJNI()"函数.
在native层, 我们的main.cpp中
会在JNI_OnLoad中有一个init函数
在Hook.cpp我们来看一下init函数:
可以看到, 我们实例化了一个FAInHook对象, new FAInHook()
.
并调用了registerHook
函数来注册对getStr的hook.
我们在使用是还会用到的doInHook
:
现在可以看到, 我们主要的任务就是分析registerHook
和doInHook
这两个函数的实现.
我们现在主要分析registerHook
函数.
先来分析参数:
在Hook之前我们首先要注册这个函数
函数申明:
参数(原始函数地址, 新函数地址, 调用原始函数).
函数主要流程:
注册函数信息, 计算hook stub.
首先判断originFunAddr
和newFunAddr
是否是函数地址.
auto info = getHookInfo(originFunAddr); 得到函数信息
然后判断函数是否已经被Hook.
检查判断指令类型(thumb or arm or x86 ...)
hook_map是一个std::map<Elf_Addr, FAInHook::HookInfo*>的map类型. find函数会返回返回一个迭代器, 可以用it->first
和it->second
来访问它的成员(key和value). 这个过程其实对已经注册过的hook函数的处理.
auto type = FAHook::Instruction::getFunctionType(orginalFunAddr);
下面是getFunctionAddr
的实现, 可以看到. 判断指令类型的方式, 是通过自己定义宏来实现的. 当然, 在Arm指令中, 我们还要是否该指令为thumb指令.
在看HookInfo.h
时, 我们可以看到FAHook
是一个namespace
, 而里面主要包含了一个HookInfo
的类:
我们先来分析它的构造函数:
这里运用了c++中的构造函数初始化列表来初始化类成员.
分析createStub(info)
我们这里分析FAHook::ThumbInstrution::createStub(FAHook::HookInfo *info)
:
thumbInstruction.cpp的实现:
基础知识:
reinterpret_cast<uint16_t*> 为类型转换
为什么要修正pc相关指令?
inlineHook原理图, 来源于gslab.
调用 used += MSGetInstructionWithThumb(reinterpret_cast<uint8_t *>(area) + used);
MSGetInstructionWithThumb: 参数为(uint16_t*).
返回结果: 为这条指令是多少字节的指令.(4 or 2)
T$32bit$i的作用: (指令(ic) & 1110 0000 0000 0000) && (ic & 0001 1000 0000 0000 != 0x0000);
第一个判断为确定高位3个bit(即bit[15], bit[14], bit[13])为1. 第二个判断为确保bit[12], bit[11]有值(即至少这两位有 1 位为 1).
其实就是判断是该thumb指令是否为thumb32指令,
thumb32指令的判断依据是 b[15:11] 为 0b11101或0b11110或0b11111.
MSGetInstructionWithThumb:
T$32bit$i:
有4个方法:
有4个field:
我们现在分析一下createExecMemory(uint32_t size)
:
createExecMemory:
hookAll():
进而转到Hook函数
分析enableJumpStub(info)
:
可以看到, 在得到了origAddr
和stubAddr
和len
之后,我们会进入到patch函数patchMemory
, 根据我们前面的分析, 它会patch原函数的入口指令的前(8 or 10?)个字节.
patchMemory:
首先会调用unProtectMemory
函数来将对应内存修改为(rwx), 然后调用memcpy
来修改内存, 最后调用protectMemory
来修改对应内存为(r-x).
现在我们就基本对该项目进行了简单的分析, 我这里总结一下:
http://ele7enxxh.com/Android-Arm-Inline-Hook.html
http://gslab.qq.com/portal.php?mod=view&aid=168
https://github.com/ele7enxxh/Android-Inline-Hook
https://github.com/F8LEFT/FAInHook
static {
System.loadLibrary("FHook");
}
public native String stringFromJNI();
jstring stringFromJNI(
JNIEnv *env,
jobject ) {
doInHook();
// doGotHook();
return env->NewStringUTF(getStr());
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void *reserved) {
JNIEnv* env = nullptr;
jint resultstr = -1;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
auto jclazz = env->FindClass("com/example/l0phtg/hookstudyf8/MainActivity");
JNINativeMethod natives[] = {
{"stringFromJNI", "()Ljava/lang/String;", (void*)stringFromJNI}};
env->RegisterNatives(jclazz, natives, 1);
env->DeleteLocalRef(jclazz);
init();
return JNI_VERSION_1_6;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2018-4-3 16:51
被LOphTg编辑
,原因: 更正文章内容