爱内涵易语言论坛

 找回密码
 立即注册

在线
客服

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

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

快速
发帖

客服
热线


7*24小时客服服务热线

关注
微信

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

4399游戏盒最新算法讲解

[复制链接]
avatar

1766

主题

1854

帖子

3万

积分

管理员

Rank: 9Rank: 9Rank: 9

金币
9845
巨币
13159
积分
39645
online_admin 发表于 2019-10-25 18:46:42 | 显示全部楼层 |阅读模式
第一次发教程 出现问题请见谅6 C% ~9 N: y" ^5 O9 d
这次是最新版本的4399游戏盒登陆密码加密讲解和两个sign的讲解  " v, y, K2 _# x" X! l' n
4 R" \0 G; ]9 D+ o
由于我测试的时候是无法对这个APP进行IDA调试的 所以就静态分析了一下5 X% X8 R3 e$ U" z% W: i( A+ B
4 G& w8 V4 `/ ~) _7 P

/ f7 \! s& p; E. u3 ^5 q" N
  1. POST https://mapi.4399api.net/user/box/android/v1.0/log-in.html HTTP/1.1
    - V; g4 y6 _4 o2 W) m0 [% _
  2. User-Agent: 4399GameCenter/5.2.0.39 (android;Nexus 6P;6.0;1440x2392;WIFI;1376.416;yaoqing)' V' t1 [: z) e
  3. mareacode: 350100! T3 B0 F& E" K
  4. a-id: decd74ca59799d58
    ! u$ s3 Q3 D: M# j1 D/ V* P
  5. e-id: 867981022896164
    9 [$ {& A8 x& I3 J  @
  6. m-id: D4%3A61%3A4E%3A13%3A10%3A1F. g4 F. P3 T' h( h
  7. s-id:
    ( b9 ?5 F9 B: Y8 m0 M. z# D
  8. mauth:
    % J5 R# f$ j: \0 e9 G" [) x
  9. mudid: 1085glt3vuUywD5g808eZb67a
    # G; G! n4 x4 q3 [$ k( u
  10. pauth:9 d, d, K. z' v+ |/ E
  11. SM-DEVICEID: 2019101514035076086dc3e7e2dc00afe0043881a46e18018036cbcdd51ca5
    : t: c9 p2 B; u8 X* R. I
  12. mdeviceId: 867981022896164* `" u' b& x1 e
  13. mauthcode:; v* e* K" }+ C& }5 d, }6 g4 J
  14. Content-Type: application/x-www-form-urlencoded
      t, N+ L$ C1 n$ k) B7 _
  15. Content-Length: 1617 Q& y+ R- J* @; j9 N
  16. Host: mapi.4399api.net
    ; r4 ^8 N9 B) W' B* z- ~0 O. w
  17. Connection: Keep-Alive
      G2 m5 f4 {4 w- y2 @" Y/ `7 N
  18. Accept-Encoding: gzip  L. s! [! W+ m5 r/ h
  19. password=JE%2FYTsyiLwE%3D&deviceIdentifier=867981022896164&dateline=1571863440&sign=c80c8c800fa61cccc02e12e87da33620&model=Nexus%206P&username=13665098754&info=1
复制代码
这是抓到的登陆包
. |+ q0 C1 J4 f5 M2 l大概能看到两个参数需要处理 一个password 一个sign
' {* e) F4 M8 \; {1 L
+ ^/ O- Z' ?" J" X) t" L5 K反编译( T- P+ U+ ?% ?
. P) G( m6 t) C7 @7 `* J/ }. _
找到关键点
6 b$ z( |1 K" E; L# m6 H7 p
: \' p: w4 I. Q& H' o跟进以后就是Native函数了 这里我们从名字就能大概知道password是一个DESCBC类型的加密(不排除重写) 我们也只是猜测8 E- h6 G$ j) f" K

5 c9 Q7 r% \% N
! U0 H/ m9 g/ ~  `( \
  1. public class AppNativeHelper {
    ( z0 L- R% h- i( k9 J
  2. static {
    ! z0 L. O! z2 \' I
  3. try {
    * e& p1 C' B* {/ L9 v0 r) _
  4. SoFix.loadLibrary (BaseApplication.getApplication (), "m4399");
    1 h+ T2 J$ v) i' Z8 U* ?# O! ~
  5. Log.d ("AppNativeHelper", "load libm4399.so");
    " e. v6 E8 p# f' x1 \3 U
  6. }  x/ b( ~3 q. m  p- y" f0 o
  7. catch (SoLoadFailureException v0) {
    8 W) C& D; d$ A% ~/ p
  8. v0.printStackTrace ();
    . l" B% L8 k# O
  9. }
    2 U& o; ?- B1 k# X! m' m. R/ o
  10. }4 \' ]1 [6 L+ t7 D2 ~
  11. public AppNativeHelper () {- s' D3 x, m6 i: [
  12. super ();- i% J' ?; e) H
  13. }
    $ A4 m) A' P0 S
  14. public static native int applyPatch (String arg0, String arg1, String arg2) {
    . z( Q! W- d1 i, J1 x6 z
  15. }7 b  |) _! @) Y
  16. public static native int delayRestartProcess (String arg0, String arg1, long arg2) {4 ]7 R" Y' ^6 R& c# n6 m- M
  17. }9 M, |4 f8 j, r. c2 U6 z/ h
  18. public static final native String desCbcDecrypt (String arg0) {5 Z6 Y1 k6 d% G- ]( M& @" ^. o6 ~
  19. }. e! k5 R) \" A3 `
  20. public static final native String desCbcEncrypt (String arg0) {
    . K9 z/ F6 J) F) z9 S- w7 ?9 I, L5 W
  21. }
复制代码
拿出libm4399.so拖进IDA进行处理  
3 a4 v. S! W' O9 m" E; v
8 B0 a# I- f0 j* ^; n/ a这个So是动态注册函数
7 b5 q* K7 W" E4 u" V) z4 W# i9 T  ]$ a2 O" U0 a
所以我们进入Jni_onload 导入头文件 找到RegisterNatives函数
' a- q, w4 \7 bRegisterNatives中第三个参数就是我们注册Java函数的实际地址: g: r* [0 e( ]5 o' ?( y, {

+ n5 t% F* _2 n* ]
' C7 x% b7 S4 f) {9 e3 C1 a4 _* n" i
进去以后是DCD格式的 第一项是函数名 第二项好像是格式还是啥 重要的是第三项 这就是我们的函数地址了 找到我们要的函数 然后找到函数地址9 B' w4 X1 F: C+ T: [2 v
6 d' w8 x5 c) _( b+ n

/ B# g/ V* l+ g4 e9 j然后进来这个函数: |$ d& D7 ~$ a1 A! X5 I

5 y. A& }. a. T; [

) P9 `  R0 f9 U# O% r
  1. int __fastcall sub_17024(int a1, int a2)5 J6 K9 E" K1 e0 b* H! a5 V$ x
  2. {
    & |/ D4 Y0 K& G" p; R- T
  3.   int v2; // r4  H' N9 K/ F$ e1 G7 k' }: H5 C6 J! Z
  4.   int v3; // r5
    3 r4 [3 |0 p% D! e" o7 Z. a
  5.   char *v4; // r6
    + }- T* Q- m2 }% c
  6.   int v5; // r0
    0 j& f0 J- R0 e5 i( h2 [
  7.   int v6; // r3
    7 E; E! ~9 V3 P+ F+ p5 ?) |1 [2 j
  8.   char v7; // r2* D/ D+ q7 X5 o- `7 G
  9.   int v8; // r4( m# M" j( B3 M

  10. + s  k. H! U1 W$ `7 Q  B
  11.   v2 = a2;% t8 g4 l! G3 N1 z0 D% V
  12.   v3 = a1;' B( [# ?3 P  Y# d7 z
  13.   v4 = sub_17274(9, 1);
    9 R7 B2 n, C$ ~7 D! P! `. l
  14.   v5 = 0;1 c! l8 q+ r; F3 U
  15.   do
    - h9 u" H7 x% }  j3 t0 \, W1 \  y
  16.   {
    ' b9 d$ u5 g* ~) X" Z
  17.     v6 = (dword_1B040[-v5] + 101) >> 15;2 o/ J! ]- v: X/ a$ m
  18.     v7 = v6 ^ 151;% \, p' c9 R+ X3 D* g! {
  19.     if ( v6 >= 102 )
    ' B$ c1 I% b/ @  x- f
  20.       v7 = v6;
    5 Z" J: e, ?+ y& x6 `
  21.     v4[-v5--] = v7;
    ; ^: L3 b" _& d" F4 o( d
  22.   }# s9 F6 H/ z, |# d; G) N0 o& T7 R
  23.   while ( v5 != -8 );                           // 循环8次 获取DESkey
    ( [7 C" `6 X; W3 }, M
  24.   v8 = sub_64B8(v3, v2, v4);                    // //进入加密函数) `% V" {/ k" T1 s5 K/ f7 L
  25.   sub_17284(v4);- f/ T! l: \( v& g9 c
  26.   return v8;
    4 Y6 T( N4 h( ?( w5 t
  27. }
复制代码
- j2 r1 D9 d) N" V0 }. q" o& m. `/ H
! q- g4 T% z2 G2 V  u
通过前前后后的分析 这里就是获取Key的重要地方了 从一个地址里面取值出来 然后循环处理8次 然后我们进入dword_1B040看
9 H7 Z7 Y) P3 L& Z3 ^* V; b0 k# N7 J. J# ]
$ v# j3 O8 ^9 Q: {: @& I! q. v# [
; ~# N0 m1 ^! V- s" U  t+ o- e7 R

  l; d% p  _5 ?3 R7 I; r5 m看不出什么猫腻 我们转换一下格式 先转Double再转为array IDA右键就有
' O" \, ^4 }8 {+ w: x4 S7 A
8 o$ x! [+ `3 J0 A# ]# ~. u

: b/ g+ m$ h, s5 V, |3 W; B( m# ^
" R9 ~, B  u' t/ H5 @3 {9 i& W1 [
9 V2 F9 _* H" A# {8 B1 N然后我用js翻译了这小段so逻辑理清楚后一下子就明白了
6 y, a6 T+ N  f+ |( t6 h
$ t/ e7 Q/ z6 R- k* O

/ p# J, S* I" M
  1. function get(a) {' @9 n; |2 f" L6 F- K( F
  2.     v6 = (a + 101) >> 15;1 w7 B( r# e' @5 |1 F7 g
  3.     v7 = v6 ^ 151;
    : C  }/ p4 H# s6 ?
  4.     if (v6 >= 102) {
    ( Z: D& o3 I6 l% B- Z+ I, P
  5.         v7 = v6;
    9 q. d6 W( x9 i5 s& b
  6.     }
    1 r( F/ T7 ]+ v; ?- k, @' G
  7.     return v7
    5 A$ o  R5 z0 C9 a- O$ g+ G- R& j2 c
  8. }
    ' L" e% F  S+ X/ u
  9. function a() {
    0 j/ y, w: u4 D: b; Q5 r
  10.     arr = [0x3A7F9B, 0xFFDAFF9B, 0x3EFF9B, 0xFFD9FF9B, 0xFFCFFF9B, 0xFFEB7F9B, 0x3B7F9B, 0xFFD37F9B];
    ( c7 l+ H% e2 |% n1 x5 P+ I( W
  11.     var aa = new Array();" D, C: I* F, w! M
  12.     for (var i = 0; i < 8; i++) {
    + F" d0 l0 }8 k2 C5 z. K: j5 C- [
  13.         aa.push(get(arr[i])), q5 X/ x) w! N9 h7 @; s/ m5 t
  14.     }
    ; E! Q, C! m% d; D( [
  15.     return aa
    - @% R' N. s) B3 V; W
  16. }
复制代码

2 b* o6 }8 P5 ]3 y' ~9 z, _" w, v
3 M4 i# q9 v# D6 T. l5 @这里返回的就应该是key数组了 {117,-223,126,-221,-201,-192,119,-208}* w! L7 k# y* M
然后转换到易语言的字节集就是{117,33,126,35,55,64,119,48}文本为u!~#[email protected] (这里的转换就是由于其他语言的byte取值范围 -128~ 127) 易语言好像没上限 所以我们只需要把-的给他加上256就能变成易语言的字节集了)! \1 ^- Z4 l; l; n+ F
. }/ O4 V. X* r
到这一步我们已经拿到了KEY了1 s# Q" i$ e" M# K, p

) |- ?- m  b. C0 i- v, f' U" N2 S' S现在就差一步IV了, d8 I& N4 Y# |8 @7 V7 u- W( g6 ~
4 s* l* }5 E. W7 h" L
前面一直没说
/ G- t( S/ r! @- Q7 s9 r7 q& q" r
1 w- b# S1 {2 ]! ^' P, l) L4 q2 H% _因为这个so函数名全是匿名的 所以在分析的时候很难去判断这个函数到底是干嘛的 这种so分析起来就需要自己花点时间和结合经验来操作了
* ^1 o8 m7 ?' j9 X$ m# [5 x/ E+ b' |. a/ m$ G% }! I1 N
这里我都给大家分析完了4 e0 `) T- `2 ~

0 K9 f; r7 K4 I+ }. f5 g& B& A

" V) p: C, |/ Y/ B5 o& ~. J8 k1 N) J% d8 {

& q9 v0 d5 u* D. G3 J$ }' o
/ C% |# j6 h1 H2 a5 y8 _- J我们已经找到了最关键的加密点了 而且我们现在key也有了 只差IV了
; E* W) g$ Z% A) }# B' {  o% |( @1 m9 ~) ~0 r2 w" g# e
sub_4720这个匿名函数其实就是DES_cbc_encrypt
5 [! q- N) m( Y' }9 P
" M, r% M+ V0 _7 d/ B2 avoid DES_ncbc_encrypt(const unsigned char *input,unsigned char *output,
# u7 A' p- C! J, `; N$ I              long length,DES_key_schedule *schedule,DES_cblock *ivec,4 z4 R' t: @( G4 d' r" @. p3 v
              int enc);
6 D& u5 D% p! y1 N5 N( \0 H* Y- _1 d5 j/ m
这是DES_cbc_encrypt参数的定义) T& p. p5 W& r* G
6 K! E! z% q& H* u) [2 s. W
依次是输入流 输出流 长度 key iv flag  j4 W( u; b( @" n

6 }4 \/ {4 Q1 e5 S+ V2 D恰好能 对应上我们的函数 所以 iv应该就是我们&v11所指向的值了  z- W: H; y/ F

/ |1 o. @/ p1 z% l+ y

- D* F; w# M* {7 V4 ?8 ?! z: j
  1. .text:00006618 ; 20:   v12 = 0xEFCDAB90;- U+ v3 e" W" f9 i2 [
  2. .text:00006618                 LDR     R0, =0xEFCDAB90$ I8 X5 Z5 j+ R$ N% |2 T: G1 y
  3. .text:0000661A                 STR     R0, [SP,#0xB0+var_9C]
    4 C! R' B* \- e( K0 N' x
  4. .text:0000661C ; 21:   v11 = 0x78563412;/ C  P& r) x: A& f  l
  5. .text:0000661C                 LDR     R0, =0x78563412
    * Q1 ?0 A0 `& e& q) k- H: f: m
  6. .text:0000661E                 STR     R0, [SP,#0xB0+var_A0]
复制代码
这里V11在我们的伪C代码中只赋值了0x78563412  但在汇编里面他实际是赋值了0xEFCDAB90 和0x78563412的 所以我们的iv应该就是0x1234567890ABCDEF0 l& q0 F; J2 _

8 P! M: B& {* W+ ]% T在我们运行的时候 取值事从后往前取得 两个一组 这个我确实也不太明白具体原因 也是在无名侠前辈哪里学得 也就是 EF CD AB 90 78 56 34 12 这样来拼接得- I0 j. _& W3 v& n) m3 p

# v9 t3 \3 X2 c好了 现在我们key iv都有了 我们在不排除有变异得情况下可以来测试一下能不能解开密文. t% O3 I+ a/ s1 u/ z7 c2 z

! O; ^6 C; v2 k4 Z4 A/ B
0 |1 |9 k6 w2 X$ Y) }% v$ m

* O6 k  o0 u" y& r7 v$ ?# w! L# U, n7 T1 N6 {
成功解开) W0 V$ t! \9 Q+ b. l
$ r. \8 Q- f# L; a8 w( ^: G* [
这次so分析得难点其实就在于无法动态调试获取key或者IV 每一步逻辑都需要自己去看3 U/ [& l3 U! i( F; @8 p2 _& ]1 W0 B
其次就是全是匿名函数 需要自己花点时间去查看每个函数的功能5 W# ?2 X# p! E' w5 t- c, ~% m) O

1 T6 F' @( x! {; c- _) M/ d但总统上还是不算难得 只是需要慢慢琢磨一下得1 x- {9 t1 a$ ^: L3 J
3 j7 ?# q2 b% v3 U; B$ G) O4 {8 D
实在是太累了 如果大家对登陆得sign和签到得sign有想法我下次再给大家写文章把2 C" u  j. S- Q# q8 k
& v  Z6 p6 d9 R# Z

; p. a8 @4 j7 M1 ]
/ E% K5 u+ I/ w" h+ T4 E
" O' q/ A) Z# A6 _0 Q1 Z8 \

本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2022-12-4 13:05 , Processed in 0.046168 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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