android逆向奇技淫巧二十九:x音AES使用分析

  1、AES也是一种非常成熟的对称加密算法了,整个流程如下:

        

   可以看到流程比较复杂,步骤很多,很多初学者光是看这个流程就晕菜了。这么多步骤,每个步骤都是干啥了?分别都有啥用了?理解了每个步骤的原理和作用,才能更好的魔改和识别魔改!

  (1)先回到加密算法最核心的作用或本质:

  • 让明文和密文之间没有明显的统计关系,找不到明文和密文之间的映射关系,俗称“混淆”。举个例子:明文是A,得到的密文是B;明文是C,得到的密文是D。如果每次都这样,逆向破解人员很容易猜到明文和密文之间的映射关系,比如看到密文是B,就能直接反推出明文是A;看到密文是D,就能反推出明文是C,这样一来破解算法就很容易了!
  • 明文一旦有变动,哪怕只有一位变动,理想情况下密文的每一位都会改变,俗称“扩散”,这样就让逆向破解人员不容易发现明文和密文在位置上的对应关系,达到“牵明文一发而动密文全身”的效果!

  为了达到上述两个效果,AES的每个步骤都是围绕这两个目的来设计和实现的!接下来我们挨个过一遍,看看每一步都是怎么达到上述两个目的的!上述的流程图非常复杂,为了抓住主干,快速了解算法全貌,这里稍微简化一下,省略部分细节,算法流程如下:

           

       (2)初始变换initial round :就是用明文异或key,这就是最原始的加密算法!只要改变key,明文和密文之间的映射关系就会改变,所以这一步的目的就是混淆!

       

   (3)接下来就是10轮循环运算了,循环的第一步:

  •   字节代换subbytes:本质就是查表,把表中数读出来替换原来的字符。比如第一个hex是0x19,那么把第1行和第9列的数字找到(这里是d4)来替换原来的0x19;这步的作用还是混淆!

       

  •    行移位ShifRows :这一步就是简单粗暴的把16byte字符挨个移动位置,目的就是扩散,达到“牵一发而动全身”的目的!

   

  由于AES的算法是公开的,所以具体到C代码的实现有多个版本,其中部分版本用IDA的F5反汇编后如下(后续看到这类代码,需要条件反射一样往shiftRows想):

  

       另一种shifRows:

  

   以上两种的特征都比较明显:5去1、9去5、13去9等.......

  •    列混合MixColumnes:这一步是输入数据与给定的举证左乘!注意:这里的左乘不是传统的矩阵乘法!算法细节可以参考末尾链接2的视频,这里不赘诉!这一步的目的还是混淆,让输入和输出之间没有明显的统计映射关系!

  

  •    轮密钥加AddRoundKey:本质还是让输入和指定的子密钥矩阵做异或,达到混淆的目的

   

   这里有两个问题需要进一步深入思考:

    •  为啥需要子密钥矩阵?这里做的是异或,如果每次都用相同的密钥key去异或不同的输入,是不是很容易被破解了?这样就达不到强混淆的目的了!
    •     怎么得到子密钥矩阵? 如果列i不是4的倍数,直接用下面的公式计算得到,本质还是两列之间异或;
    •     这里以AES-128为例,用户输入的原始key有16byte,由于需要round 10轮,每轮都需要生成子密钥,所以一共需要16+10*16=176byte的密钥数据,也就是44列密钥(每列4byte),通常用W0~W43来表示;W0~W3是用户输入的原始密钥,W4~W43是密钥扩展算法生成的密钥

       

       如果列i是4的倍数就必要复杂了,第二个T(W[i-1])需要经过下面3个步骤得到:

      • 字循环:就是把列上下循环移动位置,目的是扩散

       

      •  字节替换:比如输入是cf,就在S盒查找c行f列的数,这里是8a,就用8a替换cf,这里的目的是混淆!

       

      •  轮常量异或:轮常量是固定的,这里挨个异或,让每轮生成的子密钥roundKey都不一样,达到强混淆的目的!

                       

       经过上面几步,得到子密钥矩阵,进而可以继续运算轮密钥加,完成整个步骤混淆的目的!

   (4)总结一下:AES整个操作流程比较复杂,步骤很多,但不外乎就以下几种:

  •    异或: 这是最常规、最基础的加密方式,目的是混淆
  •    各种移位:左移、右移、上下移动、P盒转换等,目的是扩散,达到“输入牵一发而动输出全身”的效果
  •    S盒查表:本质是人为设置一种映射方式,让输入和输出之间没有明显的统计关系或规律,达到混淆的目的!

  2、(1)AES是当今世界最常见的对称加密方式了,x音这种地球级的APP肯定少不了,那么x音是怎么使用AES的了?老规矩,在IDA中继续用Signsrch插件找各种magic number,果真还找到了重要线索:在libmetasec.so中,从0x93FE8开始,直到0x963E8结束,一共0x2400byte=9KB的空间依次存放了从TE0到TE3、从TD0到TD4表,部分表数据如下(太多了,就不一一贴出来):

.rodata:00093FE8                         ; _DWORD RijnDael_AES_93FE8_TE0[256]
.rodata:00093FE8 A5 63 63 C6 84 7C 7C F8+RijnDael_AES_93FE8_TE0 DCD 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D
.rodata:00093FE8 99 77 77 EE 8D 7B 7B F6+                                        ; DATA XREF: sub_69190+60↑o
.rodata:00093FE8 0D F2 F2 FF BD 6B 6B D6+                                        ; sub_69190+62↑o ...
.rodata:00093FE8 B1 6F 6F DE 54 C5 C5 91+                DCD 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x2010103 ; <Signsrch> "Rijndael Te0 (0xc66363a5U)"
.rodata:00093FE8 50 30 30 60 03 01 01 02+                DCD 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6
.rodata:00093FE8 A9 67 67 CE 7D 2B 2B 56+                DCD 0xEC76769A, 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87
.rodata:00093FE8 19 FE FE E7 62 D7 D7 B5+                DCD 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, 0x41ADADEC
.rodata:00093FE8 E6 AB AB 4D 9A 76 76 EC+                DCD 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7
.rodata:00093FE8 45 CA CA 8F 9D 82 82 1F+                DCD 0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE
.rodata:00093FE8 40 C9 C9 89 87 7D 7D FA+                DCD 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F
.rodata:00093FE8 15 FA FA EF EB 59 59 B2+                DCD 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193
.rodata:00093FE8 C9 47 47 8E 0B F0 F0 FB+                DCD 0xABD8D873, 0x62313153, 0x2A15153F, 0x804040C, 0x95C7C752
.rodata:00093FE8 EC AD AD 41 67 D4 D4 B3+                DCD 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0xA05050F
.rodata:00093FE8 FD A2 A2 5F EA AF AF 45+                DCD 0x2F9A9AB5, 0xE070709, 0x24121236, 0x1B80809B, 0xDFE2E23D
.rodata:00093FE8 BF 9C 9C 23 F7 A4 A4 53+                DCD 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B
.rodata:00093FE8 96 72 72 E4 5B C0 C0 9B+                DCD 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2
.rodata:00093FE8 C2 B7 B7 75 1C FD FD E1+                DCD 0xB45A5AEE, 0x5BA0A0FB, 0xA45252F6, 0x763B3B4D, 0xB7D6D661
.rodata:00093FE8 AE 93 93 3D 6A 26 26 4C+                DCD 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497

  Signsrch还是很贴心地把表的类型都识别并展示出来了!除了TE和TD表,分别在0x923C0、0x91FC0和0x92BC0这里也存储了S盒,如下:

