爱内涵易语言论坛

 找回密码
 立即注册

在线
客服

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

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

快速
发帖

客服
热线


7*24小时客服服务热线

关注
微信

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

4399游戏盒最新算法讲解

[复制链接]
avatar

1767

主题

1853

帖子

3万

积分

管理员

Rank: 9Rank: 9Rank: 9

金币
9845
巨币
12887
积分
39630
online_admin 发表于 2019-10-25 18:46:42 | 显示全部楼层 |阅读模式
第一次发教程 出现问题请见谅% A& b) X7 Z; t" l9 m7 r. p+ }
这次是最新版本的4399游戏盒登陆密码加密讲解和两个sign的讲解  
( Q7 I' f- @; K7 l$ W
) X3 j, W1 L8 a1 {* n3 h由于我测试的时候是无法对这个APP进行IDA调试的 所以就静态分析了一下9 J1 u9 i; V: C8 p6 L6 k% ~

5 o2 Y! ]( T# r
$ d. S# }: Z2 m6 N
  1. POST https://mapi.4399api.net/user/box/android/v1.0/log-in.html HTTP/1.1
    $ ]5 o9 Y: D3 N) g! J! y
  2. User-Agent: 4399GameCenter/5.2.0.39 (android;Nexus 6P;6.0;1440x2392;WIFI;1376.416;yaoqing)% N, I/ V0 v* S2 r
  3. mareacode: 350100; {4 i' L4 _' ^' s0 z
  4. a-id: decd74ca59799d58
    6 t" D, T( w; n' N! Y
  5. e-id: 867981022896164* d0 W: ]9 T4 F' `0 V
  6. m-id: D4%3A61%3A4E%3A13%3A10%3A1F% I. ?0 ?6 ?0 \: }
  7. s-id:& ~8 D) i+ P8 Q* a" Q: m3 e9 {
  8. mauth:5 y" m( m1 v# b( y2 ?& \1 N
  9. mudid: 1085glt3vuUywD5g808eZb67a
    # b8 g3 Z* d4 I
  10. pauth:/ n2 E* `" _% W5 g; _4 @" J
  11. SM-DEVICEID: 2019101514035076086dc3e7e2dc00afe0043881a46e18018036cbcdd51ca53 _4 u+ m; p1 ~" R( {  {& n  h
  12. mdeviceId: 867981022896164
    ( I1 c1 N0 s. _$ r: p' D6 [. j+ b
  13. mauthcode:
    7 O; V# N! ?" x. W& s
  14. Content-Type: application/x-www-form-urlencoded* g3 ?6 a8 g8 {( `' g7 x
  15. Content-Length: 161
    4 {5 K( W4 m% ]
  16. Host: mapi.4399api.net! K4 J8 b6 h$ c5 @0 F- j, X7 ~
  17. Connection: Keep-Alive
    2 c* }' N0 k6 z0 Y9 \
  18. Accept-Encoding: gzip
    ) d* N( `- y- t' f$ H+ U  ?; a* p
  19. password=JE%2FYTsyiLwE%3D&deviceIdentifier=867981022896164&dateline=1571863440&sign=c80c8c800fa61cccc02e12e87da33620&model=Nexus%206P&username=13665098754&info=1
复制代码
这是抓到的登陆包9 L6 T/ ]9 p2 v, G* V& s
大概能看到两个参数需要处理 一个password 一个sign
# H% B, n6 F  Y2 h$ R$ ?8 I2 z. ^) z
反编译
5 i% e5 [" S1 H5 p) ?% J2 ?4 ~" V( B; Z$ v5 C
找到关键点7 r' S, [2 I7 D( j# M3 M/ i
! r/ _1 B& |7 `, d+ `
跟进以后就是Native函数了 这里我们从名字就能大概知道password是一个DESCBC类型的加密(不排除重写) 我们也只是猜测! O+ J+ \# M0 m, `. I3 l' r8 w1 K1 u

! M( F. o9 J7 L" e" s/ m8 R
4 l, c3 d4 ^- n/ X2 n) Z9 E* k
  1. public class AppNativeHelper {1 g8 W. H5 N* a7 ^
  2. static {
    ' }0 F; F+ I7 ]. t# t
  3. try {, ?! p2 Z: z( U' B) m+ o0 \& Q. Z) a
  4. SoFix.loadLibrary (BaseApplication.getApplication (), "m4399");
    % v! [% J% S; H( Q# z
  5. Log.d ("AppNativeHelper", "load libm4399.so");$ I9 k. ~4 u; _* L7 u
  6. }$ s  x( l8 z. `& w* J3 X" F9 m* }9 x
  7. catch (SoLoadFailureException v0) {
    0 t' q& F; G. U; D! j1 ^8 C
  8. v0.printStackTrace ();7 B: q8 M8 m4 p& l' l
  9. }
    0 B7 a# I- H! {) u$ D2 A& W
  10. }& T7 V. `+ }6 v- T$ c6 v) }
  11. public AppNativeHelper () {
    + N$ k7 ^' @* k) H  O
  12. super ();
    1 p% v+ a$ B7 G3 r) {7 M
  13. }
      P$ E( m7 w0 R6 f4 G
  14. public static native int applyPatch (String arg0, String arg1, String arg2) {# L- I3 S& r4 {( I. w& b/ x
  15. }
    5 v5 r  R2 U  x3 P- x% h+ _3 D1 p
  16. public static native int delayRestartProcess (String arg0, String arg1, long arg2) {" ]' ]1 y4 N# k& b
  17. }1 J  I3 u' H! t9 A
  18. public static final native String desCbcDecrypt (String arg0) {" X: H4 @9 m  [/ r7 v) h% }9 g. J7 k
  19. }& |# ~$ a9 ^& x! p2 K4 C* j8 X# O
  20. public static final native String desCbcEncrypt (String arg0) {
    8 G4 b$ s- [4 L
  21. }
复制代码
拿出libm4399.so拖进IDA进行处理  ; o2 a5 y8 O4 u3 J# _$ G/ x

; i' x3 s8 J4 f8 h( F" Y这个So是动态注册函数" t$ d/ f" @$ ?5 N3 F
# H7 X7 @( K6 u* C3 I+ j9 p
所以我们进入Jni_onload 导入头文件 找到RegisterNatives函数
+ p1 ]* Q8 F- G$ M; X. T  bRegisterNatives中第三个参数就是我们注册Java函数的实际地址
' i# Q# e( Z8 N4 i7 z- P, r$ l
! N! I0 Z0 N: T7 ~  U; X. J
* @  b& @! h; O9 H7 U
/ f$ }0 b/ c  F7 f/ @5 w进去以后是DCD格式的 第一项是函数名 第二项好像是格式还是啥 重要的是第三项 这就是我们的函数地址了 找到我们要的函数 然后找到函数地址* m) _' E+ [6 o9 @; H) d% m/ F
& F/ P# H! t2 e5 S; B4 q1 D
0 L( c* |# h* z
然后进来这个函数9 g4 l5 h6 u# G: w0 Y0 A
! b8 ^0 ^6 z6 s3 i
" S, b3 E5 s- e2 c
  1. int __fastcall sub_17024(int a1, int a2). h# r( N1 T( I" o7 v0 p
  2. {
    $ ]. L) s% i8 o6 w, d
  3.   int v2; // r4
    ) L6 l5 N" p6 F2 K
  4.   int v3; // r5
    ( N6 k9 ~" M( {
  5.   char *v4; // r6! N4 }6 b+ }& S+ r% l* [$ }* Q& t
  6.   int v5; // r0  Y$ R& F& f3 H' `* k
  7.   int v6; // r3( S& A3 y$ Q# n2 x2 L
  8.   char v7; // r2
    1 B9 |; D- c" o+ {( j8 a7 [
  9.   int v8; // r4
    . I  {3 e# Q7 Q6 x  V; t' \
  10. ) _0 n! q) q; |! g
  11.   v2 = a2;
      I2 V  Q9 c& q" c
  12.   v3 = a1;
    7 J1 Y7 ?1 e0 D3 x* [3 ?. D! @
  13.   v4 = sub_17274(9, 1);& m) V' Z, }2 z% n
  14.   v5 = 0;
    7 a8 P: i6 w" ^' Z
  15.   do
    9 R* D/ r4 H- ~( h0 ]
  16.   {
    - z4 X' ~! t  p: f
  17.     v6 = (dword_1B040[-v5] + 101) >> 15;
    2 G' p0 F' M; b9 b! i
  18.     v7 = v6 ^ 151;
    : j# U* y1 ?/ Y5 e; }
  19.     if ( v6 >= 102 )
    # }- m# C2 G+ p8 F
  20.       v7 = v6;
    " W6 ]$ Q, K+ Y% W
  21.     v4[-v5--] = v7;
    ; y; J7 D  H1 b+ J3 R% U7 R( `
  22.   }! W0 _( K1 j1 ]
  23.   while ( v5 != -8 );                           // 循环8次 获取DESkey
    1 s" z6 v. T. t9 j/ `" t8 F" \
  24.   v8 = sub_64B8(v3, v2, v4);                    // //进入加密函数
    3 _1 |( _) y2 }; w% n
  25.   sub_17284(v4);  B- w0 }& j  c$ n0 L) u
  26.   return v8;
    ) |  {7 T7 C" r5 u
  27. }
