安卓逆向|菜鸟的FRIDA学习笔记:内存读写
这是我自己的学习笔记,比较水,大佬勿喷。
假设你的手机已经root,并已开启frida服务,电脑端已安装好Python,frida,IDA,GDA。
样本地址:
链接: https://pan.baidu.com/s/1y3kIXcBv25QqKjAVzq39CQ 提取码: wzqa
打开软件,界面是这样的:
随便输入"123456",提示"验证码校验失败",将APK拖入GDA,查找该字符串,定位到这里:
逻辑很简单,如果执行的是if语句,只校验成功,关键的也就是:
this.this$0.null_securityCheck
这个函数,跟进去发现是个native函数:
-
//Package com.yaotong.crackme.MainActivity;
-
import java.lang.String;
-
-
-
native public boolean MainActivity.null_securityCheck() //method@0016
-
{
-
}
将apk中的so拖入到ida,导出函数中发现了这个:
Java_com_yaotong_crackme_MainActivity_securityCheck 000011A8
双击跟进,并按F5,查看C伪码:
导入jni.h,将第一个形参设置为 _JNIEnv 类型,第二个形参设置为 jobject,第三个形参设置为 jstring 类型,对相关函数一波 force call 操作后,代码变成这样:
while循环很明显的就是 字符串的逐个比较,只需要找出 v6位置处的字符串即可,双击 off_628C 跟进:
发现一个"wojiushidaan"的字符串,输入试试,还是提示"验证码校验失败",说明这不是答案,真正的答案应该是动态加载的。如果用IDA调试,会发现它会有反调试,真正考察的也是过反调试。不过我们既然有frida,就不用管这个反调试了。
思路:
既然我们知道了静态时的偏移,那我们通过基址 + 偏移,就是动态时的内存地址,将其读取出来,看看该位置的字符串到底是啥。
-
function main()
-
{
-
Java.perform(function() {
-
console.log("Inside Java perform");
-
-
//读取基址并加上偏移,就是该字符串在内存中的地址
-
var soAddr = Module.findBaseAddress("libcrackme.so");
-
var passwordAddr = soAddr.add(0x628c);
-
//菜鸡的我想要一步一步的观察内存中的值
-
console.log(hexdump(passwordAddr, {
-
offset: 0,
-
length: 64,
-
header: true,
-
ansi: true,
-
}));
-
})
-
}
-
setImmediate(main)
用frida Hook后的结果是这样的:
这。。。很明显不是答案啊。不过我们看前四个字节,会发现和内存地址很像(请原谅我还没有学习frida的相关api),因此我们还需要打印下 0xca733450 处的内存,看看是啥:
-
function main()
-
{
-
Java.perform(function() {
-
console.log("Inside Java perform");
-
-
//读取基址并加上偏移,就是该字符串在内存中的地址
-
var soAddr = Module.findBaseAddress("libcrackme.so");
-
var passwordAddr = soAddr.add(0x628c);
-
//菜鸡的我想要一步一步的观察内存中的值
-
console.log(hexdump(passwordAddr, {
-
offset: 0,
-
length: 64,
-
header: true,
-
ansi: true,
-
}));
-
-
console.log(hexdump(new ptr(0xca733450) ,{
-
offset: 0,
-
length: 64,
-
header: true,
-
ansi: true,
-
}));
-
-
})
-
}
-
setImmediate(main)
新增打印0xca733450内存处的代码后,frida自动运行,结果:
我们将这个 "aiyou,bucuoo"输入后(00是字符串的终止符),结果正确:
我们可以用frida自带的api进行内存的读写,直接帮我们把答案吐出来:
-
function main()
-
{
-
Java.perform(function() {
-
console.log("Inside Java perform");
-
-
//读取基址并加上偏移,就是该字符串在内存中的地址
-
var soAddr = Module.findBaseAddress("libcrackme.so");
-
var passwordAddr = soAddr.add(0x628c);
-
-
-
var pwd = Memory.readUtf8String(Memory.readPointer(passwordAddr));
-
console.log(pwd);
-
-
})
-
}
-
setImmediate(main)
运行结果如下:
如果我们想要在输入"123456"也能成功呢?这时候我们可以修改内存里面的内容,将"aiyou,bucuoo"变成"123456",可以这么操作:
-
function main()
-
{
-
Java.perform(function() {
-
console.log("Inside Java perform");
-
-
//读取基址并加上偏移,就是该字符串在内存中的地址
-
var soAddr = Module.findBaseAddress("libcrackme.so");
-
var passwordAddr = soAddr.add(0x628c);
-
-
-
Memory.writeUtf8String(Memory.readPointer(passwordAddr),"123456");
-
-
-
var pwd = Memory.readUtf8String(Memory.readPointer(passwordAddr));
-
console.log(pwd);
-
-
})
-
}
-
setImmediate(main)
运行后,再此输入 "aiyou,bucuoo",会发现校验失败,如果输入"123456",则会提示成功。这样,我们就顺利的修改了答案。
学习内容:
hexdump打印内存
new ptr 构造地址
Memory.readPointer 读取指针
Memory.readUtf8String 读取参数位置处的字符串(UTF8方式)
Memory.writeUtf8String 将第二个参数(字符串)写入第一个参数位置,修改内存。
参考文章:
https://www.52pojie.cn/thread-608505-1-1.html
https://www.anquanke.com/post/id/195215
文章来源: blog.csdn.net,作者:悦来客栈的老板,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq523176585/article/details/109508049
- 点赞
- 收藏
- 关注作者
评论(0)