总体来说逆向的题目质量挺高~感觉学到了不少东西=-=
就是第三题放题时间有点晚233没有公网的情况下做题难度确实比较大
欢迎各位师傅指出疏漏错误和交流~

Re1

JAVA层

用JEB查看反编译代码,JAVA层做了如下操作

有点绕,不知道是出题人故意还是无意地,这个处理写的很蛋疼
除了上述列出的字符以外都是保留不变的
output的范围是彼此分开的,因此可以写出该处理的反函数

def decode(x):if(x>48 and x<57):return x+1elif(x>97 and x<97+26):return 123-x+97returnelif(x>=65 and x<=65+26):return 91-x+65else:return x

接下来将处理过后的输入和this.b()送入native函数this.b(String, String)
this.b()通过getPackageInfo.signatures来获得应用签名,是一个固定值

最简单的方法当然就是直接JEB动态调试挂上去,但是运行起来发现根本没有输入框,仅有一个Check按钮
查看代码感觉没有什么隐藏的,于是找来res/layout/activity_main.xml发现

把它删掉再重打包就可以看到输入框了,当然这样重打包会导致签名不一样233

但是不重打包的话,又会由于输入内容为空而不会进入到b方法的调用中,所以动态调试就陷入一个死循环的尴尬了233

除了动态调试以外,还有两个方法在不进行重打包的情况下拿到签名:

  1. 编写应用取出“第三方”APK的签名
  2. Hook

Hook对我来说比较熟悉,所以比赛的时候用的是Xposed:

XposedHelpers.findAndHookMethod("com.example.crackme.MainActivity",lpparam.classLoader,"onClick",View.class,new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {super.afterHookedMethod(param);String md5 = (String)XposedHelpers.callMethod(param.thisObject, "b");Log.e("test", "get md5: " + md5);}});

这样在点击按钮的时候直接调用b方法即可

代码则是直接照抄,将getPacakagename()的调用改成包名即可(相关的md5及hex_decode也直接照抄,就不另附了)

        try {String sig = this.b(v0.getPackageInfo("com.example.crackme", PackageManager.GET_SIGNATURES).signatures[0].toByteArray());Log.e("test", sig);}catch(Exception e) {return ;}

通过adb logcat -s test即可获得签名

然后下一步拖lib文件夹中的so库来查看native函数
native函数的动态链接库so通常有ARM和x86两种架构,常见的ARM架构安卓平台为手机,常见的x86架构安卓平台则为平板和PC端模拟器
一般情况下,IDA反编译ARM的链接库的可读性要更好一些,这是以前被某位大佬指导过的,因此最好选用armeabi-v7a文件夹下的so库来反编译
然后就掉到出题人的坑里去了_(:з」∠)_

Native层(ARM)

首先在左侧函数列表中寻找JAVA_com_example_crackme_b函数,这是因为导入函数是有命名规则的
然而一无所获,那么只可能是在JNI_OnLoad函数中动态注册了

  j_ptrace(0, 0, 0, 0);v6 = 0;v2 = 65540;if ( ((int (__fastcall *)(JNIEnv *, JNIEnv **, signed int))(*v1)->FindClass)(v1, &v6, 65540)|| (v3 = v6,(v4 = ((int (__fastcall *)(JNIEnv *, const char *))(*v6)->FindClass)(v6, "com/example/crackme/MainActivity")) == 0)|| ((int (__fastcall *)(JNIEnv *, int, char **, signed int))(*v3)->RegisterNatives)(v3, v4, off_4004, 1) )

这里能识别到FindClass和RegisterNatives是因为我将参数a1的类型修正为了JNIEnv*类型,对其右击选择set lvar type即可

注意上面有个ptrace反调试调用,如果之后想要动态调试的话需要把这里处理掉–最简单的方法就是直接NOP掉,然后放入/data/data/com.example.crackme/lib中替换掉原来的lib(需要具有root权限)
另:x86架构模拟器不能调试ARM的动态链接库
大多数的模拟器都是x86架构的,目前我仅知道AndroidStudio下可以创建ARM架构的模拟器,并且速度奇慢无比

这里想要详细了解动态注册Native函数的话可以自己百度一波资料,我们直接找到结构体off_4004的第三个参数过去即可

