截止至今天中午12點,第八題破解人數為5人!
攻擊方排名前十名波動不大,
loudy從第十位上升至第7位,
poyoten再次衝進前十位~
前十名能否保守住自己的位置呢?
是否會有黑馬一戰成名呢?
期待ing......
接下來我們來回顧一下第八題
看看 看雪評委和出題者是怎麼說的ヾ(๑╹◡╹)ノ"。
該題亮點依然在反除錯上,用虛擬機器進行程式碼保護,透過執行緒動態加解密主要程式碼,透過校驗和檢查程式碼完整性,根據時間來反除錯,另外還將實際程式碼替換為假程式碼,防止反彙編,在反除錯方面讓攻方選手舉步維艱。演算法上採用了RSA演算法的思想,解決掉反除錯後,參考RSA演算法可以求解。
作者loudy,原名吳林峰,畢業於北京航空航天大學電子資訊工程專業,當前從事工作出於保密規定暫不公開。愛好跑步、籃球、電影;熱衷程式設計、特別是逆向分析。2007年接觸看雪,以潛水學習為主,也希望多認識有相同愛好的朋友。
一、答案
UFdVXVRTVVFYWltdXV9XQkFDQEUtLVBTV1BWVVFQUVxeWVxfWENDQkRCQE5CTEBCWFZaVVRTVlxZU1lcXC0tVGhpNV9pc19BX1ZlcnlfU2ltcGxlX1Rlc3Qh
二、基本設計思想
(1)簡單虛擬機器(使用虛擬暫存器傳值)
實現了系統函式呼叫、CMP、JNZ、XOR等呼叫
(2)反除錯
主要使用了3種
1、 執行緒動態加密解密主要程式碼
2、 CheckSum檢查主要程式碼
3、 時間判斷
(3)反彙編
主要透過將實際程式碼替換為假程式碼,防止反彙編。
(4)演算法設計
主要是利用RSA思想,其中(比較小)
P:900F0CA3041C345B
Q:98FCAE63A170C363
N:56172073862A662A8D6BB1A135999031
E:D9C382944A461EE3
D:4A064A97921BDF9E3F354E9020AE054F
首先對輸入進行base64解碼,然後將解碼後註冊碼分成三段,
1、 第一段解碼得到E,再和固定值做大數乘法運算,結果和另一固定值比較,相等則到下一步
2、 第二段解碼得到N,再和固定值做大數乘法運算,結果和另一固定值比較,相等則到下一步
3、 透過E和N對第三段加密,和記憶體固定值比較,相等則成功
三、破解思路
1、先解決反除錯和反反彙編,將真正程式碼還原
2、識別大數乘法運算,透過固定值和大數除法還原E、N,得到第一段和第二段註冊碼。
3、透過E、N解出D
4、用N和D對固定值解密,得到第三段註冊碼。
5、組合三段註冊碼,base64加密,得到最終的註冊碼。
1. TlsCallback
建立了6個執行緒, 前3個執行緒是負責smc解碼的, 後3個執行緒沒用
.text:00402D30 TlsCallback_2
執行緒1: 解碼004025DC處的跳轉及check1函式
.text:00402830 thread1
.text:004025DC push offset loc_4025E2
.text:004025E1 retn
.text:004025E2 lea ecx, [ebp+var_110]
.text:004025E8 push ecx
.text:004025E9 call check1
執行緒2: 解碼0040263C處的跳轉及check2函式
.text:00402970 thread2
.text:0040263C push offset loc_402642
.text:00402641 retn
.text:00402642 lea eax, [ebp+var_110]
.text:00402648 push eax
.text:00402649 call check2
執行緒3: 解碼0040269C處的跳轉及check3函式
.text:00402A90 thread3
.text:0040269C push offset loc_4026A2
.text:004026A1 retn
.text:004026A2 lea edx, [ebp+var_110]
.text:004026A8 push edx
.text:004026A9 call check3
2. 主流程
一個自定義的虛擬機器
校驗函式
.text:00402700 fn_check
檢測程式碼改動
.text:00402481 call check_text_areas
sn=base64_decode(sn)
.text:0040251D call base64_decode
sn的格式(共90位): (20位)--(39位)--(27位)
.text:00402573 cmp [ebp+var_130], 90
.text:0040257A jnz short loc_4025AC
.text:0040257C movsx edx, [ebp+Dst+14h]
.text:00402583 cmp edx, '-'
.text:00402586 jnz short loc_4025AC
.text:00402588 movsx eax, [ebp+Dst+15h]
.text:0040258F cmp eax, '-'
.text:00402592 jnz short loc_4025AC
.text:00402594 movsx ecx, [ebp+Dst+3Dh]
.text:0040259B cmp ecx, '-'
.text:0040259E jnz short loc_4025AC
.text:004025A0 movsx edx, [ebp+Dst+3Eh]
.text:004025A7 cmp edx, '-'
.text:004025AA jz short loc_4025B2
校驗前20位
(sn1 xor abcdefg...) * 98765432109876543210123 == 1549780652036258484424751705102781884386113
.text:004025E9 call check1
校驗中間39位
(sn2 xor abcdefg...) ^ 2 == 13095069099216326605010245808779535277211541324456558063162414338128147458401
.text:00402649 call check2
檢驗後27位, sn3視為16進位制
sn3 ^ 15691529100101820131 mod 114433688655117320765854989491151409201 == 71639176673360967005214790689576394595
.text:004026A9 call check3
sn3作為16進位制轉換的時候是有符號轉換的, 所以導致>=80的值無法正常轉換
這裡只需要關心能產生0x00的值即可(有挺多個, 如0x89)
for (int i = 8; i < 16; i++)
{
for (int k = 0; k < 16; k++)
{
int v = (char)((i << 4) | k);
char v1 = v / 16;
char v2 = v % 16;
v1 += v1 < 0 ? 0x37 : 0x30;
v2 += v2 < 0 ? 0x37 : 0x30;
// 這裡非數字字母的字元, 後面都會被0替代
printf("%02X: %c%c\n", (BYTE)v, v1, v2);
}
}
3. 後27位計算
已知:
e = 15691529100101820131
n = 114433688655117320765854989491151409201
m = 71639176673360967005214790689576394595
分解得到
d = 98395538376216701876091105738065053007
c = m ^ d mod n = 55986991232018409201158808992848352475 (2A1EB3C9579DFA307CF5B6C8730114DB)
c中>=0x80的是無法透過轉換得到的(如B3, C9, ...)
sn3(27位元組) > c (16位元組)
c ^ e mod n = m, 根據(a * b) mod n = (a mod n) * (b mod n) mod n
得 (c mod n) * (c mod n) * ... mod n = m
再由c mod n = (c + k * n) mod n, 代入上式得到
(c + k * n) ^ e mod n = m
根據下面這兩個條件可以立刻得到很多解(如: 0208674855670d0560353c3a1d3e242e217766)
sn3 = c + k * n
sn3中的位元組必須小於0x80
得到的解, 在前面填充可以轉換成00的值: 89898989898989890208674855670d0560353c3a1d3e242e217766
與前面的串連線起來base64得到最終結果
UFdVXVRTVVFYWltdXV9XQkFDQEUtLVBTV1BWVVFQUVxeWVxfWENDQkRCQE5CTEBCWFZaVVRTVlxZU1lcXC0tiYmJiYmJiYkCCGdIVWcNBWA1PDodPiQuIXdm
4. 窮舉指令碼
import itertools
n=114433688655117320765854989491151409201
e=15691529100101820131
c=55986991232018409201158808992848352475
def valid_result(v):
sv=hex(v)[2:]
sv_len=len(sv)
if (sv_len&1) != 0:
sv='0'+sv
sv_len=sv_len+1
for i in itertools.count(0,2):
if (i>=sv_len):
break
if (ord(sv[i])>=0x38):
return False
return True
def solve(ibegin,iend):
g=0
nc=c
k=0
for i in itertools.count(0):
g=g+1
nc=nc+n
if ((ibegin+i)>=iend):
break;
#print(nc)
#print(pow(nc,e,n))
if (g>=1000000):
print(ibegin+i)
g=0
if (valid_result(nc)):
print('---')
print(i)
print(nc)
print(hex(nc))
#break
return
solve(0,4294967296)
'''
---
396154
45333533916159234226406484520676079360374630
0x208674855670d0560353c3a1d3e242e217766
---
456935
52288927946305920099875916636937753163020611
0x2583f59392b7266031a47246a1e672b013943
..
最後感謝 WiFi 萬能鑰匙安全應急響應中心的贊助支援,
接下來的比賽大家一定要使出洪荒之力哦!↖(^ω^)↗
比心 ❤
贊助商
上海連尚網路科技有限公司成立於 2013 年,是一家專注於提供免費上網和內容服務的移動網際網路企業。連尚網路自主研發的核心產品 WiFi 萬能鑰匙,以分享經濟的模式,透過雲端計算和大資料技術,利用熱點主人分享的閒置WiFi資源,為使用者提供免費、穩定、安全的上網服務,以幫助更多的人上網,找到屬於他們的機會,改變自己的命運。