复制代码
# Y6 y3 e- z, T, @0 m

: ^# g# e. [& F3 w  S& d' ]' l" x通过前前后后的分析 这里就是获取Key的重要地方了 从一个地址里面取值出来 然后循环处理8次 然后我们进入dword_1B040看
( w6 P4 c  w/ [9 Z: ^+ O
# n* w8 U1 g) y/ }5 r& Y; X1 V5 g8 s
1 ~  r* r2 L& q8 y1 p! w
: Q: B  f3 e% d( t* S* N0 q
! {) V# F  x6 o
看不出什么猫腻 我们转换一下格式 先转Double再转为array IDA右键就有
8 R6 C% _- S( I$ t% H% H; t4 L, ^! b! A$ R

+ m$ y' Y# ~6 H' B  n
) F9 E  }& Z! G- S  O; I
3 j( `0 S' X# {* z然后我用js翻译了这小段so逻辑理清楚后一下子就明白了6 [: L% M( s. D7 ~+ ^& s$ R0 e; [

+ P5 b0 `; h% }  o

8 i/ Y! H3 O9 L0 }+ Z
  1. function get(a) {
    3 E) \% R: W  }1 ?$ V3 r
  2.     v6 = (a + 101) >> 15;
      k# p# X# s& l+ K( b
  3.     v7 = v6 ^ 151;' p- ?1 Q' ]+ e7 `7 Q
  4.     if (v6 >= 102) {3 X$ E# p+ m. J2 E( E
  5.         v7 = v6;
    ' V2 p0 R" t8 Z& v1 r8 [
  6.     }
    * V+ Z$ d" o3 q4 U
  7.     return v7& U/ d4 h% e8 f; a- O- k) P9 J
  8. }
    - Y1 D# {9 Q8 {2 P9 M2 D6 F
  9. function a() {
    . B0 N( D. ~' E3 _$ N+ q! m
  10.     arr = [0x3A7F9B, 0xFFDAFF9B, 0x3EFF9B, 0xFFD9FF9B, 0xFFCFFF9B, 0xFFEB7F9B, 0x3B7F9B, 0xFFD37F9B];5 w" Y; t2 D& [: N6 a
  11.     var aa = new Array();
    : K+ w  P" l0 B! h! F8 G1 Y5 ?" R7 N7 I
  12.     for (var i = 0; i < 8; i++) {$ K  k4 p  A' x/ f* R' n; t8 N
  13.         aa.push(get(arr[i]))
    5 x- m; F3 C# n& S
  14.     }
    " F" U4 L" m, d
  15.     return aa
    ( v3 }  p' o6 ^" ^6 r+ l) T# T" `
  16. }
