我的diype歷程之一(smartsearch儲存功能之新增) (16千字)
剛吐血完成diype那個網聰,現在又來吐血寫教程,寫完我就要去醫院輸血了,大家記得免費捐點:)
文章題目:我的diype歷程之一(smartsearch儲存功能之新增)
作者:greenlemon(菩提!)[FCG]
破解工具:太多。。。。
破解目的:正在思考:)
diype=Dancing In Your Program Empire(最新解釋:)
首先感謝pll621大哥為我們提供了6篇高質量的diype教程,還有許多前輩們為此作的研究,都給了我動力和幫助。diype的確是一項很累人的工作,其間upfeed對我的指點功不可沒,我謹以此篇文章獻給所有幫助我的朋友們,當然也是對我勞動的總結,同時我也想以此作為給初學者的教程(但是初學者的概念很難界定,我也是初學者,很多人還稱自己是菜鳥,雖然對我來說他們已經是肉鳥:),所以如果你覺得還看不懂那麼一定是我文筆太差,而不是你水平不夠)。
言歸正傳,讓我們磨刀霍霍向網聰(希望原作者不要看到這篇文章:)
寫在前面:這裡我希望你已經具備了win32asm的基本知識,如果沒有可以檢視一下win32asm基礎教程。
其次你應該對winapi有初步的瞭解,如果沒有至少你應該有這個winapi幫助手冊,這兩樣看雪裡都有!
網聰的這款軟體序號產生器及破解方法我以在以前的文章中說過,但是在註冊成功後,最為關鍵的儲存功能居然仍然沒有,用dede反編譯後發現那裡只有一個用來顯示什麼"付費使用者才能用此項功能"的nag而沒有其他的程式碼,說明作者沒有在這個網路下載版裡提供這項功能,這有兩種可能,1。作者根本沒在這個版裡寫程式碼,2。他寫了但是隻有付費後才會提供一個補丁修改為指向這段程式碼。(事實上在我修改程式時發現的確有一些程式碼沒有使用,可能他有寫在裡面,但是由於我已經在自己新增了,而且去尋找正確的程式碼入口也很困難,所以就沒在細究)下面我們來分析要手動新增程式碼所要做的工作:
1。回憶一下傳統的儲存功能都是怎樣的過程,首先在點選儲存後,要開啟一個對話方塊要你輸入你要儲存的檔名,這個可以用api裡getsavefilename其次在你輸入名稱後點確定,會建立一個新檔案,或者覆蓋原來的檔案,這個用createfile來實現,當然createfile只是建立檔案,你還要將資訊儲存進去,所以還要用writefile來實現,最後別忘了關閉檔案closehandle。這就是儲存檔案所要做的,當然還有記憶體的操作,這個我後面再說。
2。接下來看看我們要把什麼儲存進去,當然是我們搜尋到的電郵地址,可以通過dede很清楚地找到存放地址的控制元件是叫做stringgrid的東西,現在我們還不清楚他是怎麼儲存的,也就是說究竟以何種資料結構儲存搜尋到的結果。這是我們需要分析的。
3。我們要找到程式的空餘部分,好新增程式碼,如果你覺得不夠,還要自己加一個section,或者在原來的section上增加一些。這個工作很好做,用topo就可以:)(peter老大教的)
好我們明確了目標,就可以開始了,從最簡單的開始,3最簡單:),我們找找程式的空餘部分,我用的是4a9426開始的空間,我開始以為不夠,所以又新增了一個section,從4d4000開始。(好像差不多剛好,沒有仔細的統計,反正增加幾百位元組也無所謂,重要的是能把東西做出來:)
完成了一步很開心吧?沒有。。。太簡單了?你還要怎樣:)好進入第2,分析一下stringgrid的運作方式,開始我很迷惑,因為跟蹤後發現他存放的空間不連續,我以為那不是正確的地址,還有一塊連續的地方存放,百思不解後在upfeed的提醒下,我自己用delphi寫了一段stringgrid的程式碼,發現我的想法是對的,只不過因為這個程式用的是多執行緒,所以每個執行緒都擁有一些結果,執行緒內是連續的,執行緒之間就是不連續的分配起始地址了,看來有時候還要自己寫程式碼來分析,要不會被迷惑的,來看看它是怎麼存放的:
004A12EA ||MOV EAX,DWORD PTR DS:[4ACC14]
004A12EF ||PUSH
EAX
; /Arg1 => 00BB3DB4 ASCII "sales@eyou.com"
004A12F0 ||MOV ECX,DWORD
PTR DS:[4AD0C0] ; |
004A12F6 ||XOR EDX,EDX
; |
004A12F8
||MOV EAX,DWORD PTR DS:[EBX+2F8] ; |
004A12FE ||CALL smartsea.00468568
; \smartsea.00468568 //這個就是設定stringgrid元素值的,跟進去看看
004A1303 ||INC DWORD PTR DS:[4AD0C0]
00468568 /$>PUSH
EBP
00468569 |.>MOV EBP,ESP
0046856B |.>PUSH ECX
0046856C
|.>PUSH EBX
0046856D |.>PUSH ESI
0046856E |.>PUSH EDI
0046856F |.>MOV DWORD PTR SS:[EBP-4],ECX //當你每次執行到這裡就會發現在[ebp+8]這個堆疊裡存放著你想要的搜尋到的郵件地址
00468572 |.>MOV ESI,EDX
雖然它不是一個接一個的規律變化,原因剛才我講了,但是我們可以把這些指標儲存起來呀:)
00468574
|.>MOV EBX,EAX
00468576 |.>MOV EDX,DWORD PTR SS:[EBP-4]
00468579
|.>MOV EAX,EBX
0046857B |.>CALL smartsea.004684A4
00468580
|.>MOV ECX,DWORD PTR SS:[EBP+8]
00468583 |.>MOV EDX,ESI
00468585
|.>MOV EDI,DWORD PTR DS:[EAX]
00468587 |.>CALL DWORD PTR DS:[EDI+20]
0046858A |.>MOV CL,1
0046858C |.>MOV EDX,ESI
0046858E
|.>MOV EAX,EBX
00468590 |.>CALL smartsea.00468440
00468595
|.>XOR ECX,ECX
00468597 |.>MOV EDX,DWORD PTR SS:[EBP-4]
0046859A
|.>MOV EAX,EBX
0046859C |.>CALL smartsea.00468440
004685A1
|.>MOV ECX,DWORD PTR SS:[EBP-4]
004685A4 |.>MOV EDX,ESI
004685A6
|.>MOV EAX,EBX
004685A8 |.>CALL smartsea.004683F4
004685AD
|.>POP EDI
004685AE |.>POP ESI
004685AF |.>POP EBX
004685B0 |.>POP ECX
004685B1 |.>POP EBP
004685B2 \.>RETN
4
現在我們來做這個儲存,我原先的設想把這些指標儲存到我開闢的新的section裡,這樣不用做記憶體操作,省去一些程式碼,後來想了一想,如果以我們搜尋到1000個地址為例,因為指標是dword,也就是說需要4000位元組來存放這些指標,暈倒,所以看來不能偷懶,還是老老實實開一塊記憶體來吧。
對記憶體的操作我這樣實現,首先globalalloc一塊記憶體,然後globallock,這樣我們就可以儲存進去,最後要記得globalunlock,globalfree。(不懂就去查前面兩個手冊)那麼什麼時候申請這塊記憶體呢?我是在formcreate的時候做的,你可以在其他時候,只要保證你後面要儲存指標的時候有記憶體用。
0049B134 .>PUSH EBP
//formcreate開始
0049B135
.>MOV EBP,ESP
0049B137 .>ADD ESP,-40
0049B13A .>PUSH EBX
0049B13B .>PUSH ESI
0049B13C .>PUSH EDI
0049B13D
.>XOR ECX,ECX
0049B13F .>MOV DWORD PTR SS:[EBP-3C],ECX
0049B142
.>MOV DWORD PTR SS:[EBP-40],ECX
0049B145 .>MOV DWORD PTR SS:[EBP-34],ECX
0049B148 .>MOV DWORD PTR SS:[EBP-38],ECX
0049B14B .>MOV
DWORD PTR SS:[EBP-30],ECX
0049B14E .>MOV DWORD PTR SS:[EBP-28],ECX
0049B151 .>MOV DWORD PTR SS:[EBP-2C],ECX
0049B154 .>MOV
DWORD PTR SS:[EBP-24],ECX
0049B157 .>MOV EBX,EAX
0049B159
.>MOV ESI,smartsea.004ACC08
0049B15E .>XOR EAX,EAX
0049B160
.>PUSH EBP
0049B161 .>PUSH smartsea.0049B7FB
0049B166 .>PUSH
DWORD PTR FS:[EAX]
0049B169 .>MOV DWORD PTR FS:[EAX],ESP
0049B16C
.>JMP smartsea.004D4000 //把mov
eax, [ebx+$0308]改成這個,跳到我們的程式碼
0049B171 >NOP
0049B172
.>XOR EDX,EDX
0049B174 .>CALL smartsea.0042D0F8
為便於理解,給出globalalloc,globallock的原型
HGLOBAL GlobalAlloc(
UINT uFlags, //
要申請的記憶體的標誌,也就是說這塊記憶體是什麼型別的
DWORD dwBytes //
要申請的記憶體大小
);
LPVOID GlobalLock(
HGLOBAL
hMem // 你要鎖定的那塊記憶體的指標
);
004D4000 6>PUSH 0FFFFF
//我們要這麼大的記憶體:)
004D4005 6>PUSH 42
//GHND,標誌具體可以查手冊
004D4007 E>CALL <JMP.&kernel32.GlobalAlloc>
//這個函式的地址可以用WIN32ASM檢視,我這裡是4069A0
004D400C A>MOV DWORD PTR DS:[4D4540],EAX
//把返回的地址指標儲存起來,我存到了4D4540
004D4011 5>PUSH EAX
//我們要鎖定他
004D4012 E>CALL <JMP.&kernel32.GlobalLock>
//這個函式地址4069B8
004D4017 A>MOV DWORD PTR DS:[4D4544],EAX
//把指標儲存到4D4544
004D401C 8>MOV EAX,DWORD PTR DS:[EBX+308]
//這是原來的程式,要恢復他(這裡他沒有用到暫存器,所以我們不用儲存他們得值)
004D4022 -E>JMP
smartsea.0049B172 //返回了
有了記憶體,我們就可以儲存了,這麼大一塊記憶體,我決定不僅僅儲存指標了,把那些字串全儲存起來,以後更便於寫入檔案不是嗎?
就是剛才這段:
00468568 $>PUSH EBP
00468569 .>MOV EBP,ESP
0046856B
.>PUSH ECX
0046856C .>PUSH EBX
0046856D .>PUSH ESI
0046856E .>PUSH EDI
0046856F .>JMP smartsea.004D4027
//這裡改了,跳到我們的程式
00468574 .>MOV EBX,EAX
00468576
.>MOV EDX,DWORD PTR SS:[EBP-4]
00468579 .>MOV EAX,EBX
這裡我們也用到兩個函式:一個是字串拷貝,一個是獲取字串長度,本來我想用lstrcat這個字串連線函式,但是程式裡沒有,要自己構造麻煩,所以自己來實現吧。原型如下
LPTSTR lstrcpy(
LPTSTR lpString1, //
目的空間指標
LPCTSTR lpString2 // 源字串指標
);
int lstrlen(
LPCTSTR lpString
// 要計算長度的字串地址指標
);
004D4027 PUSH EAX
//發現他們有使用這些暫存器,而我們的操作會破壞他們的值,所以存起來先
004D4028 PUSH
ECX
004D4029 PUSH EDX
004D402A MOV EBX,DWORD PTR SS:[EBP+8]
//記得我剛才說的這裡存放著我們要的東西
004D402D CMP EBX,0
//這個比較是因為,你會發現第一次的值是0,可能是stringgrid的初始化,對我們沒用,而且會出錯
004D4030 JE SHORT smartsea.004D406B //如果是0就返回去不操作
004D4032 PUSH EBX
//源字串指標,給lstrcpy準備的
004D4033 MOV ESI,DWORD PTR
DS:[4D4544] //還記得嗎,這就是我們申請的記憶體空間指標存放處
004D4039 MOV EBX,DWORD PTR
DS:[4D4548] //這個地址用來存放一個變數,這個變數就是字串的長度,這樣,我們可以實現字串連線
004D403F
LEA EBX,DWORD PTR DS:[EBX+ESI] //上面兩個的和就指向我們要存放的目的地址的指標
004D4042 PUSH
EBX
//壓進去給lstecpy
004D4043 CALL <JMP.&kernel32.lstrcpyA> //這個函式地址是4012F8
004D4048 PUSH DWORD PTR DS:[4D4544] //來測一下現在我們現在的字串有多長
004D404E CALL <JMP.&kernel32.lstrlenA> //地址是401308
004D4053 MOV DWORD PTR DS:[4D4548],EAX //把返回的長度值存進我們的變數空間
004D4058
MOV WORD PTR DS:[EAX+ESI],0A0D //加入回車換行,目的是在儲存的檔案裡可以一行顯示一個EMAIL
004D405E
MOV BYTE PTR DS:[EAX+ESI+2],0 //再加一個字串結束標誌NULL
004D4063 ADD
EAX,2
//由於我們加了兩個位元組,所以長度變化了
004D4066 MOV DWORD PTR DS:[4D4548],EAX //再次儲存
004D406B POP EDX
//可以返回了
004D406C POP ECX
004D406D
POP EAX
004D406E MOV DWORD PTR SS:[EBP-4],ECX //這個都是源程式的東西,別忘了恢復
004D4071 MOV ESI,EDX
004D4073 JMP smartsea.00468574
//回去咯
簡單的解釋一下,如果你覺得一頭霧水的話,我們的目的是儲存成這樣的形式:
green@sina.com/r/nlemon@sina.com/r/nupfeed@sina.com/r/n......
這樣我們在檔案裡才可以存成這樣:
green@sina.com
lemon@sina.com
upfeed@sina.com
再回去理解一下,不難了吧。
第二步算是搞定了,來搞最後的一步,經過了上面,發現原來也不難是吧?:)事實上這麼簡單的程式碼,我調了n次,改了n次,所以說。。。。不知道說什麼好,可能我比較菜吧:)
來看看儲存按鈕裡有什麼:
0049E688 push $00
0049E68A
mov cx, word ptr [$49E6A0]
0049E691 mov dl,
$02
* Possible String Reference to: '付費註冊使用者才能儲存電郵'
|
0049E693
mov eax, $0049E6AC
|
0049E698 call
004510A4
0049E69D ret
沒有什麼有價值的東西,全部改掉!
這是改後的:利用到messagebox原型如下
int MessageBox(
HWND hWnd, //
父窗體的控制程式碼
LPCTSTR lpText, // 要顯示的字串指標
LPCTSTR lpCaption, // 標題欄上字串的指標
UINT uType // 訊息框的型別
);
注意到需要父窗體控制程式碼,所以要到程式裡去找找,把斷點下在createwindowex很快就可以找到,但是我原先在這裡範了一個錯誤,我直接用的是記憶體裡的地址,忘了這對每臺機器都是變動的,現在修正了一下,我把它儲存起來了!
所以首先找到這裡:
0044A0DE MOV EDX,EAX
;
0044A0E0 MOV ECX,84CA0000
; |
0044A0E5 MOV EAX,DWORD
PTR DS:[4AAAB8] ; |
0044A0EA
CALL smartsea.0040730C
; 這個進去就是creatwindowex,返回值是控制程式碼存在eax裡
0044A0EF JMP smartsea.004D4078
//跳到我們的儲存程式碼
0044A0F4 NOP
0044A0F5 CALL smartsea.00403B40
004D4078
MOV DWORD PTR DS:[4D4550],EAX //存到這
004D407D MOV DWORD PTR DS:[EBX+24],EAX
//源程式的東西恢復
004D4080 LEA EAX,DWORD PTR DS:[EBX+7C]
004D4083
JMP smartsea.0044A0F5
0049E688 call 004A9426
//到我們做一個函式那
0049E68D
cmp eax, +$00
//比較返回值,判斷我們是儲存還是取消
0049E690 jz 0049E69C
//取消的話是0,就跳
0049E692
mov eax, $004D43E9 //這裡存放著success!
0049E697 jmp 0049E6A1
0049E69C mov
eax, $004D43E0 //這裡存著faliure!,
0049E6A1
push $00
//MB_OK型
0049E6A3 push $004D4370
//這裡存著字串。。我的標誌:)
0049E6A8
push eax
//看看是成功還是失敗咯
0049E6A9 push dword ptr [$4D4550]
//這個是控制程式碼,怎麼來的?當然是跟蹤來的,把斷點下在CREATEWINDOW很快就可以找到
* Reference
to: user32.MessageBoxA()
|
0049E6AF call 00401288
0049E6B4 ret
來看看我們的函式(有點長,但很簡單:)用到了這幾個函式:
BOOL
GetSaveFileName(
LPOPENFILENAME lpofn //
指向OPENFILENAME型別的結構指標
);
這個就是結構體,引數很多,查手冊吧
typedef
struct tagOFN { // ofn
DWORD
lStructSize;
HWND hwndOwner;
HINSTANCE hInstance;
LPCTSTR
lpstrFilter;
LPTSTR
lpstrCustomFilter;
DWORD nMaxCustFilter;
DWORD nFilterIndex;
LPTSTR lpstrFile;
DWORD
nMaxFile;
LPTSTR
lpstrFileTitle;
DWORD nMaxFileTitle;
LPCTSTR lpstrInitialDir;
LPCTSTR lpstrTitle;
DWORD
Flags;
WORD
nFileOffset;
WORD nFileExtension;
LPCTSTR lpstrDefExt;
DWORD lCustData;
LPOFNHOOKPROC lpfnHook;
LPCTSTR lpTemplateName;
} OPENFILENAME;
HANDLE CreateFile(
LPCTSTR lpFileName,
// 檔名指標
DWORD dwDesiredAccess, //
授權的模式(讀,寫,還是都有)
DWORD dwShareMode, // 共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //
安全屬性
DWORD dwCreationDistribution, // 建立模式
DWORD dwFlagsAndAttributes, // 檔案屬性
HANDLE hTemplateFile // 臨時檔案
);
BOOL WriteFile(
HANDLE hFile, //
要寫入的檔案控制程式碼,一般由CREATEFILE返回的值就是
LPCVOID lpBuffer, //
要寫入檔案的緩衝區指標
DWORD nNumberOfBytesToWrite, //
寫入多少位元組
LPDWORD lpNumberOfBytesWritten, //
已寫入的位元組
LPOVERLAPPED lpOverlapped // 重疊模式指標
);
004A9426 push ebp
//儲存暫存器的值,不知道用了哪些,都存吧保險:)
004A9427 push ebx
004A9428 push
esi
004A9429 push edi
004A942A mov
dword ptr [$4D4390], $0000004C //下面是結構體的一些引數,這是整個結構體的大小,存放到從4D4390開始的一段空間裡
004A9434 push dword ptr [$4D4550]
//這個是窗體控制程式碼,上面提到過
004A943A pop dword
ptr [$4D4394] //存到第二個DWORD
004A9440
push dword ptr [$4AC4D8]
//這是模組控制程式碼,跟蹤程式開始的GETMODULEHANDLE就可以找到
004A9446 pop dword
ptr [$4D4398] //存到第3個
004A944C
mov dword ptr [$4D439C], $004D4350 //這個是檔案過濾的引數我們這裡是ALL FILES和TEXT
FILES存在4D4350處可以用16進位制編輯器預先寫入
004A9456 mov dword ptr [$4D43AC],
$004D4420 //檔名要存放的地方
004A9460 mov dword ptr [$4D43A8],
$00000002 //預設狀態的過濾引數是TEXTFILE
004A946A mov dword
ptr [$4D43B0], $00000104 //檔名最大長度不超過260位元組
004A9474 mov
dword ptr [$4D43C4], $00282806 //檔案的標誌,查手冊
004A947E mov
dword ptr [$4D43C0], $004D4370 //標題欄上的字串,還是我:)
004A9488
push $004D4390
//結構體指標給getsavefilename
* Reference to: comdlg32.GetSaveFileNameA()
|
004A948D call 0044C534
004A9492 cmp
eax, +$01
//比較一下如果是取消就返回
004A9495 jnz 004A94FA
004A9497 push $00
//createfile的七個引數
004A9499 push $20
004A949B push $02
004A949D push $00
004A949F push
$03
004A94A1 push $C0000000
004A94A6 push
$004D4420
* Reference to: kernel32.CreateFileA()
|
004A94AB call 00401210
004A94B0 mov
dword ptr [$4D454C], eax //檔案控制程式碼存起來
004A94B5
push dword ptr [$4D4544]
//看看現在我們那個記憶體空間裡有多長的字串,好準備寫入
* Reference to: kernel32.lstrlenA()
|
004A94BB call 00401308
004A94C0 push
$00
//寫入檔案用的5個引數
004A94C2 push
$004D4550
004A94C7 push eax
004A94C8 push
dword ptr [$4D4544]
004A94CE push dword ptr [$4D454C]
* Reference to: kernel32.WriteFile()
|
004A94D4 call
00401260
004A94D9 push dword ptr [$4D4544]
|
004A94DF call 004069D0我的diype歷程之一(smartsearch儲存功能之新增)
我的diype歷程之一(smartsearch儲存功能之新增)
我的diype歷程之一(smartsearch儲存功能之新增)
004A94E4 push dword ptr [$4D4540]
* Reference
to: kernel32.GlobalFree()
|
004A94EA call 004069B0
004A94EF push dword ptr [$4D454C]
* Reference
to: kernel32.CloseHandle()
|
004A94F5 call 00401208
004A94FA pop edi
004A94FB pop
esi
004A94FC pop ebx
004A94FD pop
ebp
004A94FE ret
後記:似乎看起來沒做多少工作,不過我覺得很累了:)也許我的精力比較差把,希望能拋磚引玉。不足之處還望大家多指點!
轉載請註明出處,並保持完整性,謝謝!
相關文章
- 實用的儲存過程之一 (轉)2008-03-01儲存過程
- JDK 16的新增功能:ZGC2021-03-23JDKGC
- 雲端儲存的一些功能用法2021-08-01
- 我的破解心得(5) (16千字)2001-03-13
- ORACLE資料檔案儲存之我見2008-09-17Oracle
- (PVE)新增硬碟做儲存2024-04-12硬碟
- 【rlwrap】Linux上實現Windows的SQL*Plus儲存SQL歷史記錄功能2009-09-07LinuxWindowsSQL
- 分享我儲存的Metalink文章2007-02-10
- 淺談儲存器的進化歷程2018-06-27
- zt_我對儲存storage的一些認識2013-01-24
- Linux上實現Windows的SQL*Plus儲存SQL歷史記錄功能---rlwrap(轉)2012-03-20LinuxWindowsSQL
- Android中的資料儲存之檔案儲存2020-03-11Android
- Flutter持久化儲存之檔案儲存2019-03-06Flutter持久化
- javascript cookie的儲存和刪除功能2017-04-10JavaScriptCookie
- SAP WM 有無儲存WM Level歷史庫存的Table?2018-09-13
- 圖的儲存與遍歷C++實現2021-07-06C++
- 資料儲存(1):從資料儲存看人類文明-資料儲存器發展歷程2020-07-27
- .Net執行SQL/儲存過程之易用輕量工具2022-12-20SQL儲存過程
- 二叉樹的儲存(輸入一串字元)與遍歷2020-11-22二叉樹字元
- 經歷了ADTX儲存發生的一次電源故障2009-03-01
- Flutter持久化儲存之key-value儲存2019-03-04Flutter持久化
- Flutter持久化儲存之資料庫儲存2019-03-08Flutter持久化資料庫
- 儲存學習之開源儲存軟體2014-07-17
- 集合框架(List儲存字串並遍歷)2018-04-06框架字串
- 給資料庫新增儲存空間的案例2007-03-21資料庫
- Hive之儲存格式2016-09-23Hive
- 共享儲存之ISCSI2013-11-06
- Javascrip—前端本地儲存講解(16)2018-09-28Java前端
- SQL Server 2016 Alwayson新增功能2017-09-28SQLServer
- Linux培訓教程之安全的動態磁碟儲存策略(轉)2007-08-11Linux
- 我的測試儲存過程程式碼2013-01-08儲存過程
- k8s之資料儲存-配置儲存2021-08-19K8S
- 儲存系統設計指南之儲存分類2009-01-07
- IOS資料儲存之檔案沙盒儲存2016-05-11iOS
- 杉巖:我有一套祖傳的Ceph儲存,大聖能幫我收了嗎?2021-03-02
- MySQL之四 儲存引擎2021-03-02MySql儲存引擎
- MySQL之儲存過程2018-04-17MySql儲存過程
- Hive之 資料儲存2017-09-18Hive