这里的参数同样要修改为JNIEnv*类型,可以看到一些去参数的JNI方法
后面的反编译没啥好说的,慢慢阅读即可
主逻辑为检查格式:YM-AAAABBBB-CCCCDDDD
AAAABBBBCCCCDDDD保存到一个16字节的数组中
注意这里A和B是顺序传入,而C和D是逆序传入的
然后将参数1–也就是直接传入的签名的md5做一个hexdecode,即32字节的字符串解码成16字节的数组

最后用四个8字节数组进行运算,2个数组负责前8字节、2个数组负责后8字节:

result[i]==~((~(input[i]^md5[i]))^data[i])

其中~表示按位取反运算,和!^0xff效果在python中相同(!表示非,但python中对int使用与~作用一样。而C语言中!一个非零数都会得到0,因为所有整数都可以看做布尔型)
公式很简单,data和result都可以直接提取出来,之前也拿到了签名,因此直接逆运算即可

def decode(x):if(x>48 and x<57):return x+1elif(x>123-25 and x<123):return 123-x+97elif(x>=91-25 and x<=91):return 91-x+65else:return xmd5 = bytes.fromhex("5F01C8622AA0A69B8ABEC3AD9070BA56")
data1 = [ 56, 116, 176, 23, 86, 221, 209, 188]
data2 = [  156, 211, 171, 215, 150, 37, 196, 68]
data1_result = [  85, 65, 79, 70, 76, 79, 65, 113]
data2_result = [  67, 56, 81, 74, 49, 103, 73, 75]
flag = [0 for i in range(20)]
flag[0] = ord('Y')
flag[1] = ord('O')
flag[2] = ord('-')
flag[11] = ord('-')for i in range(8):flag[3+i] = 0xff&((~(data1[i]^(0xff^data1_result[i])))^md5[i])
for i in range(8):flag[19-i] = 0xff&((~(data2[i]^(0xff^data2_result[i])))^md5[i+8])print([chr(i) for i in flag])
output = [chr(decode(i)) for i in flag]
print("".join(output))

这里的难点在于数据处理的时候ARM似乎很喜欢使用负值来作为下标,而IDA对局部变量的切分都是根据base来的,也就是说经常会出现倒着使用数组的情况
例如对于a[20],a[i]在C语言及其反编译中通常表示为*(a+i*1),而ARM总是会使用*(&a[20] - i)的方式来调用,由于符号丢失,所以IDA往往会将&a[20]作为一个变量进而增加理解难度

最恐怖的就是这一段

        do{((_BYTE *)&v60 - v13)[3] = input2[v13 + 12];++v13;}while ( v13 != 8 );

这里的v60从栈帧可以看到

int int1; // [sp+64h] [bp-30h]
int int2; // [sp+68h] [bp-2Ch]
int v59; // [sp+6Ch] [bp-28h]
int v60; // [sp+70h] [bp-24h]

正好是int1后面12个字节的地方,然后[3]表示+3即第四个字节
int1[12-v13+3],随着v13的自增,将input2的后8个字节逆序写入int1的7-15个字节

比赛的时候我没发现逆序,所以搞了半天都不对
最后回头去看了一眼x86的so,发现真简单–简单到我甚至以为这是两个算法,直到最后发现算出来的结果仅仅是后半截逆序的区别而已orz

Native层(X86)

打开x86就会发现,各种日狗的负数下标、按位取反都没有了
取而代之的就是一堆逐字节异或,将数据细心地整理一下拿出来即可

hint中x86就是用来说明这一点的阿23333真是良苦用心


md5 = bytes.fromhex("5F01C8622AA0A69B8ABEC3AD9070BA56")
data1 = [0xc7, 0x8b, 0x4f,0xe8, 0xa9, 0x22, 0x2e, 0x43]
data2 = [0xBB, 0x3b, 0xda, 0x69, 0x28, 0x54, 0x2c, 0x63]
result = [-86, -66, -1^0x4f, -71, -77, -80, -66, -114, -68, -57, -82, -75, -50, -104, -74, -76]
flag = [0 for i in range(20)]
flag[0] = ord('Y')
flag[1] = ord('O')
flag[2] = ord('-')
flag[11] = ord('-')
for i in range(8):flag[3+i] = (result[i]^data1[i]^md5[i])&0xff
for i in range(8):flag[i+12] = (result[15-i]^data2[i]^md5[15-i])&0xff
print(flag)
print("".join([chr(decode(i)) for i in flag]))