复制代码
+ z8 J/ Q3 a8 p) I5 ^1 U2 ?

' I- v" p! p2 {* ~& v这里返回的就应该是key数组了 {117,-223,126,-221,-201,-192,119,-208}1 X# U- v4 E3 n" m/ |) {, s) s
然后转换到易语言的字节集就是{117,33,126,35,55,64,119,48}文本为u!~#[email protected] (这里的转换就是由于其他语言的byte取值范围 -128~ 127) 易语言好像没上限 所以我们只需要把-的给他加上256就能变成易语言的字节集了)3 g6 C* w' ^; b$ P8 _

, p+ i1 t  g$ {, v到这一步我们已经拿到了KEY了
+ T0 {7 p# N% {! z) c
7 e( K; b3 b+ H$ X现在就差一步IV了
" s, p, }6 [6 ~! g4 i/ }* c# z. F
前面一直没说2 }! t$ B& w3 M) V- a6 `$ u* C6 |

" ^# |: }1 T; y8 F因为这个so函数名全是匿名的 所以在分析的时候很难去判断这个函数到底是干嘛的 这种so分析起来就需要自己花点时间和结合经验来操作了; K$ N- ~8 `: r# S/ w3 s

  Y- c! q* }' h" M这里我都给大家分析完了( k, G! C* I+ K5 Z  a% {: B
