代碼還原小試牛刀(一):魔改的MD5

一、目標(biāo)

2023年了志珍,MD5已經(jīng)是最基礎(chǔ)的簽名算法了刑枝,但如果你還只是對(duì)輸入做了簡單的MD5香嗓,肯定會(huì)被同行們嘲笑迅腔。加點(diǎn)鹽(salt)是一種基本的提升装畅,但在這個(gè)就業(yè)形勢嚴(yán)峻的時(shí)代,僅僅加鹽肯定不夠了沧烈。

今天我們就來講一講魔改的MD5掠兄,讓這個(gè)算法高大上起來。

1锌雀、菜卷

最簡單的魔改方法就是改變MD5的初始參數(shù)蚂夕,

     context->state[0] = 0x67452301;
     context->state[1] = 0xEFCDAB89;
     context->state[2] = 0x98BADCFE;
     context->state[3] = 0x10325476;

把這四個(gè)參數(shù)修改一下就行了。通過修改這些參數(shù)腋逆,我們可以改變MD5的運(yùn)算結(jié)果婿牍。但這種方法實(shí)在太簡單了,卷不起來惩歉。

接下來等脂,我們要介紹更高級(jí)的卷法俏蛮。

2、肉卷

md5會(huì)進(jìn)行64輪運(yùn)算上遥,每輪運(yùn)算都會(huì)用到一個(gè)常量搏屑,組成一個(gè)常量表K。

K原始值的計(jì)算方式是 2^32 * |sin i |粉楚,而后取其整數(shù)部分辣恋。

那么有理想的同學(xué)就可以更改這個(gè)K值,比如把 sin改成 cos或者tan之類的模软,這樣就可以卷起來了伟骨。

3、卷中卷

//F,G,H,I四個(gè)非線性變換函數(shù)
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
//x循環(huán)左移n位的操作
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))

要真正卷起來燃异,我們需要改變MD5中的四個(gè)非線性變換函數(shù)F底靠、G、H特铝、I暑中。我們可以加上 異或 或者 減少 操作,整個(gè)算法就換了個(gè)面貌鲫剿。這種高級(jí)卷法可以忽悠住老板鳄逾,讓算法高大上起來。

我們今天的目標(biāo)是嘗試還原一個(gè)魔改之后的MD5算法灵莲,通過這次實(shí)踐來了解算法還原的基本方法雕凹。

這個(gè)樣本我們的入?yún)⑹亲址? "1677038066553"

返回值是32個(gè)字符: "DD89CA684D91818B970710F75A75743D"

二、步驟

第一步

我們需要用Unidbg跑通算法政冻,比起上古時(shí)期用ida調(diào)試的前輩枚抵,Unidbg的出現(xiàn)直接把算法還原的難度降了一個(gè)數(shù)量級(jí)。

第二步

我們需要把結(jié)果Z通過反向推導(dǎo)一步一步回到原始輸入A明场。這種方法叫做倒果為因汽摹,是逆向分析的一種基本套路。

我們假設(shè)這個(gè)樣本是MD5或者是魔改的MD5苦锨,我們可以用以下幾種方法來還原算法:

1逼泣、調(diào)試斷點(diǎn)

2、條件斷點(diǎn)

3舟舒、數(shù)據(jù)打印

4拉庶、Trace內(nèi)存讀寫

5、Trace代碼

1秃励、調(diào)試斷點(diǎn)

逆向分析是經(jīng)驗(yàn)科學(xué)氏仗,雖然有一些基本套路,但是還是以試為主夺鲜,先用IDA打開 libnative-lib.so皆尔,從 Exports 導(dǎo)出表里面找到導(dǎo)出函數(shù) Java_com_littleq_cryptography_md5_MainActivity_sign

這個(gè)函數(shù)的開始地址在0x1234, 結(jié)束地址在0x12B4,但是主要的代碼邏輯在函數(shù)sub_A3C里面帚稠, 我們先在sub_A3C函數(shù)的末端下個(gè)斷點(diǎn)試試,

text:00000000000011D4 E0 07 40 F9                 LDR             X0, [SP,#0x110+var_108]
.text:00000000000011D8 03 00 00 90+                ADRL            X3, aSSSS ; "%s%s%s%s"
.text:00000000000011D8 63 EC 0A 91
.text:00000000000011E0 E4 83 01 91                 ADD             X4, SP, #0x110+var_B0
.text:00000000000011E4 E5 43 01 91                 ADD             X5, SP, #0x110+var_C0
.text:00000000000011E8 E6 03 01 91                 ADD             X6, SP, #0x110+var_D0
.text:00000000000011EC E7 C3 00 91                 ADD             X7, SP, #0x110+var_E0
.text:00000000000011F0 01 00 80 92                 MOV             X1, #0xFFFFFFFFFFFFFFFF
.text:00000000000011F4 02 08 80 52                 MOV             W2, #0x40 ; '@'

這個(gè) 0x11D8 很像是格式化字符串床佳。

我們?cè)赨nidbg里面給 0x11D8 下個(gè)斷點(diǎn)

    Debugger debugger = emulator.attach();
    debugger.addBreakPoint(module.base + 0x11D8);