这里的第二段其实也有一个逆序操作,但是在整理的过程中毫无意外地注意到了,然后修正一下即可得到flag

关于调试的步骤网上有很多教程、之前的博客里也有,就不赘述了
如果需要在模拟器中调试so,那么需要使用x86的so,并将兼容模式关掉


否则会报B747B9D2: got unknown signal #33 (exc.code 21的错误,这个signal #33查了一下好像是线程切换相关的异常,猜测是兼容模式中通过x86来模拟ARM啥的,不是很懂_(:з」∠)_

另外由于输入内容需要重打包,而校验flag需要正确的签名,因此可以重打包之后通过Hook或者Patch来修改b方法的返回值从而正确校验check
比方说Xposed

            XposedHelpers.findAndHookMethod("com.example.crackme.MainActivity",lpparam.classLoader,"b",new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {super.afterHookedMethod(param);param.setResult("5F01C8622AA0A69B8ABEC3AD9070BA56");}});

Re2

这题的代码量小了很多,Java层操作了一个AES解密然后比较前8个字节
懒得折腾CBC、IV向量啥的,直接动调拿到结果

“A1B8E6PJ”

然后又是Native方法check
与上题一样是动态注册,找到结构体的第三个内容跳过去,发现不可读
刚开始以为是壳,但是看了一波JNI_OnLoad和.init_array都没有可疑的函数
最后注意到了地址是奇数,即最低位为1
这说明这里的指令为Thumb状态

Thumb是ARM体系结构中一种16位的指令集。Thumb指令集可以看作是ARM指令压缩形式的子集,它是为减小代码量而提出,具有16bit的代码密度。Thumb指令体系并不完整,只支持通用功能,必要时仍需要使用ARM指令,如进入异常时。其指令的格式与使用方式与ARM指令集类似,而且使用并不频繁,Thumb指令集作一般了解。

简单来说就是ARM架构中的另一种解释方式,在IDA中可以通过快捷键Alt+G将低位修改成1来切换

这里默认情况下是CODE32,即ARM指令集
所以修改为CODE16,即Thumb指令集试试,发现可读了

再重新按P来CreateFunction即可,这一点绕过以后算法很简单,只是一个Table的累加和而已
不再多说,直接附上代码

s = "6U8DPTKtVHSOYE8IFwpl1T8OCrqfog17"
t = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
sum = 0
indexs = []
for i in s[::-1]:indexs.append(t.index(i))
print(indexs)
flag = ""
for i in indexs:for x in range(32, 127):if((sum+x)%62==i):sum += xbreakflag += chr(x)
print(flag[::-1])

至于RE3_(:з」∠)很容易看出来是Lua_JIT的打包版本,需要从中Dump出JIT的字节码然后通过工具反编译
跟直接做过的JIT的格式不一致,于是没有在断网的情况下做出来
(:з」∠)_
过两天有空再搞他