7 Q# k% F# y+ j5 p7 [. t' ^

, _1 Z/ k& s  [5 B  P
. ^! n9 `+ }" u/ a  w) v' G% h3 D: ~+ ~' X+ `7 d9 L8 ]) q& L

: K$ b: E: o$ _7 ~我们已经找到了最关键的加密点了 而且我们现在key也有了 只差IV了' W0 w1 [; f$ H0 h& ]  ~/ g5 t, i

3 Y9 I1 R3 F  Bsub_4720这个匿名函数其实就是DES_cbc_encrypt
- x$ b& ?0 H# u9 e
" \. j4 t& b* J/ {7 b; t/ qvoid DES_ncbc_encrypt(const unsigned char *input,unsigned char *output,1 X8 i& I5 D- R4 g" |2 N
              long length,DES_key_schedule *schedule,DES_cblock *ivec,
- g. r% \, [" O+ C0 K0 P              int enc);# g, ]$ D/ \+ e' l  x. f0 V

/ y. k" o, H7 c, N这是DES_cbc_encrypt参数的定义
$ O( n. u& P* _- z; {/ u5 J
" a4 p( F4 n2 ]! I9 C) K/ l0 d依次是输入流 输出流 长度 key iv flag( q9 F; V- P) `0 U5 p, K

8 u0 d5 J: D3 |+ |7 ?5 x: Z恰好能 对应上我们的函数 所以 iv应该就是我们&v11所指向的值了& @! b: z; m- h& [* @# Z! }

1 m4 @  {9 A5 b2 k. T
  U/ h& q4 C7 X9 o8 F, k
  1. .text:00006618 ; 20:   v12 = 0xEFCDAB90;
    # R! Q( e/ z! k, Z( g9 Y
  2. .text:00006618                 LDR     R0, =0xEFCDAB909 b4 L6 O9 I' [7 G
  3. .text:0000661A                 STR     R0, [SP,#0xB0+var_9C]$ E9 j! [, e% f/ ?$ k. m
  4. .text:0000661C ; 21:   v11 = 0x78563412;
    ! @* v0 t- M8 k+ S; Q6 V1 i5 Q
  5. .text:0000661C                 LDR     R0, =0x785634121 w" L; z! P& L* f4 M0 L2 g
  6. .text:0000661E                 STR     R0, [SP,#0xB0+var_A0]
复制代码
这里V11在我们的伪C代码中只赋值了0x78563412  但在汇编里面他实际是赋值了0xEFCDAB90 和0x78563412的 所以我们的iv应该就是0x1234567890ABCDEF5 K; W9 F( l/ d) O. o
1 @. T. k: o; a, l  L& d
在我们运行的时候 取值事从后往前取得 两个一组 这个我确实也不太明白具体原因 也是在无名侠前辈哪里学得 也就是 EF CD AB 90 78 56 34 12 这样来拼接得  V; ?, }8 a5 s% B$ Y

! Q8 a( v: P( g2 o) N好了 现在我们key iv都有了 我们在不排除有变异得情况下可以来测试一下能不能解开密文
5 S  U/ b& W" X5 U# c$ d" x& T% b" u: S+ M; h5 y  }
! E- A/ e: z% H0 d7 s
4 n' `0 l; I& Z* O  \% w* `
8 `. Y/ I1 e* q* s; i# e) c" Z
成功解开
0 O- p' B' m1 v: j' o) u# }% p& |  v+ t
这次so分析得难点其实就在于无法动态调试获取key或者IV 每一步逻辑都需要自己去看
# f3 P: Q8 _. @+ q其次就是全是匿名函数 需要自己花点时间去查看每个函数的功能3 U4 W% M. z# t6 t
, |" D" [/ r7 Q  h, O. e3 T
但总统上还是不算难得 只是需要慢慢琢磨一下得
! r- d- ~/ T& J. j+ m! H# g/ [) N% T; m: E- d, X7 ]
实在是太累了 如果大家对登陆得sign和签到得sign有想法我下次再给大家写文章把
3 x" d  F# z7 R( C0 R: V9 Y0 H
' b6 f$ @; s" c- t; `. q+ j% J

* U# ]7 K! r2 P, X
" z  i2 ]' F8 }7 a' ]2 O

9 ]' ^$ Y, q( d7 p+ H

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2022-7-6 09:00 , Processed in 0.053127 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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