運(yùn)行一下滋早,順利的斷下來了

debugger break at: 0x400011d8 @ Function64 address=0x40001234, arguments=[unidbg@0xfffe1640[libandroid.so]0x640, 1853170425, 2008362258]
>>> x0=0xbffff690(-1073744240) x1=0x0 x2=0x4 x3=0xbfffed20 x4=0x40230200 x5=0x402302c0 x6=0x1 x7=0xbffff708 x8=0x0 x9=0x0 x10=0x1 x11=0x0 x12=0x8 x13=0x8 x14=0x8
>>> x15=0x8 x16=0x40228d70 x17=0x40177ddc x18=0x8 x19=0x4cf3a208 x20=0x400012b8 x21=0x0 x22=0x68ca89dd x23=0x3d74755a x24=0x72e737bb x25=0xddf5ac1 x26=0xd0d5adc6 x27=0x8b81914d x28=0xf7100797 fp=0xbffff680
LR=RX@0x400011d4[libnative-lib.so]0x11d4
SP=0xbffff570
PC=RX@0x400011d8[libnative-lib.so]0x11d8
nzcv: N=0, Z=1, C=1, V=0, EL0, use SP_EL0
start + 0xae8
=> *[libnative-lib.so*0x011d8]*[03000090]*0x400011d8:*"adrp x3, #0x40001000"
    [libnative-lib.so 0x011dc] [63ec0a91] 0x400011dc: "add x3, x3, #0x2bb"
    [libnative-lib.so 0x011e0] [e4830191] 0x400011e0: "add x4, sp, #0x60"
    [libnative-lib.so 0x011e4] [e5430191] 0x400011e4: "add x5, sp, #0x50"
    [libnative-lib.so 0x011e8] [e6030191] 0x400011e8: "add x6, sp, #0x40"
    [libnative-lib.so 0x011ec] [e7c30091] 0x400011ec: "add x7, sp, #0x30"
    [libnative-lib.so 0x011f0] [01008092] 0x400011f0: "mov x1, #-1"
    [libnative-lib.so 0x011f4] [02088052] 0x400011f4: "mov w2, #0x40"
    [libnative-lib.so 0x011f8] [5bfdff97] 0x400011f8: "bl #0x40000764"

在Arm匯編里面,調(diào)用一個(gè)函數(shù)之前砌们,會(huì)把入?yún)⒋嫒氲?x0,x1,x2 ……

從這段代碼可以看出 地址 0x400011f8 會(huì)調(diào)用 0x40000764 函數(shù)杆麸,并且傳入了 7個(gè)參數(shù), 從x0浪感,一直賦值到x7昔头。

Unidbg的調(diào)試雖然有些簡陋,但是已經(jīng)夠用了影兽,有如此神器在手揭斧,你還要啥自行車?

調(diào)試命令先掌握以下幾個(gè):

s 單步步入峻堰,就是遇到函數(shù)調(diào)用會(huì)進(jìn)入讹开。

n 單步步過,遇到函數(shù)調(diào)用不會(huì)進(jìn)入函數(shù)捐名。

c 繼續(xù)執(zhí)行

b 下斷點(diǎn)

r 取消當(dāng)前斷點(diǎn)

m 查看內(nèi)存

我們先 s s s 幾下旦万,單步執(zhí)行到 0x400011f8

debugger break at: 0x400011f8 @ Function64 address=0x40001234, arguments=[unidbg@0xfffe1640[libandroid.so]0x640, 1853170425, 2008362258]
>>> x0=0xbffff690(-1073744240) x1=0xffffffffffffffff x2=0x40 x3=0x400012bb x4=0xbffff5d0 x5=0xbffff5c0 x6=0xbffff5b0 x7=0xbffff5a0 x8=0x0 x9=0x0 x10=0x1 x11=0x0 x12=0x8 x13=0x8 x14=0x8
LR=RX@0x400011d4[libnative-lib.so]0x11d4
SP=0xbffff570
PC=RX@0x400011f8[libnative-lib.so]0x11f8
nzcv: N=0, Z=1, C=1, V=0, EL0, use SP_EL0
start + 0xb08
=> *[libnative-lib.so*0x011f8]*[5bfdff97]*0x400011f8:*"bl #0x40000764"

