安卓逆向学习之CyberTruckChallenge2019

Challenge3 to unlock car3. “Mr Truck: Unlock me Baby!”

  • 50pts: There is an interesting string in the native code. Can you catch it?

  • 100pts: Get the secret generated at runtime to unlock the carid=3. Security by obscurity is not a great design. Use real crypto! (hint: check the length when submitting the secret!)

  • 参考:CyberTruckChallenge19

静态key

第一种解法

  • 分析题目后发现应该是对原生代码进行一个分析,所以应该会加载.so文件。
  • 在MainActivity中找到了对原生库的加载:
    在这里插入图片描述
  • 在android killer中发现其实只有一个原生库:
    在这里插入图片描述
  • 想要找到其中的字符串一个简单的方法就是直接用strings命令,找到了静态flag
    在这里插入图片描述

第二种解法

  • 而在参考CyberTruckChallenge19中作者使用了Frida动态获取该字符串
  • 具体做法是首先打开so(作者使用的是Ghidra,我是用的是IDApro)分析发现里面只有一个函数,查看其C源码:
    在这里插入图片描述
  • 发现v18的值比较特别:
    在这里插入图片描述
  • 首先将一个字符串赋给了v18(其实这里以及可以判断这是静态flag了,不过作者在Ghidra好像没有获取到这个值),然后通过strlen函数获取了v18字符串的长度,最终存放在v13中,在while循环里通过比较v12与v13(字符串长度)的大小关系进行循环判断,并且将该字符串与另一个字符进行了异或操作。
  • 上述整个过程其实非常像用密钥key对一个值进行加密的过程了。因为这里strlen()函数用该字符串做了参数,所以思路就是截获strlen()函数的参数即可
  • 但是这里存在一个问题:在函数中可能有多次调用strlen()函数的地方那么哪一个是我们想要找到的呢?
  • 作者使用的方法是判断strlen的返回地址,若该返回地址在上述第三方库的内存地址之内,那么就是该第三方库调用的strlen函数
  • 编写JS脚本如下:
// 该函数用来确认strlen函数是不是libnative-lib.so库中的那个,因为整个程序可能调用很多strlen
function isAddressInModule(moduleName, address) {
  var module = Process.findModuleByName(moduleName)//返回对应的库
  return address >= module.base && address < module.base.add(module.size);//base:基地址 
}

function challenge3() {
	//使用Interceptor.attach拦截目标函数的调用
  Interceptor.attach(Module.findExportByName("libnative-lib.so", "Java_org_nowsecure_cybertruck_MainActivity_init"), {
    onEnter: function(args) {
      // 用第二个Interceptor 来attach libc.so 中的strlen函数
			// 用this.strlen指向下一个Interceptor便于后面detach
			//this指的是第一个Interceptor
      this.strlen = Interceptor.attach(Module.findExportByName("libc.so", "strlen"), {
				//如果在Java_org_nowsecure_cybertruck_MainActivity_init中调用了strlen就会进入onEnter
        onEnter: function(args) {
          // 对感兴趣的strlen输出其参数
		//这里的this指的是第二个Interceptor对象所以是strlen函数
		//this.returnAddress是strlen函数的返回地址也就是调用stelen下一条指令的地址(应该在libnative-lib.so库地址的范围中)
          if (isAddressInModule('libnative-lib.so', this.returnAddress)) {
						//如果在这个范围中就输出strlen参数的值
            console.log("Challenge 3 key: "+ args[0].readUtf8String(32));
          }
        }
      });
    },
    onLeave: function(retval) {
      // 退出第一个Interceptor时不在监听strlen
      this.strlen.detach();
    }
  });
}

function c3(){
	//获取org.nowsecure.cybertruck.MainActivity类的实例
	var mainActivity = Java.use("org.nowsecure.cybertruck.MainActivity");
	//hook c3的k方法,在k方法中对库进行拦截,并执行k方法
	mainActivity.k.implementation = function(){
		challenge3();
		this.k();//要在implementation中运行
	}
}

//frida的main
Java.perform(function(){
	c3();
});
  • 使用Frida进行hook并加载脚本就可以得到strlen函数的参数啦:
    在这里插入图片描述
  • 点击unlock按钮后:
    在这里插入图片描述

动态key

  • 经过上面的分析我们知道动态key其实就是v8里的值,但该函数没有返回v8,所以不能用常规的方法输出v8的值,这里的思路如下:
  • 当该函数返回时,存在栈中的局部变量并没有被清除,这时我们只需要输出栈顶指针更新前到更新后这之间栈的值就可以得到动态的key
  • 又因为栈向低地址增长所以在Java_org_nowsecure_cybertruck_MainActivity_init返回后输出一定空间的sp指针之前的值就可能输出v8中存储的值。
  • 所以在上面脚本的onLeave中输出栈中的情况即可
  • 新的onLeave如下所示:

test

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值