爱内涵论坛

 找回密码
 立即注册
搜索
查看: 318|回复: 0

4399游戏盒最新算法讲解

[复制链接]

897

主题

952

帖子

3万

积分

管理员

Rank: 9Rank: 9Rank: 9

金币
9855
巨币
6119
积分
37376

2019年众筹小组s2019年众筹小组ss2019年众筹小组sss

发表于 2019-10-25 18:46:42 | 显示全部楼层 |阅读模式
第一次发教程 出现问题请见谅; t2 U0 Q, }) W0 m, d8 U
这次是最新版本的4399游戏盒登陆密码加密讲解和两个sign的讲解  8 T  {8 L/ J# h9 _

! g) @+ M/ I' C, A  j8 R, D8 Z由于我测试的时候是无法对这个APP进行IDA调试的 所以就静态分析了一下3 D7 V$ b, }5 k) X7 H) w( z
6 [/ ^2 C, F9 [
4 E$ v/ Q' t( [% L
  1. POST https://mapi.4399api.net/user/box/android/v1.0/log-in.html HTTP/1.1/ Z* p$ \/ [& B* x% J
  2. User-Agent: 4399GameCenter/5.2.0.39 (android;Nexus 6P;6.0;1440x2392;WIFI;1376.416;yaoqing)- i1 q7 F: c0 d. r& \
  3. mareacode: 350100. G: ~# y$ v3 v# o+ }
  4. a-id: decd74ca59799d584 a) ^8 @  R( F) \- X! p1 c
  5. e-id: 867981022896164
    ! g- M0 T1 _/ e0 q
  6. m-id: D4%3A61%3A4E%3A13%3A10%3A1F4 H" u8 O4 s2 W. i7 E0 M$ E
  7. s-id:
    4 A: C* ^% S; K' Y! h& {
  8. mauth:1 ^6 T5 g  U$ V& B4 C* g$ a; d
  9. mudid: 1085glt3vuUywD5g808eZb67a
    5 ?+ T( E7 |0 P* n! x
  10. pauth:
    . E+ e" ~! \# s, z
  11. SM-DEVICEID: 2019101514035076086dc3e7e2dc00afe0043881a46e18018036cbcdd51ca50 O" y+ K4 g2 F# X
  12. mdeviceId: 867981022896164
      t- u6 [) L* K. M) N2 V7 q
  13. mauthcode:
    - q( _+ U4 ?" X% {5 P4 W
  14. Content-Type: application/x-www-form-urlencoded
    9 A1 m2 f- u) p3 I+ h& q7 V
  15. Content-Length: 161
    & C  d0 n* v* {5 [" y8 W* j+ L3 x
  16. Host: mapi.4399api.net
    ; I. @2 E3 F  c+ }4 l. u' O* N
  17. Connection: Keep-Alive
    & W" s0 H4 K4 y, }
  18. Accept-Encoding: gzip
    * T" x# x  U* U( d6 l6 L
  19. password=JE%2FYTsyiLwE%3D&deviceIdentifier=867981022896164&dateline=1571863440&sign=c80c8c800fa61cccc02e12e87da33620&model=Nexus%206P&username=13665098754&info=1
复制代码
这是抓到的登陆包
% E& H2 b9 N* f* \# ]! ^# y大概能看到两个参数需要处理 一个password 一个sign% x( s" ~( B/ t1 L; _4 A+ J
; T/ c7 R/ N  _
反编译4 m4 k  \+ E  I" f5 W
3 Z4 `9 ?, [9 o
找到关键点
* Q) u9 h- `8 Q# s  M- u! M* W
- Y; _* b# A% Y/ {: f" s+ ^跟进以后就是Native函数了 这里我们从名字就能大概知道password是一个DESCBC类型的加密(不排除重写) 我们也只是猜测. ?. ?& U( P# p/ A8 [4 b6 J

4 c3 O: C2 T% g6 K- ?

) o6 B/ K( j$ Z
  1. public class AppNativeHelper {
    4 I. r% u$ ~: r1 i
  2. static {* D; t8 y% N$ s1 ^- P2 E7 p
  3. try {1 b: E' w( C' O2 R) @; G/ c
  4. SoFix.loadLibrary (BaseApplication.getApplication (), "m4399");
    . f+ N, i; b7 ^# F3 _2 a$ e
  5. Log.d ("AppNativeHelper", "load libm4399.so");6 ^! r! y: o7 V+ W- d* t' N
  6. }% a/ L5 e$ Z6 s1 c
  7. catch (SoLoadFailureException v0) {5 {& T' B. y) u$ }) D
  8. v0.printStackTrace ();; F6 j2 e* h/ V9 o
  9. }4 d5 f* ~; w4 @, `5 o6 b5 I
  10. }+ l2 B' v+ f: j
  11. public AppNativeHelper () {& P7 ~- `# j# y- p, d
  12. super ();* a9 P# A3 p  G, {$ I/ ]) ]3 ]; j
  13. }2 W. o8 o+ A. G4 `  h) V4 k2 @& O
  14. public static native int applyPatch (String arg0, String arg1, String arg2) {7 S: w' i- P( l$ d8 \- d% ?
  15. }
    # l7 t0 {; E3 X6 [1 X$ P
  16. public static native int delayRestartProcess (String arg0, String arg1, long arg2) {
    5 e( j% A' q" t- b
  17. }! k* T, W! A- Z& D" P/ ~7 Z3 Z+ ?+ Q( }5 G
  18. public static final native String desCbcDecrypt (String arg0) {3 P1 I0 H) |: B: H3 `7 K0 s/ M9 M2 R
  19. }
    ( P* s5 n1 g: r. b0 j" ^
  20. public static final native String desCbcEncrypt (String arg0) {( e! \9 d: O, E* i/ ]$ I
  21. }
复制代码
拿出libm4399.so拖进IDA进行处理  % M+ P& \& @; a6 b+ v7 C, N
- n( N' Z; l# X- Q+ a) @
这个So是动态注册函数
$ }! A5 G% @& O! S- f" ?# V, D
. Y8 o& q$ u6 [. B$ s9 N* @/ Z所以我们进入Jni_onload 导入头文件 找到RegisterNatives函数) n  [4 Y! e1 r+ o7 ~. j  U) Z
RegisterNatives中第三个参数就是我们注册Java函数的实际地址5 Y/ ~& ?7 H8 n/ s
6 l( Z. ~0 a$ V2 L
! x8 S  `/ p3 M  H' l9 g2 ?

# I. @. K# _4 N+ F进去以后是DCD格式的 第一项是函数名 第二项好像是格式还是啥 重要的是第三项 这就是我们的函数地址了 找到我们要的函数 然后找到函数地址
- s/ Z$ t! i5 L5 g
: E. ^) Z4 D8 P& A
* r' B3 y  h+ M% ?  A然后进来这个函数
' p& W0 D; e! v1 |6 B6 s; o4 o$ @7 \0 p: d8 t! I6 I

  T8 z$ ~9 w6 S% ]6 p2 T& n# L7 b
  1. int __fastcall sub_17024(int a1, int a2). y  }% M, e# K# |
  2. {' `7 k" w4 j* S' q1 i
  3.   int v2; // r47 d+ u2 u% z5 E; y
  4.   int v3; // r5
    ; T. U$ c0 Y; S+ [
  5.   char *v4; // r6
    4 [- b3 U# B0 i' c% X0 l. c8 V& ?" E
  6.   int v5; // r0* g4 M* A% r' i- T: O
  7.   int v6; // r36 c& t8 V) h3 }; f* x- ~- E, a
  8.   char v7; // r2) }1 B: H% F( n! _$ k* G
  9.   int v8; // r4$ ?5 g  R2 M" z3 C. I. \+ ?

  10. 8 @$ @4 R3 ^: x- h* \; Q
  11.   v2 = a2;
    4 W( h9 L! F+ M% E
  12.   v3 = a1;
    & ^/ Y" c* e% d; o1 v  L8 I5 J" y) _
  13.   v4 = sub_17274(9, 1);
    ) r7 H; y, N& y( F5 q$ {/ Z
  14.   v5 = 0;6 t9 ]5 D1 c; P1 a4 w' g6 Y5 G
  15.   do
    1 j/ d* s0 v8 W/ o: K) x% s! T
  16.   {
    / o( }% \9 h5 P& C; Q4 d
  17.     v6 = (dword_1B040[-v5] + 101) >> 15;& M! c; x1 i' c) {$ y
  18.     v7 = v6 ^ 151;
    & Q) \1 g6 ~/ t% h3 \6 z
  19.     if ( v6 >= 102 )3 Q. S8 z- J& V8 Q# @% E
  20.       v7 = v6;- y& g, ?- v& B
  21.     v4[-v5--] = v7;  S6 i) `0 q: _3 y' {
  22.   }
    + q7 w# `3 O) D& o! d  y8 ~0 E
  23.   while ( v5 != -8 );                           // 循环8次 获取DESkey) z, e- z% E1 j( l4 U( \# w2 F3 }
  24.   v8 = sub_64B8(v3, v2, v4);                    // //进入加密函数
    , C4 T; s5 E% K# X
  25.   sub_17284(v4);
    $ g5 X4 v5 t, R  |7 t* `* O/ o, M5 c
  26.   return v8;
    % e( U: m8 `; I2 a
  27. }
复制代码
- A7 A& t4 D( }5 R9 c
, |: K5 s$ B7 m# u0 ]2 ^0 c
通过前前后后的分析 这里就是获取Key的重要地方了 从一个地址里面取值出来 然后循环处理8次 然后我们进入dword_1B040看7 y4 l0 m+ }$ N

7 z4 c. p! D2 D9 ~, F$ W9 F0 p& U
1 \7 d8 f' d. i4 r: l. u% Y  K

- N) \7 _& w9 F$ |! i  C
/ B. t4 E, m" r. V- _: H9 q$ J看不出什么猫腻 我们转换一下格式 先转Double再转为array IDA右键就有, I: i6 k7 K! @2 u0 y  |& q0 L( d* [

