2019腾讯游戏安全技术竞赛移动端题目解析

2019腾讯游戏安全技术竞赛移动端初赛题目解析

前言

前几天朋友发了腾讯游戏安全技术竞赛链接给我,看了看感觉自己挺适合这方面的比赛。我初三买了第一台安卓机子,从root到网络渗透,从美化系统到自制rom,从脱壳破解软件到安卓开发。16年的时候我高二,CF手游发布,在葫芦侠社区跟着大佬们学习U3D手游的美术资源逆向修改,自己做好枪械贴图逆向封包到AB资源包里,然后发布到自己开发的软件上。这是当时我开发的软件,后来过了将近一年我发现被腾讯游戏安全实验室分析收录了。

https://gslab.qq.com/article-331-1.html

后来高三的时候我自己研究球球大作战的美术资源校验和读取逻辑,给他们提交过资源校验上的漏洞,同时还发现球球将本机登录过得账号存放在SD卡上一个数据库文件里,而其他人只要拿到这个文件就能直接登录该账号,这个漏洞相当于强登器。

上了大学以后安全方面玩的不多了,也就CFM试了试透明墙壁实现透视,拿了天津安全比赛的一个奖,给几个小网站提交了漏洞,这次看到比赛拿奖有绿色实习通道,又重燃了点兴趣。

我先在京东买了本赛前充电推荐的书,腾讯实验室出的游戏安全技术入门,先把书看了一遍。因为之前玩的都是JAVA层的开发和破解,native层开发没做过,第一次接触到so层的逆向,第一次用IDA做调试,但好在高中学了两年的C,自学的安卓开发没白学,自认为底子还可以,多练练就好。

找了历年的比赛题目,发现19年的题目网上还没出现解题思路,就拿这个开始练手。

https://gslab.qq.com/html/competition/20190311/page02.htm

首先上题目

Android客户端安全:初赛评分标准
初赛共2题,第一题为普通版,满分100分,第二题为进阶版,满分100分
2题分数可累加,累加后分数为初赛最终得分
题目
ReqCode与VerifyCode是一一对应的关系,填入正确的ReqCode和VerifyCode点击EasyMode或HardMode按钮出现注册结果提示,成功提示如图所示。
在这里插入图片描述
要求根据CrackMe写出对应注册机,注册机能根据任意合法请求码生成正确的注册码。
本程序运行要求Android系统版本大于4.4, 并且不支持模拟器

答题要求:
注意,提交的答案必须完全符合以下条件,否则视为为无效答案:
1.提交的答案包括完整的注册机代码、注册机使用说明(包括一对可用的ReqCode和VerifyCode)、详细分析过程文档,三者缺一不可。
2.注册机实现方式仅限于python(须注明版本),java和C/C++.Java或C/C++的代码需要包含工程文件,能在vs2008或vs2015平台直接编译生成注册机,或者可以直接在android下执行的bin文件或者以apk文件形式提供。
3.不能截取本题目二进制文件逆向汇编作为注册机的源码。
4.不能以任何形式将本题目二进制文件做为依赖库。

评分标准:
1.本题满分100分
2.使用能够体现技术水平的方法获得一对能够在CrackMe中校验通过的ReqCode和VerifyCode,可以获得10%分数。
根据提交的详细描述分析过程文档,视具体破解的程度及方法给分,最多可获90%的分数。

首先按照我个人习惯,用MT管理器打开APK安装包,发现dex没有加壳,直接打开反编译成java语法,看了一下JAVA层大概就是将用户输入的req字符串先自己校验一下格式,如果格式没问题再用so层的方法校验一下,接着将req和Verify俩字符串传入so层的verify函数完成注册机校验。题目主要考察的都是so层的东西。MT反编译后截图
说实话我这是第一次见到java加载so库,我之前知道java可以调C++,但着实没见过,百度了一下这个就是JNI。static静态块语句加载了两个so库在这里插入图片描述,并且声明了三个native层的方法,cmd看了下java层的代码是作为一个log打印方法可以不用管,inputcheck方法是作为输入的reqcode校验格式,verify就是校验加密了。
那这里暂时还不知道三个方法分别在哪个so库里,OpenCV看着很眼熟,搜了一下是一个C++图形库,怀疑是出题者故意混淆视线。于是我把crackme.so文件改名为OpenCV文件打包进apk覆盖原来的opencv文件,签名安装APP正常运行,所以opencvso文件是不起作用的。
接下来就是用IDA静态分析Crackme.so文件,拖到IDA里发现没有JAVA_开头的函数。一般在java层声明的native方法都要和so文件里一个JAVA_包名_方法名的函数绑定的。一开始我以为我搞错了,又看了一遍opencvso文件,里面也没找到那三个原生声明的方法。后来我找了几天资料,问了我朋友,他让我搜下JNI动态注册。所以如果在so文件里没找到JAVA_开头的函数,一般就是JNI动态注册绑定的so层函数。JNI动态注册一般在JNI_OnLoad方法里用RegisterNatives函数来注册。在这里插入图片描述
就像这样,JNINativeMethod结构体里存放了三个参数,分别是JAVA层方法名,方法签名,SO层函数地址,动态注册实际上就是把方法和函数绑定到一块。所以照这个原理来讲。我们只要找到对应的结构体,就能知道对应的so层函数了。
在这里插入图片描述
在so文件里找到JNIOnLoad函数后F5一下,找到了RegisterNatives函数,推断第三个参数就是结构体地址,第四个参数是注册的方法数量,跟进去第三个参数。
在这里插入图片描述
到了这里推断每个结构体有三个参数,三个方法是九个参数,数量上是对的上的。但这里%4我不知道什么意思,猜测是开辟空间但未赋值。进一步猜测会有个函数来给这块空间赋值,应该就是右侧提示的sub_ACF50400,DATA XREF书上说是指其他函数操作过这块内存,然后跟进到去。
在这里插入图片描述
这块汇编看的不清楚,直接F5看伪代码
在这里插入图片描述
看起来就是一个简单的赋值语句,但是应该有三个java方法名和三个方法签名,这里做了混淆处理,通过一个ID号用sub_ACF57968这个函数来取到对应的字符串。剩下三个应该就是三个native层函数了,只是这里还不知道谁是谁。
在这里插入图片描述
这函数跟进来实在是太长了,静态分析就太过费劲,考虑动态分析直接看内存吧。动态分析步骤我先略过了网上都有的我也是现学现做踩坑无数讲的不一定有其他人的好。
这一步我卡了几天,一开始用的模拟器做动态调试老出问题,因为这次题目的so文件是arm指令,模拟器是X86架构。但我自己的NEX机子root不了。过了几天我把我妈的一加一拿回来之后才开始真机调试
接下来我在动态调试过程中遇到了一个问题,因为注册函数在JNI_OnLoad里,JNI_OnLoad函数执行的很早,需要把app设置成调试模式以中断APP运行,这样可以从app运行之前连上IDA。但我app调试模式老是自动调试libc.so,而且F9跳不过去,按了F9APP还是阻塞中,只能按F8看着一步一步在libc里跑完又跑到Dalvik,跑着跑着还崩了。我现在还不知道哪里的问题,只能换个思路,不分析注册函数结构体里具体的值,只需要知道三个函数里哪个是校验函数就行。
然后我用app非调试模式,也就是app加载完了以后连上IDA调试,先给三个函数里第一个函数打了断点,点了check按钮发现没反应,也即是说第一个函数应该就是CMD函数,app校验过程中没有调用它。
在这里插入图片描述

这里我讲一个我踩的坑,动态调试的时候so文件IDA不会自动解析成函数或者指令,统统都是DCB,这个时候你下断点会弹框,你需要先按P把DCB编程函数或者按C变成指令。这个卡了我好几天,没基础真的泪。

接着我下了第二个函数的断点,这次按按钮会断了。但是按钮按下时同时调用了input和verify两个方法。
在这里插入图片描述
这里可以看到先input校验,再执行verify校验,所以我想了个法子,把reqcode改成1111-223363333-4444,这样子程序流程只会执行input校验,酱紫测出来第二个函数中断了,也就是是说第三个函数就是verify函数了。
但是写到这里我突然想到,如果把二三两个函数都断点,然后正常执行程序,哪个先断哪个不就是input校验了吗…。。。
既然知道了第三个函数是校验函数,先静态分析一下。
在这里插入图片描述
说实话静态分析我很难看出来什么,初学者对不太能看得懂。推测一开始应该是把java层传入的字符串jstring类型转成C++处理的字符串类型,然后以DCheck函数(这个函数名是我备注的)。跟进去看一下校验函数。
在这里插入图片描述
果不其然奇长无比,直接动态分析一下吧,但我有注意到strcmp函数就是标红的那个,这是一个C语言里用来比较字符串的函数,而且它的返回值最终作为校验函数的返回值,我猜测断点在这里很可能会拿到正确的秘钥。
因为刚听竞赛举办方说20年的移动端题目不再是做注册机了,只需要破解一个验证码就行,所以我这次文章也就会破解出一组key,虽然题目要求把校验算法和注册机做出来,但分析伪代码对我一个初学者来说有点难,可能我后面会再写文章把算法捋一遍,但这里我就先只拿到最低要求一组key,好歹能混个10%分数。
调试之前给verify方法下好断点,然后在app里点按钮check
在这里插入图片描述
我们这里按F5伪代码调试更直观一下
在这里插入图片描述
先看一下几个形参分别都是什么
a1a12应该是jnienv,这个我不太熟,a3指向栈里一个地址,栈里这个地址指向堆内存
在这里插入图片描述
显然a3就是我们输入的reqcode,下图为a4,即verifycode
在这里插入图片描述
a5值为1,应该是esaymode的意思,基础题,进阶版可能是0或者2,搞不好俩题是一个so文件,我还没看进阶版。
在这里插入图片描述
然后reqcode赋值给v25,verifycode赋值给v24,
在这里插入图片描述
然后reqcode赋值给v20,verifycode赋值给v17,reqcode又给v16,
在这里插入图片描述
这里连接了一个字符串出来,结果在内存里找字符串的时候看到这个

这就是我之前想调试给注册方法的结构体赋值语句的加密字符串,方法名和方法签名。
继续说正事上面做了一个字符串出来com/tencent/sec2019/crackme/Native././proc/self/ma/flag.jpg.这个是apk里的一张图片在这里插入图片描述
我估摸着这里应该还是出题者混淆视线,没啥用。然后到了比较关键的地方
在这里插入图片描述
!](https://img-blog.csdnimg.cn/20200331172039334.png)
在这里插入图片描述
v16是一个字符数组,指向的值就是我们输入的reqcode1112222那个,v17指向十六进制数30633010,转成字符就是0c0,应该在V17的地址后面几个字符一直到\0为止,这里IDA把它当做整形数据了。a5值为1为基础版加密。那到这里就比较清楚了。这个函数就是真正的校验函数,我们F7跟进去看一下。
在这里插入图片描述
跟进去发现a1成了二级指针,到内存里看一下
在这里插入图片描述
注意arm设备一般是小端,所以这里我们倒着把四个字节写出来B2E0B110再跳到这个地址
在这里插入图片描述
这里我不太明白为什么这里是不连续的,但这个跟上一层函数看的一样确实是reqcode。
在这里插入图片描述
然后这是a2指向的内存就是verifycode,a3仍旧为1.
在这里插入图片描述
接下来reqcode给了v3,verifycode给了v29,V33为1
在这里插入图片描述
看到这里明白为什么之前的内存不连续,这里可能是12个字节为一个单位,四个数字只占了四个,空余出8个,这个循环嵌套函数,一层一层的看不懂了。
在这里插入图片描述
然后判断是基础题还是进阶题进行加密,这段因为调用了其他函数,不知道其他函数具体什么作用,猜测应该是加密处理了reqcode,最后计算出一个串
在这里插入图片描述
然后调用了这个函数将计算出的串转成了一个8位字符串
在这里插入图片描述
在这里插入图片描述
然后将这个8位串以十六进制输出前8位,不足8位用0补齐。
在这里插入图片描述
这里是把输出到V59的8位字符串的指针,和我们输入的verifycode相比较,这里V59的值如下图
在这里插入图片描述
那到这一步很清楚了,V59就是程序计算出来的正确verifycode,和我们输入的code比较后并将返回值作为函数的返回值。但是我吧0X61333436输入到app里显示错误,那么那里出错了呢。
在这里插入图片描述
这段函数猜测应该是出题者混淆视线的,先把V23的8位字符串输出成8位十六进制数字,然后把地址传入strcmp函数,在IDA里我们看比较字符串以为是0x61333436,实际上传入的是这个数字的地址,也就是说,这个地址依旧是V23的8位字符串地址,strcmp函数真正比较的是那8位字符串643A22CA,输入到程序里校验通过!
在这里插入图片描述

那么这里我们拿到的key就是

1111-2222-3333-4444
643A22CA

就先写到这里,如果要具体分析算法做注册机,需要把DCheck函数里调用的其他未命名函数都跟进去看一遍
在这里插入图片描述
可以看到调用过程非常…所以要分析算法需要再多看看,主要知道这个长串的算法就可以了
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值