最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊

新160個(gè)CrackMe分析-第5組:41-50(上)

2022-10-13 00:00 作者:rkvir逆向工程學(xué)院  | 我要投稿

作者:selph

目錄:

??041-genocidel1

??042-crackme2

??043-riijj_cm_200411213

??044-tsrh-crackme4

??045-CyTom-crackme5

??046-keyme16

??047-surre7

??048-monkeycrackme18

??049-THraw-crackme89

??050-daxxor10

1.??????041-genocidel

???????????算法難度:??????????????爆破難度:?

信息收集

運(yùn)行情況:

彈窗提示說這里應(yīng)該有個(gè)Reg.dat文件


??????????創(chuàng)建這個(gè)文件之后就能打開頁面了:


??????????

查殼與脫殼:

UPX殼,ESP定律即可脫殼??????????


調(diào)試分析

OK按鈕按下的時(shí)候:直接彈窗Success??????????



但是這個(gè)OK按鈕按不下去,應(yīng)該是驗(yàn)證在別的地方這里還有一個(gè)事件就是Serial的四個(gè)框發(fā)生值改變的時(shí)候:


??????????會(huì)調(diào)用同一個(gè)函數(shù),這個(gè)函數(shù)應(yīng)是校驗(yàn)了,參數(shù)是第幾個(gè)框的標(biāo)識(shí)這個(gè)函數(shù)一進(jìn)去就是一個(gè)switch分支,分別對應(yīng)四個(gè)框處理


??????????四個(gè)框的處理相同:都是把值保存在一個(gè)數(shù)組里,然后調(diào)用同一個(gè)函數(shù)

??????????這個(gè)調(diào)用的函數(shù)才是真正驗(yàn)證的部分:首先獲取Name部分,Name長度需要大于等于5,這里分別取1345四個(gè)字符除以10保存到一個(gè)數(shù)組里

??????????然后接下來就是一個(gè)循環(huán):這個(gè)循環(huán)的作用是剛剛那個(gè)數(shù)組里保存的值是否為個(gè)位數(shù),如果不是,就再次除以10,得到一個(gè)個(gè)位數(shù)的值

??????????最后,又是一個(gè)循環(huán),依次比對剛剛保存的四個(gè)值,和上一層函數(shù)從四個(gè)框里保存的四個(gè)值是否相同,如果都相同就啟用OK按鈕,否則就不啟用??????????

??????????

注冊機(jī)

注冊碼生成算法:(CSharp)?????string Name = Console.ReadLine();
if (Name == null) return;

for (int i = 0; i < Name.Length; i++)
??? if(i is 0 or 2 or 3 or 4)
??? {
??????? int tmp = (int)Name[i];
??????? if (tmp >= 100) tmp /= 100;
??????? else if (tmp >= 10) tmp /= 10;
??????? Console.Write(tmp+" ");
??? }效果:

??????????

總結(jié)

編輯框更變事件里驗(yàn)證,首先把編輯框4個(gè)值保存起來,然后用Name計(jì)算4個(gè)值,然后進(jìn)行比對,4個(gè)值都比對成功,就成功比之前遇到的那些還算有了點(diǎn)新意

2.??????042-crackme

算法難度:????爆破難度:??

信息收集

運(yùn)行情況:

直接打開說需要一個(gè)dat文件??????????



創(chuàng)建了之后,說你確定這是正確的keyfile?感覺意思是啟動(dòng)時(shí)驗(yàn)證,根據(jù)文件內(nèi)容驗(yàn)證

??????????

查殼與脫殼:

無殼:C++程序??????

????

調(diào)試分析

C++程序就抄起IDA干!首先是創(chuàng)建對話框,這里主要進(jìn)這個(gè)窗口函數(shù)去看

??????????這里是窗口過程函數(shù),根據(jù)不同的消息碼有一大堆分支,這里只有一個(gè)分支調(diào)用了自定義的函數(shù):上面一堆無關(guān)緊要的部分,這個(gè)函數(shù)很可疑

??????????這就是個(gè)check函數(shù)了:首先是一堆變量初始化工作,就跳過不管了,程序首先是通過push和pop給edi賦值了初值:3然后緊接著就是打開文件key.dat,打開失?。ㄎ募淮嬖冢┚惋@示提示信息,如果有這個(gè)文件就往下跳過

??????????往下就是讀取文件內(nèi)容的操作,這里會(huì)判斷讀取的字節(jié)數(shù),如果為0則意味著沒內(nèi)容,就跳到能通往Fail的程序路線

??????????接下來讀取到內(nèi)容了之后,有兩個(gè)循環(huán):–?循環(huán)1:首先是使用讀取的字節(jié)數(shù)對每一個(gè)字節(jié)進(jìn)行一次異或操作–?接下來對于前三個(gè)字節(jié),額外再異或一個(gè)魔數(shù),分別異或0x54,0x4d0x47–?循環(huán)2:三個(gè)字節(jié)為一組,向后異或,14,25,36的值進(jìn)行異或,然后47,5869的值進(jìn)行異或,依次進(jìn)行下去,處理完輸入的長度,因?yàn)槭侨齻€(gè)一組,所以最后可能長度比輸入的長度長,需要手動(dòng)在字節(jié)數(shù)組結(jié)尾賦值0來截?cái)?/span>
??

????????接下來:獲取一個(gè)地址,405030,這是個(gè)字符數(shù)組(注意這個(gè)值??!后面有用到)然后使用我們的輸入的前三個(gè)字節(jié),循環(huán)去異或這個(gè)字節(jié)數(shù)組,依然是3個(gè)一組,對于字符數(shù)組,每三個(gè)字節(jié),都分別與輸入的前三字節(jié)異或一遍,直到字符數(shù)組的結(jié)尾標(biāo)識(shí)FF出現(xiàn)跳出循環(huán)之后,是第一層校驗(yàn):前三個(gè)字節(jié)的乘積為0x2A8BF4如果不是,則就顯示提示信息說我們的輸入是錯(cuò)誤的

??????????接下來緊接著又是一個(gè)循環(huán),遍歷輸入的值,復(fù)制到一個(gè)緩沖區(qū)里,結(jié)束標(biāo)志是出現(xiàn)0x20,給緩沖區(qū)的字符串一個(gè)00結(jié)尾(實(shí)際上這一段是在定位UserName)

??????????接下來是另一個(gè)循環(huán),循環(huán)遍歷的對象依然是我們的輸入,這個(gè)循環(huán)的起點(diǎn)是上一個(gè)循環(huán)的終點(diǎn),在0x20之后開始,把每一個(gè)字節(jié)都復(fù)制到另一個(gè)局部變量里[ebp+ver_58](實(shí)際這就是解密出來的用戶名)

??????????接下來是一個(gè)神奇的VirtualProtect調(diào)用,可能有人覺得到前面驗(yàn)證三數(shù)乘積的時(shí)候就結(jié)束了,實(shí)際上并沒有,之前對一個(gè)字符數(shù)組進(jìn)行了大量的異或,然后這里使用VirtualProtect函數(shù)給字符數(shù)組修改了內(nèi)存屬性,然后直接call了這個(gè)字符數(shù)組的地址合著這字符數(shù)組是shellcode啊,然后那一堆異或是解密操作!

??????????關(guān)于shellcode的功能,就不詳細(xì)分析了,具體功能是生成字符串Registered to:?然后拼接用戶名到這里就分析完了驗(yàn)證流程,接下來該寫注冊機(jī)了,接下來分析注冊機(jī)怎么寫

注冊機(jī)分析

這里驗(yàn)證如下:a.?經(jīng)過一系列異或之后的前三字節(jié)的乘積為固定值b.?前三個(gè)字節(jié)可以用于解密shellcode,解密的結(jié)果可執(zhí)行c.?輸入的字符里存在分隔符,分隔符經(jīng)過一系列異或之后的值為0x20,分隔符之后的內(nèi)容則是UserName,經(jīng)過一系列異或解密出UserName,如果沒有這個(gè)分隔符則會(huì)奔潰退出程序
首先處理第一個(gè)驗(yàn)證,三個(gè)值的乘積為固定值,這三個(gè)值是輸入的前三字節(jié)經(jīng)過已知數(shù)值的異或而得到,所以這個(gè)計(jì)算是可逆的;處理思路是找到滿足要求的三字節(jié),然后反推找到原始的前三字節(jié),數(shù)據(jù)量不大,簡單粗暴處理:?????void getvalue() {
??? for (size_t i = 0; i < 0xff; i++)
??????? for (size_t j = 0; j < 0xff; j++)
??????????? for (size_t k = 0; k < 0xff; k++)
??????????????? if (i * j * k == 0x2A8BF4)
??????????????????? std::cout << i << " " << j << " " << k << std::endl;;???????????得到一組結(jié)果:?????unsigned char val[] = {
85, 139, 236,
85, 236, 139,
118, 139, 170,
118, 170, 139,
139, 85, 236,
139, 85, 236,
139, 118, 170,
139, 170, 118,
139, 236, 85,
170, 118, 139,
170, 139, 118,
236, 85, 139,
236, 139, 85 };接下來使用這組結(jié)果去進(jìn)行異或反推得到新的一組輸入值:每個(gè)字節(jié)會(huì)異或字符數(shù)組對應(yīng)的字節(jié),然后異或固定的值,然后異或讀取字符長度?????int main()
{
??? //字符數(shù)組的前三字節(jié):0x1E, 0xBF, 0xA2
??? for (int i = 0; i < 39; i+=3)
??? {
??????? int len = 3;
??????? val[i] ^= 0x1E^0x54^len;
??????? val[i+1] ^= 0xbf^0x4d^len;
??????? val[i+2] ^= 0xa2^0x47^len;
??????? printf("%02x %02x %02x \n",val[i],val[i+1],val[i+2]);
??? }
}得到一組結(jié)果:?????1c 7a 0a
1c 1d 6d
3f 7a 4c
3f 5b 6d
c2 a4 0a
c2 a4 0a
c2 87 4c
c2 5b 90
c2 1d b3
e3 87 6d
e3 7a 90
a5 a4 6d
a5 7a b3這一組結(jié)果作為輸入的前三字節(jié),經(jīng)過一系列異或之后的乘積滿足固定值要求因?yàn)榻Y(jié)果有限,可能只有一組,也可能有多組答案能解密shellcode,所以這里先不管接下來是計(jì)算分隔符,沒有分隔符程序會(huì)崩潰:因?yàn)榘逊指舴旁诘谒奈?,所以根?jù)之前的異或操作規(guī)律,需要和第一個(gè)值進(jìn)行異或一下:?????int main()
{
??? for (int i = 0; i < 39; i+=3)
??? {
??????? int len = 3+1;
??????? val[i] ^= 0x1E^0x54^len;
??????? val[i+1] ^= 0xbf^0x4d^len;
??????? val[i+2] ^= 0xa2^0x47^len;

??????? char tmp = 0x20 ^ val[i] ^ 0x54;
??????? printf("%02x %02x %02x %02x \n",val[i],val[i+1],val[i+2],tmp);
??? }
}得到新的一組結(jié)果:?????1b 7d 0d 6f
1b 1a 6a 6f
38 7d 4b 4c
38 5c 6a 4c
c5 a3 0d ffffffb1
c5 a3 0d ffffffb1
c5 80 4b ffffffb1
c5 5c 97 ffffffb1
c5 1a b4 ffffffb1
e4 80 6a ffffff90
e4 7d 97 ffffff90
a2 a3 6a ffffffd6
a2 7d b4 ffffffd6到這里如果計(jì)算沒錯(cuò)的話,程序應(yīng)該可以正常運(yùn)行了,使用第一組輸入試試:成功運(yùn)行,顯示提示字符已注冊

??????????但是這里用戶名還沒有顯示出來,用戶名經(jīng)過的操作只有兩次,一次是最初的對每個(gè)字符都異或一遍讀取長度,然后就是用前三字節(jié)去循環(huán)異或用戶名了:?????int main()
{
??? char name[100] = {0};
??? std::cin >> name;
??? int tmp_len = strlen(name);
??? int nLen = tmp_len % 3 == 0 ? tmp_len : tmp_len + 3-(tmp_len % 3);

??? //0x1E, 0xBF, 0xA2
??? for (int i = 0; i < 39; i+=3)
??? {
??????? int len = 3+1+nLen;
??????? val[i] ^= 0x1E^0x54^len;
??????? val[i+1] ^= 0xbf^0x4d^len;
??????? val[i+2] ^= 0xa2^0x47^len;
??????? for (int j = 0; j < strlen(name); j += 3) {
??????????? name[j] ^= val[i+1]^0x4d;
??????????? name[j+1] ^= val[i+2]^0x47;
??????????? name[j+2] ^= val[i]^0x54;
??????? }
??????? char tmp = 0x20 ^ val[i] ^ 0x54;
??????? printf("%02x %02x %02x %02x ",val[i],val[i+1],val[i+2],tmp);
??????? for (int j = 0; j < strlen(name); j++)
??????? {
??????????? printf("%02x ",name[j]);
??????? }
??????? printf("\n");
??? }

}計(jì)算結(jié)果:用戶名:selph,結(jié)果:15 73 03 61 4d 21 2d 4e 2c 41,用010 editor寫入key文件,打開程序:用戶名也出來了,到此完成這個(gè)CM?的算法分析

??????????

總結(jié)

這個(gè)有意思,通過key文件進(jìn)行校驗(yàn),key里有分隔符決定程序是否會(huì)崩潰,分隔符后面的是用戶名,通過異或操作進(jìn)行解密這里還通過前三字節(jié)作為密碼去解密一段shellcode,然后執(zhí)行shellcode來生成驗(yàn)證通過的字符串進(jìn)行顯示

3.??????043-riijj_cm_20041121

算法難度:???(這個(gè)有意思)爆破難度:??反調(diào)試:??

信息收集

運(yùn)行情況:

???????

???

查殼與脫殼:

無殼,但是自帶了一個(gè)dll文件??????

? ??


調(diào)試分析

是個(gè)C/C++程序,直接打開可以運(yùn)行,但是用x86dbg打開則會(huì)發(fā)生異常,因?yàn)樘D(zhuǎn)到的0地址執(zhí)行

??????????因?yàn)檎{(diào)試器會(huì)接管異常的緣故,不管怎么點(diǎn)運(yùn)行,程序都停留在了這里首先推測是這里存在反調(diào)試!有兩個(gè)可能:a.?在這之前進(jìn)行反調(diào)試檢測,檢測到調(diào)試器,則不往這個(gè)地址里填值,使得這里讀取到的內(nèi)容是0b.?這里就是通過故意觸發(fā)異常來進(jìn)行反調(diào)試的
接下來先對抗一下反調(diào)試

處理反調(diào)試

對于猜想1,我先啟動(dòng)了程序,然后再附加查看內(nèi)存,這個(gè)地址的內(nèi)容依然是0,所以要么是猜想1不成立,要么是跳轉(zhuǎn)完成之后又把值改為了0,經(jīng)過IDA靜態(tài)分析里查找這個(gè)變量,通過交叉引用查看,發(fā)現(xiàn)并沒有修改這個(gè)變量的跡象,故認(rèn)為猜想1不成立對于猜想2,由于這個(gè)函數(shù)在跳轉(zhuǎn)0地址之前,注冊了一個(gè)SEH處理函數(shù),所以這里就讓SEH來處理異常,我們?nèi)EH里下斷點(diǎn)(4024D0),同時(shí)設(shè)置x86dbg忽略0xc0000005異常


程序成功在異常處理里斷下了,如果只是簡單的通過讓調(diào)試器接管異常使得程序不能進(jìn)行下去來反調(diào)試,那么到此程序應(yīng)該就能運(yùn)行下去了,點(diǎn)擊運(yùn)行之后,又再次執(zhí)行到了異常處理里的斷點(diǎn)處:

??????????這不對勁,有貓膩!經(jīng)過不停的步過,發(fā)現(xiàn)異常處理函數(shù)下面的這個(gè)call造成了異常:這個(gè)call的地址取決于edi和ecx,edi是個(gè)基址,ecx是索引??????????



這里ecx的值不同,就會(huì)執(zhí)行不同的函數(shù),一定有一個(gè)是程序正常執(zhí)行需要執(zhí)行的,然后有很多干擾項(xiàng)不停的運(yùn)行,到這里ecx的值依次增加3:0,3,6,9......當(dāng)運(yùn)行到某一個(gè)函數(shù)的時(shí)候(ecx=C):手動(dòng)生成了一個(gè)奇怪的異常(之前都是jmp 0地址)????


再往下,第7次進(jìn)入這個(gè)異常處理的時(shí)候,call了另一個(gè)不一樣的函數(shù)


???????????這個(gè)函數(shù)調(diào)用了函數(shù)SetUnhandledExceptionFilter經(jīng)過查閱資料:這個(gè)函數(shù)的功能注冊一個(gè)終極異常處理函數(shù)通常來說,當(dāng)程序發(fā)生異常之后,如果沒有異常處理器能處理,就會(huì)執(zhí)行終極異常處理:UnhandledExceptionFilter,而這個(gè)函數(shù)的作用就是自定義一個(gè)終極異常處理函數(shù)
而這個(gè)終極異常處理函數(shù)在調(diào)試器下不會(huì)被調(diào)用,在調(diào)試器下,處理不了的異常就交給調(diào)試器了,只有在無調(diào)試器情況下才會(huì)交給終極異常處理讓程序正常執(zhí)行,從而達(dá)到反調(diào)試的效果
也正因?yàn)樘幚聿涣说漠惓?huì)交給調(diào)試器,所以調(diào)試的時(shí)候能見到同一個(gè)異常出現(xiàn)了很多次程序都不退出
這里因?yàn)樵谡{(diào)試器下沒法進(jìn)入這個(gè)終極異常處理,所以這里對程序進(jìn)行一些修改,這個(gè)call之下有一個(gè)push F,然后再下面的那個(gè)call會(huì)產(chǎn)生異常,所以這里干脆直接讓下面的程序直接變成跳轉(zhuǎn)到異常處理里,修改如下:

??????????運(yùn)行,程序能跑起來了,接下來打補(bǔ)丁保存這個(gè)修改,右鍵,patch,patch file調(diào)試新保存的程序,結(jié)果依然跑不起來,發(fā)生了異常:又在jmp 0地址,但是右下角給出了提示,IsDebuggerPresent,看來是另一個(gè)反調(diào)試

??????????這個(gè)反調(diào)試好處理,直接修改fs:[30]地址處的第二個(gè)字節(jié)為0即可,或者用x86dbg插件ScallyHide來隱藏PEB調(diào)試痕跡

??????????然后再次重新運(yùn)行,程序可以調(diào)試了,反調(diào)試都處理完了(應(yīng)該)

??????????

定位校驗(yàn)函數(shù)

輸入Name?和Serial,點(diǎn)擊按鈕,發(fā)現(xiàn)沒反應(yīng),沒有錯(cuò)誤提示那就用老辦法去找C++界面程序的按鈕事件,學(xué)習(xí)Win32編程的時(shí)候,我們知道窗口程序有一個(gè)窗口過程函數(shù),當(dāng)有消息了,就傳遞給窗口過程來處理使用xspy工具查看控件ID:按鈕id=3ee

??????????接下來,用IDA分析,在導(dǎo)入表中找到分發(fā)消息的程序段一定會(huì)用的函數(shù):DispatchMessage,然后通過交叉引用定位找到窗口創(chuàng)建函數(shù),在上面不遠(yuǎn)處看到窗口過程函數(shù):


這個(gè)函數(shù)很簡單:就處理一個(gè)事件
查閱資料[3]可知,按鈕按下的事件是一個(gè)WM_COMMAND消息,這個(gè)按鈕ID剛好是e33,那這個(gè)處理就是按鈕按下的過程了(實(shí)際測試,在動(dòng)態(tài)調(diào)試器下,按下按鈕確實(shí)會(huì)斷在這里)這里的功能是給一個(gè)變量賦值為1?????


接下來看看這個(gè)變量是干嘛用的:這里如果按鈕按下了,就會(huì)進(jìn)入一大段程序里,否則就跳出??????

????這一大段程序除了不知道干啥的初始化和賦值,值得關(guān)注的就是這個(gè)call了(名字是逆向完之后重命名的)


交叉引用查看這個(gè)call的地址,找到賦值的地方:是來自dll的導(dǎo)出函數(shù)

??????????上面那個(gè)call:fp_CopyDll,的功能是復(fù)制dll到某個(gè)地方,然后將文件名保存到全局變量里:????

??????然后對dll文件進(jìn)行一個(gè)解密循環(huán)操作:? ??


???????????(難怪之前直接dll拖IDA識(shí)別不出來),等執(zhí)行完這個(gè)循環(huán)去臨時(shí)目錄拿到解密后的dll來繼續(xù)分析導(dǎo)出函數(shù),這里按鈕的功能就是調(diào)用這個(gè)導(dǎo)出函數(shù)

分析校驗(yàn)函數(shù)

隨便輸入點(diǎn)啥,調(diào)用導(dǎo)出函數(shù)之前下個(gè)斷點(diǎn),看看參數(shù)是啥:參數(shù)1是用戶名,參數(shù)2是序列號(hào)

??????????這個(gè)校驗(yàn)函數(shù)的內(nèi)容就很簡單:上面的初始化過程就跳過不管了,這里分為兩部分:a.?生成真碼b.?序列號(hào)對比
后者就是strcmp,沒啥好說的,這里主要就是真碼的生成:–?遍歷Name,取一個(gè)字節(jié)–?除以0x62得到余數(shù)–?余數(shù)作為一個(gè)超長隨機(jī)字符串的索引,取2個(gè)值,拼接在一起–?依次循環(huán),直到拼接完成每個(gè)字節(jié)索引到的兩個(gè)字符

??????????

注冊機(jī)

注冊碼生成算法:?????#include
auto arr = "fytugjhkuijonlbpvqmcnxbvzdaeqrwtryetdgfkgphonuivmdbxfanqydexzwztqnkcfkvcpvlbmhotyiufdkdnjxuzyqh";
int main()
{
??? char name[100] = { 0 };
??? char serial[100] = {0};

??? std::cin >> name;
??? int len = strlen(name);

??? for (int i = 0,j=0; i < len; i++,j+=2)
??? {
??????? int tmp = name[i];
??????? serial[j] = arr[tmp % 0x62];
??????? serial[j + 1] = arr[tmp % 0x62 + 1];
??? }
??? std::cout << serial;
}效果:

??????????

總結(jié)

這個(gè)有意思,基于異常的反調(diào)試和基于PEB的反調(diào)試,解密dll文件使用導(dǎo)出函數(shù)進(jìn)行密碼校驗(yàn)這個(gè)反調(diào)試對于新手來說,確實(shí)不好搞,很有價(jià)值的一次逆向?qū)W習(xí)!

參考資料

–[1]?Anti-Debug: Exceptions (checkpoint.com)

[2]反調(diào)試?- SetUnhandledExceptionFilter_(-: LYSM :-)的博客-CSDN博客_setunhandledexceptionfilter

?[3]?(Winuser.h) WM_COMMAND消息?- Win32 apps | Microsoft Docs

[4]虛擬鍵碼鍵盤消息(初稿)_tiandyoin的博客-CSDN博客


4.??????044-tsrh-crackme

算法難度:????爆破難度:?

信息收集

運(yùn)行情況:

一開始就是Nag:

??????????然后進(jìn)入界面:

??????????

查殼與脫殼:

? ? ? ?

???

調(diào)試分析

首先是一個(gè)創(chuàng)建互斥量,然后接收一個(gè)錯(cuò)誤,如果是特定錯(cuò)誤就不執(zhí)行程序,這是一種簡單有效的防多開手段,然后就是創(chuàng)建窗口了,這里跟進(jìn)窗口函數(shù)

??????????

去除Nag

窗口過程的開頭:

??????????第一個(gè)0x110號(hào)消息的分支里,存在一個(gè)MessageBoxA的調(diào)用,查閱資料[1]可知,創(chuàng)建對話框的時(shí)候,會(huì)有一個(gè)初始化消息會(huì)發(fā)送到消息循環(huán),這個(gè)時(shí)候窗口還未顯示出來,這個(gè)消息WM_INITDIALOG就是0x110號(hào)消息
Nag存在于這個(gè)消息里,而這里MessageBox調(diào)用前面有一個(gè)跳過的條件,這里如果要消除Nag,就直接改這個(gè)跳轉(zhuǎn)語句jz為jmp即可

分析校驗(yàn)算法

進(jìn)入之后就是switch-case里的多分支語句了,使用xray查看check按鈕id=22b,按鈕按下的消息碼是0x111,直接找111消息碼控件id為22b的分支:首先是先獲取Name到全局變量里(長度需要大于等于5)

??????????接下來是Serial校驗(yàn)過程這里調(diào)用了三個(gè)生成真碼的函數(shù),這一段反匯編的主要功能就是這三個(gè)函數(shù),中間的這些對比可以忽視,是提升效率用的

??????????先看第一個(gè)生成函數(shù):獲取了Name長度,保存到全局變量里然后拼接字符串:tsrh-一個(gè)數(shù)字-

??????????第二個(gè)生成函數(shù):獲取生成Serial的長度,遍歷用戶名,對于每個(gè)用戶名字節(jié),都進(jìn)行一系列計(jì)算得到一個(gè)新的數(shù)值,以十六進(jìn)制的形式拼接到生成Serial的后面

??????????第三個(gè)生成函數(shù):這里分別從Name和生成Serial里取一個(gè)字節(jié),異或(Name從頭開始取,Serial從12偏移處開始?。┌呀Y(jié)果變成大寫字母,然后把該大寫字母以int賦值的形式,賦值到Serial第10字節(jié)處最后調(diào)用對比函數(shù)

??????????對比函數(shù):逐字節(jié)對比,如果全都一樣,則返回1,返回1則會(huì)跳轉(zhuǎn)到成功提示彈窗處

??????????

注冊機(jī)

注冊碼生成算法:?????#define _CRT_SECURE_NO_WARNINGS
#include

#pragma region check
int midValue = 0;
char serial[100];
char name[100];
void GenSerial1() {
??? midValue = strlen(name);
??? sprintf(serial,"tsrh-%d-",midValue+0x7d3);
}
void GenSerial2() {
??? int len = strlen(serial);
??? int tmp = midValue;
??? for (int i = 0; i < midValue; i++)
??? {
??????? int tmp1 = name[i] + 0xc;
??????? int tmp2 = tmp1 - 0x11 + tmp1 - len;
??????? tmp1 ^= tmp2;
??????? sprintf(&serial[len], "%X", tmp1);

??????? len = strlen(serial);
??? }
}
void GenSerial3() {
??? for (int i = 0; i < 0x10; i++)
??? {
??????? if (name[i] == 0)break;
??????? char tmpn = name[i]+1;
??????? char tmps = serial[i + 12];
??????? char c = tmpn ^= tmps;
??????? while (c < 'A')c += 8;
??????? while (c > 'Z')c -= 3;

??????? *(int*)&serial[i + 10] = c;
??? }
??? std::cout << serial;
}
#pragma endregion?校驗(yàn)函數(shù)

int main()
{
??? std::cin >> name;
??? GenSerial1();
??? GenSerial2();
??? GenSerial3();
}效果:??

????????

總結(jié)

分析這類的窗口程序,如果知道常見的窗口消息是什么,那就很好定位到控件操作的事件

參考資料

[1]WM_INITDIALOG消息?(Winuser.h) - Win32 apps | Microsoft Docs


5.??????045-CyTom-crackme

算法難度:??

爆破難度:?

信息收集

運(yùn)行情況:


??????????

查殼與脫殼:


??????????

調(diào)試分析

雖然上面寫的Delphi程序,然而IDR并不能識(shí)別,使用DD去反編譯倒是成功了,可能版本Delphi太低吧

找到按鈕函數(shù):

邏輯很簡單:獲取Serial,獲取Name,對Serial計(jì)算一個(gè)值,對Name計(jì)算一個(gè)值,然后進(jìn)行比對


??????????

對Serial的計(jì)算:

首先判斷第一個(gè)字符是否合法,不合法就跳轉(zhuǎn)

然后是一個(gè)循環(huán),分析發(fā)現(xiàn),又分析了一遍_atoi函數(shù)

這個(gè)計(jì)算的本質(zhì)就是把Serial字符串轉(zhuǎn)換成數(shù)字


??????????

??????????

對Name的計(jì)算:

依然很簡單,累乘每一個(gè)字節(jié),得到最后的累乘值


??????????

注冊機(jī)

?注冊碼生成算法:

?????#include

int main()
{
??? char name[100] = { 0 };
??? char serial[100] = { 0 };
??? int checknum = 1;

??? // Name計(jì)算出校驗(yàn)值
??? std::cin >> name;
??? for (int i = 0; i < strlen(name);i++) {
??????? checknum *= name[i];
??? }
??? checknum &= 0x0FFFFFFF;

??? //?校驗(yàn)值反推Serial
??? printf("%d",checknum);

}

效果:

???????

???



新160個(gè)CrackMe分析-第5組:41-50(上)的評論 (共 條)

分享到微博請遵守國家法律
眉山市| 克什克腾旗| 阿巴嘎旗| 光山县| 沽源县| 高阳县| 章丘市| 辽阳市| 秦皇岛市| 垫江县| 平果县| 天台县| 芮城县| 潍坊市| 黔西| 靖宇县| 砚山县| 榆社县| 西和县| 勐海县| 霍山县| 吴忠市| 津南区| 沭阳县| 镇安县| 自贡市| 龙胜| 长垣县| 新泰市| 陆河县| 西林县| 克什克腾旗| 醴陵市| 贵南县| 丹寨县| 丰都县| 博野县| 阿坝| 锦屏县| 滦平县| 郑州市|