這個(gè)時(shí)間點(diǎn),入?yún)⒍家呀?jīng)準(zhǔn)備好了镶蹋,我們來一個(gè)一個(gè)看看這些入?yún)ⅰ?/p>

mx7

>-----------------------------------------------------------------------------<
[10:40:26 646]x7=unidbg@0xbffff5a0, md5=d6c164ca9ef531557fc14e1bf7173663,
size: 112
0000: 35 41 37 35 37 34 33 44 00 B3 22 40 00 00 00 00    5A75743D.."@....
0010: 39 37 30 37 31 30 46 37 00 8D 09 40 00 00 00 00    970710F7...@....
0020: 34 44 39 31 38 31 38 42 00 77 12 40 02 00 00 00    4D91818B.w.@....
0030: 44 44 38 39 43 41 36 38 00 1B 17 40 02 00 00 00    DD89CA68...@....
0040: 31 36 37 37 30 33 38 30 36 36 35 35 33 80 00 00    1677038066553...
0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
^-----------------------------------------------------------------------------^

可以看到這次調(diào)用 函數(shù) 0x40000764成艘, 基本就是在組裝最后的結(jié)果了。

我們要做的就是找到這些結(jié)果生成的位置贺归,來分析最終結(jié)果是如何計(jì)算出來的淆两,也就是 Y → Z 的過程。

4拂酣、Trace內(nèi)存讀寫

現(xiàn)在我們已經(jīng)知道了結(jié)果Z的位置秋冰,下一步就是需要知道誰計(jì)算出了Z。

這就需要用到Unidbg的一個(gè)強(qiáng)大功能:內(nèi)存讀寫監(jiān)控

這一次我們先把調(diào)試斷點(diǎn)下早一點(diǎn)踱葛,在 sub_A3C 函數(shù)開頭就斷下來丹莲。

debugger break at: 0x40000a3c @ Function64 address=0x40001234, arguments=[unidbg@0xfffe1640[libandroid.so]0x640, 1853170425, 2008362258]
>>> x0=0x40004000 x1=0xbffff690 x2=0x0 x3=0x1 x4=0x0 x5=0x1 x6=0x0 x7=0x0 x8=0xfffe0a70 x9=0x3002 x10=0x0 x11=0x1 x12=0x3 x13=0x40003018 x14=0x40003028
>>> x15=0x1 x16=0x40228910 x17=0x0 x18=0x17 x19=0xfffe1640 x20=0xbffff708 x21=0x0 x22=0x0 x23=0x0 x24=0x0 x25=0x0 x26=0x0 x27=0x0 x28=0x0 fp=0xbffff6f0
LR=RX@0x40001280[libnative-lib.so]0x1280
SP=0xbffff690
PC=RX@0x40000a3c[libnative-lib.so]0xa3c
nzcv: N=0, Z=0, C=1, V=0, EL0, use SP_EL0
start + 0x34c
=> *[libnative-lib.so*0x00a3c]*[ff8304d1]*0x40000a3c:*"sub sp, sp, #0x120"

traceWrite 0xbffff5d0 0xbffff5d8
Set trace 0xbffff5d0->0xbffff5d8 memory write success.
c
[11:41:41 656] Memory WRITE at 0xbffff5d8, data size = 1, data value = 0x0, PC=RX@0x40001168[libnative-lib.so]0x1168, LR=null
[11:41:41 657] Memory WRITE at 0xbffff5d0, data size = 8, data value = 0x0, PC=RX@0x4000116c[libnative-lib.so]0x116c, LR=null
[11:41:41 661] Memory WRITE at 0xbffff5d8, data size = 1, data value = 0x0, PC=RX@0x401b48cc[libc.so]0x648cc, LR=RX@0x401b48c8[libc.so]0x648c8

traceWrite 就是監(jiān)控寫內(nèi)存命令。

看上去0xbffff5d0這段內(nèi)存尸诽,寫入 DD89CA68 數(shù)據(jù)的位置是: 0x116c

text:000000000000114C 14 00 00 90+                ADRL            X20, unk_12B8
.text:000000000000114C 94 E2 0A 91
.text:0000000000001154 C4 0A C0 5A                 REV             W4, W22
.text:0000000000001158 E0 83 01 91                 ADD             X0, SP, #0x110+var_B0
.text:000000000000115C 21 01 80 52                 MOV             W1, #9
.text:0000000000001160 22 01 80 52                 MOV             W2, #9
.text:0000000000001164 E3 03 14 AA                 MOV             X3, X20
.text:0000000000001168 FF A3 01 39                 STRB            WZR, [SP,#0x110+var_A8]
.text:000000000000116C FF 33 00 F9                 STR             XZR, [SP,#0x110+var_B0]
.text:0000000000001170 7D FD FF 97                 BL              sub_764

0x116c 的指令 STR XZR 是寫入 沒錯(cuò),但是看上去不像是寫入數(shù)據(jù)盯另,而是把 SP,#0x110+var_B0 這個(gè)地址的數(shù)據(jù)清零性含。

那我們重來一次,(Unidbg的優(yōu)點(diǎn)就是可以無限重放鸳惯,比真機(jī)調(diào)試App方便了不知道多少倍商蕴。)

這次往前一點(diǎn)點(diǎn)叠萍,在 0x114C 下斷點(diǎn)。

斷下來之后绪商,每s單步一次之后苛谷,就去查看 m0xbffff5d0。

最后發(fā)現(xiàn)跑完 0x1170 , 0xbffff5d0內(nèi)存的值就改變成了格郁, DD89CA68 腹殿。 這說明 0xbffff5d0 是 sub_764 函數(shù)去寫的。

debugger break at: 0x40001170 @ Function64 address=0x40001234, arguments=[unidbg@0xfffe1640[libandroid.so]0x640, 1853170425, 2008362258]
>>> x0=0xbffff5d0(-1073744432) x1=0x9 x2=0x9 x3=0x400012b8 x4=0xdd89ca68 x5=0xe6cd8e62 x6=0x24523012 x7=0x29b9c389 x8=0x40 x9=0x40318041 x10=0xbffff5e0 x11=0x40 x12=0x3d5ebb2b x13=0x6450c165 x14=0xfc63b7e7
>>> x15=0x49ac16b x16=0xac6af723 x17=0xf3d1564b x18=0x18 x19=0x4cf3a208 x20=0x400012b8 x21=0x0 x22=0x68ca89dd x23=0x3d74755a x24=0x72e737bb x25=0xddf5ac1 x26=0xd0d5adc6 x27=0x8b81914d x28=0xf7100797 fp=0xbffff680
LR=null
SP=0xbffff570
PC=RX@0x40001170[libnative-lib.so]0x1170
nzcv: N=0, Z=1, C=1, V=0, EL0, use SP_EL0
start + 0xa80
=> *[libnative-lib.so*0x01170]*[7dfdff97]*0x40001170:*"bl #0x40000764"

不過回到 0x1170,我們發(fā)現(xiàn)了一串熟悉的數(shù)字 x4=0xdd89ca68 例书, 好吧锣尉,我們的問題又變成了 x4的值是怎么算出來的?

三决采、總結(jié)

首先要習(xí)慣看Arm匯編自沧,一步一步單步調(diào)試,然后熟悉寄存器的變化树瞭。特別對(duì)一些關(guān)鍵數(shù)字要敏感拇厢。

要掌握Unidbg的基礎(chǔ)調(diào)試命令。

常見的加密算法要熟悉一下晒喷,在開發(fā)環(huán)境里多調(diào)試幾遍旺嬉,熟悉它的算法流程。

ffshow.jpg

1:ffshow

多方分別厨埋,是非之竇易開邪媳;一味圓融,人我之見不立荡陷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雨效,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子废赞,更是在濱河造成了極大的恐慌徽龟,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唉地,死亡現(xiàn)場離奇詭異据悔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)耘沼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門极颓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人群嗤,你說我怎么就攤上這事菠隆。” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵骇径,是天一觀的道長躯肌。 經(jīng)常有香客問我,道長破衔,這世上最難降的妖魔是什么清女? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮晰筛,結(jié)果婚禮上嫡丙,老公的妹妹穿的比我還像新娘。我一直安慰自己传惠,他們只是感情好迄沫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卦方,像睡著了一般羊瘩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盼砍,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天尘吗,我揣著相機(jī)與錄音,去河邊找鬼浇坐。 笑死睬捶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的近刘。 我是一名探鬼主播擒贸,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼觉渴!你這毒婦竟也來了介劫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤案淋,失蹤者是張志新(化名)和其女友劉穎座韵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踢京,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡誉碴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓣距。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黔帕。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖旨涝,靈堂內(nèi)的尸體忽然破棺而出蹬屹,到底是詐尸還是另有隱情侣背,我是刑警寧澤白华,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布慨默,位于F島的核電站,受9級(jí)特大地震影響弧腥,放射性物質(zhì)發(fā)生泄漏厦取。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一管搪、第九天 我趴在偏房一處隱蔽的房頂上張望虾攻。 院中可真熱鬧,春花似錦更鲁、人聲如沸霎箍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漂坏。三九已至,卻和暖如春媒至,著一層夾襖步出監(jiān)牢的瞬間顶别,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工拒啰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驯绎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓谋旦,卻偏偏與公主長得像剩失,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子册着,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容