# ^. F2 b/ I/ a/ I9 N

, l" ~; G; e8 R2 G4 I! J$ w
4 Z# X( T5 H# j8 ^: V8 m
3 c& U' i' z8 f然后我用js翻译了这小段so逻辑理清楚后一下子就明白了
9 r4 e9 A$ ]' t8 j& d/ o9 L. v* k# p! X! E6 v
9 e: ]. S9 T9 l! F
  1. function get(a) {
    4 |$ b: @* L) M( i  j
  2.     v6 = (a + 101) >> 15;
    . q+ c$ \8 n3 K& t3 k$ m$ U: I0 l
  3.     v7 = v6 ^ 151;
    : w( ]) t* W3 n, X- S: K; e  Q" ]. u
  4.     if (v6 >= 102) {3 {# e9 [3 c. Z: Z) b
  5.         v7 = v6;
    / o2 |) c) ^  O1 V; \. y
  6.     }3 k4 v  y* g# j) C5 T& }3 F. ~- c
  7.     return v7
    ! J5 l( X$ I( {% |5 W+ F/ j  T. `5 t  X
  8. }
    ) Y6 w0 }$ G- O* r7 R. r$ _# s& V9 \
  9. function a() {
      k3 d- R) }# }" H* x; H! d
  10.     arr = [0x3A7F9B, 0xFFDAFF9B, 0x3EFF9B, 0xFFD9FF9B, 0xFFCFFF9B, 0xFFEB7F9B, 0x3B7F9B, 0xFFD37F9B];
    $ s. W! m- ]# Z) t9 S3 z' l/ m' ?
  11.     var aa = new Array();
    5 u9 |  n0 p; \. k$ Z: t2 e/ \0 Y1 ?
  12.     for (var i = 0; i < 8; i++) {
    / q" b& S/ l" |! b% y) @( ]5 q, Z
  13.         aa.push(get(arr[i]))& q. R( m- W$ {7 ]% Z( A. {8 x3 ]
  14.     }  N& c3 k' J% \5 B0 f$ {& o
  15.     return aa2 t1 j) C5 h. P" x0 k( T4 ?
  16. }
复制代码

2 V/ N, L/ C* v" \8 |- U+ s5 h- G  V; R7 K! t2 t0 Q
这里返回的就应该是key数组了 {117,-223,126,-221,-201,-192,119,-208}' J! n- z* @1 Q, j, i
然后转换到易语言的字节集就是{117,33,126,35,55,64,119,48}文本为u!~#7@w0 (这里的转换就是由于其他语言的byte取值范围 -128~ 127) 易语言好像没上限 所以我们只需要把-的给他加上256就能变成易语言的字节集了)5 i& y/ U) }  ~3 e
+ U+ e) p4 n* z; {
到这一步我们已经拿到了KEY了4 h, U5 e' M8 s# p: t; E% l
: z1 j( U. y3 Y. Z
现在就差一步IV了; Z; P$ y0 W7 {1 p
* m- j$ @' P' S+ m% s
前面一直没说
. e4 b3 h. u% I, Y" L) U7 g4 }, N, G  t9 [' j# w
因为这个so函数名全是匿名的 所以在分析的时候很难去判断这个函数到底是干嘛的 这种so分析起来就需要自己花点时间和结合经验来操作了
/ P8 Y% `3 L- d/ p0 m1 ]3 H
* F( z, A& z3 D3 j1 n这里我都给大家分析完了
: c* Q1 B: h' K0 x7 l* M+ X* T
  ]" k$ f+ q0 J- O

0 t# b* E% ?' ]. g7 L
; z, E, k0 O2 a9 \& o& }# u
; v6 C0 z% Y8 r' h$ |# m: C+ _# s
0 {7 ~  Q; Z; A' p0 ]& w我们已经找到了最关键的加密点了 而且我们现在key也有了 只差IV了, T& ~; y" _# c  @- {- }
7 [, q; b- Z  T, f8 U; j
sub_4720这个匿名函数其实就是DES_cbc_encrypt2 x: o9 c$ V* I  e

  v3 A( a$ h# p$ ~" zvoid DES_ncbc_encrypt(const unsigned char *input,unsigned char *output,
! ^0 t) b& \# O$ B1 i) h$ R/ _% B              long length,DES_key_schedule *schedule,DES_cblock *ivec,& z* W2 M' Z, U' `: k
              int enc);
8 J8 \* F" \0 E3 M0 b
% X- A6 k) {$ Q" C4 t0 V这是DES_cbc_encrypt参数的定义: d% `( l  l& h, \4 g8 [' o3 i/ R
6 Y: M! M* r) g9 C/ U( ?: @
依次是输入流 输出流 长度 key iv flag! O$ ?) i7 z9 \% q( a( R- f

  N1 b5 c0 L4 C) J6 X9 {2 X' L恰好能 对应上我们的函数 所以 iv应该就是我们&v11所指向的值了8 z8 u0 |" x5 _) M& O
, m' B4 k3 G+ ]4 M( a

+ U# P) A6 `. |5 p. u/ v9 O
  1. .text:00006618 ; 20:   v12 = 0xEFCDAB90;
    " D! A: A+ d5 K) p- y. G1 P
  2. .text:00006618                 LDR     R0, =0xEFCDAB90
    + B5 A  q' e! [9 \/ D+ ]2 K, d2 `1 r( `
  3. .text:0000661A                 STR     R0, [SP,#0xB0+var_9C]
    2 s. h' |: {1 Y+ l5 k
  4. .text:0000661C ; 21:   v11 = 0x78563412;! M7 l  I* n" f; b* X) l' O
  5. .text:0000661C                 LDR     R0, =0x785634121 ~) X' B0 M- m7 I7 U. T) X
  6. .text:0000661E                 STR     R0, [SP,#0xB0+var_A0]
复制代码
这里V11在我们的伪C代码中只赋值了0x78563412  但在汇编里面他实际是赋值了0xEFCDAB90 和0x78563412的 所以我们的iv应该就是0x1234567890ABCDEF% X4 z) T6 J, f  u4 y

" I3 I$ K7 N% q在我们运行的时候 取值事从后往前取得 两个一组 这个我确实也不太明白具体原因 也是在无名侠前辈哪里学得 也就是 EF CD AB 90 78 56 34 12 这样来拼接得4 e# f8 J; o" ?" S

& G% G/ v7 O( L; k9 m; X  k6 Y, r好了 现在我们key iv都有了 我们在不排除有变异得情况下可以来测试一下能不能解开密文
; h" e" `" G3 S: R
7 y3 }! T( ^$ G' o1 [% w

; w  a5 R* i: \9 N9 o
5 I& P" _7 J6 c* P7 d
- r7 |! p3 `! L2 y1 I成功解开: l6 S: T& |, W" x& ?" |5 E) t
9 o; x& A$ C0 i% G; q
这次so分析得难点其实就在于无法动态调试获取key或者IV 每一步逻辑都需要自己去看
$ Q6 s$ B& f, Y: E' W* ?0 `其次就是全是匿名函数 需要自己花点时间去查看每个函数的功能
$ F' v! M& |! [0 M( p
. r- Y$ ~5 c# t  h% T但总统上还是不算难得 只是需要慢慢琢磨一下得
" k; B3 j" U) _; u1 Y
: \: j& ~" z4 [) @1 D实在是太累了 如果大家对登陆得sign和签到得sign有想法我下次再给大家写文章把/ A4 n) M5 [" A( [

7 N* W$ h! k$ f+ T& D6 X# t1 n1 d& _
0 u1 n5 [: `7 C7 ]4 {& H' ^, m0 B

7 b, i& q* m' ?5 @1 j
* S, b' ^+ _' Q( J

本帖子中包含更多资源

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

x
爱内涵论坛关注易语言与按键精灵的脚本辅助软件开发领域。                     VIP视频目录            VIP会员介绍            自助加入会员            联系客服加入会员            爱内涵免费①群            爱内涵免费②群            爱内涵免费③群
回复

使用道具 举报

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

本版积分规则

QQ|Archiver|手机版|小黑屋|爱内涵论坛 ( 浙ICP备19016710号-3

GMT+8, 2020-11-24 19:31 , Processed in 0.541118 second(s), 13 queries , Gzip On, File On.

Powered by Discuz! X3.3

© 2001-2020 爱内涵论坛

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