从事移动安全行业以来,一直在做Android方面的安全及逆向,也曾想过了解下iOS的机制,奈何总是对自己下不了决心,一方面觉得精力有限,Android上好多东西自己也并没有完全熟练掌握。另一方面可能自己太懒,不太想花费太多时间成本,何况如果没有实操,所学的一切很快就会忘记,所以之前也仅仅是在心里埋下了这个种子而已。不过大概几周前,笔者实属有幸,因机缘巧合,向iOS逆向大佬猫大人好好请教了一番,至此也算是入了个iOS的小门。
因此本文也算是一个从Android视角来看待iOS逆向,iOS相关的深入点不会进行阐述。也仅以文本纪念下和大佬们在一起做安全逆向的时光~
从这里开始,是比较基础的东西,但是由于我也是刚刚学习到,所以就列出来记录一下,有基础可以直接跳过第二节,从第三节/或第四节阅读。
在Android上通常用于逆向的手机是pixel/nexus系列,Android系统6~13都可,然后自己刷入magisk进行root。而iOS呢肯定是iPhone了,但是如何选系统如何自己越狱呢?因此在了解相关版本后,为了方便,在某宝买了一台二手的iphone8(800左右),ios14左右的系统,商家已经帮你越狱好了(unc0ver,14系统上每次手机重启还需点击软件进行越狱,不麻烦)。
当然其他手机也可以,按照大佬的建议,iOS系统最好不要最新,像13,14左右就可以,手机的话像年头久一点的iPhone 6(大概3,4百左右),iphone8/X/SE,也都可以做逆向。切记!买手机时要问有无id锁,是否可以刷机。如果手机来源不正规,自然就会被锁住,也不方便逆向用了。
手机选好后,自然就要安装一些相关软件,就像android逆向root之后要按各种插件,比如抓包用AlwaysTrustUserCerts信任证书之类的。iOS也是一样,iOS越狱后有个Cydia的商店,里边可以下载安装各种越狱插件,包括自己写的越狱开发插件也会在这里进行管理。
常用的iOS插件:
当然以上的插件,是我在买好手机后,就已经安装好了,自己并没有额外做什么操作,除了frida。
frida:frida的安装在cydia里默认是最新的,因此可以去frida官网的release(https://github.com/frida/frida/releases)下载对应的包,这里和android不同的是,要下载deb的包,然后通过如ifunbox的工具,安装到手机的目录,然后在手机上通过Filza点击deb包进行安装。安装好后,frida由cydia进行管理,frida-server默认开启,类似Android上的MagiskFrida
这里记录一下遇到过的问题,及一些杂项。比如手机越狱后,发现开不开机无法进入主界面,有可能是注入的插件有问题。可以通过ssh进入手机目录:$ ssh root@127.0.0.1 -p 2222 ,默认密码是alpine。然后可以进入插件列表 cd /Library/MobileSubstrate/DynamicLibraries,这里是所有安装过的插件列表,比如我这里是这样的,也可以看到我这个二手手机可能也是用了好几年淘汰下来的
所以如果你怀疑哪个插件有问题,可以重命名这个插件,然后在上述目录重启系统进程:killall -9 SpringBoard; killall -9 backboard。
或者可以重启所有进程:ldrestart 。总之到这里,我开不开机的问题是解决了。
通过上边的知识,即便没有ios逆向基础,也可以开始准备逆向了。
由于软件要上架appstore,苹果市场是默认会对应用进行加壳的。因此我们的第一步在appstore下载好相关软件后,就可以进行脱壳。
手机上安装好软件后,电脑开启端口转发:iproxy 2222 22
。然后进入frida-ios-dump脚本的目录直接执行./dump 包名
稍等片刻,在当前目录会生成脱壳后的ipa文件。然后我们需要找到该应用的主包,以便拖入ida分析:
首先将脱壳后的.ipa文件改后缀为.zip(和Android APK一样,也是个压缩包),解压后进入Payload,会有一个.app的文件包
点击显示包内容,通常我们要拖入ida里分析的包,名字和上层xxx.app是相同的,然后就可以拖进ida,由于包比较大,ida分析时间会很慢
这里也使用class-dump将头文件导出class-dump -H ./osee2unifiedRelease.app/osee2unifiedRelease -o ./osee2unifiedReleaseH
,导出头文件的作用是,方便我们查看OC中类的所有方法/属性
这里和Android没什么区别,在手机上安装charles证书,信任证书,然后抓包。我们关注下相关的登录接口
发现body是加密的,于是看看body是如何加密的。
首先在ida里搜索登录相关字符串/api/account/prod/sign_in,发现可以直接找到,查看相关交叉引用
发现很多,随便找几个先看看,都是调用了同一个函数sub_1063DF0A8(),但是奇怪的是这个函数的第二个参数/api/account/prod/sign_in,在F5里并没有看到
但是在汇编里是能看到的,我不知道这样做的目的是什么,看了很多iOS逆向的帖子也没有看到这样的情况,或者说这是ida反混淆的问题?总之,这不重要。(如果有大佬知道,烦请解答)
然后通过回溯堆栈(console.log(Thread.backtrace(this.context, Backtracer.ACCURATE) .map(DebugSymbol.fromAddress).join('\n'));
),看能否定位到关键信息。
这里和Android逆向so也完全一样,稍有区别的是,iOS查找基址填入的是整个库名,如:
回溯出来堆栈之后,可以对整个堆栈链路的函数进行分析及hook,不过遗憾的是,或许是对iOS网络框架不熟,我并没有办法仅凭查找url,就能定位到加密算法。不过逆向有意思的地方也在这里,当一条路走不通了,放松下自己换一条。
我们观察body其实可以发现他是个base64,那我们大概猜一下,他使用系统库的方式。
经查资料,可以hook OC中NSData的base64EncodedStringWithOptions方法,在OC的语法中函数调用的方式可以用[类名 方法名:参数],hook的方式发现网上大多采用frida-trace。在我印象里好像没什么印象,即便有,也是听了个名词,因为在Android中我基本没用到过。于是使用这个命令进行hook,减号代表实例方法,相反加号代表类方法,只是个格式而已,也可以用*匹配
这个脚本会在当前目录生成./__handlers__/
文件夹,并生成对应函数的js代码,发现其实这就是Interceptor.attach的那个回调函数,只不过frida-trace帮你自动生成好了,方便你改脚本。
当然到这里,运气也比较好,发现返回值的确可以跟抓包的body对应上,于是打堆栈
进入[ encryptDataBase64String:]函数看看,发现密钥(93020...)是写死的360位的hex字符串(hex转换为bytes后长度是180)
总体是进行了三种加密,分别是
sub_106B3E2A0 -> preDataIn160:secureKey:iv:
sub_106B1CA20 -> laesEncryptData:secureKey:iv:
sub_106B3E2E0 -> preDataOut160:secureKey:iv:
这里的_objc_msgSend是OC底层通过发送消息,来进行函数调用的,其中a1是类,第二个参数是方法名,其余是参数。我们也可以到之前class-dump出来的头文件里看看,还是很清晰的
然后我们hook这个三个函数的入参和出参,就可以得到整个从明文到密文的加密链路。当然,这里需要注意的,虽然我们还是可以使用Android frida hook的方式(基址+偏移),但是我们打印参数时,却不能脱离OC的方式。
比如我们hook 这个函数laesEncryptData,即便我们知道真正的参数从a3开始(类似OC的调用约定吧,从第三个参数开始传参),但是我们像在Android那样,仅通过hexdump是无法打印出预期的值的。打印OC有点类似打印JNI,需要使用对应的方法,比如在输出a3时,可以先使用new ObjC.Object(this.arg2)
打印下对象,如果输出的类似这种{length = 32, bytes = 0x36666161 39316535 38616339 63346661 ... 37363438 38323730 }
(如是字符串类型直接能输出)就可以使用Memory.readByteArray(data.bytes(),data.length())
来进行hexdump了,其余的没什么区别。
在我们定位好关键算法之后,通常为了测试方便,往往是需要主动调用函数的,和Android无异。比如这个app,他总是有线程在做加密,即便把网关掉了也不行,这对于我们分析输出日志是很不方便的。我们可以通过Interceptor.replace函数替换掉某个方法,而我们自己主动调用时,调其内部的方法即可。
比如,我们这里分析到laesEncryptData函数内部会调用sub_1000902A8方法,这个sub_1000902A8方法内部会调用sub_100090420这个方法,因此我们可以主动调用sub_100090420,替换掉sub_1000902A8,就可以去除干扰(另两个函数preDataIn160,preDataOut160不是核心算法,也不复杂,这里不做过多阐述)
这里还有一点和Android不一样,就是地址偏移,在iOS中,使用基址+偏移的方式hook时,ida中的地址要减去10000000。下为替换算法
当然,在这里我遇到了一点小坑,其实如上的反汇编代码是不准确的,该函数共有9个参数,根据arm64的调用约定,超过8个参数,会通过栈传递,也就是最后一个参数v10,并不是如伪代码那样直接传递的。
另外一种定位a9是如何传值的:跳转进函数后,查看a9的交叉引用,可以发现v20是个数组,最多用到了v20[7]
结合frida hook的结果
可以判断,a9是一个int数组,长度为4(int占4字节空间)*8=32(0x20)大小。
因此使用frida构造a9参数时使用:
主动调用的代码如下,其中sub_100090420这个函数的前8个参数分别的,输入/长度,输出/长度,iv/长度,key/长度,输入随便找的hook时真实的数据
至此主动调用成功,后要详细分析sub_100090420算法
在我们正式分析魔改的aes算法之前,我想应该是要介绍下aes标准算法的原理,就当是回顾下知识点,所以这一节可能会比较枯燥,不过这里还是只介绍下相关的概念,不会太深入细节。因此这一节可以粗略的过下,甚至跳过,后面的内容如果迷惑了,可以返回来看看。下面我们大概概述下标准AES算法的加密流程。
AES-128接收16字节的明文输入,16字节的密钥,输出16字节的密文结果。且每增加64位,AES-128/192/256算法的循环会增加2轮。
以AES-128为例,共加密10轮,其中包含的操作为:
AddRoundKey:轮密钥加(通过密钥编排得来,首次使用为主密钥)
其中初始变换只执行AddRoundKey,算法循环第1~9轮依次执行SubBytes,ShiftRows,MixColumns,AddRoundKey。最终轮(第10轮)不包含MixColumns。算法完毕
上边就是AES的整体流程,和要用到的知识点。
回过头来,接着看sub_100090420这个函数,确实已经脱离了OC,进入了熟悉的C环境,虽然没有混淆,但是其内部分支跳转太多,静态看起来也不是很方便。
于是我用到了Virenz大佬写好的stalker脚本,分函数trace和指令trace,格式非常清晰方便,推荐使用
分别对sub_100090420进行函数/指令trace,首先看下function trace,发现调用的函数并不多,这里先将关键函数的作用写出,后续将详细分析该算法是如何魔改aes的
通过function trace打印了函数执行流程后,可以查看密文result的交叉引用,并hook相关函数(从function trace来看并不多),打印输入输出,最终定位到了这里
看下sub_100094360这个函数
发现这个函数将result分割16个字节,每次循环首先将明文与iv异或并作为sub_100091FAC(v10)的参数,调用完后,将结果重新赋值给iv,并进行下一轮循环。
这里其实就是分组密码常见的CBC模式,因为aes也是分组密码,在进行加密之前,先将明文分组,如果不够分了,就进行相应规则填充数据。过程就是将明文分组与前一个密文分组进行XOR异或运算,首轮的话就与iv异或,上述代码ida反编译的很好了,对照下图,应该就可以理解了
接下来我们要分析核心算法sub_100091fac,先看下好像并不多
他的第一个参数和第二个参数是相同的,都是明文,在函数结束后也都变成了密文,第三个参数是密钥key,从上面来看也并不是16位的。
其实逆向到这里,我一直怀疑着,就是bangcle算法究竟把aes魔改到什么程度?虽然最外层的算法名写的是laes,而且上层函数也的确明文分组与iv异或,并且根据trace及分析来看,中间也的确是9轮循环。那么他是否仅仅改了码表而已?还是说不仅改了码表,甚至连aes内部算法也重写了?我能否对照标准的aes来还原他?以及他的key为什么是180位,而标准的aes仅仅是16位,又如何用key呢?带着这些个疑问,我开始了进入了使用trace还原算法的世界。
首先我这里还原的方式,是通过之前的指令trace日志+clion还原代码时调试一步步分析。
如上边这一段代码(1)处,把ida里的伪代码拷贝进去,并控制好和trace时一样的入参
发现这里的v3返回0x80,查看ida汇编地址,找到对应的trace结果,ida的伪码分析没错
那这里判断算法是否输出正确,有两种方式。首先是传统的方式,这个循环里最后生成的值是*(&v44 + i),而这个值最终是通过异或得来,因此我们查看ida里汇编的地址
也即w12,也就是这16次for循环的结果,因此去trace里对照1000920B8地址
第二种方式,得益于frida stalker在trace时可以定制化输出,比如在大佬的trace脚本中,我们可以将readCString()改成hexdump出了两行内容
于是我们也可以直接去trace搜整个for循环的结果4c da e9 c4 5a a1 0f 28 1e a2 01 ed 5b b6 62 b9,发现内存里有很多地方都有,也即证明了此步还原准确。
接下来,又进入了一个大循环中for ( j = 1; j < (v3 >> 5) + 6; ++j )
因为上一步中已经还原出v3=0x80,因此手动计算下(v3 >> 5) + 6 = (0x80 >> 5) + 6 = 10。也即aes标准算法中的9轮循环。
其实上一步的算法还原,还算容易,只需要照抄ida代码即可,但是这一轮算法里,虽然看起来伪码很整洁很规律,4个一组4个一组
但我遇到了很疑惑的问题,甚至还怀疑了ida是不是有问题。
首先就是,这一部分代码里,无论是输入还是输出都是局部变量。比如像这一行还好说v28 = dword_106EF9168[v44] >> 24;
v44也就是上一个算法的结果,但v28是谁呢?甚至于下一个4组v32 = dword_106EF9168[v48] >> 24;
v32,v48都是局部变量,这又该如何还原呢?
首先还是先猜,最开始计算了16个字节的v44的值,那就先尝试下使用v44,于是我还原的代码如下
和之前一样去ida找地址,在trace里查结果,像这个计算查右移相关的指令lsr即可。很幸运,尝到了一丝甜头。
于是,第一个四组的计算已经成功。可是到了下一个四组
我尝试将v48认为是v44+1的值(0xda)来进行计算(v44 = 4c da e9 c4 5a a1 0f 28 1e a2 01 ed 5b b6 62 b9,最最初计算的16字节的结果,在第一组v44等于4c),但遗憾的是我得出来的值却无法与trace结果相对应
我计算出来的v32/v33是0x18/0x67,但trace的结果却是0x2d/0x37 ??? 看来事情并没有我所猜测这么简单。于是分析trace,看看值是怎么来的。
发现两个值都是从0x2d3737af偏移而来,而0x2d3737af也是魔改后码表里的值dword_106EF9168[v48];
,也就是说真正要看的是v48如何等于5a。跟到5a最初被赋值的地方ldurb w10, [x29, #-0x14]; # x10: 0x6d --> 0x5a
发现是从x29-0x14的地方取值,按正常逻辑,只要搜,谁往[x29, #-0x14]的地方赋值就行,不过trace里搜不到。所以到这里差不多就比较懵,值跟不下去了。
于是我又换了另一种猜想,如果v44不是一个char数组呢?假设他是一个int指针,那么如果v48=*(v44+1),那么v48的值应该是v44往后偏移4个字节,于是查看完整的v44: 4c da e9 c4 5a a1 0f 28 1e a2 01 ed 5b b6 62 b9,第一个值是4c没问题,第一个四组验证过了。如果按照刚刚的猜想,往后偏移4个字节,那么v48应该是?5a!发现对上了!那赶紧趁热打铁,验证接下来的两个值是不是1e和5b,也就是v49=1e,v50=5b。查看下trace
漂亮!那么到这里我心中大概有点数了,接下来的4组应该是继续从下一个偏移0xda开始,然后分别使用da,a1,a2,b6。也即他把这个16字节的数组"立"了过来
然后继续验证,发现猜想中本应是da的值,但是却变成了a1?本应是a1的值,却变成了a2?
咦?这难道,就是AES的行移位算法?!没错
我们最初介绍了aes的标准流程时,提到了aes的内部小算法,这个就是行移位算法。aes将16个字节先看成是一个4*4的矩阵,然后分别对矩阵进行变化,所谓的行移位算法也是固定的一种模式,如下图
也就是说,我们这16个字节真正的使用方式是,先进行ShiftRows行移位,然后在进行SubBytes字节替换(魔改码表里取值),这也是bangcle_laes的一个混合小算法。
那么我们还原算法时,就要自己写一个行移位了,而之前猜想v44是一个int指针也完全不对,他仍是一个char指针,只不过取值之前,已经对里边的内容进行了变换!
其次在将行移位后的矩阵进行转置。
因此,我们还原算法时,就可以按照标准aes那样,先将16字节转成一个4*4的矩阵,然后对矩阵进行行移位操作等变换。
最终在内存里的格式变换为:
还原过程中最困难的部分已经完成,其余部分按照之前的思路也都可以对照,结果不对就跟trace分析。
至此,9轮循环里的混合算法还原完毕。
其实到这里,虽说算法还原成功,但是过程却极其艰难。我也抱怨过ida里为什么不把算法的过程表现出来呢?看来还是ida反汇编有问题?这确实是我当时的疑惑。后来与Virenz大佬讨论一番,发现并不是ida没有表现,而是因为你并不理解ida的"想法"。
回过头来看,发现ida早已清清楚楚的告诉了你,虽然他不能精准的将代码全部还原,仅仅以一些局部变量表示。但是他会告诉你他反汇编的内在逻辑。比如上图中可分为两块,v28~v43这16个字段是顺序的,通过结果来看其在内存中也是连续的,也即可以表示为一个数组。
再比如v44,v48,v52这些码表里的索引值,也都清清楚楚告诉你他们的关系,仔细观察的话,其实是可以看出行移位的,内存值里为:
上图第1块里取的4个索引为,v44,v48,v52,v56
到了第2块里取的4个索引为,v49,v53,v57,v45
可以明显发现,的确进行了行移位操作。如果还原时能了解这一点,可能就不用费劲追trace,或许只用看也能看出大概了。
通过上边的分析,这里其实也大差不差,唯一有些注意的点就是看好每一步小算法的入参出参,也就是谁进行了运算,又返回给了谁。
最后我们对照下完整算法的返回结果:
还是得益于frida trace时的定制化,我们可以直接在结果中搜即可
也就证明了算法还原成功。
通过上边的分析,发现这个bangcle的AES魔改的很厉害,基本就是一个AES的架子,内部已经完全混乱了。其次还有他的密钥key我们还没有分析,也在这里说明下。我们都知道,正常的AES key是16位的,他的主要作用就是在AES算法中进行AddRoundKey(轮密钥加)的过程。
AddRoundKey的算法就是将16字节的“输入”与16字节子密钥进行异或得到输出数据,而子密钥的获取是通过密钥拓展编排算法得来(密钥编排算法就不做过多介绍,较复杂)。从之前的AES算法流程中也可以看到,从初始变换到10轮加密计算,总共用到了11次AddRoundKey,也就是说,密钥扩展编排后,总共会占11*16=176个字节的内存空间。
而bangcle的AES原本传入的密钥就是180位的,也可以说,他把密钥编排的算法前移了。那可能有小伙伴就问了,你不是说密钥编排后,总共是176位吗,那多出来的4位呢?其实在进行加密算法前,他也对密钥key进行了处理。我们看下相关的计算
可以清楚的看到,他key的前4位( key[i%3] )实际上是用于"解密"后边176位的密钥,也就是说原始的key实际是加密(异或)过的。这样做的目的,我也只是有个猜想,那就是他解密后的176字节的key真的是用密钥编排算法算出来的,而不是没有规则的key。因为密钥编排算法编出来的子密钥,实际上是能逆推出主密钥的,有兴趣的小伙伴可以去了解下DFA差分故障攻击的原理,也是会用到这一点。
至此,我们完整的分析并还原了魔改的aes算法,想必如果这个算法再加了混淆,难度可想而知。
到这里,本文也已经结束了,也许各位已经看的很累了,但总之还是希望对你有所帮助!本文的样本相信仔细看的小伙伴都能看出是哪个app,想练手的话就在AppStore下载最新版就行。
最后感谢观看,谢谢!
参考:
https://github.com/Virenz/frida-js
https://blog.csdn.net/u012620515/article/details/49634749
.
/
dump.py com.xxx
Dumping xxx to
/
var
/
folders
/
rl
/
6nvyvpmj3z352q0m8xvm0db40000gn
/
T
[frida
-
ios
-
dump]: ZmFFmpeg.framework has been loaded.
[frida
-
ios
-
dump]: libswift_Concurrency.dylib has been dlopen.
...
libswift_Concurrency.dylib.fid:
100
%
|█████████████████████████████|
408k
/
408k
[
00
:
00
<
00
:
00
,
5.97MB
/
s]
Validated.plist:
251MB
[
00
:
14
,
18.2MB
/
s]
0.00B
[
00
:
00
, ?B
/
s]Generating
"xxx.ipa"
.
/
dump.py com.xxx
Dumping xxx to
/
var
/
folders
/
rl
/
6nvyvpmj3z352q0m8xvm0db40000gn
/
T
[frida
-
ios
-
dump]: ZmFFmpeg.framework has been loaded.
[frida
-
ios
-
dump]: libswift_Concurrency.dylib has been dlopen.
...
libswift_Concurrency.dylib.fid:
100
%
|█████████████████████████████|
408k
/
408k
[
00
:
00
<
00
:
00
,
5.97MB
/
s]
Validated.plist:
251MB
[
00
:
14
,
18.2MB
/
s]
0.00B
[
00
:
00
, ?B
/
s]Generating
"xxx.ipa"
0x106913598
osee2unifiedRelease!
0x63d7598
(
0x1063d7598
)
0x1069131fc
osee2unifiedRelease!
0x63d71fc
(
0x1063d71fc
)
0x1068e27d0
osee2unifiedRelease!
0x63a67d0
(
0x1063a67d0
)
0x10690767c
osee2unifiedRelease!
0x63cb67c
(
0x1063cb67c
)
0x1020724bc
osee2unifiedRelease!
0x1b364bc
(
0x101b364bc
)
0x10207256c
osee2unifiedRelease!
0x1b3656c
(
0x101b3656c
)
0x102061e10
osee2unifiedRelease!
0x1b25e10
(
0x101b25e10
)
0x100608f90
osee2unifiedRelease!
0xccf90
(
0x1000ccf90
)
0x1a0ec1298
libdispatch.dylib!_dispatch_call_block_and_release
0x106913598
osee2unifiedRelease!
0x63d7598
(
0x1063d7598
)
0x1069131fc
osee2unifiedRelease!
0x63d71fc
(
0x1063d71fc
)
0x1068e27d0
osee2unifiedRelease!
0x63a67d0
(
0x1063a67d0
)
0x10690767c
osee2unifiedRelease!
0x63cb67c
(
0x1063cb67c
)
0x1020724bc
osee2unifiedRelease!
0x1b364bc
(
0x101b364bc
)
0x10207256c
osee2unifiedRelease!
0x1b3656c
(
0x101b3656c
)
0x102061e10
osee2unifiedRelease!
0x1b25e10
(
0x101b25e10
)
0x100608f90
osee2unifiedRelease!
0xccf90
(
0x1000ccf90
)
0x1a0ec1298
libdispatch.dylib!_dispatch_call_block_and_release
var base
=
Module.getBaseAddress(
"osee2unifiedRelease"
);
console.log(
"base: "
,base);
var base
=
Module.getBaseAddress(
"osee2unifiedRelease"
);
console.log(
"base: "
,base);
frida
-
trace
-
UF
-
m
"-[NSData base64EncodedStringWithOptions:]"
frida
-
trace
-
UF
-
m
"-[NSData base64EncodedStringWithOptions:]"
{
onEnter(log, args, state) {
this.
self
=
args[
0
];
},
onLeave(log, retval, state) {
var before
=
ObjC.classes.NSString.alloc().initWithData_encoding_(this.
self
,
4
);
var after
=
new ObjC.
Object
(retval);
log(`
-
[NSData base64EncodedStringWithOptions:]before
=
${before}
=
`);
log(`
-
[NSData base64EncodedStringWithOptions:]after
=
${after}
=
`);
if
(after.toString().indexOf(
"sEn8t"
)>
=
0
){
console.log(Thread.backtrace(this.context, Backtracer.ACCURATE) .
map
(DebugSymbol.fromAddress).join(
'\n'
));
}
}
}
{
onEnter(log, args, state) {
this.
self
=
args[
0
];
},
onLeave(log, retval, state) {
var before
=
ObjC.classes.NSString.alloc().initWithData_encoding_(this.
self
,
4
);
var after
=
new ObjC.
Object
(retval);
log(`
-
[NSData base64EncodedStringWithOptions:]before
=
${before}
=
`);
log(`
-
[NSData base64EncodedStringWithOptions:]after
=
${after}
=
`);
if
(after.toString().indexOf(
"sEn8t"
)>
=
0
){
console.log(Thread.backtrace(this.context, Backtracer.ACCURATE) .
map
(DebugSymbol.fromAddress).join(
'\n'
));
}
}
}
0x102e0a7d8
osee2unifiedRelease!
+
[ZHWhiteBoxEncryptTool encryptDataBase64String:]
0x102e0a6b8
osee2unifiedRelease!
+
[ZHWhiteBoxEncryptTool encryptData:]
0x10444b098
osee2unifiedRelease!
+
[NSURLRequest zh_whiteBoxEncryptRegisterLoginURLHTTPBody:]
0x10447c3f0
osee2unifiedRelease!
+
[ZHURLProtocol canonicalRequestForRequest:]
0x1a1863ffc
CFNetwork!
0x3ffc
(
0x180a47ffc
)
...
0x102e0a7d8
osee2unifiedRelease!
+
[ZHWhiteBoxEncryptTool encryptDataBase64String:]
0x102e0a6b8
osee2unifiedRelease!
+
[ZHWhiteBoxEncryptTool encryptData:]
0x10444b098
osee2unifiedRelease!
+
[NSURLRequest zh_whiteBoxEncryptRegisterLoginURLHTTPBody:]
0x10447c3f0
osee2unifiedRelease!
+
[ZHURLProtocol canonicalRequestForRequest:]
0x1a1863ffc
CFNetwork!
0x3ffc
(
0x180a47ffc
)
...
void
*
__fastcall sub_106B3E2A0(void
*
a1, void
*
a2, void
*
a3, void
*
a4, void
*
a5)
{
return
_objc_msgSend(a1,
"preDataIn160:secureKey:iv:"
, a3, a4, a5);
}
void
*
__fastcall sub_106B3E2A0(void
*
a1, void
*
a2, void
*
a3, void
*
a4, void
*
a5)
{
return
_objc_msgSend(a1,
"preDataIn160:secureKey:iv:"
, a3, a4, a5);
}
void
*
__fastcall sub_106B1CA20(void
*
a1, void
*
a2, void
*
a3, void
*
a4, void
*
a5)
{
return
_objc_msgSend(a1,
"laesEncryptData:secureKey:iv:"
, a3, a4, a5);
}
void
*
__fastcall sub_106B1CA20(void
*
a1, void
*
a2, void
*
a3, void
*
a4, void
*
a5)
{
return
_objc_msgSend(a1,
"laesEncryptData:secureKey:iv:"
, a3, a4, a5);
}
void
*
__fastcall sub_106B3E2E0(void
*
a1, void
*
a2, void
*
a3, void
*
a4, void
*
a15)
{
return
_objc_msgSend(a1,
"preDataOut160:secureKey:iv:"
, a3, a4, a15);
}
void
*
__fastcall sub_106B3E2E0(void
*
a1, void
*
a2, void
*
a3, void
*
a4, void
*
a15)
{
return
_objc_msgSend(a1,
"preDataOut160:secureKey:iv:"
, a3, a4, a15);
}
id
__cdecl
+
[BangcleCryptoTool laesEncryptData:secureKey:iv:](BangcleCryptoTool_meta
*
self
, SEL a2,
id
a3,
id
a4,
id
a5)
id
__cdecl
+
[BangcleCryptoTool laesEncryptData:secureKey:iv:](BangcleCryptoTool_meta
*
self
, SEL a2,
id
a3,
id
a4,
id
a5)
__int64 __fastcall sub_1000902A8(__int64 a1, unsigned
int
a2, __int64 a3, __int64 a4, __int64 a5, unsigned
int
a6, __int64 a7, unsigned
int
a8,
int
a9)
{
v24
=
a1;
v23
=
a2;
v22
=
a3;
v21
=
a4;
v20
=
a5;
v19
=
a6;
a7a
=
a7;
a8a
=
a8;
v16
=
a9;
LODWORD(v10)
=
1
;
HIDWORD(v10)
=
4
;
v14
=
1
;
v15
=
a9;
v12
=
1
;
v13
=
0
;
v11
=
0
;
return
sub_100090420(a1, a2, a3, (
int
*
)a4, a5, a6, a7, a8, &v10);
}
__int64 __fastcall sub_1000902A8(__int64 a1, unsigned
int
a2, __int64 a3, __int64 a4, __int64 a5, unsigned
int
a6, __int64 a7, unsigned
int
a8,
int
a9)
{
v24
=
a1;
v23
=
a2;
v22
=
a3;
v21
=
a4;
v20
=
a5;
v19
=
a6;
a7a
=
a7;
a8a
=
a8;
v16
=
a9;
LODWORD(v10)
=
1
;
HIDWORD(v10)
=
4
;
v14
=
1
;
v15
=
a9;
v12
=
1
;
v13
=
0
;
v11
=
0
;
return
sub_100090420(a1, a2, a3, (
int
*
)a4, a5, a6, a7, a8, &v10);
}
function replace(){
var base
=
Module.getBaseAddress(
"osee2unifiedRelease"
);
Interceptor.replace(base.add(
0x902A8
),new NativeCallback(function(a,b,c,d,e,f,g,h,i){
return
0
;
},
'int'
,[
'pointer'
,
'int'
,
'pointer'
,
'int'
,
'pointer'
,
'int'
,
'pointer'
,
'int'
,
'pointer'
]));
}
function replace(){
var base
=
Module.getBaseAddress(
"osee2unifiedRelease"
);
Interceptor.replace(base.add(
0x902A8
),new NativeCallback(function(a,b,c,d,e,f,g,h,i){
return
0
;
},
'int'
,[
'pointer'
,
'int'
,
'pointer'
,
'int'
,
'pointer'
,
'int'
,
'pointer'
,
'int'
,
'pointer'
]));
}
__text:
00000001000902A8
sub_1000902A8
__text:
00000001000902A8
STP X29, X30, [SP,
__text:
00000001000902AC
MOV X29, SP
__text:
00000001000902B0
SUB SP, SP,
__text:
00000001000902B4
LDR W8, [X29,
__text:
00000001000902B8
ADD X9, SP,
__text:
00000001000902BC
MOV W10,
__text:
00000001000902C0
MOV W11,
__text:
00000001000902C4
STUR X0, [X29,
__text:
00000001000902C8
STUR W1, [X29,
__text:
00000001000902CC
STUR X2, [X29,
__text:
00000001000902D0
STUR X3, [X29,
__text:
00000001000902D4
STUR X4, [X29,
__text:
00000001000902D8
STUR W5, [X29,
__text:
00000001000902DC
STR
X6, [SP,
__text:
00000001000902E0
STR
W7, [SP,
__text:
00000001000902E4
STR
W8, [SP,
__text:
00000001000902E8
STR
W10, [SP,
__text:
00000001000902EC
STR
W11, [SP,
__text:
00000001000902F0
STR
W10, [SP,
__text:
00000001000902F4
LDR W8, [SP,
__text:
00000001000902F8
STR
W8, [SP,
__text:
00000001000902FC
STR
W10, [SP,
__text:
0000000100090300
STR
WZR, [SP,
__text:
0000000100090304
STR
WZR, [SP,
__text:
0000000100090308
LDUR X0, [X29,
__text:
000000010009030C
LDUR W1, [X29,
__text:
0000000100090310
LDUR X2, [X29,
__text:
0000000100090314
LDUR X3, [X29,
__text:
0000000100090318
LDUR X4, [X29,
__text:
000000010009031C
LDUR W5, [X29,
__text:
0000000100090320
LDR X6, [SP,
__text:
0000000100090324
LDR W7, [SP,
__text:
0000000100090328
STR
X9, [SP] ; a9 a9参数通过sp传递
__text:
000000010009032C
BL sub_100090420
__text:
0000000100090330
MOV SP, X29
__text:
0000000100090334
LDP X29, X30, [SP
+
var_s0],
__text:
0000000100090338
RET
__text:
00000001000902A8
sub_1000902A8
__text:
00000001000902A8
STP X29, X30, [SP,
__text:
00000001000902AC
MOV X29, SP
__text:
00000001000902B0
SUB SP, SP,
__text:
00000001000902B4
LDR W8, [X29,
__text:
00000001000902B8
ADD X9, SP,
__text:
00000001000902BC
MOV W10,
__text:
00000001000902C0
MOV W11,
__text:
00000001000902C4
STUR X0, [X29,
__text:
00000001000902C8
STUR W1, [X29,
__text:
00000001000902CC
STUR X2, [X29,
__text:
00000001000902D0
STUR X3, [X29,
__text:
00000001000902D4
STUR X4, [X29,
__text:
00000001000902D8
STUR W5, [X29,
__text:
00000001000902DC
STR
X6, [SP,
__text:
00000001000902E0
STR
W7, [SP,
__text:
00000001000902E4
STR
W8, [SP,
__text:
00000001000902E8
STR
W10, [SP,
__text:
00000001000902EC
STR
W11, [SP,
__text:
00000001000902F0
STR
W10, [SP,
__text:
00000001000902F4
LDR W8, [SP,
__text:
00000001000902F8
STR
W8, [SP,
__text:
00000001000902FC
STR
W10, [SP,
__text:
0000000100090300
STR
WZR, [SP,
__text:
0000000100090304
STR
WZR, [SP,
__text:
0000000100090308
LDUR X0, [X29,
__text:
000000010009030C
LDUR W1, [X29,
__text:
0000000100090310
LDUR X2, [X29,
__text:
0000000100090314
LDUR X3, [X29,
__text:
0000000100090318
LDUR X4, [X29,
__text:
000000010009031C
LDUR W5, [X29,
__text:
0000000100090320
LDR X6, [SP,
__text:
0000000100090324
LDR W7, [SP,
__text:
0000000100090328
STR
X9, [SP] ; a9 a9参数通过sp传递
__text:
000000010009032C
BL sub_100090420
__text:
0000000100090330
MOV SP, X29
__text:
0000000100090334
LDP X29, X30, [SP
+
var_s0],
__text:
0000000100090338
RET
var dword
=
Memory.alloc(
32
);
Memory.writeUInt(dword,
1
);
Memory.writeUInt(dword.add(
4
),
4
);
Memory.writeUInt(dword.add(
4
*
2
),
0
);
Memory.writeUInt(dword.add(
4
*
3
),
1
);
Memory.writeUInt(dword.add(
4
*
4
),
1
);
Memory.writeUInt(dword.add(
4
*
5
),
0
);
Memory.writeUInt(dword.add(
4
*
6
),
1
);
Memory.writeUInt(dword.add(
4
*
7
),
1
);
var dword
=
Memory.alloc(
32
);
Memory.writeUInt(dword,
1
);
Memory.writeUInt(dword.add(
4
),
4
);
Memory.writeUInt(dword.add(
4
*
2
),
0
);
Memory.writeUInt(dword.add(
4
*
3
),
1
);
Memory.writeUInt(dword.add(
4
*
4
),
1
);
Memory.writeUInt(dword.add(
4
*
5
),
0
);
Memory.writeUInt(dword.add(
4
*
6
),
1
);
Memory.writeUInt(dword.add(
4
*
7
),
1
);
function call_aes(){
var base
=
Module.getBaseAddress(
"osee2unifiedRelease"
);
console.log(
"base: "
,base);
var aes
=
new NativeFunction(base.add(
0x90420
),
'int'
,[
'pointer'
,
'int'
,
'pointer'
,
'pointer'
,
'pointer'
,
'int'
,
'pointer'
,
'int'
,
'pointer'
]);
/
/
输入
var data_len
=
0x20
;
const data
=
Memory.alloc(data_len);
Memory.writeByteArray(data,[
0xca
,
0xcc
,
0x6e
,
0x68
,
0x64
,
0x63
,
0xc6
,
0x6e
,
0x60
,
0xc2
,
0x66
,
0xc4
,
0xc8
,
0x6c
,
0xc4
,
0xc6
,
0xca
,
0xc2
,
0x60
,
0xc4
,
0x6c
,
0x64
,
0x61
,
0x61
,
0x61
,
0xc4
,
0xc6
,
0xc4
,
0xc2
,
0xc8
,
0x6c
,
0x62
]);
/
/
输出:空的byte数组,函数返回后,有值
var result_len
=
16
*
(data_len
/
16
+
1
);
var result
=
Memory.alloc(result_len);
var result_len_ptr
=
Memory.alloc(Process.pointerSize);
result_len_ptr.writeUInt(result_len);
/
/
iv
var iv_len
=
0x10
;
const iv
=
Memory.alloc(iv_len);
Memory.writeByteArray(iv,[
0x4c
,
0x41
,
0xb2
,
0xc9
,
0xb4
,
0xba
,
0xff
,
0x8a
,
0x6a
,
0x69
,
0xa5
,
0x99
,
0x02
,
0x5f
,
0x03
,
0x15
]);
/
/
key
var key_len
=
0xb4
;
/
/
长度
180
const key
=
Memory.alloc(key_len);
Memory.writeByteArray(key,[
0x93
,
0x02
,
0x01
,
0x9f
,
0xbf
,
0xa1
,
0xbb
,
0x6b
,
0xdb
,
0x9f
,
0xca
,
0x46
,
0x84
,
0xb3
,
0xe7
,
0xf6
,
0x38
,
0x30
,
0x44
,
0x18
,
0x14
,
0x06
,
0x35
,
0x60
,
0x29
,
0x7e
,
0x4f
,
0x00
,
0xde
,
0x63
,
0x69
,
0x41
,
0x66
,
0x4f
,
0x7e
,
0xa3
,
0x94
,
0x29
,
0xb2
,
0x60
,
0x4e
,
0x4f
,
0x93
,
0xa7
,
0x84
,
0x0e
,
0xcf
,
0x12
,
0x54
,
0xcb
,
0xa8
,
0xd9
,
0xea
,
0x29
,
0xcd
,
0xf4
,
0xf7
,
0xe4
,
0x01
,
0x97
,
0xb5
,
0x0d
,
0xf7
,
0x7e
,
0x19
,
0xfb
,
0x07
,
0xf2
,
0xf9
,
0x74
,
0xe7
,
0x87
,
0xcf
,
0x87
,
0x32
,
0xa6
,
0x2a
,
0x1e
,
0x2e
,
0x0f
,
0xcb
,
0xfa
,
0x2a
,
0xcb
,
0xac
,
0x63
,
0x76
,
0xc8
,
0x32
,
0xc0
,
0x82
,
0x39
,
0xa0
,
0xb5
,
0xd9
,
0xe0
,
0xe7
,
0x06
,
0xeb
,
0x27
,
0xb8
,
0x31
,
0xe5
,
0xef
,
0xfc
,
0xdb
,
0x3d
,
0x00
,
0x08
,
0x7e
,
0x62
,
0xa6
,
0x02
,
0x92
,
0x31
,
0xf6
,
0x4a
,
0x2b
,
0x30
,
0x99
,
0x72
,
0x07
,
0x59
,
0xe3
,
0x1f
,
0x9d
,
0xfa
,
0x12
,
0x8b
,
0xc7
,
0xe9
,
0x6a
,
0x83
,
0xd7
,
0x1a
,
0xf7
,
0x9a
,
0xa4
,
0x89
,
0xb9
,
0xe5
,
0x6f
,
0xfd
,
0xd5
,
0xe2
,
0xf1
,
0x42
,
0xa3
,
0xf9
,
0xac
,
0x11
,
0xe4
,
0xab
,
0xce
,
0x01
,
0xc6
,
0xf2
,
0xfb
,
0xca
,
0x01
,
0xb7
,
0x59
,
0xac
,
0x84
,
0x2f
,
0x14
,
0x91
,
0xa1
,
0xa5
,
0x8d
,
0x74
,
0xea
,
0xdd
,
0x2b
,
0x38
,
0x09
,
0x1e
,
0xb8
,
0x21
,
0x16
])
/
/
最后一个参数
var dword
=
Memory.alloc(
32
);
Memory.writeUInt(dword,
1
);
Memory.writeUInt(dword.add(
4
),
4
);
Memory.writeUInt(dword.add(
4
*
2
),
0
);
Memory.writeUInt(dword.add(
4
*
3
),
1
);
Memory.writeUInt(dword.add(
4
*
4
),
1
);
Memory.writeUInt(dword.add(
4
*
5
),
0
);
Memory.writeUInt(dword.add(
4
*
6
),
1
);
Memory.writeUInt(dword.add(
4
*
7
),
1
);
/
/
主动调用
var aes_r
=
aes(data,data_len,result,result_len_ptr,iv,iv_len,key,key_len,dword);
console.log(
"aes_r"
,aes_r,hexdump(result,{length:result_len}));
}
function call_aes(){
var base
=
Module.getBaseAddress(
"osee2unifiedRelease"
);
console.log(
"base: "
,base);
var aes
=
new NativeFunction(base.add(
0x90420
),
'int'
,[
'pointer'
,
'int'
,
'pointer'
,
'pointer'
,
'pointer'
,
'int'
,
'pointer'
,
'int'
,
'pointer'
]);
/
/
输入
var data_len
=
0x20
;
const data
=
Memory.alloc(data_len);
Memory.writeByteArray(data,[
0xca
,
0xcc
,
0x6e
,
0x68
,
0x64
,
0x63
,
0xc6
,
0x6e
,
0x60
,
0xc2
,
0x66
,
0xc4
,
0xc8
,
0x6c
,
0xc4
,
0xc6
,
0xca
,
0xc2
,
0x60
,
0xc4
,
0x6c
,
0x64
,
0x61
,
0x61
,
0x61
,
0xc4
,
0xc6
,
0xc4
,
0xc2
,
0xc8
,
0x6c
,
0x62
]);
/
/
输出:空的byte数组,函数返回后,有值
var result_len
=
16
*
(data_len
/
16
+
1
);
var result
=
Memory.alloc(result_len);
var result_len_ptr
=
Memory.alloc(Process.pointerSize);
result_len_ptr.writeUInt(result_len);
/
/
iv
var iv_len
=
0x10
;
const iv
=
Memory.alloc(iv_len);
Memory.writeByteArray(iv,[
0x4c
,
0x41
,
0xb2
,
0xc9
,
0xb4
,
0xba
,
0xff
,
0x8a
,
0x6a
,
0x69
,
0xa5
,
0x99
,
0x02
,
0x5f
,
0x03
,
0x15
]);
/
/
key
var key_len
=
0xb4
;
/
/
长度
180
const key
=
Memory.alloc(key_len);
Memory.writeByteArray(key,[
0x93
,
0x02
,
0x01
,
0x9f
,
0xbf
,
0xa1
,
0xbb
,
0x6b
,
0xdb
,
0x9f
,
0xca
,
0x46
,
0x84
,
0xb3
,
0xe7
,
0xf6
,
0x38
,
0x30
,
0x44
,
0x18
,
0x14
,
0x06
,
0x35
,
0x60
,
0x29
,
0x7e
,
0x4f
,
0x00
,
0xde
,
0x63
,
0x69
,
0x41
,
0x66
,
0x4f
,
0x7e
,
0xa3
,
0x94
,
0x29
,
0xb2
,
0x60
,
0x4e
,
0x4f
,
0x93
,
0xa7
,
0x84
,
0x0e
,
0xcf
,
0x12
,
0x54
,
0xcb
,
0xa8
,
0xd9
,
0xea
,
0x29
,
0xcd
,
0xf4
,
0xf7
,
0xe4
,
0x01
,
0x97
,
0xb5
,
0x0d
,
0xf7
,
0x7e
,
0x19
,
0xfb
,
0x07
,
0xf2
,
0xf9
,
0x74
,
0xe7
,
0x87
,
0xcf
,
0x87
,
0x32
,
0xa6
,
0x2a
,
0x1e
,
0x2e
,
0x0f
,
0xcb
,
0xfa
,
0x2a
,
0xcb
,
0xac
,
0x63
,
0x76
,
0xc8
,
0x32
,
0xc0
,
0x82
,
0x39
,
0xa0
,
0xb5
,
0xd9
,
0xe0
,
0xe7
,
0x06
,
0xeb
,
0x27
,
0xb8
,
0x31
,
0xe5
,
0xef
,
0xfc
,
0xdb
,
0x3d
,
0x00
,
0x08
,
0x7e
,
0x62
,
0xa6
,
0x02
,
0x92
,
0x31
,
0xf6
,
0x4a
,
0x2b
,
0x30
,
0x99
,
0x72
,
0x07
,
0x59
,
0xe3
,
0x1f
,
0x9d
,
0xfa
,
0x12
,
0x8b
,
0xc7
,
0xe9
,
0x6a
,
0x83
,
0xd7
,
0x1a
,
0xf7
,
0x9a
,
0xa4
,
0x89
,
0xb9
,
0xe5
,
0x6f
,
0xfd
,
0xd5
,
0xe2
,
0xf1
,
0x42
,
0xa3
,
0xf9
,
0xac
,
0x11
,
0xe4
,
0xab
,
0xce
,
0x01
,
0xc6
,
0xf2
,
0xfb
,
0xca
,
0x01
,
0xb7
,
0x59
,
0xac
,
0x84
,
0x2f
,
0x14
,
0x91
,
0xa1
,
0xa5
,
0x8d
,
0x74
,
0xea
,
0xdd
,
0x2b
,
0x38
,
0x09
,
0x1e
,
0xb8
,
0x21
,
0x16
])
/
/
最后一个参数
var dword
=
Memory.alloc(
32
);
Memory.writeUInt(dword,
1
);
Memory.writeUInt(dword.add(
4
),
4
);
Memory.writeUInt(dword.add(
4
*
2
),
0
);
Memory.writeUInt(dword.add(
4
*
3
),
1
);
Memory.writeUInt(dword.add(
4
*
4
),
1
);
Memory.writeUInt(dword.add(
4
*
5
),
0
);
Memory.writeUInt(dword.add(
4
*
6
),
1
);
Memory.writeUInt(dword.add(
4
*
7
),
1
);
/
/
主动调用
var aes_r
=
aes(data,data_len,result,result_len_ptr,iv,iv_len,key,key_len,dword);
console.log(
"aes_r"
,aes_r,hexdump(result,{length:result_len}));
}
function trace:
[函数地址]([调用地址])
-
-
调用层级
[
0x100091054
]( [
0x10009047c
] )
-
-
0
/
/
1.
密钥编排后的处理
[
0x106a9b340
]( [
0x100091074
] )
-
-
1
/
/
malloc
[
0x100091b3c
]( [
0x100090520
] )
-
-
0
[
0x100091bcc
]( [
0x100090548
] )
-
-
0
[
0x106a9a530
]( [
0x100090614
] )
-
-
0
/
/
calloc
[
0x106a9a1e8
]( [
0x10009062c
] )
-
-
0
/
/
memcpy
[
0x100091c7c
]( [
0x100090664
] )
-
-
0
/
/
类似pkcs填充
[
0x106a9a1f4
]( [
0x100091cf8
] )
-
-
1
/
/
使用memset进行填充
[
0x106a9a1f4
]( [
0x100091d6c
] )
-
-
1
/
/
使用memset进行填充
[
0x100094360
]( [
0x100090b18
] )
-
-
0
/
/
2.
关键函数,CBC模式,明文异或
[
0x100091fac
]( [
0x10009440c
] )
-
-
1
/
/
3.
真正魔改aes的加密,测试时输出明文为
32
个字节,通过填充后,输出为
48
个字节,且aes128每轮循环加密
16
字节,故
48
/
16
=
3
,
0x100091fac
函数循环
3
轮
[
0x100091fac
]( [
0x10009440c
] )
-
-
1
[
0x100091fac
]( [
0x10009440c
] )
-
-
1
[
0x106a9aaa0
]( [
0x100091038
] )
-
-
0
/
/
free
[
0x100091ef4
]( [
0x100091040
] )
-
-
0
[
0x106a9aaa0
]( [
0x100091f18
] )
-
-
1
/
/
free
function trace:
[函数地址]([调用地址])
-
-
调用层级
[
0x100091054
]( [
0x10009047c
] )
-
-
0
/
/
1.
密钥编排后的处理
[
0x106a9b340
]( [
0x100091074
] )
-
-
1
/
/
malloc
[
0x100091b3c
]( [
0x100090520
] )
-
-
0
[
0x100091bcc
]( [
0x100090548
] )
-
-
0
[
0x106a9a530
]( [
0x100090614
] )
-
-
0
/
/
calloc
[
0x106a9a1e8
]( [
0x10009062c
] )
-
-
0
/
/
memcpy
[
0x100091c7c
]( [
0x100090664
] )
-
-
0
/
/
类似pkcs填充
[
0x106a9a1f4
]( [
0x100091cf8
] )
-
-
1
/
/
使用memset进行填充
[
0x106a9a1f4
]( [
0x100091d6c
] )
-
-
1
/
/
使用memset进行填充
[
0x100094360
]( [
0x100090b18
] )
-
-
0
/
/
2.
关键函数,CBC模式,明文异或
[
0x100091fac
]( [
0x10009440c
] )
-
-
1
/
/
3.
真正魔改aes的加密,测试时输出明文为
32
个字节,通过填充后,输出为
48
个字节,且aes128每轮循环加密
16
字节,故
48
/
16
=
3
,
0x100091fac
函数循环
3
轮
[
0x100091fac
]( [
0x10009440c
] )
-
-
1
[
0x100091fac
]( [
0x10009440c
] )
-
-
1
[
0x106a9aaa0
]( [
0x100091038
] )
-
-
0
/
/
free
[
0x100091ef4
]( [
0x100091040
] )
-
-
0
[
0x106a9aaa0
]( [
0x100091f18
] )
-
-
1
/
/
free
__int64 __fastcall sub_100094360(__int64 a1, __int64 a2,
int
a3, __int64 a4, __int64 a5, void (__fastcall
*
a6)(__int64, __int64, __int64, unsigned
int
*
))
{
__int64 iv_1;
/
/
[xsp
+
0h
] [xbp
-
40h
]
signed
int
i;
/
/
[xsp
+
8h
] [xbp
-
38h
]
unsigned
int
v9;
/
/
[xsp
+
Ch] [xbp
-
34h
]
void (__fastcall
*
v10)(__int64, __int64, __int64);
/
/
[xsp
+
10h
] [xbp
-
30h
]
__int64 keyptr;
/
/
[xsp
+
18h
] [xbp
-
28h
]
__int64 iv;
/
/
[xsp
+
20h
] [xbp
-
20h
]
int
result_len;
/
/
[xsp
+
2Ch
] [xbp
-
14h
]
__int64 result;
/
/
[xsp
+
30h
] [xbp
-
10h
]
__int64 data;
/
/
[xsp
+
38h
] [xbp
-
8h
]
data
=
a1;
result
=
a2;
result_len
=
a3;
iv
=
a4;
keyptr
=
a5;
v10
=
a6;
v9
=
0
;
iv_1
=
a4;
while
( result_len >
=
16
)
{
for
( i
=
0
; i <
16
;
+
+
i )
*
(result
+
i)
=
*
(data
+
i) ^
*
(iv_1
+
i);
(v10)(result, result, keyptr, &v9);
/
/
aes加密算法
iv_1
=
result;
result_len
-
=
16
;
data
+
=
16LL
;
result
+
=
16LL
;
}
return
v9;
}
__int64 __fastcall sub_100094360(__int64 a1, __int64 a2,
int
a3, __int64 a4, __int64 a5, void (__fastcall
*
a6)(__int64, __int64, __int64, unsigned
int
*
))
{
__int64 iv_1;
/
/
[xsp
+
0h
] [xbp
-
40h
]
signed
int
i;
/
/
[xsp
+
8h
] [xbp
-
38h
]
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2023-6-10 15:27
被SilverBullet编辑
,原因: