爱内涵易语言论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

快捷登录

在线
客服

支付故障请联系客服服务时间: 9:00-24:00

选择下列客服马上在线沟通:

快速
发帖

客服
热线


7*24小时客服服务热线

关注
微信

关注微信二维码
顶部
查看: 755|回复: 0

4399游戏盒最新算法讲解

[复制链接]

1766

主题

1852

帖子

3万

积分

管理员

Rank: 9Rank: 9Rank: 9

金币
9845
巨币
12233
积分
39555
发表于 2019-10-25 18:46:42 | 显示全部楼层 |阅读模式
第一次发教程 出现问题请见谅
0 O. C4 _% e: X0 |  ]6 Y这次是最新版本的4399游戏盒登陆密码加密讲解和两个sign的讲解  & [8 [$ _3 }3 t3 @' m9 \

  e5 e" [5 H* C4 V7 p8 K由于我测试的时候是无法对这个APP进行IDA调试的 所以就静态分析了一下3 p0 S( d! O! f

8 Z0 `7 W* Y: h" c5 G9 R: M2 K

' {( N4 d( R: w! b7 C# C! P, H0 w
  1. POST https://mapi.4399api.net/user/box/android/v1.0/log-in.html HTTP/1.1. ]  p( I" ]8 U) J' `
  2. User-Agent: 4399GameCenter/5.2.0.39 (android;Nexus 6P;6.0;1440x2392;WIFI;1376.416;yaoqing)
    ) N9 T. j3 O; V4 f
  3. mareacode: 350100
    * M8 f. \4 V7 P- T" A. T
  4. a-id: decd74ca59799d58
    9 C9 X! |# t/ R; |1 y  {
  5. e-id: 867981022896164
    " o4 g4 }( S% L( e( d+ y0 B
  6. m-id: D4%3A61%3A4E%3A13%3A10%3A1F8 P" o& L6 ^! g; a
  7. s-id:3 X$ {7 g( S& x  Q% c' v" q+ t
  8. mauth:$ [6 F% C5 q/ }
  9. mudid: 1085glt3vuUywD5g808eZb67a
    + O" W4 P) t) I
  10. pauth:
    $ C. P2 _! ~" E# r7 V0 u# q
  11. SM-DEVICEID: 2019101514035076086dc3e7e2dc00afe0043881a46e18018036cbcdd51ca5" Y; G0 G: g5 y) b$ G
  12. mdeviceId: 867981022896164" Q) j# l6 T3 Z
  13. mauthcode:; Y" n0 B6 n" C4 m$ h
  14. Content-Type: application/x-www-form-urlencoded
    2 i3 Z6 H9 m& }" F  H* p3 J3 }0 ^
  15. Content-Length: 1618 y! M, u1 \# p: n" `1 {# S3 C; f2 {
  16. Host: mapi.4399api.net: U- r8 i- L- f
  17. Connection: Keep-Alive
    0 R3 }, R- k! W# _
  18. Accept-Encoding: gzip5 H/ Z( {2 O; `8 E' w2 ~
  19. password=JE%2FYTsyiLwE%3D&deviceIdentifier=867981022896164&dateline=1571863440&sign=c80c8c800fa61cccc02e12e87da33620&model=Nexus%206P&username=13665098754&info=1
复制代码
这是抓到的登陆包) J8 X7 \' }8 k; F
大概能看到两个参数需要处理 一个password 一个sign
; c! _- `: b: G. o$ _. w6 X0 ?
) k, c+ `4 N2 P& j( t. w反编译2 N3 G; l' R3 W, n& P$ e0 t

8 Q9 s; \" d* X! r2 x- U: K+ D' S  q找到关键点
: Y1 c* Q% G. S* q6 u
1 f. g! w. ]1 u跟进以后就是Native函数了 这里我们从名字就能大概知道password是一个DESCBC类型的加密(不排除重写) 我们也只是猜测. A' d6 X4 Q2 c0 O6 C
/ o# N) ~: ]+ ]  S; Z

5 r* B0 _: q" T; K/ N
  1. public class AppNativeHelper {4 f; E4 l& |  J' |" e) S
  2. static {+ K1 _# t7 [/ D5 I( ]# W2 @7 D$ d
  3. try {
    ' W8 }. e4 M: F( b; M, K. V5 @
  4. SoFix.loadLibrary (BaseApplication.getApplication (), "m4399");
    ) h5 {, a& ], F4 S4 c
  5. Log.d ("AppNativeHelper", "load libm4399.so");; v, z$ ?# F# t) A
  6. }
    7 @* n1 j' j* _% s8 u2 k
  7. catch (SoLoadFailureException v0) {6 B: U4 J4 i& T* @" i5 v
  8. v0.printStackTrace ();& B/ x  }5 ^1 y. _
  9. }
    / H2 i: ?5 X+ _! s
  10. }# g  g+ g) y0 U
  11. public AppNativeHelper () {
    ( x& Y; H1 f( l& d0 k  M
  12. super ();
    8 O% s- L0 V% |7 x
  13. }4 E1 {3 U2 ^9 I% ~/ S$ m
  14. public static native int applyPatch (String arg0, String arg1, String arg2) {
    8 s" i# X7 C1 k& s1 X& a
  15. }
    & |/ _9 l# \# q. r
  16. public static native int delayRestartProcess (String arg0, String arg1, long arg2) {
    2 C4 [7 @) r0 z4 e+ h1 J% _
  17. }
    / O1 L$ g' U. h9 R
  18. public static final native String desCbcDecrypt (String arg0) {# U1 |2 e% O7 M' Z/ W2 f8 J
  19. }
    - o2 @1 Z' ^  P2 B" |2 {& O/ f3 g
  20. public static final native String desCbcEncrypt (String arg0) {
    6 z. o; _, N: `# `8 ?1 {! D& @
  21. }
复制代码
拿出libm4399.so拖进IDA进行处理  ' {. f& W% L# T5 Q3 c
; s  q. E8 k4 c& |
这个So是动态注册函数
' n5 V; ?# s1 {4 n; D* }! L' M, [4 M9 y5 c% c+ |
所以我们进入Jni_onload 导入头文件 找到RegisterNatives函数( Y1 W( y6 S, J' J3 Q/ V
RegisterNatives中第三个参数就是我们注册Java函数的实际地址
9 L; F9 `( Q/ G
; k% i  G( g" Y. J( W$ B; N2 \" c& f. i5 D: a( ]" Y+ F% y

7 F/ `6 `$ S: m; V- M2 A0 ~进去以后是DCD格式的 第一项是函数名 第二项好像是格式还是啥 重要的是第三项 这就是我们的函数地址了 找到我们要的函数 然后找到函数地址5 V" Q0 {" P5 l" N. _
' V+ K/ P$ [/ {$ j- [8 E, C
$ \# U( I8 ]4 O7 M: n% j" b2 y7 S' n
然后进来这个函数: |8 t4 _; o) B9 Q
" U  K) d' O! S2 j4 i" V* K
/ g+ m( s" J) k; V# o
  1. int __fastcall sub_17024(int a1, int a2)9 [; D3 h: ^, ^# F0 d( l
  2. {
    1 {; H2 o2 f- f( B# y3 q& T& H7 t
  3.   int v2; // r4% u+ p6 J9 G# [" Y9 ?2 M- b  r
  4.   int v3; // r5! }2 }/ M( S' D7 x# c/ o
  5.   char *v4; // r6
    6 Y; W8 ]2 [8 q# x) ~' R
  6.   int v5; // r05 j; K2 e% l" `( v  F8 D
  7.   int v6; // r3
    , U7 O, D: c1 ^/ J* b- n" w
  8.   char v7; // r26 s" S" b$ O# T; l: w( R
  9.   int v8; // r48 a3 J1 U: G% h# G3 G' |6 w
  10. # O' ?4 C/ E. M! E. o7 J5 U1 ?/ M( v
  11.   v2 = a2;; Q4 f- g0 _5 x& j  V* n
  12.   v3 = a1;: A+ v9 S/ X+ Y  E# K/ [: P- W
  13.   v4 = sub_17274(9, 1);* m7 U1 M$ ]3 |) w1 i! o5 [
  14.   v5 = 0;
    9 D7 {  a, r6 i4 `3 R5 g
  15.   do: q9 R: ^0 b6 G
  16.   {
    2 Z5 O) t7 b0 N6 W" V, ], s
  17.     v6 = (dword_1B040[-v5] + 101) >> 15;% F, R/ R! f/ h1 j" F( G0 E
  18.     v7 = v6 ^ 151;# u) m- b# g( J2 v+ H5 T6 j9 [3 R
  19.     if ( v6 >= 102 )! W( c# U4 }1 [4 }1 |
  20.       v7 = v6;4 Z& Y9 E% o( z/ h9 O
  21.     v4[-v5--] = v7;
    / R, d' F$ k% m) N7 S1 |. ?% g
  22.   }8 r9 O) Z" t! q. m3 J6 }
  23.   while ( v5 != -8 );                           // 循环8次 获取DESkey
    / Z8 i- W1 v  ?2 e
  24.   v8 = sub_64B8(v3, v2, v4);                    // //进入加密函数7 ^. ~! {: ]/ ?+ U9 }$ ^/ A& c
  25.   sub_17284(v4);
    4 B7 A0 Y9 ~& `. K
  26.   return v8;
    ) |. N; @4 P; t7 Y6 u% B: e& Z
  27. }
复制代码
. u" F/ R2 f# X! [) v; D* b

. e3 h* n1 _* a( E' J2 a通过前前后后的分析 这里就是获取Key的重要地方了 从一个地址里面取值出来 然后循环处理8次 然后我们进入dword_1B040看
" x% S4 m* B( H! P0 L' R; |. D: x! t

1 z9 n/ F7 N, T( ], @, X$ O% F! a- X' l( m* G/ `3 H; l: t

0 ]: J  \, m( A看不出什么猫腻 我们转换一下格式 先转Double再转为array IDA右键就有
! e0 _$ ^% B6 g/ V4 I" C, h
/ }4 c* @: h' R+ W- _$ C
0 v: A5 e$ q! k, W$ x1 V
4 W" L6 h4 N* S8 h* C
+ N& {1 f. Q! U1 i& |8 g( ?! ]
然后我用js翻译了这小段so逻辑理清楚后一下子就明白了
6 X0 ^( W8 u% O$ @( g/ _  R) n5 ?) e* {

5 Q9 Z, ^. l* b7 X: ^9 p
  1. function get(a) {
    1 A9 G5 B- }* Y) m. N3 W; u' V8 F' H. E
  2.     v6 = (a + 101) >> 15;
    1 _% [4 b; L) L7 a1 w6 u7 w9 M! V0 L- p
  3.     v7 = v6 ^ 151;
    * `0 J$ N& ~" T. g: t
  4.     if (v6 >= 102) {
    6 m/ \4 k; g4 {) O/ G* h
  5.         v7 = v6;" s/ B3 `' k- f$ `5 T% u! h
  6.     }
    ( G* `, F9 w4 N  Y& Q: `
  7.     return v7
      _% Q8 x5 t0 \- h" X! ~/ w
  8. }
    " G6 \& P% B2 f7 P0 W  w& w8 q( ^
  9. function a() {2 K- `' V% Y! P( i1 p) g2 d/ R4 L
  10.     arr = [0x3A7F9B, 0xFFDAFF9B, 0x3EFF9B, 0xFFD9FF9B, 0xFFCFFF9B, 0xFFEB7F9B, 0x3B7F9B, 0xFFD37F9B];) C7 |1 U5 q$ I; A2 k- j
  11.     var aa = new Array();$ n" j0 d8 u* ?9 J
  12.     for (var i = 0; i < 8; i++) {
    ) g& p5 A& j) E% G+ V6 J9 u# v, v; C
  13.         aa.push(get(arr[i]))
    1 A6 Y0 l* R* @6 |! W6 l: u. h: ~! G
  14.     }% U; ~( ?: O; r9 g0 A/ V! V
  15.     return aa
    3 y) |) D, W2 ]
  16. }
复制代码
% i: P4 I2 m3 T, G5 C
9 S* t8 v% T2 _% n: y
这里返回的就应该是key数组了 {117,-223,126,-221,-201,-192,119,-208}
% N+ Z, C' i9 j' o8 Z$ N# N) R. z然后转换到易语言的字节集就是{117,33,126,35,55,64,119,48}文本为u!~#7@w0 (这里的转换就是由于其他语言的byte取值范围 -128~ 127) 易语言好像没上限 所以我们只需要把-的给他加上256就能变成易语言的字节集了)
3 X. _* w" Y5 b  A  g1 ^- k1 O+ l  |6 y
到这一步我们已经拿到了KEY了
$ p# O$ I  Z) O. p  c' o  m  h' ]+ l3 ?; Q  Y1 e
现在就差一步IV了
& }7 S+ Y6 F- M* J  g2 f
# F. |' l4 V5 I6 j前面一直没说
8 W% y3 X( [' Z7 z% V: ^% }  A( i, [- i! K1 l; b0 {4 k
因为这个so函数名全是匿名的 所以在分析的时候很难去判断这个函数到底是干嘛的 这种so分析起来就需要自己花点时间和结合经验来操作了
: w9 U0 r* y5 c: B1 b
! h* F& J* U  C, K9 M这里我都给大家分析完了, S$ z0 A- s7 {1 b0 g
6 O7 Q1 I8 h2 w! V; L1 i1 `
) f0 P4 m; |( e9 d
& H: W. H. g! o  L- ]
' ^2 e1 o) I2 L+ y4 Q& s/ S
6 N; H) D9 X* j2 b9 {- Q0 e
我们已经找到了最关键的加密点了 而且我们现在key也有了 只差IV了5 H6 M5 D/ H% l4 s6 _; ]" f
4 p* C6 T& B* U) _
sub_4720这个匿名函数其实就是DES_cbc_encrypt
* k0 S6 F: c. q* o' y* T: m3 \9 S- O* U) B/ k
void DES_ncbc_encrypt(const unsigned char *input,unsigned char *output,
( r# ?' ]; g* }, }! W& D+ _, K0 {              long length,DES_key_schedule *schedule,DES_cblock *ivec,7 x% J/ P  \( l* b* C! R
              int enc);
& h8 y- k) @: n3 F/ h) x6 g' l5 E& K& g- j  n' B
这是DES_cbc_encrypt参数的定义
4 o  ]) s/ b+ l5 }7 J& \& v  H$ ~" R6 n3 G, d
依次是输入流 输出流 长度 key iv flag
3 z1 Z! [+ @0 W
( L* ]6 M) o& r+ Z0 R  J: O! V恰好能 对应上我们的函数 所以 iv应该就是我们&v11所指向的值了
9 x. O# Z- D# K2 D6 y9 E
& K! ]. u4 ~2 c- {& W: b# q" _! @

  x8 g" g2 ]( h* G
  1. .text:00006618 ; 20:   v12 = 0xEFCDAB90;/ ]9 t6 H) s/ ]/ ~
  2. .text:00006618                 LDR     R0, =0xEFCDAB90
    5 F1 a7 d! w0 F2 }7 H! N# P" R. r% Y
  3. .text:0000661A                 STR     R0, [SP,#0xB0+var_9C]
    # ]4 L, w; B- h8 P, r  w% s
  4. .text:0000661C ; 21:   v11 = 0x78563412;
    ; o; o4 |9 m% j
  5. .text:0000661C                 LDR     R0, =0x78563412: q1 k. t- I" M
  6. .text:0000661E                 STR     R0, [SP,#0xB0+var_A0]
复制代码
这里V11在我们的伪C代码中只赋值了0x78563412  但在汇编里面他实际是赋值了0xEFCDAB90 和0x78563412的 所以我们的iv应该就是0x1234567890ABCDEF0 m+ n9 B, n* z

/ B! n! n+ t# F在我们运行的时候 取值事从后往前取得 两个一组 这个我确实也不太明白具体原因 也是在无名侠前辈哪里学得 也就是 EF CD AB 90 78 56 34 12 这样来拼接得$ A( o$ Y, D6 v
" q% [7 [9 X9 I& b) r, o3 T2 g
好了 现在我们key iv都有了 我们在不排除有变异得情况下可以来测试一下能不能解开密文; V2 W( s0 W* P: m0 C
+ H8 x0 F6 r. G! ^9 X

( M; }& z: S8 M4 J$ V1 e2 M) }6 D0 V0 y& N

+ b4 s% ~7 _1 N成功解开5 P4 q, G$ X0 R1 Y. }* ^7 }0 c( B

$ l! ^6 ?8 }( z* O, ^2 ^# J. u这次so分析得难点其实就在于无法动态调试获取key或者IV 每一步逻辑都需要自己去看
( x- A2 }$ |$ H- F. y; Q+ d其次就是全是匿名函数 需要自己花点时间去查看每个函数的功能
' B: q( X3 W; `; k9 J
, U0 k  Q: g; D: z# R4 R- ]但总统上还是不算难得 只是需要慢慢琢磨一下得
0 d5 |0 H* P2 w4 [. t
0 ]% P2 \' l0 {' m, n4 e实在是太累了 如果大家对登陆得sign和签到得sign有想法我下次再给大家写文章把
' n5 z7 r2 G; M- V  d" f) U- g- K/ n
* {) [9 `( J! a) W( X  C% A
  d+ T) F$ ]5 s/ E. e6 _# H4 C  v) S0 V

" f0 J/ f; J2 O- g# u5 U

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|小黑屋|爱内涵易语言论坛 ( 浙ICP备19016710号-3 )

GMT+8, 2022-1-17 15:12 , Processed in 0.082378 second(s), 24 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表