【原創】菜鳥也演算法分析 -- 區域網檢視工具(LanSee V1.52

看雪資料發表於2015-11-15

菜鳥也演算法分析 -- 區域網檢視工具(LanSee V1.52)註冊演算法分析
  
  軟體說明:

  區域網檢視工具(LanSee)是一款主要用於對區域網(Internet上也適用)上的各種資訊進行檢視的工具。採用多執行緒技術,搜尋速度很快。它將區域網上比較實用的功能完美地融合在一起,比如搜尋計算機(包括計算機名,IP地址,MAC地址,所在工作組,使用者),搜尋共享資源,搜尋共享檔案,多執行緒複製檔案(支援斷點傳輸),發短訊息,高速埠掃描,捕獲指定計算機上的資料包,檢視本地計算機上活動的埠,遠端重啟/關閉計算機等,功能十分強大。該軟體是一款綠色軟體,解壓後直接開啟執行,無需安裝。

  軟體資訊:

  未加殼,用Delphi編譯器編寫。

  平臺:Windows XP SP1
  工具:W32Dasm 8.93,OLLYDBG1.10

  分析說明:
  
  僅僅分析演算法,進行技術交流,不做商業用途。如果你條件允許並喜歡這個軟體的話,請支援正版。

  Cracker: prince
  E-mail : Cracker_prince@163.com

  V1.52版下載地址:http://www.yqdown.com/soft/7854.htm

  W32Dasm載入反彙編,根據提示資訊很容易找到爆破點。根據提示來到這裡(然後用OD下斷00492307,F9執行除錯,輸入使用者名稱prince,註冊碼:987654321012):
................................................
:00492307 55                      push ebp
:00492308 68FD234900              push 004923FD
:0049230D 64FF30                  push dword ptr fs:[eax]
:00492310 648920                  mov dword ptr fs:[eax], esp
:00492313 8D55FC                  lea edx, dword ptr [ebp-04]
:00492316 8B83FC020000            mov eax, dword ptr [ebx+000002FC]
:0049231C E83B14FBFF              call 0044375C                       <--- 獲得使用者輸入的註冊碼個數
:00492321 8B45FC                  mov eax, dword ptr [ebp-04]         <--- [ebp-04]中是使用者輸入的註冊碼
:00492324 E82FFFFFFF              call 00492258                       <--- 像這種下面比較完就跳的CALL最可疑,跟進
:00492329 84C0                    test al, al
:0049232B 0F84A7000000            je 004923D8                         <--- 這裡跳到錯誤提示(爆破點之一)
:00492331 8D55F8                  lea edx, dword ptr [ebp-08]
:00492334 8B830C030000            mov eax, dword ptr [ebx+0000030C]
:0049233A E81D14FBFF              call 0044375C                       <--- 得到使用者名稱的長度
:0049233F 8B45F8                  mov eax, dword ptr [ebp-08]
:00492342 E8CDFDFFFF              call 00492114                       <--- 關鍵CALL,跟進
:00492347 84C0                    test al, al 
:00492349 0F8489000000            je 004923D8                         <--- 這裡跳到錯誤提示(爆破點之一)
:0049234F B201                    mov dl, 01
:00492351 A1AC014700              mov eax, dword ptr [004701AC]
...................................................................
根據省力不蠻幹的原則,前幾遍跟蹤都是粗跟,不是十分可疑的CALL都F8帶過,但是要注意CALL過之後暫存器的變化,尤其是EAX暫存器的值,必要時把值註釋在旁邊。這個軟體檢測註冊的地方互動呼叫很多,如果上來就都F7跟進的話,呵呵,很快你就會暈了。繼續分析上面的程式碼,在0049231C這個CALL時,F8帶過,看EAX暫存器,變成了多少?0XC,嘿嘿,0XC不就是十進位制的12嗎?我們“恰好”也輸入了12個字元作為註冊碼,明白了吧?這個CALL就是用來計算使用者輸入的註冊碼個數的。執行完下面那一句,EAX中就是我們輸入的假碼了。再往下又是一個CALL,而且下面比較完會跳到出錯的地方,足夠可疑!跟進!來到這裡:
...................................................................
:00492258 55                      push ebp
:00492259 8BEC                    mov ebp, esp
:0049225B 83C4F8                  add esp, FFFFFFF8
:0049225E 53                      push ebx
:0049225F 33D2                    xor edx, edx
:00492261 8955F8                  mov dword ptr [ebp-08], edx
:00492264 8945FC                  mov dword ptr [ebp-04], eax
:00492267 8B45FC                  mov eax, dword ptr [ebp-04]
:0049226A E85527F7FF              call 004049C4                    <--- 這個CALL是幹什麼的?不管它,先F8帶過
:0049226F 33C0                    xor eax, eax
:00492271 55                      push ebp
:00492272 68E1224900              push 004922E1
:00492277 64FF30                  push dword ptr fs:[eax]
:0049227A 648920                  mov dword ptr fs:[eax], esp
:0049227D 33DB                    xor ebx, ebx
:0049227F 8D55F8                  lea edx, dword ptr [ebp-08]
:00492282 8B45FC                  mov eax, dword ptr [ebp-04]
:00492285 E84E68F7FF              call 00408AD8                    <--- 未知,先帶過
:0049228A 8B45F8                  mov eax, dword ptr [ebp-08]
:0049228D E84A25F7FF              call 004047DC                    <--- 未知,同樣帶過,但是注意EAX變成了0XC,也就是使用者輸入的註冊碼的個數
:00492292 83F80C                  cmp eax, 0000000C                <--- 個數同0XC(12)進行比較,
:00492295 7C2F                    jl 004922C6                      <--- 小於12個就跳走,哈哈,這下知道為什麼輸入12個字元作為註冊碼了吧?
:00492297 8B45F8                  mov eax, dword ptr [ebp-08]      <--- [ebp-8]為假碼
:0049229A 80780131                cmp byte ptr [eax+01], 31        <--- 將假碼的第2位同ASCII碼0X31(數字1)進行比較
:0049229E 7526                    jne 004922C6         <--- 不等就失敗啦!
:004922A0 8B45F8                  mov eax, dword ptr [ebp-08]
:004922A3 80780439                cmp byte ptr [eax+04], 39        <--- 將假碼的第5位同ASCII碼0X39(數字9)進行比較
:004922A7 751D                    jne 004922C6         
:004922A9 8B45F8                  mov eax, dword ptr [ebp-08]
:004922AC 80780639                cmp byte ptr [eax+06], 39        <--- 將假碼的第7位同ASCII碼0X39(數字9)進行比較
:004922B0 7514                    jne 004922C6
:004922B2 8B45F8                  mov eax, dword ptr [ebp-08]
:004922B5 80780737                cmp byte ptr [eax+07], 37        <--- 將假碼的第8位同ASCII碼0X37(數字7)進行比較
:004922B9 750B                    jne 004922C6
:004922BB 8B45F8                  mov eax, dword ptr [ebp-08]
:004922BE 80780935                cmp byte ptr [eax+09], 35        <--- 將假碼的第10位同ASCII碼0X35(數字5)進行比較
:004922C2 7502                    jne 004922C6
:004922C4 B301                    mov bl, 01
...................................................................
看到這裡你可能感到奇怪:怎麼不用根據使用者名稱計算註冊碼嗎?怎麼直接就比較使用者輸入的註冊碼了?呵呵,其實這個軟體的註冊碼比較部分到這就全部結束了。別急,00492342處還有一個CALL呢,下面也會跳到錯誤提示的地方啊!讓我們繼續跟。0049233A這個CALL同樣用F8帶過,EAX變成了6,有了上一次的經驗,你應該知道了吧?這個是得到使用者名稱的長度。接下來來到00492342第2個關鍵CALL,F7跟進,來到這裡:
...................................................................
首先不要被這麼長的程式碼嚇到,很多是我們不需要了解的,如果你看到程式碼很長就放棄的話,你就永遠也不會有提高。
|:00492342   
|
:00492114 55                      push ebp                       <--- 保護現場原來的EBP指標
:00492115 8BEC                    mov ebp, esp                   <--- 設定新的EBP指標,指向棧頂ESP  
:00492117 83C4D4                  add esp, FFFFFFD4              <--- 在堆疊中留出空間放區域性變數,這三句都是子程式的老套路了,如果不懂,記住也行。
:0049211A 53                      push ebx
:0049211B 33D2                    xor edx, edx                   <--- EDX清零
:0049211D 8955F4                  mov dword ptr [ebp-0C], edx    <--- [EBP-0C]清零
:00492120 8955D4                  mov dword ptr [ebp-2C], edx    <--- [EBP-2C]清零
:00492123 8955F0                  mov dword ptr [ebp-10], edx   <--- [EBP-10]清零
:00492126 8955F8                  mov dword ptr [ebp-08], edx   <--- [EBP-08]清零
:00492129 8945FC                  mov dword ptr [ebp-04], eax   <--- 使用者名稱寫入[EBP-04]
:0049212C 8B45FC                  mov eax, dword ptr [ebp-04]    <--- 這句很奇怪,EAX本來就是使用者名稱,幹嗎寫進寫出的?
:0049212F E89028F7FF              call 004049C4                  <--- 這個CALL很短,你也可以跟進去看看。它是計算出使用者名稱地址-8的記憶體資料然後放到EDX中
:00492134 33C0                    xor eax, eax
:00492136 55                      push ebp
:00492137 683A224900              push 0049223A
:0049213C 64FF30                  push dword ptr fs:[eax]
:0049213F 648920                  mov dword ptr fs:[eax], esp
:00492142 33DB                    xor ebx, ebx
:00492144 8D55F8                  lea edx, dword ptr [ebp-08]
:00492147 8B45FC                  mov eax, dword ptr [ebp-04]    <--- 使用者名稱放入EAX中,準備給下面的CALL用
:0049214A E88969F7FF              call 00408AD8                  <--- 可以帶過,它是用來檢查使用者名稱中是否含有非法字元(ASCII碼小於等於20h的它就認為是非法字元)
:0049214F 8B45F8                  mov eax, dword ptr [ebp-08]    <--- 使用者名稱放入EAX中,準備給下面的CALL用
:00492152 E88526F7FF              call 004047DC                  <--- 帶過,看暫存器,EAX變化了,變成了6(我的使用者名稱長度),對了,就是用來得到使用者名稱長度的
:00492157 83F804                  cmp eax, 00000004              <--- 這句很明顯吧,使用者名稱長度同4比較
:0049215A 0F8CB7000000            jl 00492217                    <--- 小於4就沒的玩了
:00492160 8D45EC                  lea eax, dword ptr [ebp-14]    <--- 儲存返回地址
:00492163 8B55F8                  mov edx, dword ptr [ebp-08]    <--- 使用者名稱送至EDX
:00492166 8A12                    mov dl, byte ptr [edx]         <--- 將使用者名稱的第1個字元存入DL
:00492168 885001                  mov byte ptr [eax+01], dl      <--- 將DL寫入記憶體[EAX+01]中
:0049216B C60001                  mov byte ptr [eax], 01         <--- 把1寫入記憶體[EAX]中
:0049216E 8D55EC                  lea edx, dword ptr [ebp-14]    
:00492171 8D45E8                  lea eax, dword ptr [ebp-18]
:00492174 E85B0DF7FF              call 00402ED4                  <--- 先帶過,這種下面還要經常呼叫的CALL通常都是“大戰之前的準備”,不要在無謂的地方浪費時間,大不了回頭再跟。 :)
:00492179 8D45E4                  lea eax, dword ptr [ebp-1C]
:0049217C 8B55F8                  mov edx, dword ptr [ebp-08]    <--- 使用者名稱送至EDX
:0049217F 8A5201                  mov dl, byte ptr [edx+01]      <--- 將使用者名稱的第2個字元送入DL
:00492182 885001                  mov byte ptr [eax+01], dl      <--- DL寫入記憶體[EAX+01]處
:00492185 C60001                  mov byte ptr [eax], 01         <--- 1寫入[EAX]所指的記憶體中
:00492188 8D55E4                  lea edx, dword ptr [ebp-1C]
:0049218B 8D45E8                  lea eax, dword ptr [ebp-18]
:0049218E B102                    mov cl, 02                     <--- 注意這裡,執行下面CALL之前CL賦值為2
:00492190 E80F0DF7FF              call 00402EA4                  <--- 先帶過,因為下面還要呼叫,走幾遍再猜
:00492195 8D55E8                  lea edx, dword ptr [ebp-18]    <--- 這裡執行完,EDX裡是什麼?哈,“02,"pr" (使用者名稱的前兩位)”
:00492198 8D45E0                  lea eax, dword ptr [ebp-20]
:0049219B E8340DF7FF              call 00402ED4                  <--- 這個CALL上面已經呼叫過了,不妨再帶過,因為下面還有嘛,但是注意,EAX有變化,EAX=3
:004921A0 8D45E4                  lea eax, dword ptr [ebp-1C]
:004921A3 8B55F8                  mov edx, dword ptr [ebp-08]    <--- 使用者名稱存至EDX
:004921A6 8A5202                  mov dl, byte ptr [edx+02]       <--- 熟悉吧?將使用者名稱的第3個字元送到DL中
:004921A9 885001                  mov byte ptr [eax+01], dl   <--- 寫入記憶體[EAX+01]中
:004921AC C60001                  mov byte ptr [eax], 01   <--- 記憶體[EAX]寫入1
:004921AF 8D55E4                  lea edx, dword ptr [ebp-1C]
:004921B2 8D45E0                  lea eax, dword ptr [ebp-20]
:004921B5 B103                    mov cl, 03                     <--- 好象見過?對了,上面呼叫CALL 00402EA4之前CL送入的值是2,這次是3,呵呵,明白了吧?下面這個CALL就是用來取使用者名稱的CL個字元的
:004921B7 E8E80CF7FF              call 00402EA4                  <--- 現在知道了,取使用者名稱的某些字元
:004921BC 8D55E0                  lea edx, dword ptr [ebp-20]    <--- 這裡執行完EDX內容為:03,"pri"
:004921BF 8D45D8                  lea eax, dword ptr [ebp-28]
:004921C2 E80D0DF7FF              call 00402ED4       <--- 又是它!帶過看EAX,EAX=4,結合上面看看,哦,原來它是用來取它需要的第EAX個字元的!
:004921C7 8D45E4                  lea eax, dword ptr [ebp-1C]
:004921CA 8B55F8                  mov edx, dword ptr [ebp-08]    <--- 使用者名稱送至EDX
:004921CD 8A5205                  mov dl, byte ptr [edx+05]      <--- 注意這裡,上面取的是使用者名稱的第3個字元,這裡沒有繼續按順序往下取,而是取使用者名稱的第6個字元!
:004921D0 885001                  mov byte ptr [eax+01], dl      <--- 第6個字元寫入記憶體[EAX+01]
:004921D3 C60001                  mov byte ptr [eax], 01   <--- 1寫入[EAX]
:004921D6 8D55E4                  lea edx, dword ptr [ebp-1C]
:004921D9 8D45D8                  lea eax, dword ptr [ebp-28]    <--- 執行完EAX是:03, "pri"
:004921DC B104                    mov cl, 04                     <--- 看,又來了吧!取它需要的第4個字元啦!
:004921DE E8C10CF7FF              call 00402EA4                  <--- 取它需要的第4個字元,注意是它需要的,不是使用者名稱的第4個字元
:004921E3 8D55D8                  lea edx, dword ptr [ebp-28]   <--- 果然吧,EDX:04, "prie",因為它取了使用者名稱的第6個字元,所以這裡是"e"
:004921E6 8D45F0                  lea eax, dword ptr [ebp-10]    
:004921E9 E89225F7FF              call 00404780                  <--- 這個CALL沒見過,省力原則先帶過,EDX被清零
:004921EE 8B45F0                  mov eax, dword ptr [ebp-10]    <--- 將它需要的四個字元"prie"送入EAX
:004921F1 8D55F4                  lea edx, dword ptr [ebp-0C]
:004921F4 E88F66F7FF              call 00408888                  <--- 這個是幹什麼的呢?看到下面還要呼叫,先帶過
:004921F9 8B45F4                  mov eax, dword ptr [ebp-0C]    <--- 執行完,EAX= ASCII "PRIE",哈哈,原來是小寫轉大寫用的
:004921FC 50                      push eax       <--- 準備工作做完了,壓棧準備“開戰”了,呵呵
:004921FD 8D55D4                  lea edx, dword ptr [ebp-2C]

