天天看點

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

0x1

示範例子:

•Sina Weibo•Xiao Hongshu

參考資料: r2wiki[1]、enovella wiki[2]

0x2

首先安裝r2frida[3],自行克隆安裝

然後用

frida-ls-devices

工具擷取

usb device id

;接着用

frida-ps -U | grep xhs

擷取完整包名

然後根據

id

package name

radare

連接配接

frida

:

r2 frida://c0e668cc/com.xingin.xhs           

複制

然後你會得到一個r2dare的互動模式

❯ r2 frida://c0e668cc/com.xingin.xhs
WARNING: r_bin_open_buf: assertion '(st64)opt->sz >= 0' failed (line 250)
 -- SSAbotage from ISIL
[0x00000000]>           

複制

0x2.1> help

首先介紹怎麼使用

help

;對了,要使用

r2frida

的指令,得在指令的前面加上

\

=!

;比如擷取

help

# =!? or \?
[0x00000000]> =!?
r2frida commands available via =! or \ prefix
. script                   Run script
  frida-expression         Run given expression inside the agent
/[x][j] <string|hexpairs>  Search hex/string pattern in memory ranges (see search.in=?)
/v[1248][j] value          Search for a value honoring `e cfg.bigendian` of given width
/w[j] string               Search wide string
<space> code..             Evaluate Cycript code
?                          Show this help
?V                         Show target Frida version
chcon file                 Change SELinux context (dl might require this)
d.                         Start the chrome tools debugger
db (<addr>|<sym>)          List or place breakpoint
db- (<addr>|<sym>)|*       Remove breakpoint(s)
dc                         Continue breakpoints or resume a spawned process
dd[j-][fd] ([newfd])       List, dup2 or close filedescriptors (ddj for JSON)
di[0,1,-1] [addr]          Intercept and replace return value of address
dk ([pid]) [sig]           Send specific signal to specific pid in the remote system
dkr                        Print the crash report (if the app has crashed)
dl libname                 Dlopen a library (Android see chcon)
dl2 libname [main]         Inject library using Frida's >= 8.2 new API
dm[.|j|*]                  Show memory regions
dma <size>                 Allocate <size> bytes on the heap, address is returned
... 有點長           

複制

這是擷取所有指令的幫助,如果想要擷取某個字母有哪些指令隻需要在其後面加

?

即可

例如我想知道

i

字母開頭的有哪些指令,都是幹嘛的

[0x00000000]> \i?
 i    dump info
 i*    dump info r2
 iAE    list all exports
 iAE*    list all exports r2
 iAEj    list all exports json
 iAn    list all classes natives
 iAs    list all symbols
 iAs*    list all symbols r2
 iAsj    list all symbols json
 iE    list exports
 iE*    list exports r2
 iE.    lookup symbol here
 iEa    lookup export
 iEa*    lookup export r2
 ...           

複制

0x2.2> dm

簡單介紹下常用指令。首先是擷取so的資訊指令

dm

,比如位址。這裡用到的

比對符~

,這個符号類似grep指令

[0x00000000]> \dm~shield
0xc5a1a000 - 0xc5a95000 r-x /data/app/com.xingin.xhs-9gUqbwWzalUnAgU88apeTQ==/lib/arm/libshield.so
0xc5a95000 - 0xc5a99000 r-- /data/app/com.xingin.xhs-9gUqbwWzalUnAgU88apeTQ==/lib/arm/libshield.so
0xc5a99000 - 0xc5a9a000 rw- /data/app/com.xingin.xhs-9gUqbwWzalUnAgU88apeTQ==/lib/arm/libshield.so
[0x00000000]>           

複制

你也可以以radare的格式輸出,隻需要在指令後面加個

*

符号

[0x00000000]> \dm*~shield
f map.0xc5a1a000 = 0xc5a1a000 # r-x /data/app/com.xingin.xhs-9gUqbwWzalUnAgU88apeTQ==/lib/arm/libshield.so
f map.0xc5a95000 = 0xc5a95000 # r-- /data/app/com.xingin.xhs-9gUqbwWzalUnAgU88apeTQ==/lib/arm/libshield.so
f map.0xc5a99000 = 0xc5a99000 # rw- /data/app/com.xingin.xhs-9gUqbwWzalUnAgU88apeTQ==/lib/arm/libshield.so           

複制

然後呢,如果你想更友善的把擷取到的資料直接使用,可以輸出為json格式,隻需要在指令後面加

j

[0x00000000]> \dmj~shield
Do you want to print 1 lines? (y/N) y
[{"base":"0x12c00000","size":3145728,"protection":"rw-","file":{"path":"/dev/ashmem/dalvik-main space (region space) (deleted)","offset":0,"size":0}},{"base":"0x12f00000","size":4456448,"protection":"---","file":{"path":"/dev/ashmem/dalvik-main space (region space) (deleted)","offset":3145728,"size":0}},{"base":"0x13340000","size":262144,"protection":"rw-","file":{"path":"/dev/ashmem/dalvik-main space (region space) (deleted)","offset":7602176,"size":0}},{"base":"0x13380000","size":262144,"protection":"---","file":{"path":"/dev/ashmem/dalvik-main space (region space) (deleted)",...           

複制

0x2.3> iE

然後是擷取so檔案的所有導出函數指令

iE

,應該是

info exports

(我猜的

[0x00000000]> \iE* libshield.so
f sym.fun._Znaj = 0xc5a3f8b5
f sym.fun._ZdaPv = 0xc5a3e579
f sym.fun._ZdlPv = 0xc5a3e575
f sym.fun.__cxa_begin_catch = 0xc5a3ebd5
f sym.fun._ZSt9terminatev = 0xc5a3f4bd
f sym.fun._Znwj = 0xc5a3f861
f sym.var._ZTVN10__cxxabiv117__class_type_infoE = 0xc5a97290
f sym.fun.JNI_OnLoad = 0xc5a257a9
f sym.fun.__cxa_allocate_exception = 0xc5a3e655
f sym.fun.__cxa_throw = 0xc5a3f571
f sym.fun.__cxa_free_exception = 0xc5a3e6fd
f sym.fun.__cxa_rethrow = 0xc5a3f5f1
f sym.fun.__cxa_end_catch = 0xc5a3ec65
f sym.var._ZSt7nothrow = 0xc5a94138
f sym.fun._ZNSt8_Rb_treeISsSsSt9_IdentityISsESt4lessISsESaISsEE5clearEv = 0xc5a36c99
f sym.fun._ZNSt8_Rb_treeISsSsSt9_IdentityISsESt4lessISsESaISsEE16_M_insert_uniqueISsEESt4pairISt17_Rb_tree_iteratorISsEbEOT_ = 0xc5a36d3d
f sym.fun._ZNSt8_Rb_treeISsSsSt9_IdentityISsESt4lessISsESaISsEE4findERKSs = 0xc5a38701
f sym.fun._ZNSt6vectorISsSaISsEED2Ev = 0xc5a2df71
f sym.fun._ZNSt8_Rb_treeISsSsSt9_IdentityISsESt4lessISsESaISsEED2Ev = 0xc5a36f11
f sym.fun._ZNSt6vectorISsSaISsEE7reserveEj = 0xc5a32455
f sym.fun._ZNSt6vectorISsSaISsEE19_M_emplace_back_auxIJSsEEEvDpOT_ = 0xc5a39361
f sym.fun.__cxa_guard_acquire = 0xc5a3f665
f sym.fun.__cxa_guard_release = 0xc5a3f7dd
f sym.fun._ZNSt9exceptionD2Ev = 0xc5a3ed01
...           

複制

\/

搜尋記憶體中的資料

\/

;首先看看help

[0x00000000]> \?~^/
/[x][j] <string|hexpairs>  Search hex/string pattern in memory ranges (see search.in=?)
/v[1248][j] value          Search for a value honoring `e cfg.bigendian` of given width
/w[j] string               Search wide string
[0x00000000]>           

複制

基礎使用方法:\/ keyword

比如我要搜尋.....emmmmmm:

TracerPid

;首先是一頓輸出,然後會出現找到的個數,比如這裡的12個,然後對應着位址和内容

[0x00000000]> \/ TracerPid
Searching 9 bytes: 54 72 61 63 65 72 50 69 64
Searching 9 bytes in [0x12c00000-0x15180000]
Searching 9 bytes in [0x151c0000-0x155c0000]
Searching 9 bytes in [0x15640000-0x15680000]
...
Searching 9 bytes in [0xff508000-0xffd07000]
Searching 9 bytes in [0xffff0000-0xffff1000]
hits: 12
0x14626d48 hit0_0 TracerPid:
0xab1108f4 hit0_1 TracerPid:
0xc2972232 hit0_2 TracerPid:
0xc4c1e76c hit0_3 TracerPid
0xc5aa7810 hit0_4 TracerPid:0
0xc5ab2da8 hit0_5 TracerPid
0xc8eb9c5e hit0_6 TracerPid:0Uid:10185101851018510185Gid:10185101851
0xcb15818c hit0_7 TracerPid:
0xd21ff45e hit0_8 TracerPid:0Uid:10185101851018510185Gid:10185101851
0xd21ff85e hit0_9 TracerPid:0Uid:10185101851018510185Gid:10185101851
0xd277b892 hit0_10 TracerPid:
0xdf57105d hit0_11 TracerPid:0Uid:10185101851018510185Gid:10185101851

[0x00000000]>           

複制

為了驗證我剛剛所說的,直接看記憶體,正好可以教用一個字母看記憶體資料,這個指令是radare的指令,這就是互動的好處。為了更好的凸顯資料,我選擇的是比較長的那個字元串,位址是:

0xc8eb9c5e

[0x00000000]> x @ 0xc8eb9c5e
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xc8eb9c5e  5472 6163 6572 5069 643a 0930 0a55 6964  TracerPid:.0.Uid
0xc8eb9c6e  3a09 3130 3138 3509 3130 3138 3509 3130  :.10185.10185.10
0xc8eb9c7e  3138 3509 3130 3138 350a 4769 643a 0931  185.10185.Gid:.1
0xc8eb9c8e  3031 3835 0931 3031 3835 0931 3031 3835  0185.10185.10185
0xc8eb9c9e  0931 3031 3835 0a46 4453 697a 653a 0935  .10185.FDSize:.5
0xc8eb9cae  3132 0a47 726f 7570 733a 0933 3030 3320  12.Groups:.3003
0xc8eb9cbe  3939 3937 2032 3031 3835 2035 3031 3835  9997 20185 50185
0xc8eb9cce  2039 3939 3039 3939 3720 0a56 6d50 6561   99909997 .VmPea
0xc8eb9cde  6b3a 0920 3234 3131 3832 3020 6b42 0a56  k:. 2411820 kB.V
0xc8eb9cee  6d53 697a 653a 0920 3233 3439 3730 3820  mSize:. 2349708
0xc8eb9cfe  6b42 0a56 6d4c 636b 3a09 2020 2020 2031  kB.VmLck:.     1
0xc8eb9d0e  3136 206b 420a 566d 5069 6e3a 0920 2020  16 kB.VmPin:.
0xc8eb9d1e  2020 2020 3020 6b42 0a56 6d48 574d 3a09      0 kB.VmHWM:.
0xc8eb9d2e  2020 3637 3539 3336 206b 420a 566d 5253    675936 kB.VmRS
0xc8eb9d3e  533a 0920 2035 3636 3431 3620 6b42 0a52  S:.  566416 kB.R
0xc8eb9d4e  7373 416e 6f6e 3a09 2020 3130 3630 3136  ssAnon:.  106016
[0x00000000]>           

複制

x

px

指令的簡寫,這個指令作用是

show hexdump

。從上面可以明确的看到字元串;還可以用

ps

指令直接輸出pretty的字元串,當然得事先知道指定的位址内容存的是字元串,不然傳回的就不知道是一堆啥玩意兒了,使用方法和

px

差不多

[0x00000000]> ps @ 0xc8eb9c5e
TracerPid:\x090
Uid:\x0910185\x0910185\x0910185\x0910185
Gid:\x0910185\x0910185\x0910185\x0910185
FDSize:\x09512
Groups:\x093003 9997 20185 50185 99909997
VmPeak:\x09 2411820 kB
VmSize:\x09 2358724 kB
VmLck:\x09     116 kB
VmPin:\x09       0 kB
VmHWM:\x09  675936 kB
VmRSS:\x09  522464 kB
RssAnon:\x09  100820
[0x00000000]>           

複制

這裡用json格式輸出就很舒服了

[0x00000000]> psj @ 0xc8eb9c5e
{"string":"TracerPid:\u00090\u000aUid:\u000910185\u000910185\u000910185\u000910185\u000aGid:\u000910185\u000910185\u000910185\u000910185\u000aFDSize:\u0009512\u000aGroups:\u00093003 9997 20185 50185 99909997 \u000aVmPeak:\u0009 2411820 kB\u000aVmSize:\u0009 2253264 kB\u000aVmLck:\u0009     116 kB\u000aVmPin:\u0009       0 kB\u000aVmHWM:\u0009  675936 kB\u000aVmRSS:\u0009   84988 kB\u000aRssAnon:\u0009       0","offset":3370884190,"section":"unknown","length":256,"type":"ascii"}
[0x00000000]>           

複制

搜尋也可以指定搜尋的資料類型以及輸出的格式,比如以十六進制搜尋輸出json格式的結果

[0x00000000]> \/xj 547261636572506964
Searching 9 bytes: 54 72 61 63 65 72 50 69 64
Searching 9 bytes in [0x12c00000-0x12d80000]
Searching 9 bytes in [0x12f80000-0x12fc0000]
Searching 9 bytes in [0x13000000-0x13040000]
Searching 9 bytes in [0x13340000-0x13380000]
...
Searching 9 bytes in [0xffff0000-0xffff1000]
hits: 12
[{"address":"0x13033778","size":9,"flag":"hit2_0","content":"547261636572506964"},{"address":"0xab1108f4","size":9,"flag":"hit2_1","content":"547261636572506964"},{"address":"0xc2972232","size":9,"flag":"hit2_2","content":"547261636572506964"},{"address":"0xc4c1e76c","size":9,"flag":"hit2_3","content":"547261636572506964"},{"address":"0xc5aa7810","size":9,"flag":"hit2_4","content":"547261636572506964"},{"address":"0xc5ab2da8","size":9,"flag":"hit2_5","content":"547261636572506964"},{"address":"0xc8eb9c5e","size":9,"flag":"hit2_6","content":"547261636572506964"},{"address":"0xcb15818c","size":9,"flag":"hit2_7","content":"547261636572506964"},{"address":"0xd21ff45e","size":9,"flag":"hit2_8","content":"547261636572506964"},{"address":"0xd21ff85e","size":9,"flag":"hit2_9","content":"547261636572506964"},{"address":"0xd277b892","size":9,"flag":"hit2_10","content":"547261636572506964"},{"address":"0xdf57105d","size":9,"flag":"hit2_11","content":"547261636572506964"}]           

複制

0x3 Dynamic

這個功能特别牛逼,啊不,應該說

radare+frida

在這方法特别牛逼,是以我要單獨拿出來做一個大塊說。

首先看help

[0x00000000]> \d?
 db    breakpoint
 db-    breakpoint unset
 dbj    breakpoint json
 dc    breakpoint continue
 dcu    breakpoint continue until
 dd    list file descriptors
 dd-    close file descriptors
 ddj    list file descriptors json
 di    intercept help
 di-1    intercept ret_1
 di0    intercept ret0
 di1    intercept ret1
 dis    intercept ret string
 dk    send signal
 dl    dlopen
 dm    list memory ranges
 dm*    list memory ranges r2
 dm.    list memory ranges here
 dma    alloc size
 dma-    remove alloc
 dmad    alloc dup
 dmal    list allocs
 dmas    alloc string
 dmh    list malloc ranges
 dmh*    list malloc ranges r2
 dmhj    list malloc ranges json
 dmhm    list malloc maps
 dmj    list memory ranges json
 dmm    list memory maps
 dmm.    list memory ranges here
 dmp    change memory protection
 dp    get pid
 dpj    get pid json
 dpt    list threads
 dptj    list threads json
 dr    dump registers
 dr*    dump registers r2
 dr8    dump register arena
 drj    dump registers json
 drp    dump register profile
 drr    dump registers recursively
 dt    trace
 dt*    trace r2
 dt-    clear trace
 dt-*    clear all trace
 dt.    trace here
 dtf    trace format
 dth    trace hook
 dtj    trace json
 dtl    trace log dump
 dtl*    trace log dump r2
 dtl-    trace log clear
 dtl-*    trace log clear all
 dtlj    trace log dump json
 dtlq    trace log dump quiet
 dtq    trace quiet
 dtr    trace regs
 dts    stalk trace everything
 dts*    stalk trace everything r2
 dts?    stalk trace everything help
 dtsf    stalk trace function
 dtsf*    stalk trace function r2
 dtsfj    stalk trace function json
 dtsj    stalk trace everything json
 dxc    dx call

[0x00000000]>           

複制

我挑幾個我用的最頻繁的指令,因為實在是太多了。。。

dm

上面已經用過了就不說了

說一下和

dm

在字母個數方面差不了多少的指令

dma

,這個指令是配置設定記憶體大小用的。可以看它的詳細help

[0x00000000]> \dma?
 dma    alloc size
 dma-    remove alloc
 dmad    alloc dup
 dmal    list allocs
 dmas    alloc string

[0x00000000]>           

複制

dma

配置設定記憶體大小

dma-

删除所有配置設定的記憶體

dmad

... 沒用過,翻譯是重複配置設定

dmal

列出所有配置設定的記憶體的位址

dmas

配置設定字元串

0x3.1> dma

[0x00000000]> \dma 10
0xc09622b8
[0x00000000]> x @ 0xc09622b8
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xc09622b8  0000 0000 0000 0000 0000 0000 c300 0000  ................
0xc09622c8  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc09622d8  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc09622e8  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc09622f8  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc0962308  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc0962318  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc0962328  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc0962338  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc0962348  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc0962358  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc0962368  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xc0962378  0000 0000 0000 0000 0000 0000 d901 0000  ................
0xc0962388  d0dd 4ed1 9873 95c0 102c dbc3 e0e1 4ed1  ..N..s...,....N.
0xc0962398  3c01 afc5 0100 0000 0000 0000 0000 0000  <...............
0xc09623a8  0000 0000 0000 0000 0000 0000 0000 0000  ................
[0x00000000]>           

複制

配置設定字元串

[0x00000000]> \dmas hellworld
0xc3db1648
[0x00000000]> ps @ 0xc3db1648
hellworld
[0x00000000]> x @ 0xc3db1648
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xc3db1648  6865 6c6c 776f 726c 6400 0000 1300 0000  hellworld.......
0xc3db1658  6847 e7da 000d 2f0e 5016 dbc3 1b00 0000  hG..../.P.......
0xc3db1668  7847 e7da 580b a702 0100 0000 9801 0d34  xG..X..........4
0xc3db1678  1800 0000 1300 0000 3ce8 dfb6 7465 7200  ........<...ter.
0xc3db1688  6500 0000 1300 0000 10f8 e6da 7465 7200  e...........ter.
0xc3db1698  246f dab6 1300 0000 3ce8 dfb6 3ce8 dfb6  $o......<...<...
0xc3db16a8  6500 0000 1300 0000 20f8 e6da 7465 7200  e....... ...ter.
0xc3db16b8  246f dab6 1300 0000 30f8 e6da 7465 7200  $o......0...ter.
0xc3db16c8  6500 0000 2300 0000 4817 dbc3 e186 1a17  e...#...H.......
0xc3db16d8  0937 d4b8 3092 e3c3 0001 0000 3092 e3c3  .7..0.......0...
0xc3db16e8  0080 45c1 1300 0000 d888 1fb7 0000 0000  ..E.............
0xc3db16f8  1000 0000 1300 0000 3ce8 dfb6 3ce8 dfb6  ........<...<...
0xc3db1708  6500 000f 1300 0000 50f8 e6da 7465 7200  e.......P...ter.
0xc3db1718  8403 2900 1b00 0000 3ce8 dfb6 3ce8 dfb6  ..).....<...<...
0xc3db1728  3ce8 dfb6 3ce8 dfb6 f01c fbc2 1300 0000  <...<...........
0xc3db1738  60f8 e6da 7465 7200 0100 0000 2300 0000  `...ter.....#...
[0x00000000]>           

複制

列出所有已配置設定記憶體位址

[0x00000000]> clear
[0x00000000]> \dmal
0xc09622b8    ""
0xc3db1648    "hellworld"

[0x00000000]>           

複制

删除所有

[0x00000000]> \dma-
[0x00000000]> \dmal

[0x00000000]>           

複制

dtf trace address;Usage:

例子中,

pp

是方法的參數個數和類型;

^

表示

onEnter

還是

onExit

,和

Interceptor.attach

的回調一樣

[0x00000000]> \dtf 0xd0c4a143 pp^
true
" 1: 0x1155f251)RACE] dt0xedb88eb9d0c4a1libart.so0: "0��0xb9eb9�0
        0xd0c4a54d      libwbutil.so    0x454d
        0xd0c49d65      libwbutil.so    Java_com_sina_weibo_WeiboApplication_newCalculateS+0x64
        0xd1130b25      base.odex       0xf9b25

" 1: 0x1155f251)0xd0c4a10xedb88eb9: "0��libart.so       0xb9eb9
        0xd0c4a54d      libwbutil.so    0x454d
        0xd0c49d65      libwbutil.so    Java_com_sina_weibo_WeiboApplication_newCalculateS+0x64
        0xd1130b25      base.odex       0xf9b25           

複制

... 其他的指令等有空在補充吧,或者自己學習

0x4 Memory

以Share Weibo為例,改寫記憶體資料,是改寫,不是寫入。首先擷取基址

\dm~wbutil

中的

~

是通配符,如果你不太記得so的檔案全名就可以用這個來比對。其中有

讀和執行

權限的那條中的第一個位址

0xcdddc000

是我們要的

[0x00000000]> \dm~wbutil
0xcdddc000 - 0xcdde8000 r-x /data/app/com.hengye.share-xI074YHFAARyeqAB7fhP4w==/lib/arm/libwbutil.so
0xcdde8000 - 0xcdde9000 r-- /data/app/com.hengye.share-xI074YHFAARyeqAB7fhP4w==/lib/arm/libwbutil.so
0xcdde9000 - 0xcddea000 rw- /data/app/com.hengye.share-xI074YHFAARyeqAB7fhP4w==/lib/arm/libwbutil.so
[0x00000000]>           

複制

先說下目标;需要在 native 方法

newCalculateS

中找到計算出加密字元串

s

的算法 經過分析,在

Java_com_sina_weibo_WeiboApplication_newCalculate

方法裡中的最後是傳回的

newCalculateS

方法;其中參數1是

env指針

,參數2是

WeiboApplication對象

,參數3是

uid

不過其中還有一大塊代碼看似沒有用到。首先是判斷0xd0c4有沒有資料,這是一個字元串,char*類型。然後判斷0xd0c8,這是一個char。下面的方法看了下有點複雜,先看

newCalculateS

方法邏輯吧

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

這個方法全貌如圖;

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

整體邏輯是:

1、通過調用

getOriginalString

uid

擷取

key1

2、然後通過

getKeyString

擷取

key2

3、接着通過

getIndex

key2

處理,傳回一個

jintArray

對象 4、然後通過這個

jintArray

對象從

key1

中擷取對應索引的字元,并使用java的

StringBuilder

拼接成

jstring

對象

0x4.1 getOriginalString

這個方法如圖所示

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

很簡單的幾行代碼,難處在

g_pin

g_from

這兩個變量;可能剛打開到這個方法

CallObjectMethod

隻有三個參數,并沒有第四個參數;這裡就是拼接字元串,

g_pin + uid + g_from

;我們需要找到g_pin和g_from,這裡可以先用下面的代碼hook一下看看是什麼東西;

Interceptor.attach(Module.findExportByName("libwbutil.so", "_ZN7_JNIEnv16CallObjectMethodEP8_jobjectP10_jmethodIDz"), {
    onEnter: function(args) {
        Java.perform(function() {
           var String = Java.use("java.lang.String");
           var ret = Java.cast(ptr(args[3]), String);
           console.warn("CallObjectMethod(".concat(args[0])
                            + ", ".concat(args[1])
                            + ", ".concat(args[2])
                            + ", ".concat(ret) + ")");
        });
    }
});           

複制

輸出

CallObjectMethod(0xccb76780, 0x119, 0x70dd9e70, 5l0WXnhiY4pJ794KIJ7Rw5F45VXg9sjo)
CallObjectMethod(0xccb76780, 0x119, 0x70dd9e70, 73586191xx)
CallObjectMethod(0xccb76780, 0x119, 0x70dd9e70, 109C0950xx)           

複制

然後就是将拼接好的字元串進行

sha512

加密并傳回

0x4.2 getKeyString

反編譯如下

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

這裡隻append了

g_from

,然後用

sha512

加密後傳回

0x4.3 getIndex

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

這裡稍微複雜點的就是do while;前面是将十六進制的key2轉為bytearray 在do while裡

1、首先從bytearray裡取内容,索引是v10;然後将其轉為int 2、然後将索引v10與轉換後的byte相加,轉而變成新索引 3、v9自增4 4、當v9 == 32結束while 這裡一共處理了8次,也就是最後的資料是長度為8 是以下面new了一個長度為8的int數組,然後把資料複制到裡面,然後傳回

0x4.4 g_pin、g_from

回到最初到哪個

newCalculateS

方法,這裡有個 app_setPin 方法很可疑,而且它的第二參數和上面的那串字元串參數的方法有關。這個方法就是把 a2 設定為

g_pin

int __fastcall app_setPin(int result, int a2)
{
  if ( !g_pin )
  {
    result = _JNIEnv::NewGlobalRef(result, a2);
    g_pin = result;
  }
  return result;
}           

複制

而這個a2是sub_451C方法傳回的内容經過new轉為jstring的;是以隻要解決這個方法就行了。這個方法的第三個參數是十六進制字元串,不清楚是什麼。我們可以hook看看傳回值是什麼

function sh(a, s){console.error(hexdump(ptr(String(a)),{offset:0,length:s,header:true,ansi:false}))}
var base = Module.getBaseAddress("libwbutil.so");
Interceptor.attach(ptr(base.add(0x451c+1)), {
    onLeave: function(retval) {
        console.log('\n');
        sh(retval, 64); // hexdump
    }
});           

複制

不出意外的話什麼都沒輸出,應該是沒調用。

首先看看最先判斷的那個變量是什麼玩意兒,這裡用r2frida會特别友善;先用dm指令擷取基址,然後通過px指令擷取記憶體十六進制輸出;可以看到是個位址

[0x00000000]> \dm~wbutil
0xcddd0000 - 0xcdddc000 r-x /data/app/com.hengye.share-xI074YHFAARyeqAB7fhP4w==/lib/arm/libwbutil.so
0xcdddc000 - 0xcdddd000 r-- /data/app/com.hengye.share-xI074YHFAARyeqAB7fhP4w==/lib/arm/libwbutil.so
0xcdddd000 - 0xcddde000 rw- /data/app/com.hengye.share-xI074YHFAARyeqAB7fhP4w==/lib/arm/libwbutil.so
[0x00000000]> px @ 0xcddd0000+0xd0c4
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xcdddd0c4  70dc 10e5 0100 0000 0000 0000 0000 0000  p...............
0xcdddd0d4  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd0e4  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd0f4  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd104  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd114  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd124  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd134  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd144  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd154  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd164  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd174  0000 0000 0000 0000 0000 0000 c243 0000  .............C..
0xcdddd184  a247 0000 0000 0000 0000 0000 0000 0000  .G..............
0xcdddd194  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd1a4  0000 0000 0000 0000 0000 0000 0000 0000  ................
0xcdddd1b4  0000 0000 0000 0000 0000 0000 0000 0000  ................
[0x00000000]>           

複制

而這個位址的内容恰好是和上面的g_pin内容一樣

[0x00000000]> x @ 0xe510dc70
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xe510dc70  356c 3057 586e 6869 5934 704a 3739 344b  5l0WXnhiY4pJ794K
0xe510dc80  494a 3752 7735 4634 3556 5867 3973 6a6f  IJ7Rw5F45VXg9sjo           

複制

不過這個位址貌似一直都有東西,是以首個if會不成立,直接調用

newCalculateS

;這裡可以嘗試改指令,把指令直接改成BEQ,不過這樣做會運作一會就閃退,是以這裡我卡了一點時間,不過好在

radare2

能改記憶體資料,而

frida

加上這個功能基本可以和

ida

剛了,我還覺得比ida好用。

這裡用r2的

wx

指令就能修改 help:

[0x00000000]> wx?
Usage: wx[f] [arg]  
| wx 9090     write two intel nops
| wxf -|file  write contents of hexpairs file here
| wxs 9090    write hexpairs and seek at the end
[0x00000000]>           

複制

修改為0

[0x00000000]> x 16 @ 0xcddd0000+0xd0c4
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xcdddd0c4  a897 a1cb 0100 0000 0000 0000 0000 0000  ................
[0x00000000]> wx 000000000000 @ 0xcddd0000+0xd0c4
[0x00000000]> x 16 @ 0xcddd0000+0xd0c4
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0xcdddd0c4  0000 0000 0000 0000 0000 0000 0000 0000  ................
[0x00000000]>           

複制

然後再hook一次

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
c768dd98  35 6c 30 57 58 6e 68 69 59 34 70 4a 37 39 34 4b  5l0WXnhiY4pJ794K
c768dda8  49 4a 37 52 77 35 46 34 35 56 58 67 39 73 6a 6f  IJ7Rw5F45VXg9sjo
c768ddb8  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
c768ddc8  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................           

複制

可以看到傳回值就是g_from,既然不知道dword_D0C4是從哪指派的那就自己生成吧

0x4.5 sub_451C

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

這裡有幾個方法的調用,先不管,統統hook一遍;hook之前記得把

dword_D0C4

位址内容置00

###

sub_4142

:

var base = Module.getBaseAddress("libwbutil.so");
Interceptor.attach(ptr(base.add(0x4124+1)), {
    onEnter: function(args) {

    },
    onLeave: function(retval) {
        console.log('\n');
        sh(retval, 64);
    }
});           

複制

output:

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
c5f4f140  37 30 34 65 36 63 31 62 00 00 6f 00 0a 16 00 00  704e6c1b..o.....
c5f4f150  61 73 73 65 74 73 2f 63 66 67 2e 6a 73 6f 6e 00  assets/cfg.json.
c5f4f160  2e 64 65 62 75 67 5f 6c 69 6e 65 00 01 00 00 00  .debug_line.....
c5f4f170  2e 64 65 62 75 67 5f 6c 69 6e 65 00 67 73 00 00  .debug_line.gs..           

複制

mbedtls_decode

:

Interceptor.attach(Module.findExportByName("libwbutil.so", "mbedtls_decode"), {
    onEnter: function(args) {
        console.log('\n')
        console.warn('mbedtls_decode('.concat(Memory.readCString(args[0]))
                    + ", ".concat(args[1])
                    + ", ".concat(args[2])
                    + ", ".concat(args[3]) + ")");
        sh(args[2], 16);
        sh(args[3], 16);
    }
});           

複制

output:

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

經過hook + 分析後可以斷定這個方法的作用就是為了解密那串十六進制字元串;在

mbedtls_decode

方法中有一個行代碼是des解密,使用的是mbedtls_des_crypt_ecb,這個方法在google一搜就能找到對應的doc[4],好像是mbedtls庫裡的一個方法,這個庫沒用過是以不熟悉。從api解釋可以看出這是一個des ecb模式加解密方法

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)
第一個參數是des的上下文; 第二個參數是8個位元組(64bit)的輸入; 第三個參數是8個位元組(64bit)的輸出;

是解密還是加密可以從上面的

mbedtls_des_setkey_dec

猜到,這是解密

RADARE2+FRIDA=R2FRIDA Best Dynamic Debugging Tool (Weibo Crack)

那就需要擷取到這個key了,從上圖可以看出第二個參數就是key

Interceptor.attach(Module.findExportByName("libwbutil.so", "mbedtls_des_setkey_dec"), {
    onEnter: function(args) {
        sh(args[1], 16)
    }
});           

複制

output:

0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
cea66290  37 30 34 65 36 63 31 62 00 a5 e0 46 d9 fc a6 bd  704e6c1b...F....           

複制

des的key長度是8個位元組,是以key是

704e6c1b

有了key知道模式就很簡單了。

0x5 算法還原

4種語言總有看得懂的把

Java:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.lang.StringBuilder;


class Demo {

    private static final char[] TEMP = "0123456789ABCDEF".toCharArray();
    private static final String KEY2 = "109C195010";
    private static final String UID = "7358119308";
    private static final String KEY1 = "5l0WXnhiY4pJ794KIJ7Rw5F45VXg9sjo" + UID + KEY2;

    public static void main(String args[]) {
        String key2_s = sha512(KEY2).toLowerCase();
        String key1_s = sha512(KEY1).toLowerCase();
        System.out.println("KEY1:" + key1_s + "(" + KEY1 + ")");
        System.out.println("KEY2:" + key2_s + "(" + KEY2 + ")");
        char bytes[] = key2_s.toCharArray();
        int i = 0, j = 0, k = 0;
        StringBuilder sb = new StringBuilder();
        do {
            k = converByte2Int(bytes[j]);
            System.out.println(k);
            j += k;
            sb.append(key1_s.charAt(j));
            i += 4;
        } while (i!=32);
        System.out.println(sb.toString());
    }

    public static int converByte2Int(int a) {
        if (a - 48 <= 9) return a - 48;
        if (a - 65 > 5) return a - 87;
        return a - 55;
    }

    public static String sha512(String text) {
        try {
            MessageDigest sha512 = MessageDigest.getInstance("SHA-512");
            sha512.update(text.getBytes());
            String ret = bytes2hex(sha512.digest());
            return ret;
        } catch (NoSuchAlgorithmException e) {
        }
        return null;
    }

    public static String bytes2hex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = TEMP[v>>4];
            hexChars[j * 2 + 1] = TEMP[v&0x0f];
        }
        return new String(hexChars);
    }
}           

複制

Golang:

package main

import (
    "fmt"
    "crypto/sha512"
    "strconv"
    )


var KEY = "5l0WXnhiY4pJ794KIJ7Rw5F45VXg9sjo"
var UID = "1014653719052"
var KEY2 = "109A395010"
var KEY1 = KEY + UID + KEY2

func enSha512(text string) string {
    return fmt.Sprintf("%x", sha512.Sum512([]byte(text)))
}

func getIndex(text string) string {
    var ret string
    var j int
    bytes := []byte(text)
    for i := 0; i < 8; i++ {
        k := converByte2Int(int(bytes[j]))
        j += k
        ret += fmt.Sprintf("%x", k)
    }
    return ret
}

func converByte2Int(b int) int {
    if b - 48 <= 9 { return b - 48 }
    if b - 65 > 5 { return b - 87 }
    return b - 55
}

func main() {
    key1_s := enSha512(KEY1)
    key2_s := enSha512(KEY2)
    fmt.Printf("key1: %s(%s)\n", key1_s, KEY1)
    fmt.Printf("key2: %s(%s)\n", key2_s, KEY2)
    // key2_s byte array
    k2si_ba := getIndex(key2_s)
    var result string
    var j uint64 = 0
    for i := range k2si_ba {
        index, _ := strconv.ParseUint(string(k2si_ba[i]), 16, 32)
        j += index
        result += string(key1_s[j])
    }
    fmt.Println("s: ", result)
}           

複制

C++(

sha512.h太長了,直接去github下載下傳把

):

#include <iostream>
#include "sha512.h"

using namespace std;
using namespace sw;

const string UID = "5715174600";
const string FROM = "109C295010";
const string KEY = "5l0WXnhiY4pJ794KIJ7Rw5F45VXg9sjo" + UID + FROM;


int converByte2Int(int b) {
    if (b - 48 <= 9) return b - 48;
    if (b - 64 > 5) return b - 87;
    return b - 55;
}

int main() {
    const string k_s = sha512::calculate(KEY);
    const string f_s = sha512::calculate(FROM);
    int i = 0;
    int j = 0;
    int k = 0;
    do {
        k = converByte2Int(int(f_s[i]));
        i += k;
        j += 4;
        cout << k_s[i];
    } while(j != 32);

    cout << "\n";
    return 0;
}           

複制

Python:

import hashlib


KEY2 = "109A395010"
UID = "1014653719052"
KEY1 = "5l0WXnhiY4pJ794KIJ7Rw5F45VXg9sjo%s%s" % (UID, KEY2)

def converByte2Int(b):
    if b - 48 <= 9: return b - 48
    if b - 65 > 5: return b - 87
    return a - 55


def main():
    key1_s = hashlib.sha512(KEY1.encode('utf-8')).hexdigest()
    key2_s = hashlib.sha512(KEY2.encode('utf-8')).hexdigest()
    print(f"KEY1: {key1_s} ({KEY1})")
    print(f"KEY2: {key2_s} ({KEY2})")
    ret = ""
    j = 0
    for _ in range(8):
        k = converByte2Int(ord(key2_s[j]))
        j += k
        ret += key1_s[j]
    print(ret)


if __name__ == "__main__":
    main()           

複制

最後

•項目位址:https://github.com/ZCKun/Weibo•WebSite: 2h0n9[5]•WeChat公衆号: the2h0Ng•WeChat: zlztxwd

References

[1]

r2wiki: https://r2wiki.readthedocs.io/en/latest/radare-plugins/frida/

[2]

enovella wiki: https://github.com/enovella/r2frida-wiki

[3]

r2frida: https://github.com/nowsecure/r2frida

[4]

doc: https://tls.mbed.org/api/des_8h.html

[5]

2h0n9: http://2h0n9.com/