181124 逆向-2018“柏鹭杯”厦大邀请赛初赛(Re1、2)相关推荐

  1. 2018厦门大学计算机技术分数线,厦大录取分数线2018 各省最新录取情况

    厦大录取分数线2018 各省最新录取情况2018-09-28 10:17:36文/叶丹 2018厦大各省录取分数线是多少,厦大各批次录取分数线是多少,下面是小编从厦大官网整理的分数线相关信息,欢迎阅读 ...

  2. 厦门大学计算机科学每年的保研率是多少,厦大保研率大曝光,高达30%!研厦党该何去何从?...

    原标题:厦大保研率大曝光,高达30%!研厦党该何去何从? 厦门大学2020年研究生推免拟录取名单已经公布了,很多小伙伴们对其推免名额是非常关心的!作为一个贴心的小厦,怎么不能做个好榜样呢?现在就为大家 ...

  3. 2018湖湘杯海选复赛Writeup

    2018湖湘杯Writeup 0x01 签到题 0x02 MISC Flow 0x03 WEB Code Check 0x04 WEB Readflag 0x05 WEB XmeO 0x06 Reve ...

  4. 腾讯优图×厦大再破三项医疗AI世界纪录,提升胸部多器官分割准确度

    李根 假装发自 芙蓉寺  量子位 报道 | 公众号 QbitAI 腾讯的救命AI征程,又往前迈出重要一步. 最新揭晓结果的全球胸部多器官分割大赛,腾讯旗下顶级AI实验室--腾讯优图与厦门大学王连生老师 ...

  5. 励志!送女儿去厦大读研后,爸爸回家就考了厦大的博士,现在是女儿的“学弟”...

    全世界只有3.14 % 的人关注了 爆炸吧知识 2020上半年,在安徽阜阳家里,女儿王睿在房间内上着厦门大学在线专业课,父亲王健作为师范高校教师直播着自己的思政公共课和生命教育有关课程. 然而一到周末 ...

  6. AI研究生的文学情怀,厦大硕士毕业生文言致谢聊三年求学路

    转载自:机器之心 厦门大学人工智能方向硕士毕业生李慧霞的一篇文言文式致谢彰显了现当代携科学素养的AI研究者的风范. 论文致谢仅是一篇论文中的一部分内容,向自己导师.学校.家人以及朋友表达感激之情.而当 ...

  7. 才女!厦大硕士毕业生文言文致谢走红网络,理科生的文学素养令人惊艳

    点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送达 机器之心发布 厦门大学人工智能方向硕士毕业生李慧霞的一篇文言文式致谢彰显了现当代携科学 ...

  8. 2018“云移杯- 景区口碑评价分值预测

    2018"云移杯- 景区口碑评价分值预测 (初赛第9) github链接:https://github.com/demonSong/DF_CCF_CONTEST 前言 实在太忙,找实习,天池 ...

  9. 保研中科大软件工程(还有南开offer,厦大offer,山大offer,软件所offer,南大替补补到offer,东南替补补到offer,浙大替补)

    0.个人背景: 华东某四非,新兴工科专业,专业排名1/65,学院排名1/263,国家奖学金,CET-6 462,只有一点水奖,例如:蓝桥杯全国软件和信息技术专业人才大赛江苏赛区C/C++程序B组二等奖 ...

最新文章

  1. 你可能不知道的小程序
  2. 提高jQuery执行效率
  3. UA OPTI501 电磁波 Lorentz Oscillator Model 3 相速度与群速度
  4. Linux TCP 连接数修改
  5. Java方法中的参数太多,第2部分:参数对象
  6. 特斯拉工程师当UP主评测自动驾驶,结果被公司开除
  7. 转载-聊一聊深度学习的activation function
  8. ORA-12011+ORA-06512–job执行失败问题
  9. Filter过滤器输出HelloFilter
  10. 利用图片指纹检测高相似度图片--相似图片搜索的原理
  11. 浅层砂过滤器 全自动浅层介质过滤系统
  12. [GAMP学习笔记]计算STEC程序中遇到的一些问题小结
  13. 电气工程及其自动化计算机配置,电气工程及其自动化
  14. nginx的网页压缩以及图片的压缩
  15. 代码覆盖率工具lcov
  16. 无线网络经常掉线的原因以及网络的设置
  17. 测试开发进阶——常用中间件概念——线程与线程池理解
  18. 【那些年我们用过的Redis】还记得大明湖畔那些Redis数据吗?
  19. 微信小程序使用wxparse插件,渲染文章不换行问题
  20. 英雄之盾-第11届蓝桥杯Scratch省赛真题第4题

热门文章

  1. Duang~MySQLi 扩展库来袭
  2. Python压缩解压--lzma
  3. Solidity中文文档(内部)
  4. DS 500PM mobil便携式智能图表记录仪订购代码0500 5340_A1_B1_C1_D1_E1
  5. 股票 江恩二十一条买卖法则
  6. 人工智能七大应用领域!你难道还没真香吗?
  7. 华为生成很多html文件,原来只要按下华为手机这个键,100页纸质文件就能立马扫描成PDF...
  8. bbqsql安装使用踩坑总结
  9. python网格交易法详解_给大家科普一下网格交易法
  10. SpringMVC中文件的上传和下载