题目来自看雪2020春季班10月份第一题和第三题。这两个题目本身难度不高,但是确实考察对源码的理解,同时也不失为一个frida
的案例。
在HttpURLConnection
的开发过程中,设置参数时会用到以下方法。分析并hook
上这些方法,写出一两个参数的自吐。
具体在测试时可以自己写一个简单的demo
并在APP中显示调用如下函数
测试app功能正常后,用Objection
直接把以下两个类全都hook
上:java.net.URLConnection
以及java.net.HttpURLConnection
结果如图发现反复调用这几个函数,其他函数都没有调用:
怀疑底层是否真实使用这些类实现的,找到对应源码,发现其实HttpURLConnection
类也是一个抽象类,就是说在Java
中实际上是其Impl
类去实现:
使用WallBreaker
去搜索HttpURLConnection
会发现确实有一个类com.android.okhttp.internal.huc.HttpURLConnectionImpl
去源码里搜了搜发现,确实这个类实现了这个函数
源码看HttpURLConnectionImpl
晕死,结果这个类也是okHttp做的底层???先hook一下这个类
会发现这个实现类确实实现了之前没有hook到的三个函数
那么最终脚本就直接写就是了
最终效果如下
在课时⑨中给出的init array的自吐 hook_linker,32位版本解决了,请分析64位版本,尝试给出解决方案并解决。
以8.1为例,查看源码后会发现
dlopen
调用过程中最终是
目录/bionic/linker/linker_soinfo.cpp
这个函数是模版函数,把linker拷到IDA上一看,会发现这个函数是唯一的,且参数是4个,同时会发现64位的linker中是没有call_function
这个函数的,这个函数被优化成了代码片段,插进call_constructors
函数和call_array
函数中了。
最终模仿这个函数直接写一个js版本就行了关键的代码如下
但是这样只是hook
了so
中init_array
节中函数,还存在.init_proc
的构造函数并未hook
,和32位一样本来是继续去hook
call_function
函数,在脱出/system/lib64/libart.so
后,发现call_function
这个symbol
无法找到,观察下图发现这个函数被inline
了。
但是仔细观察.init_proc
和.init_array
函数调用前后,都会有一个log的判断,直接去hook
这个_dl_async_safe_format_log
函数吧
但是首先得_dl_g_ld_debug_verbosity
这个值大于等于2这个函数才会执行,那么先使用frida
去这个变量的地址,然后修改这个变量的值使其达到_dl_async_safe_format_log
函数会执行的条件即可。
最终frida
关键代码如下:
最终效果如下,
64位:
32位效果:
同样的完整代码已经上传github
,看这里
一切答案都在源码中。
/
/
URLConnection
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setDoInput(true);
HttpUrlConnection.setUseCaches(false);
httpUrlConnection.setRequestProperty(
"Content-type"
,
"application/x-java-serialized-object"
);
httpUrlConnection.connect();
/
/
HttpURLConnection
httpUrlConnection.setRequestMethod(
"POST"
);
/
/
URLConnection
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setDoInput(true);
HttpUrlConnection.setUseCaches(false);
httpUrlConnection.setRequestProperty(
"Content-type"
,
"application/x-java-serialized-object"
);
httpUrlConnection.connect();
/
/
HttpURLConnection
httpUrlConnection.setRequestMethod(
"POST"
);
function hook_java(){
Java.perform(function(){
/
/
httpUrlConnection.setDoOutput(true);
/
/
httpUrlConnection.setDoInput(true);
/
/
HttpUrlConnection.setUseCaches(false);
var URLConnection
=
Java.use(
"java.net.URLConnection"
)
URLConnection.setDoOutput.implementation
=
function(isOutput){
console.log(
"URLConnection.setDoOutput : "
,isOutput);
return
this.setDoOutput(isOutput);
}
URLConnection.setDoInput.implementation
=
function(isInput){
console.log(
"URLConnection.setDoInput : "
,isInput);
return
this.setDoInput(isInput);
}
URLConnection.setUseCaches.implementation
=
function(isUseCaches){
console.log(
"URLConnection.setUseCaches : "
,isUseCaches);
return
this.setUseCaches(isUseCaches);
}
/
/
com.android.okhttp.internal.huc.HttpURLConnectionImpl
var HttpURLConnectionImpl
=
Java.use(
"com.android.okhttp.internal.huc.HttpURLConnectionImpl"
);
HttpURLConnectionImpl.setRequestProperty.implementation
=
function(name,value){
console.log(
"HttpURLConnectionImpl.setRequestProperty => "
,name,
": "
,value);
return
this.setRequestProperty(name,value);
}
HttpURLConnectionImpl.setRequestMethod.implementation
=
function(
type
){
console.log(
"HttpURLConnectionImpl.setRequestMethod : "
,
type
);
return
this.setRequestMethod(
type
);
}
HttpURLConnectionImpl.connect.implementation
=
function(){
console.log(
"HttpURLConnectionImpl.connect"
);
return
this.connect();
}
});
}
function main(){
hook_java();
}
setImmediate(main);
function hook_java(){
Java.perform(function(){
/
/
httpUrlConnection.setDoOutput(true);
/
/
httpUrlConnection.setDoInput(true);
/
/
HttpUrlConnection.setUseCaches(false);
var URLConnection
=
Java.use(
"java.net.URLConnection"
)
URLConnection.setDoOutput.implementation
=
function(isOutput){
console.log(
"URLConnection.setDoOutput : "
,isOutput);
return
this.setDoOutput(isOutput);
}
URLConnection.setDoInput.implementation
=
function(isInput){
console.log(
"URLConnection.setDoInput : "
,isInput);
return
this.setDoInput(isInput);
}
URLConnection.setUseCaches.implementation
=
function(isUseCaches){
console.log(
"URLConnection.setUseCaches : "
,isUseCaches);
return
this.setUseCaches(isUseCaches);
}
/
/
com.android.okhttp.internal.huc.HttpURLConnectionImpl
var HttpURLConnectionImpl
=
Java.use(
"com.android.okhttp.internal.huc.HttpURLConnectionImpl"
);
HttpURLConnectionImpl.setRequestProperty.implementation
=
function(name,value){
console.log(
"HttpURLConnectionImpl.setRequestProperty => "
,name,
": "
,value);
return
this.setRequestProperty(name,value);
}
HttpURLConnectionImpl.setRequestMethod.implementation
=
function(
type
){
console.log(
"HttpURLConnectionImpl.setRequestMethod : "
,
type
);
return
this.setRequestMethod(
type
);
}
HttpURLConnectionImpl.connect.implementation
=
function(){
console.log(
"HttpURLConnectionImpl.connect"
);
return
this.connect();
}
});
}
function main(){
hook_java();
}
setImmediate(main);
soinfo::call_constructors()
call_function(
"DT_INIT"
, init_func_, get_realpath());
call_array(
"DT_INIT_ARRAY"
, init_array_, init_array_count_, false, get_realpath());
-
-
-
-
-
-
>循环调用了 call_function(
"function"
, functions[i], realpath);
soinfo::call_constructors()
call_function(
"DT_INIT"
, init_func_, get_realpath());
call_array(
"DT_INIT_ARRAY"
, init_array_, init_array_count_, false, get_realpath());
-
-
-
-
-
-
>循环调用了 call_function(
"function"
, functions[i], realpath);
function hook_init_array() {
/
/
console.log(
"hook_constructor"
,Process.pointerSize);
if
(Process.pointerSize
=
=
4
) {
var linker
=
Process.findModuleByName(
"linker"
);
}
else
if
(Process.pointerSize
=
=
8
) {
var linker
=
Process.findModuleByName(
"linker64"
);
}
var addr_call_array
=
null;
if
(linker) {
var symbols
=
linker.enumerateSymbols();
for
(var i
=
0
; i < symbols.length; i
+
+
) {
var name
=
symbols[i].name;
if
(name.indexOf(
"call_array"
) >
=
0
) {
addr_call_array
=
symbols[i].address;
}
}
}
if
(addr_call_array) {
Interceptor.attach(addr_call_array, {
onEnter: function (args) {
this.
type
=
ptr(args[
0
]).readCString();
/
/
console.log(this.
type
,args[
1
],args[
2
],args[
3
])
if
(this.
type
=
=
"DT_INIT_ARRAY"
) {
this.count
=
args[
2
];
/
/
this.addrArray
=
new Array(this.count);
this.path
=
ptr(args[
3
]).readCString();
var strs
=
new Array();
/
/
定义一数组
strs
=
this.path.split(
"/"
);
/
/
字符分割
this.filename
=
strs.pop();
if
(this.count >
0
){
console.log(
"path : "
, this.path);
console.log(
"filename : "
, this.filename);
}
for
(var i
=
0
; i < this.count; i
+
+
) {
console.log(
"offset : init_array["
+
i
+
"] = "
, ptr(args[
1
]).add(Process.pointerSize
*
i).readPointer().sub(Module.findBaseAddress(this.filename)));
/
/
插入hook init_array代码
}
}
},
onLeave: function (retval) {
}
});
}
}
function hook_init_array() {
/
/
console.log(
"hook_constructor"
,Process.pointerSize);
if
(Process.pointerSize
=
=
4
) {
var linker
=
Process.findModuleByName(
"linker"
);
}
else
if
(Process.pointerSize
=
=
8
) {
var linker
=
Process.findModuleByName(
"linker64"
);
}
var addr_call_array
=
null;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2021-5-11 11:34
被Simp1er编辑
,原因: