无名侠 发表于 2016-4-23 23:30

音悦台下载加密算法s2k分析

这是我给我学生准备的一个例子。

音悦台在下载的时候会发一个包:
http://mapi.yinyuetai.com/download/statistics.json?D-A=0&s=3dcfae0fd9ff76e83ef2c2eef357ebdebK37u4&id=2553946
其中S参数是在SO库中完成计算的。

通过搜索download关键字能很快定位到下载位置,然后能找到com/yinyuetai/utils/S2K这个类完成了加密工作。

这个类中有一个native函数:
private static native s2k(Ljava/lang/String;)Ljava/lang/String;

SO库名是:
s2k_chris

用IDA载入这个SO,在导出表中搜索“Java”,能快速筛选所有对Java层的接口。
导出函数:
Java_com_yinyuetai_utils_S2K_s2k

这个函数的流程很简单:
1、Log输出输入参数。
2、调用s2k函数。
3、Log输出s2k函数返回结果
4、对char * 字符串进行转换并返回。

既然这个SO已经为我们提供了输出功能,那就再好不过了。
如图:
注意“+”不属于参数的一部分,这是开发者为了好看吧。

输入参数是一串我们看不懂的东西,其实这个是服务器返回的,查询这个字符串的封包如下(id就是下载文件的ID了):
GET http://mapi.yinyuetai.com/download/statistics.json?D-A=0&id=2553946
返回json数据,s字段就是输入参数。

s2k才是核心函数,我们继续分析:
a1是输入字符串,a2应该是一个很长的缓冲区
.text:0000190C ; int __fastcall s2k(const char *a1, char *a2)
.text:0000190C               EXPORT s2k
.text:0000190C s2k                                     ; CODE XREF: Java_com_yinyuetai_utils_S2K_s2k+5Ap
.text:0000190C
.text:0000190C var_E0          = -0xE0
.text:0000190C var_DC          = -0xDC
.text:0000190C var_D8          = -0xD8
.text:0000190C var_D4          = -0xD4
.text:0000190C var_D0          = -0xD0
.text:0000190C var_CC          = -0xCC
.text:0000190C var_C8          = -0xC8
.text:0000190C var_C4          = -0xC4
.text:0000190C var_C0          = -0xC0
.text:0000190C var_BC          = -0xBC
.text:0000190C var_B8          = -0xB8
.text:0000190C var_B4          = -0xB4
.text:0000190C var_B0          = -0xB0
.text:0000190C var_AC          = -0xAC
.text:0000190C var_A4          = -0xA4
.text:0000190C var_4C          = -0x4C
.text:0000190C dest            = -0x44
.text:0000190C var_24          = -0x24
.text:0000190C
.text:0000190C               PUSH    {R4-R7,LR}
.text:0000190E               MOV   R7, R9
.text:00001910               MOV   R6, R8
.text:00001912               PUSH    {R6,R7}
.text:00001914               LDR   R3, =(__stack_chk_guard_ptr - 0x191E)
.text:00001916               SUB   SP, SP, #0xC4
.text:00001918               ADD   R5, SP, #0x94
.text:0000191A               ADD   R3, PC ; __stack_chk_guard_ptr
.text:0000191C               LDR   R6, ; __stack_chk_guard
.text:0000191E               MOVS    R2, #0x4A
.text:00001920               MOV   R9, R0
.text:00001922               LDR   R3,
.text:00001924               MOV   R8, R1
.text:00001926               ADD   R0, SP, #0x9C   ; dest
.text:00001928               STR   R3,
.text:0000192A               STRB    R2,
.text:0000192C               MOVS    R2, #0x37       ; MD5求值前缀J7k$x*U5
.text:0000192E               STRB    R2,    ; R5指向最终MD5计算的字符串缓冲区
.text:00001930               MOVS    R2, #0x6B
.text:00001932               STRB    R2,
.text:00001934               MOVS    R2, #0x24
.text:00001936               STRB    R2,
.text:00001938               MOVS    R2, #0x78
.text:0000193A               STRB    R2,
.text:0000193C               MOVS    R2, #0x2A
.text:0000193E               STRB    R2,
.text:00001940               MOVS    R2, #0x55
.text:00001942               STRB    R2,
.text:00001944               MOVS    R2, #0x35
.text:00001946               MOVS    R3, #0
.text:00001948               STRB    R2,
.text:0000194A               MOV   R1, R9          ; src
.text:0000194C               MOVS    R2, #0x10       ; n
.text:0000194E               STR   R3, ; 初始化缓冲区
.text:00001950               STR   R3,
.text:00001952               STR   R3,
.text:00001954               STR   R3,
.text:00001956               STR   R3,
.text:00001958               STR   R3,
.text:0000195A               STR   R3,
.text:0000195C               STR   R3,
.text:0000195E               BLX   strncat         ; 把输入字符串拼接到R0
.text:0000195E                                       ; R5=SP+#0x94 初始串“J7k$x*U5”8字节
.text:0000195E                                       ; R0=SP+#0x9C
.text:0000195E                                       ; 实际相当于 “J7k$x*U5”+输入字符串
.text:00001962               LDR   R0, =(aRandom_seedS - 0x196C)
.text:00001964               MOVS    R1, R5
.text:00001966               ADD   R7, SP, #0xE0+var_A4
.text:00001968               ADD   R0, PC          ; "random_seed= -%s-\n"
.text:0000196A               BLX   printf
.text:0000196E               MOVS    R0, R7          ; R7=MD5的ctx结构
.text:00001970               BL      MD5Init
.text:00001974               MOVS    R0, R5          ; s
.text:00001976               BLX   strlen
.text:0000197A               ADD   R4, SP, #0xE0+dest.field_0+0x10
.text:0000197C               MOVS    R2, R0
.text:0000197E               MOVS    R1, R5          ; R5 = 刚才拼接的字符串
.text:00001980               MOVS    R0, R7
.text:00001982               BL      MD5Update
.text:00001986               MOVS    R0, R7
.text:00001988               MOVS    R1, R4
.text:0000198A               BL      MD5Final
.text:0000198E               LDRB    R0,
.text:00001990               LDRB    R3,
.text:00001992               LDRB    R2,
.text:00001994               STR   R0,
.text:00001996               LDRB    R0,
.text:00001998               LDR   R1, =(a02x02x02x02x02 - 0x19A2)
.text:0000199A               STR   R0,
.text:0000199C               LDRB    R0,
.text:0000199E               ADD   R1, PC          ; "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02"...
.text:000019A0               STR   R0,
.text:000019A2               LDRB    R0,
.text:000019A4               STR   R0,
.text:000019A6               LDRB    R0,
.text:000019A8               STR   R0,
.text:000019AA               LDRB    R0,
.text:000019AC               STR   R0,
.text:000019AE               LDRB    R0,
.text:000019B0               STR   R0,
.text:000019B2               LDRB    R0,
.text:000019B4               STR   R0,
.text:000019B6               LDRB    R0,
.text:000019B8               STR   R0,
.text:000019BA               LDRB    R0,
.text:000019BC               STR   R0,
.text:000019BE               LDRB    R0,
.text:000019C0               STR   R0,
.text:000019C2               LDRB    R0,
.text:000019C4               STR   R0,
.text:000019C6               LDRB    R0,
.text:000019C8               STR   R0,
.text:000019CA               LDRB    R0,
.text:000019CC               STR   R0,
.text:000019CE               MOV   R0, R8          ; s
.text:000019D0               BLX   sprintf         ; 把md5格式化成文本流
.text:000019D4               MOV   R0, R8
.text:000019D6               MOVS    R2, #6          ; n
.text:000019D8               MOV   R1, R9          ; src
.text:000019DA               ADDS    R0, #0x20       ; dest // R0=R8+32就是跳过32个字符,在MD5文本结果的后面追加6个字符。
.text:000019DA                                       ; 源字符串指针R9,也就是第一个参数。
.text:000019DC               BLX   strncat
.text:000019E0               LDR   R0, =(aFlash_encrypt_ - 0x19E8)
.text:000019E2               MOV   R1, R8
.text:000019E4               ADD   R0, PC          ; "flash_encrypt_k= -%s-\n"
.text:000019E6               BLX   printf
.text:000019EA               LDR   R2,
.text:000019EC               LDR   R3,
.text:000019EE               MOVS    R0, #0
.text:000019F0               CMP   R2, R3
.text:000019F2               BNE   loc_19FE
.text:000019F4               ADD   SP, SP, #0xC4
.text:000019F6               POP   {R2,R3}
.text:000019F8               MOV   R8, R2
.text:000019FA               MOV   R9, R3
.text:000019FC               POP   {R4-R7,PC}

因此,这个算法的过程很简单: 取MD5("J7k$x*U5"+输入文本)+取文本左边(输入文本,6)



经验总结:
我一开始是不知道"J7k$x*U5"+输入文本是如何拼接的,因为IDA把一个缓冲区给分成了多个变量标号,所以看着很晕,动态调试的时候反应过来了。
R5=SP+#0x94 初始串“J7k$x*U5”8字节
R0=SP+#0x9C R0是参数拼接的位置

差值正好是8
所以R5最后指向的就是“J7k$x*U5”+参数


a4431693 发表于 2016-4-23 23:43

比我厉害,哈哈。。。。。至少你看懂了

chenjingyes 发表于 2016-4-24 00:28

楼主幸苦了哈哈哈谢谢分享

stayoulove 发表于 2016-4-24 02:27

厉害啊,看来我还要加倍学习。谢谢分享

Mir丶翰林 发表于 2016-4-24 07:39

厉害 学习了

Programmer 发表于 2016-4-25 03:57

赞。。。。。。。。。

junxuan 发表于 2016-4-26 19:25

没明白,有详细点的代码吗?

liaoxueyong 发表于 2016-4-26 20:37

路过 不过也看看

Gordon0918 发表于 2016-6-22 22:39

膜拜ing!!

沧晓 发表于 2016-6-24 07:28

表示膜拜
页: [1] 2 3
查看完整版本: 音悦台下载加密算法s2k分析