rodata:000923C0                         ; _DWORD SBox[256]
.rodata:000923C0 00 00 63 00 00 00 7C 00+SBox            DCD 0x630000, 0x7C0000, 0x770000, 0x7B0000, 0xF20000, 0x6B0000
.rodata:000923C0 00 00 77 00 00 00 7B 00+                                        ; DATA XREF: sub_68D90+4E↑o
.rodata:000923C0 00 00 F2 00 00 00 6B 00+                                        ; sub_68D90+50↑o ...
.rodata:000923C0 00 00 6F 00 00 00 C5 00+                DCD 0x6F0000, 0xC50000, 0x300000, 0x10000, 0x670000, 0x2B0000
.rodata:000923C0 00 00 30 00 00 00 01 00+                DCD 0xFE0000, 0xD70000, 0xAB0000, 0x760000, 0xCA0000, 0x820000
.rodata:000923C0 00 00 67 00 00 00 2B 00+                DCD 0xC90000, 0x7D0000, 0xFA0000, 0x590000, 0x470000, 0xF00000
.rodata:000923C0 00 00 FE 00 00 00 D7 00+                DCD 0xAD0000, 0xD40000, 0xA20000, 0xAF0000, 0x9C0000, 0xA40000
.rodata:000923C0 00 00 AB 00 00 00 76 00+                DCD 0x720000, 0xC00000, 0xB70000, 0xFD0000, 0x930000, 0x260000
.rodata:000923C0 00 00 CA 00 00 00 82 00+                DCD 0x360000, 0x3F0000, 0xF70000, 0xCC0000, 0x340000, 0xA50000
.rodata:000923C0 00 00 C9 00 00 00 7D 00+                DCD 0xE50000, 0xF10000, 0x710000, 0xD80000, 0x310000, 0x150000
.rodata:000923C0 00 00 FA 00 00 00 59 00+                DCD 0x40000, 0xC70000, 0x230000, 0xC30000, 0x180000, 0x960000
.rodata:000923C0 00 00 47 00 00 00 F0 00+                DCD 0x50000, 0x9A0000, 0x70000, 0x120000, 0x800000, 0xE20000
.rodata:000923C0 00 00 AD 00 00 00 D4 00+                DCD 0xEB0000, 0x270000, 0xB20000, 0x750000, 0x90000, 0x830000
.rodata:000923C0 00 00 A2 00 00 00 AF 00+                DCD 0x2C0000, 0x1A0000, 0x1B0000, 0x6E0000, 0x5A0000, 0xA00000
.rodata:000923C0 00 00 9C 00 00 00 A4 00+                DCD 0x520000, 0x3B0000, 0xD60000, 0xB30000, 0x290000, 0xE30000
.rodata:000923C0 00 00 72 00 00 00 C0 00+                DCD 0x2F0000, 0x840000, 0x530000, 0xD10000, 0, 0xED0000
.rodata:000923C0 00 00 B7 00 00 00 FD 00+                DCD 0x200000, 0xFC0000, 0xB10000, 0x5B0000, 0x6A0000, 0xCB0000
.rodata:000923C0 00 00 93 00 00 00 26 00+                DCD 0xBE0000, 0x390000, 0x4A0000, 0x4C0000, 0x580000, 0xCF0000
.rodata:000923C0 00 00 36 00 00 00 3F 00+                DCD 0xD00000, 0xEF0000, 0xAA0000, 0xFB0000, 0x430000, 0x4D0000
.rodata:000923C0 00 00 F7 00 00 00 CC 00+                DCD 0x330000, 0x850000, 0x450000, 0xF90000, 0x20000, 0x7F0000
.rodata:000923C0 00 00 34 00 00 00 A5 00+                DCD 0x500000, 0x3C0000, 0x9F0000, 0xA80000, 0x510000, 0xA30000
.rodata:000923C0 00 00 E5 00 00 00 F1 00+                DCD 0x400000, 0x8F0000, 0x920000, 0x9D0000, 0x380000, 0xF50000
.rodata:000923C0 00 00 71 00 00 00 D8 00+                DCD 0xBC0000, 0xB60000, 0xDA0000, 0x210000, 0x100000, 0xFF0000
.rodata:000923C0 00 00 31 00 00 00 15 00+                DCD 0xF30000, 0xD20000, 0xCD0000, 0xC0000, 0x130000, 0xEC0000
.rodata:000923C0 00 00 04 00 00 00 C7 00+                DCD 0x5F0000, 0x970000, 0x440000, 0x170000, 0xC40000, 0xA70000
.rodata:000923C0 00 00 23 00 00 00 C3 00+                DCD 0x7E0000, 0x3D0000, 0x640000, 0x5D0000, 0x190000, 0x730000
.rodata:000923C0 00 00 18 00 00 00 96 00+                DCD 0x600000, 0x810000, 0x4F0000, 0xDC0000, 0x220000, 0x2A0000
.rodata:000923C0 00 00 05 00 00 00 9A 00+                DCD 0x900000, 0x880000, 0x460000, 0xEE0000, 0xB80000, 0x140000
.rodata:000923C0 00 00 07 00 00 00 12 00+                DCD 0xDE0000, 0x5E0000, 0xB0000, 0xDB0000, 0xE00000, 0x320000
.rodata:000923C0 00 00 80 00 00 00 E2 00+                DCD 0x3A0000, 0xA0000, 0x490000, 0x60000, 0x240000, 0x5C0000
.rodata:000923C0 00 00 EB 00 00 00 27 00+                DCD 0xC20000, 0xD30000, 0xAC0000, 0x620000, 0x910000, 0x950000
.rodata:000923C0 00 00 B2 00 00 00 75 00+                DCD 0xE40000, 0x790000, 0xE70000, 0xC80000, 0x370000, 0x6D0000
.rodata:000923C0 00 00 09 00 00 00 83 00+                DCD 0x8D0000, 0xD50000, 0x4E0000, 0xA90000, 0x6C0000, 0x560000
.rodata:000923C0 00 00 2C 00 00 00 1A 00+                DCD 0xF40000, 0xEA0000, 0x650000, 0x7A0000, 0xAE0000, 0x80000
.rodata:000923C0 00 00 1B 00 00 00 6E 00+                DCD 0xBA0000, 0x780000, 0x250000, 0x2E0000, 0x1C0000, 0xA60000
.rodata:000923C0 00 00 5A 00 00 00 A0 00+                DCD 0xB40000, 0xC60000, 0xE80000, 0xDD0000, 0x740000, 0x1F0000
.rodata:000923C0 00 00 52 00 00 00 3B 00+                DCD 0x4B0000, 0xBD0000, 0x8B0000, 0x8A0000, 0x700000, 0x3E0000
.rodata:000923C0 00 00 D6 00 00 00 B3 00+                DCD 0xB50000, 0x660000, 0x480000, 0x30000, 0xF60000, 0xE0000
.rodata:000923C0 00 00 29 00 00 00 E3 00+                DCD 0x610000, 0x350000, 0x570000, 0xB90000, 0x860000, 0xC10000
.rodata:000923C0 00 00 2F 00 00 00 84 00+                DCD 0x1D0000, 0x9E0000, 0xE10000, 0xF80000, 0x980000, 0x110000
.rodata:000923C0 00 00 53 00 00 00 D1 00+                DCD 0x690000, 0xD90000, 0x8E0000, 0x940000, 0x9B0000, 0x1E0000
.rodata:000923C0 00 00 00 00 00 00 ED 00+                DCD 0x870000, 0xE90000, 0xCE0000, 0x550000, 0x280000, 0xDF0000
.rodata:000923C0 00 00 20 00 00 00 FC 00+                DCD 0x8C0000, 0xA10000, 0x890000, 0xD0000, 0xBF0000, 0xE60000
.rodata:000923C0 00 00 B1 00 00 00 5B 00+                DCD 0x420000, 0x680000, 0x410000, 0x990000, 0x2D0000, 0xF0000
.rodata:000923C0 00 00 6A 00 00 00 CB 00+                DCD 0xB00000, 0x540000, 0xBB0000, 0x160000

  这3个地方存储的S盒每个元素分别占用了1、3、4字节的空间,我也很好奇为啥同样的S盒要放在3个不同的地方(从后续得代码看不同的SBox之间在异或,原因不详)......

  既然占用了这么多存储空间存放AES的magic number,肯定时要用的!那么问题来了,AES的代码是怎么写的了?由于AES算法本身是公开的,理论上谁都可以自己实现AES算法。对于x音这种全球级别的大厂,技术大牛云集,他们会不会自己实现AES算法了?我个人觉得不太可能,原因很简单:自己做测试写个AES算法很简单,但是x音这种地球级别的APP,每天访问量都是以亿为单位统计的,自己实现AES可能会有两个坑:

  • 性能问题:不一定是最优的,换句话说加解密的速度不一定是最快的
  • 安全问题:自己实现的AES万一有漏洞咋办?

    所以此时市面上比较流行的开源AES就是首选了!原因很简单:开源的AES接受了大量业界技术大牛长时间的检验,如果性能或安全有严重缺陷,早就修复了!就算发现漏洞,也会第一时间修补,后续的运维支持有保障,所以x音的AES可能会选用哪个开源框架实现了?

    (2)还记得boringssl么?google的大牛基于openssl做的更改,x音把boringssl编译程了libttboringssl.so库,并调用SSL_CTX_set_custom_verify函数来防止抓包;既然是基于openssl改的,那么在boringssl\crypto\aes\aes.c文件中也实现了aes算法,x音会不会直接用这个版本的AES了?

  • 首先打开boringssl\crypto\aes\aes.c文件,前面开始就是9个大数组,分别存储了TE0~TE3、TD0~TD4的数字,和libmetasec_ml.so中AES的存储顺序惊人地完全一样(我这里是从73行开始)

    

  •  其次,上述的TE表在sub_69190函数被使用,F5后里面有while(1)循环,并且有TE0~TE3表内数据的异或,和aes.c中AES_set_encrypt_key源码的结构也很类似(这是典型的查表法实现,也就是说把subBytes、shiftRows、mixColums三个步骤的“结果”提前固化到几张表里面了(为啥不也把addRoundKey加进去了?因为key是变化的啊!),用的时候直接通过查表的方式得到结果,是典型的空间换时间打法!详情可参考文章末尾链接4),对比如下:

  

  注意:这里只有1个while循环,是因为密钥的长度是固定的,所以只需要一个while循环就够了!(密钥长度不同,while循环的次数也不同,AES有3种情况:128bit循环10次,192bit循环12次,256bit循环14次)

  •  最后,同样是在sub_69190函数种还有疑似shiftRows的代码,如下(通过LBYTE/BYTE1/BYTE2/HBYTE方式取4个不同位置的数据):

       

  •  借用上图,还发现不同的SBox之间互相异或,这是啥骚操作了?懂得大佬求指导! 

  以上种种迹象表明,x音的AES很有可能用了boringssl的aes实现,先根据boringssl的aes把反编译的函数名、变量名改改,便于静态分析!

   3、光说不练假把式,现在来调试看看这个sub_69190函数到底是不是AES_set_encrypt_key函数,如下:

         

   注意:第一个参数在R2,这里应该是key(如果以0x00算结尾,怎么感觉是17byte长了?后续还要继续深入调试再研究研究);第二个参数是bits,存放在R3,取值是0x100=256,所以这次的AES大概是AES-256!第三个是AES_KEY,注意是放栈上的,不是R4!

 

总结:

  1、截至目前,AES是业界公认最好的对称加密算法了,并且没有之一(DES和3DES就没必要提及了)。所以一旦涉及到双方保密通信,对称加密的算法大概是会是AES啦(这点不像hash算法,有md5、sha1、sha256等,逆向人员还要进一步判断到底是哪种)!用AES的magic number搜索,肯定一抓一个准

 

参考:

1、http://www.ssdfans.com/?p=8086  AES加密流程

2、https://www.bilibili.com/video/BV1i341187fK?spm_id_from=333.337.search-card.all.click  AES算法详解

3、https://blog.csdn.net/Jasmineaha/article/details/81412711  异或的性质和应用 

4、https://zhuanlan.zhihu.com/p/42264499  aes查表法实现

posted @ 2022-05-29 12:53  第七子007  阅读(1899)  评论(0编辑  收藏  举报