* Possible StringData Ref from Code Obj ->"lane"
                                  |
:00492200 B850224900              mov eax, 00492250              <--- 將字串常量"lane"送至EAX
:00492205 E87E66F7FF              call 00408888       <--- 上面用過的,小寫轉大寫
:0049220A 8B55D4                  mov edx, dword ptr [ebp-2C]    <--- 轉換結果送至EDX
:0049220D 58                      pop eax       <--- EAX出棧,哼哼,危險訊號,EAX就是已經取完的使用者名稱啊!
:0049220E E80D27F7FF              call 00404920       <--- 上面這麼敏感,下面又有跳轉!還不夠關鍵嗎?跟進!
:00492213 7502                    jne 00492217
:00492215 B301                    mov bl, 01

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0049215A(C), :00492213(C)
|
:00492217 33C0                    xor eax, eax
:00492219 5A                      pop edx
:0049221A 59                      pop ecx
:0049221B 59                      pop ecx
:0049221C 648910                  mov dword ptr fs:[eax], edx
:0049221F 6841224900              push 00492241
...................................................................
只是粗跟就已經得到這麼多有用的資訊了,對於不是很複雜的演算法來說有時就足夠了!我們接著看,0049220E處的關鍵CALL跟進來到這裡:
...................................................................
大概看一下,恩,沒有呼叫了,更可疑!說明是比較判斷的關鍵部分了!
:00404920 53                      push ebx
:00404921 56                      push esi
:00404922 57                      push edi
:00404923 89C6                    mov esi, eax                   <--- EAX是什麼來著?"PRIE"
:00404925 89D7                    mov edi, edx       <--- EDX: "LANE"
:00404927 39D0                    cmp eax, edx       <--- 比較是否相等
:00404929 0F848F000000            je 004049BE       <--- 相等就跳了!不過跳了是好事還是壞事呢?試試看才知道嘛。雙擊Z flag改變跳轉標誌,F9執行,看到什麼了?嘿嘿,感謝註冊!好,先高興會兒,等下回頭總結。
:0040492F 85F6                    test esi, esi
:00404931 7468                    je 0040499B
:00404933 85FF                    test edi, edi
:00404935 746B                    je 004049A2
:00404937 8B46FC                  mov eax, dword ptr [esi-04]
:0040493A 8B57FC                  mov edx, dword ptr [edi-04]
:0040493D 29D0                    sub eax, edx
:0040493F 7702                    ja 00404943
:00404941 01C2                    add edx, eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040493F(C)
|
:00404943 52                      push edx
:00404944 C1EA02                  shr edx, 02
:00404947 7426                    je 0040496F
...................................................................

  剛拿到這個軟體的時候看到沒有加殼,爆破點又清晰明瞭,就想他肯定是明碼比較註冊碼,就搜記憶體,堆疊,結果不行。於是我以為是非明碼比較的註冊演算法,所以拿出OD...可是沒想到,“演算法”竟然是這樣的。

總結:

  判斷條件1:
  使用者名稱不得少於4個字元(程式裡這麼寫的),但我想應該是不能少於6個字元吧?其中前三個字元必須為:lan, 隨後兩個字元隨便填,第6個字元必須為e,然後就隨便填了。
  判斷條件2:
  註冊碼不得少於12個字元,其中第2,5,7,8,10個字元必須分別為:1,9,9,7,5,其他字元就隨便填了。

  只要以上兩個條件都滿足,註冊成功!簡單清晰明瞭,序號產生器就不用寫了吧?

注:最新版V1.59註冊演算法已經更改,如果你有興趣可以自己分析。

  V1.59版下載地址: http://www1.skycn.com/soft/14357.html  

  菜鳥寫菜文,歡迎高手指正。
                                    prince 2005.01.13

相關文章