Archive for October, 2015

[IDA Plugin] IDA Stingray

Posted: October 9, 2015 in IDA Stingray
Tags: ,

stingray
Tác giả: darx0r

Site: https://github.com/darx0r/Stingray

Sơ lược:

Stingray là một IDAPython plugin, tính năng chính của plugin này tìm kiếm các chuỗi (strings) có trong hàm, hỗ trợ thực hiện tìm kiếm đệ quy thông qua khả năng cho phép cấu hình độ sâu của việc tìm kiếm. Đối với mỗi string được tìm thấy sẽ được hiển thị thêm thông tin về địa chỉ xrefs (địa chỉ sử dụng string), địa chỉ của chuỗi, kiểu chuỗi (string type).

Yêu cầu cài đặt:

Phải sử dụng IDA (Hex Rays Interactive Disassembler) có phiên bản >= 6 cùng với IDAPython.

Sử dụng:

Chép file Stingray.py vào thư mục chứa Plugin của IDA. Nếu thành công, khi khởi động IDA và phân tích target, Stingray sẽ xuất hiện tại : Edit/Plguins/Stingray. Mặc định Stingray đã được tác giả cấu hình với độ sâu tìm kiếm là 0 (không sử dụng tìm kiếm đệ quy) và phím tắt của plugin là Shift+S. Tuy nhiên, có thể cấu hình lại Stingray bất kỳ lúc nào thông qua Options\Stingray Config . Nếu không muốn tìm kiếm đệ quy, cấu hình lại chế độ search. lựa chọn độ sâu là 0.

StingrayHình minh họa


Tải crackme tại: http://crackmes.de/users/san01suke/somecrypto02/

Bài viết tham khảo write-up của Johannesbade , tại : http://johannesbader.ch/2014/07/crackmes-de-san01sukes-somecrypto02/

1.Patch file để lấy full code

Giao diện của crackme khi thực thi tương tự như SomeCrypto~01:
01

Load crackme vào OllyDBG. Tại EP có được code như sau:
02

Quan sát, nhận thấy có hai điểm khá thú vị:

  • Vùng code trước 0x4014D3 không thể disassembly được và trông giống như đã bị làm rối (obfuscated).
  • Vùng code sau EP rõ ràng sẽ làm thay đổi code của crackme. Bắt đầu tại vị trí 0x401000, lệnh XOR được sử dụng để XOR chính xác 0x4D3 bytes (lưu tại ecx) với giá trị 0x20h (lưu tại al).

Vùng code tại 0x401000 trước khi thay đổi:

03

Nhấn F8 để trace thử một vài lần sẽ thấy được các bytes đã được thay đổi:

04

Để có đầy đủ các byte sau khi XOR, đặt BP tại lệnh 004014EF   . FFD0       call   eax, sau đó nhấn F9, break tại BP. Lúc này đã có toàn bộ code sau khi XOR, nhưng OllyDbg không tự động phân tích lại và vẫn hiển thị các bytes. Nhấn Ctrl + A để phân tích lại code sẽ có được đầy đủ thông tin:

05

Lưu lại bản patched của crackme sau khi các bytes từ 0x401000 tới 0x4014D2 đã được XOR với 20h (Dump file và sửa lại EP của file mới thành 0x14B0). Sau đó, sử dụng IDA Pro để load file mới:

06

2. Phân tích sub_4011E0 – lần 1

Mở Subviews Strings (Shift + F12), quan sát thấy có chuỗi “Success”:

07

Tìm tới đoạn code liên quan tới chuỗi này:

08

Theo đoạn code trong hình, ta sẽ nhận được thông báo “Success” nếu sub_4011E0 trả về một giá trị khác 0 tại thanh ghi eax. Tiến hành phân tích sub_4011E0:

09

Theo thông tin cung cấp khi debug với OllyDBG, ta thấy rằng thanh ghi edi sẽ chứa chuỗi szSerial mà ta nhập vào:

10

Quan sát đoạn mã tại loc_401296:

11

Với thông tin có được, chuyển sang mã giả ta như sau:

serial = edi
IF strlen(serial) == 0 THEN
    RETURN 0 // loc_401296
END

Nếu có nhập serial (serial không phải là chuỗi rỗng) thì đoạn mã tiếp theo được thực hiện:

12

Đoạn mã trên thực hiện tính toán chiều dài của serial và trả về 0 nếu không phải là 7. Ta có mã giả như sau:

serial_length = strlen(serial)
IF serial_length != 7 THEN
    RETURN 0 // loc_401296
END

Nếu chiều dài nhập vào lớn hơn 7, đoạn mã tiếp theo sẽ thực hiện lời gọi tới một subroutine khác:

13

eax là một biến cục bộ. Vùng bộ nhớ ebp+arg_0 = ebp+8 trỏ đến nội dung của Name textbox, kiểm tra bằng OllyDbg ta có được:

14

var_1C là biến mà chưa biết kiểu, mã giả có được như sau:

sub_401000(&var_1C, szName)

3. Phân tích sub_401000

Chuyển tới sub_401000, toàn bộ code tại đây như sau:

.text:00401000 ; =============== S U B R O U T I N E =======================================
.text:00401000
.text:00401000
.text:00401000 ; int __usercall sub_401000@<eax>(int mapping@<eax>, int szName@<edx>)
.text:00401000 sub_401000      proc near               ; CODE XREF: sub_4011E0+26p
.text:00401000                 mov     dword ptr [eax], 0 ; mapping[0] = 0x0
.text:00401006                 mov     dword ptr [eax+4], 1 ; mapping[4] = 0x1
.text:0040100D                 mov     dword ptr [eax+8], 2 ; mapping[8] = 0x2
.text:00401014                 mov     dword ptr [eax+0Ch], 3 ; mapping[12] = 0x3
.text:0040101B                 mov     dword ptr [eax+10h], 4 ; mapping[16] = 0x4
.text:00401022                 mov     dword ptr [eax+14h], 5 ; mapping[20] = 0x5
.text:00401029                 mov     dword ptr [eax+18h], 6 ; mapping[24] = 0x6
.text:00401030                 mov     cl, [edx]
.text:00401032                 test    cl, cl          ; if szName[i] is null
.text:00401034                 jz      short locret_40108C ; then exit sub
.text:00401036                 push    esi             ; save esi
.text:00401037                 jmp     short top_Loop
.text:00401037 ; ---------------------------------------------------------------------------
.text:00401039                 align 10h
.text:00401040
.text:00401040 top_Loop:                               ; CODE XREF: sub_401000+37j
.text:00401040                                         ; sub_401000+89j
.text:00401040                 movsx   ecx, cl         ; Temp = szName[i]
.text:00401043                 and     ecx, 80000001h  ; Temp &= 0x80000001; set SF = 1 if result is 80000000h
.text:00401049                 jns     short swap_mapping ; if Temp != 0 then swap(mapping[0], mapping[4])
.text:0040104B                 dec     ecx
.text:0040104C                 or      ecx, 0FFFFFFFEh
.text:0040104F                 inc     ecx
.text:00401050
.text:00401050 swap_mapping:                           ; CODE XREF: sub_401000+49j
.text:00401050                 jz      short rotate_left ; if Temp = 0 then rotate_left_mapping
.text:00401052                 mov     esi, [eax+4]    ; \
.text:00401055                 mov     ecx, [eax]      ; |<- swap(mapping[0], mapping[4])
.text:00401057                 mov     [eax], esi      ; |
.text:00401059                 mov     [eax+4], ecx    ; /
.text:0040105C
.text:0040105C rotate_left:                            ; CODE XREF: sub_401000:swap_mappingj
.text:0040105C                 mov     ecx, [eax]      ; ecx = mapping[0]
.text:0040105E                 mov     esi, [eax+4]
.text:00401061                 mov     [eax], esi      ; mapping[0] = mapping[4]
.text:00401063                 mov     esi, [eax+8]
.text:00401066                 mov     [eax+4], esi    ; mapping[4] = mapping[8]
.text:00401069                 mov     esi, [eax+0Ch]
.text:0040106C                 mov     [eax+8], esi    ; mapping[8] = mapping[12]
.text:0040106F                 mov     esi, [eax+10h]
.text:00401072                 mov     [eax+0Ch], esi  ; mapping[12] = mapping[16]
.text:00401075                 mov     esi, [eax+14h]
.text:00401078                 mov     [eax+10h], esi  ; mapping[16] = mapping[20]
.text:0040107B                 mov     esi, [eax+18h]
.text:0040107E                 mov     [eax+14h], esi  ; mapping[20] = mapping[24]
.text:00401081                 inc     edx
.text:00401082                 mov     [eax+18h], ecx  ; mapping[24] = ecx
.text:00401085                 mov     cl, [edx]       ; cl = next char of szName
.text:00401087                 test    cl, cl          ; if not null
.text:00401089                 jnz     short top_Loop  ; continue Loop
.text:0040108B                 pop     esi             ; restore esi
.text:0040108C
.text:0040108C locret_40108C:                          ; CODE XREF: sub_401000+34j
.text:0040108C                 retn
.text:0040108C sub_401000      endp
.text:0040108C

Phân tích subroutine từ đầu tới cuối có được thông tin như sau:

  • Khởi tạo một mảng, tạm đặt tên là mapping[] và gán các giá trị cho mảng: {0,1,2,3,4,5,6}
  • Kiểm tra từng kí tự trong chuỗi szName nhập vào theo biểu thức: Temp &= 0x80000001 (với Temp = szName[i])
    • Nếu Temp != 0, thực hiện đổi vị trí hai giá trị đầu tiên của mảng. Ví dụ, sau khi đổi sẽ là {0,1,2,3,4,5,6} -> {0,1,2,3,4,5,6}
    • Nếu Temp = 0, thực hiện việc gán lại các giá trị trong mảng theo kiểu dịch trái quay vòng. Ví dụ, sau khi thực hiện sẽ có {0,1,2,3,4,5,6} -> {0,1,2,3,4,5,6}
  • Lặp lại cho đến khi hết chuỗi szName, kết quả trả về là mảng mapping[] sau khi thực hiện các phép hoán đối và gán lại.

Mã giả của sub_401000 có được như sau:

FUNCTION sub_401000(mapping<var_1C>, szName)
    mapping = {0,1,2,3,4,5,6} // in eax = &var_1C
    FOR character IN szName DO
        IF character % 2 != 0 DO
            swap(mapping[0], mapping[1])
        ENDIF
        circular_left_shift(mapping)
    ENDFOR
    RETURN mapping
END

4. Phân tích sub_4011E0 – lần 2

Phân tích xong sub_401000, quay trở lại sub_4011E0 để phân tích tiếp các lệnh bên dưới:

15

Đoạn code này đơn giản thực hiện việc copy chuỗi mặc định của crackme tại địa chỉ byte_403010 (hardcoded_str) tới byte_403140 (copy_hardcoded_str). Sau đó kiểm tra xem chuỗi sau khi copy có null hay không? (Điều kiện này hơi thừa vì đã copy vào rồi thì null thế nào được 🙂 ). Mã giả của đoạn code trên như sau:

STRCPY(byte_403140, byte_403010) // copy string byte_403010 to byte_403140
IF byte_403140 == NULL THEN
    GOTO loc_40123A \\ should never happen
ENDIF

Chuỗi hardcoded ban đầu của crackme tại địa chỉ byte_403010 như hình bên dưới:

16

Tiếp theo là một vòng lặp nhỏ khác:

17

Vòng lặp này thực hiện duyệt toàn bộ chuỗi sau khi copy tại byte_403140 (copy_hardcoded_str) cho tới khi gặp null và tăng dần thanh ghi esi. Kết thúc vòng lặp thì giá trị có được của thanh ghi esi chính là độ dài của chuỗi tại byte_403140, ta có mã giả như sau:

esi = strlen(byte_403140)

Đoạn code tiếp theo sẽ là lời gọi tới một subroutine khác với hai tham số truyền vào là var_1Cstrlen(byte_403140):

18

Trong đó, tham số var_1C chính là mảng mapping[] đã phân tích ở trên, chứa các giá trị từ 0 đến 6 đã được trộn lại bởi sub_401000.

5. Phân tích sub_401110

.text:00401110 ; =============== S U B R O U T I N E =======================================
.text:00401110 ; Attributes: bp-based frame
.text:00401110 ; _UNKNOWN *__userpurge sub_401110@<eax>(_UNKNOWN *result@<eax>, int len_copy_hardcoded)
.text:00401110 sub_401110      proc near               ; CODE XREF: sub_4011E0+5Ep
.text:00401110                                         ; sub_4011E0+71p
.text:00401110
.text:00401110 var_1C          = dword ptr -1Ch
.text:00401110 var_18          = word ptr -18h
.text:00401110 var_16          = byte ptr -16h
.text:00401110 var_14          = dword ptr -14h
.text:00401110 var_10          = dword ptr -10h
.text:00401110 var_C           = dword ptr -0Ch
.text:00401110 var_8           = dword ptr -8
.text:00401110 var_4           = dword ptr -4
.text:00401110 len_copy_hardcoded= dword ptr  8
.text:00401110
.text:00401110                 push    ebp
.text:00401111                 mov     ebp, esp
.text:00401113                 mov     ecx, 7          ; ecx = 7
.text:00401118                 sub     esp, 1Ch
.text:0040111B                 cmp     [ebp+len_copy_hardcoded], ecx ; If strlen(copy_hardcoded) < ecx
.text:0040111E                 jle     exit_sub        ; then exit_sub()
.text:00401124                 mov     edx, [eax+8]
.text:00401127                 lea     edx, [ebp+edx+var_1C]
.text:0040112B                 mov     [ebp+var_4], edx ; v0 = mapping[8]
.text:0040112E                 mov     edx, [eax+0Ch]
.text:00401131                 lea     edx, [ebp+edx+var_1C]
.text:00401135                 mov     [ebp+var_8], edx ; v1 = mapping[12]
.text:00401138                 mov     edx, [eax+10h]
.text:0040113B                 lea     edx, [ebp+edx+var_1C]
.text:0040113F                 push    ebx
.text:00401140                 push    esi
.text:00401141                 mov     esi, [eax]
.text:00401143                 mov     [ebp+var_C], edx ; v2 = mapping[16]
.text:00401146                 mov     edx, [eax+14h]
.text:00401149                 push    edi
.text:0040114A                 mov     edi, [eax+4]
.text:0040114D                 mov     eax, [eax+18h]
.text:00401150                 lea     edx, [ebp+edx+var_1C]
.text:00401154                 mov     [ebp+var_10], edx ; v3 = mapping[20]
.text:00401157                 lea     edx, [ebp+eax+var_1C]
.text:0040115B                 mov     eax, offset copy_hardcoded ; j = 2
.text:00401160                 lea     esi, [ebp+esi+var_1C] ; v5 = mapping[0]
.text:00401164                 lea     edi, [ebp+edi+var_1C] ; v6 = mapping[4]
.text:00401168                 mov     [ebp+var_14], edx ; v4 = mapping[24]
.text:0040116B                 sub     ecx, eax        ; ecx -= eax
.text:0040116D                 lea     ecx, [ecx+0]    ; ecx = &ecx
.text:00401170
.text:00401170 top_Loop:                               ; CODE XREF: sub_401110+B6j
.text:00401170                 movzx   edx, byte ptr [eax-2]
.text:00401174                 mov     ebx, [ebp+var_4]
.text:00401177                 mov     [esi], dl       ; temp_arr[v5] = copy_hardcoded[j-2]
.text:00401179                 movzx   edx, byte ptr [eax-1]
.text:0040117D                 mov     [edi], dl       ; temp_arr[v6] =copy_hardcoded[j-1]
.text:0040117F                 movzx   edx, byte ptr [eax]
.text:00401182                 mov     [ebx], dl       ; temp_arr[v0] = copy_hardcoded[j]
.text:00401184                 movzx   edx, byte ptr [eax+1]
.text:00401188                 mov     ebx, [ebp+var_8]
.text:0040118B                 mov     [ebx], dl       ; temp_arr[v1] = copy_hardcoded[j+1]
.text:0040118D                 movzx   edx, byte ptr [eax+2]
.text:00401191                 mov     ebx, [ebp+var_C]
.text:00401194                 mov     [ebx], dl       ; temp_arr[v2] = copy_hardcoded[j+2]
.text:00401196                 movzx   edx, byte ptr [eax+3]
.text:0040119A                 mov     ebx, [ebp+var_10]
.text:0040119D                 mov     [ebx], dl       ; temp_arr[v3] = copy_hardcoded[j+3]
.text:0040119F                 movzx   edx, byte ptr [eax+4]
.text:004011A3                 mov     ebx, [ebp+var_14]
.text:004011A6                 mov     [ebx], dl       ; temp_arr[v4] = copy_hardcoded[j+4]
.text:004011A8                 mov     edx, [ebp+var_1C]
.text:004011AB                 mov     [eax-2], edx
.text:004011AE                 mov     dx, [ebp+var_18]
.text:004011B2                 mov     [eax+2], dx
.text:004011B6                 movzx   edx, [ebp+var_16]
.text:004011BA                 mov     [eax+4], dl
.text:004011BD                 add     eax, 7          ; j += 7
.text:004011C0                 lea     edx, [ecx+eax]  ; edx = ecx + 7
.text:004011C3                 cmp     edx, [ebp+len_copy_hardcoded] ; If edx < strlen(copy_hardcoded)
.text:004011C6                 jl      short top_Loop  ; then continue Loop
.text:004011C8                 pop     edi
.text:004011C9                 pop     esi
.text:004011CA                 pop     ebx
.text:004011CB
.text:004011CB exit_sub:                               ; CODE XREF: sub_401110+Ej
.text:004011CB                 mov     esp, ebp
.text:004011CD                 pop     ebp
.text:004011CE                 retn    4
.text:004011CE sub_401110      endp
.text:004011CE ; ---------------------------------------------------------------------------

Toàn bộ đoạn code trên thực hiện việc hoán đổi kí tự trong chuỗi byte_403140 (copy_hardcoded_str) dựa trên mảng mapping[] đã được tạo ra bởi sub_401000 đã phân tích trước đó. Mỗi lần thực hiện sẽ xử lý 7 kí tự của chuỗi byte_403140. Mã giả của đoạn code này được viết lại như sau:

FUNCTION sub_401110(mapping)
{
	int i=0, j = 2, ecx = 7, edx=0, k=0
	//create index for temp_arr[]
	v0 = mapping[8]
	v1 = mapping[12]
	v2 = mapping[16]
	v3 = mapping[20]
	v5 = mapping[0]
	v6 = mapping[4]
	v4 = mapping[24]
	do
	{
		temp_arr[v5] = copy_hardcoded[j-2]
		temp_arr[v6] = copy_hardcoded[j-1]
		temp_arr[v0] = copy_hardcoded[j]
		temp_arr[v1] = copy_hardcoded[j+1]
		temp_arr[v2] = copy_hardcoded[j+2]
		temp_arr[v3] = copy_hardcoded[j+3]
		temp_arr[v4] = copy_hardcoded[j+4]
		for (i=0; i&lt;=6; i++)
		{
			copy_hardcoded[k+i] = temp_arr[i];
		}
		j+=7
		edx = edx + ecx
		k = k+i
	}while (edx &lt;= strlen(copy_hardcoded))
	return copy_hardcoded	//after permute
}

Tổng kết lại, sub_401110 thực hiện phép hoán đối vị trí của kí tự tại byte_403140. Nó xây dựng index cho mảng temp_array[] dựa trên mảng mapping[] đã được tạo bởi sub_401000 và thực hiện hoán đổi từng khối 7 kí tự.

6. Phân tích sub_4011E0 – lần 3

Sau khi thực hiện xong sub_401110 ta sẽ quay trở về sub_4011E0, ta có đoạn code sau:

.text:00401243                 mov     ecx, edi        ; ecx = edi = szSerial
.text:00401245                 lea     eax, [ebp+var_1C] ; eax = &mapping[]
.text:00401248                 call    sub_401090

Ta thấy sẽ sub_401090 xử lý trên hai tham số truyền vào : [ebp+var_1C] như đã biết chứa thông tin về mảng mapping[], còn thanh ghi ecx edi lưu thông tin về szSerial mà ta nhập vào. Mã giả của đoạn code trên như sau:

sub_401090(mapping, serial)

7. Phân tích sub_401090

Toàn bộ code của sub như dưới đây:

.text:00401090 ; =============== S U B R O U T I N E =======================================
.text:00401090 sub_401090      proc near               ; CODE XREF: sub_4011E0+68p
.text:00401090                 movsx   edx, byte ptr [ecx] ; edx = szSerial[i]
.text:00401093                 add     edx, 0FFFFFFD0h ; edx = edx - 30h
.text:00401096                 push    esi             ; save esi
.text:00401097                 xor     esi, esi        ; esi = 0
.text:00401099                 mov     [eax], edx      ; mapping[0] = edx
.text:0040109B                 cmp     edx, 7          ; if edx >= 7
.text:0040109E                 jb      short loc_4010A2
.text:004010A0                 mov     [eax], esi      ; then mapping[0] = esi
.text:004010A2
.text:004010A2 loc_4010A2:                             ; CODE XREF: sub_401090+Ej
.text:004010A2                 movsx   edx, byte ptr [ecx+1] ; else edx = szSerial[i+1]
.text:004010A6                 add     edx, 0FFFFFFD0h ; edx = edx - 30h
.text:004010A9                 mov     [eax+4], edx    ; mapping[4] = edx
.text:004010AC                 cmp     edx, 7          ; if edx >= 7
.text:004010AF                 jb      short loc_4010B4
.text:004010B1                 mov     [eax+4], esi    ; then mapping[4] = esi
.text:004010B4
.text:004010B4 loc_4010B4:                             ; CODE XREF: sub_401090+1Fj
.text:004010B4                 movsx   edx, byte ptr [ecx+2] ; else edx = szSerial[i+2]
.text:004010B8                 add     edx, 0FFFFFFD0h ; edx = edx - 30h
.text:004010BB                 mov     [eax+8], edx    ; mapping[8] = edx
.text:004010BE                 cmp     edx, 7          ; if edx >= 7
.text:004010C1                 jb      short loc_4010C6
.text:004010C3                 mov     [eax+8], esi    ; then mapping[8] = esi
.text:004010C6
.text:004010C6 loc_4010C6:                             ; CODE XREF: sub_401090+31j
.text:004010C6                 movsx   edx, byte ptr [ecx+3] ; else edx = szSerial[i+3]
.text:004010CA                 add     edx, 0FFFFFFD0h ; edx = edx - 30h
.text:004010CD                 mov     [eax+0Ch], edx  ; mapping[12] = edx
.text:004010D0                 cmp     edx, 7          ; if edx >= 7
.text:004010D3                 jb      short loc_4010D8
.text:004010D5                 mov     [eax+0Ch], esi  ; then mapping[12] = esi
.text:004010D8
.text:004010D8 loc_4010D8:                             ; CODE XREF: sub_401090+43j
.text:004010D8                 movsx   edx, byte ptr [ecx+4] ; else edx = szSerial[i+4]
.text:004010DC                 add     edx, 0FFFFFFD0h ; edx = edx - 30h
.text:004010DF                 mov     [eax+10h], edx  ; mapping[16] = edx
.text:004010E2                 cmp     edx, 7          ; if edx >= 7
.text:004010E5                 jb      short loc_4010EA
.text:004010E7                 mov     [eax+10h], esi  ; then mapping[16] = esi
.text:004010EA
.text:004010EA loc_4010EA:                             ; CODE XREF: sub_401090+55j
.text:004010EA                 movsx   edx, byte ptr [ecx+5] ; else edx = szSerial[i+5]
.text:004010EE                 add     edx, 0FFFFFFD0h ; edx = edx - 30h
.text:004010F1                 mov     [eax+14h], edx  ; mapping[20] = edx
.text:004010F4                 cmp     edx, 7          ; if edx >= 7
.text:004010F7                 jb      short loc_4010FC
.text:004010F9                 mov     [eax+14h], esi  ; then mapping[20] = esi
.text:004010FC
.text:004010FC loc_4010FC:                             ; CODE XREF: sub_401090+67j
.text:004010FC                 movsx   ecx, byte ptr [ecx+6] ; esle ecx = szSerial[i+6]
.text:00401100                 add     ecx, 0FFFFFFD0h ; ecx = ecx - 30h
.text:00401103                 mov     [eax+18h], ecx  ; mapping[24] = ecx
.text:00401106                 cmp     ecx, 7          ; if ecx >= 7
.text:00401109                 jb      short loc_40110E
.text:0040110B                 mov     [eax+18h], esi  ; then mapping[24] = esi
.text:0040110E
.text:0040110E loc_40110E:                             ; CODE XREF: sub_401090+79j
.text:0040110E                 pop     esi             ; restore esi
.text:0040110F                 retn
.text:0040110F sub_401090      endp
.text:00401110 ; =============== S U B R O U T I N E =======================================

Nhìn thì thấy code khá dài, nhưng thuật toán của nó khá đơn giản. Mục đích cuối cùng là xây dựng lại mảng mapping[] dựa trên Serial đã nhập vào. Chuỗi Serial nhập vào bao gồm 7 chữ cái, được chuyển đổi thành 7 số nguyên và được lưu vào mảng mapping[] (nếu số đó nhỏ hơn 7) Mã giả của sub_401090 như sau:

FUNCTION sub_401090(mapping, serial)
    FOR i = 0 TO 6 DO
        temp = serial[i] - '0'
        IF nr >= 7 THEN
            mapping[i] = 0
        ELSE
            mapping[i] = temp
        ENDIF
    ENDFOR
END

8. Phân tích sub_4011E0 – lần 4

Sau khi sub_401090 nạp xong serial vào mảng mapping[], trở về sub_4011E0 và thấy lại tiếp tục có lời gọi tới sub_401110 để thực hiện hoán đổi kí tự một lần nữa:

.text:0040124D                 push    esi             ; len_copy_hardcoded
.text:0040124E                 lea     eax, [ebp+var_1C] ; eax = &mapping
.text:00401251                 call    sub_401110

sub_4011E0 kết thúc bằng một đoạn code thực hiện tính toán hash cho chuỗi byte_403140 (copy_hardcoded_str). Nếu như hash sau khi tính toán có giá trị tại eax là 0B45D7873h thì sẽ nhận được thông báo “Success”.

.text:00401256                 or      eax, 0FFFFFFFFh ; eax = 0xFFFFFFFF
.text:00401259                 mov     ecx, esi        ; ecx = strlen(copy_hardcoded_str)
.text:0040125B                 mov     edx, offset copy_hardcoded_str
.text:00401260                 test    esi, esi
.text:00401262                 jz      short loc_40127D
.text:00401264
.text:00401264 create_Hash:                            ; CODE XREF: sub_4011E0+9Bj
.text:00401264                 movzx   esi, byte ptr [edx] ; esi = copy_hardcoded_str[i]
.text:00401267                 xor     esi, eax        ; esi = esi ^ eax
.text:00401269                 and     esi, 0FFh       ; esi = esi & 0xFF
.text:0040126F                 shr     eax, 8          ; eax = eax / 100h (100h = 256)
.text:00401272                 xor     eax, ds:dword_402058[esi*4] ; eax = eax ^ (esi*4+402058)
.text:00401279                 inc     edx             ; i++ (next char of copy_hardcoded_str)
.text:0040127A                 dec     ecx             ; ecx--
.text:0040127B                 jnz     short create_Hash ; Loop until ecx = 0
.text:0040127D
.text:0040127D loc_40127D:                             ; CODE XREF: sub_4011E0+82j
.text:0040127D                 not     eax             ; eax = ~eax
.text:0040127F                 pop     esi
.text:00401280                 cmp     eax, 0B45D7873h ; If eax = 0xB45D7873h
.text:00401285                 jnz     short return_al_0
.text:00401287                 mov     eax, [ebp+arg_4]
.text:0040128A                 mov     dword ptr [eax], offset copy_hardcoded_str
.text:00401290                 mov     al, 1           ; then set al = 1
.text:00401292                 mov     esp, ebp
.text:00401294                 pop     ebp
.text:00401295                 retn
.text:00401296 ; ---------------------------------------------------------------------------
.text:00401296 return_al_0:                            ; CODE XREF: sub_4011E0+Aj
.text:00401296                                         ; sub_4011E0+1Aj ...
.text:00401296                 xor     al, al          ; else set al = 0
.text:00401298                 mov     esp, ebp
.text:0040129A                 pop     ebp
.text:0040129B                 retn
.text:0040129B sub_4011E0      endp
.text:0040129B ; ---------------------------------------------------------------------------

Mã giả của đoạn code trên như sau:

cal_hash = cal_hash_routine(message)
IF cal_hash = '0B45D7873h' THEN
    RETURN 1 // success
ELSE
    RETURN 0 // failure
ENDIF

9. Pseudo-Code

Tổng kết lại toàn bộ quá trình phân tích trên ta có được mã giả tương đối tường minh như sau:

FUNCTION name_mapping(szName)
    mapping = {0,1,2,3,4,5,6} // in eax = &var_1C
    FOR character IN szName DO
        IF character % 2 != 0 DO
            swap(mapping[0], mapping[1])
        ENDIF
        circular_left_shift(mapping)
    ENDFOR
    RETURN mapping
END

FUNCTION serial_mapping(szSerial)
    FOR i = 0 TO 6 DO
        temp = serial[i] - '0'
        IF nr >= 7 THEN
            mapping[i] = 0
        ELSE
            mapping[i] = temp
        ENDIF
    ENDFOR
    RETURN mapping
END

FUNCTION permutation(mapping)
{
	int i=0, j = 2, ecx = 7, edx=0, k=0
	//create index for temp_arr[]
	v0 = mapping[2]
	v1 = mapping[3]
	v2 = mapping[4]
	v3 = mapping[5]
	v5 = mapping[0]
	v6 = mapping[1]
	v4 = mapping[6]
	do
	{
		temp_arr[v5] = copy_hardcoded[j-2]
		temp_arr[v6] = copy_hardcoded[j-1]
		temp_arr[v0] = copy_hardcoded[j]
		temp_arr[v1] = copy_hardcoded[j+1]
		temp_arr[v2] = copy_hardcoded[j+2]
		temp_arr[v3] = copy_hardcoded[j+3]
		temp_arr[v4] = copy_hardcoded[j+4]
		for (i=0; i<=6; i++)
		{
			copy_hardcoded[k+i] = temp_arr[i];
		}
		j+=7
		edx = edx + ecx
		k = k+i
	}while (edx <= strlen(copy_hardcoded))
	return copy_hardcoded	//after permute
}

FUNCTION CHECK_SERIAL(szSerial, szName)
    IF strlen(serial) != 7 THEN
        RETURN 0
    END
    mapping = name_mapping(szName)

    STRCPY(copy_hardcoded_str, hard_coded_str) // clone hard coded message
    IF copy_hardcoded_str == NULL THEN
        GOTO loc_40123A \\ should never happen
    ENDIF
    copy_hardcoded_str = permutation(mapping)
    mapping = serial_mapping(szSerial)
    copy_hardcoded_str = permutation(mapping)
    cal_hash = cal_hash_routine(copy_hardcoded_str)
    IF cal_hash = '0B45D7873h' THEN
        RETURN 1 // success
    ELSE
        RETURN 0 // failure
    ENDIF
END

CHECK_SERIAL(szSerial, szName)

10. Tìm Key

Qua quá trình phân tích ở trên, ta đã nắm được cơ chế hoạt động của thuật toán. Việc tiếp theo là cần phải tìm ra quá trình hoán đối vị trí (permutation) sẽ tạo ra thông điệp plaintext (bản rõ) như thế nào. Ta có thông tin về thông điệp được mã hóa lưu tại byte_403010 là:

prncyI haorptge ,apy iamttru onbxo bPo -(r ix so)ot ehami  fbdofu-hftss igulnpodt e  trueemnrrtao beps sorat cisbSs -osn xsioer,us ptnntiieauf ifgdh inwsoatl rienssoinpg.

Để giải mã, chỉ cần tìm ra phép hoán vị cho một khối 7 kí tự. 7 chữ cái đầu tiên của bản mã là (bao gồm cả dấu cách):

prncyI

Nhìn vào 7 chữ cái này, ta có thể đoán chữ hoa “I” phải là kí tự đầu tiên, phần còn lại không quá khó để đoán, ta có được:

In cryp

Từ thông tin này ta suy luận ra được mảng mapping[] chuẩn phục vụ cho việc giải mã như sau:19

Như trên hình, chữ cái đầu tiên sẽ nằm ở vị trí thứ 6, chữ cái thứ hai nằm ở vị trí thứ 4, v..v… Từ đó, ta có bản đồ giải mã đúng là: 6 4 1 3 5 0 2

11. Viết Keygen sinh Serial theo Name nhập vào

Theo như quá trình phân tích ở trên, ta thấy crackme sử dụng hai lần phép hoán vị đối với bản mã (cipher text) để có được bản rõ (plain text). Lần đầu tiên thực hiện trên chuỗi Name, lần thứ hai thực hiện trên chuỗi Serial. Để viết được thuật toán sinh Serial cho chuỗi Name nhập vào, chúng ta cần phải tính toán kết quả mapping bằng việc thực hiện đoạn code name_mapping. Sau đó, ta có thể xác định mapping thứ hai sau khi kết hợp name mapping với kết quả mapping chính xác là 6 4 1 3 5 0 2.

Keygen code bằng C:

#include <stdio.h>
#include <string.h>

int main()
{
    char szName[20];
    char szSerial[8]="";
    int correct_key[] = {6, 4, 1, 3, 5, 0, 2};
    int mapping[] = {0, 1, 2, 3, 4, 5, 6};
    int i, temp=0;

    printf("Please enter your name: ");
    scanf("%s", szName);
    for (i=0; i&amp;lt;strlen(szName); i++)
    {
        if (szName[i] % 2 != 0)
        {
            temp = mapping[0];
            mapping[0] = mapping[1];
            mapping[1] = temp;
        }
        temp = mapping[0];
        mapping[0] = mapping[1];
        mapping[1] = mapping[2];
        mapping[2] = mapping[3];
        mapping[3] = mapping[4];
        mapping[4] = mapping[5];
        mapping[5] = mapping[6];
        mapping[6] = temp;
    }
    for (i=0; i&amp;lt;7; i++)
    {
        szSerial[mapping[i]] = (correct_key[i] + 0x30);
    }
    printf("Serial : %s", szSerial);

    return 0;
}

Keygen code bằng Python:

import argparse
from collections import deque

parser = argparse.ArgumentParser(description="SomeCrypto~02 keygen")
parser.add_argument('name')
args = parser.parse_args()
name = args.name #get Name args

correct_key = [6, 4, 1, 3, 5, 0, 2]
cypher = deque(list(range(7)))

#create mapping array based on Name.
for c in name:
    if ord(c) % 2:
        cypher[0], cypher[1] = cypher[1], cypher[0]
    cypher.rotate(-1)

serial = 7*[None] #create serial array and set None

for c, k in zip(cypher, correct_key):
    serial[c] = k

print('Right serial: ' + ''.join(str(s) for s in serial))

Kiểm tra key:

Kết quả kiểm tra keygen có được như sau:

Toàn bộ bài viết đến đây là kết thúc. Happy Reversing!!

Best Regards,

m4n0w4r


This plug-in is released by my friend, Vic aka vic4key (http://viclab.biz/)
Latest version: 2.06

Change Log:

—– [ MENU ] —–
Show the toolbar in the title of OllyDbg window
Maximize OllyDbg window when staring
Maximize OllyDbg child windows when staring
Show address info in status bar
Use APIs menu in OllyDbg menu bar
Apply confirm exit for OllyDbg
Make the transparency for OllyDbg window
Debuggee Data
Delete UDD data of the current session
Delete all UDD data
Open UDD data list
Delete recent debuggee files
Data Converter
DLL Process Viewer
File Location Converter
PE Viewer
Thread Viewer
Lookup Error Code
Find events of C++ Builder / Delphi VCL GUI application
Advanced Map File Importer
Map File Importer
Open Label window
Open Comment window
Bypass Anti Debugging
Hide the PEB
Data Copier
VA Address
RVA Address
Offset Address
ANSI String
UNICODE String
Code Ripped
Breakpoint Manager
INT3 Delete all
INT3 Import
INT3 Export
HWBP Delete all
HWBP Import
HWBP Export
MBP Delete all
MBP Import
MBP Export
Follow Me
Follow in Disassembler at <address>
Follow in Dump at <address>
Copy <address> to clipboard
Check for update
Infomation

—–[ Version 2.06 ]—–

[+] DATE UPDATE -> 24/09/2015

[+] NEW FEATURES
1. Show address info in status bar
2. Use APIs menu in OllyDbg menu bar (easier to set INT3 Breakpoint)
3. Apply confirm exit for OllyDbg (just ask for quit while you’re debugging)
4. Debuggee Data
Delete UDD data of the current session
Open UDD data list
Delete recent debuggee files
5. Thread Viewer (full thread infomation with Debug Register)
6. Find events of C++ Builder / Delphi VCL GUI application (working well, no need run to find)
7. Advanced Map File Importer
Open Label window
Open Comment window
8. Data Converter
Python/Ruby
9. Data Copier
ANSI String
UNICODE String
10. Breakpoint Manager (with my breakpoint file format)
INT3 Delete all
INT3 Import
INT3 Export
HWBP Delete all
HWBP Import
HWBP Export
MBP Delete all
MBP Import
MBP Export
11. Follow Me
Follow in Disassembler at <address>
Follow in Dump at <address>
Copy <address> to clipboard
12. Check for update (Update my plug-in by this function from now. No update via forums, blog, …)

[+] BUG FIX:
1. Show the toolbar in the title of OllyDbg window (fix for Windows 10)
2. File Location Converter (sync with ImageBase on loaded image, not file on disk)
3. Advanced Map File Importer
Map File Importer (sync with ImageBase & multi-modules)
4. Data Copier
VA Address
RVA Address
Offset Address

—–[ Version 2.05 ]—–

[+] DATE UPDATE -> 13/10/2013

[+] NEW FEATURES
<None>

[+] BUG FIX:
1. Crash OllyDbg when not used the toolbar
2. Delete UDD data
3. DATA Converter

—–[ Version 2.04 ]—–

[+] DATE UPDATE -> 24/03/2013

[+] NEW FEATURES
1. Lookup Error Code
2. Bypass anti debugging
Hide the PEB
3. Address copier
Copy VA
Copy RVA
Copy Offset

[+] BUG FIX:
1. Show the toolbar
2. DATA Converter
3. File Location Converter
4. Finding the Point Events in Delphi executables
5. Map file importer
Import labels
Import comments

Some screen shots:

Screenshot (0)Screenshot (1)Download here:

https://drive.google.com/file/d/0BzonFc1Y-m59Y1hmS0lfQTRKN0k/view

Regards,

m4n0w4r


Xin nói luôn là script này là để vui và để tìm hiểu thêm về Python, chứ còn thằng IDM nó dư sức làm việc này lolz ^-^.

Nhiều khi gặp một site tương tự như (https://crypto.stanford.edu/cs155/syllabus.html),  có chứa rất nhiều link tới các file pdfs và ppts/pptx, muốn download toàn bộ các file về nhưng mà ngại phải nhấn vào từng link một … rồi chọn Save As… Một vài file còn được chứ tầm trên chục file là ngại rồi 🙂 . Dưới đây là một python script, tôi vô tình thấy trên mạng (http://pastebin.com/nRVXgmqF), tôi và cậu em cùng phòng (Hiep-TH) đã chỉnh sửa code chút xíu để có thể download thêm (ppt & pptx) cũng như fix một vài bug nhỏ trong quá trình thực hiện script để download file.

#Greatz thanks to Man Wuzi for this script (http://pastebin.com/nRVXgmqF)
#A little bit modify by me & my bro (Hiep-TH)

import urlparse
import urllib2
import os
import sys

try:
    from bs4 import BeautifulSoup
except ImportError:
    print "[*] Please download and install Beautiful Soup first"
    sys.exit(0)

url = raw_input("[+] Enter the url: ")
download_path = raw_input("[+] Enter the download path in full: ")

try:
    #set headers to make it look legit for the url
    headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
       'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
       'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
       'Accept-Encoding': 'none',
       'Accept-Language': 'en-US,en;q=0.8',
       'Connection': 'keep-alive'}

    i = 0    #count downloaded file

    request = urllib2.Request(url, None, headers) #requests URL with fake header
    html = urllib2.urlopen(request) #open URL and return file-like for page object
    
    html_src = html.read() #get all source code of specific page
    html_src_edited = html_src.replace("--!>", "-->")        #repalce --!> to --> (ex: cseweb.ucsd.edu/classes/su15/cse140-a/syllabus.html)
    
    #soup = BeautifulSoup(html.read()) #to parse the website
    soup = BeautifulSoup(html_src_edited, 'html.parser')

    for tag in soup.findAll('a', href=True): #find <a> tags with href in it so you know it is for urls
        #so that if it doesn't contain the full url it can the url itself to it for the download
        tag['href'] = urlparse.urljoin(url, tag['href'])

        #this is pretty easy we are getting the extension (splitext) from the last name of the full url(basename)
        #the splitext splits it into the filename and the extension so the [1] is for the second part( the extension)
        ext = os.path.splitext(os.path.basename(tag['href']))[1]
        if ext == '.pdf' or ext == '.ppt' or ext == '.pptx':
            request = urllib2.Request(tag['href'], None, headers)
            try:
                current = urllib2.urlopen(request)
                f = open(download_path + "\\" +os.path.basename(tag['href']), "wb")
                f.write(current.read())
                f.close()
                i+=1
                print "\n[*] Downloaded: %s" %(os.path.basename(tag['href']))
            except:
                print "\n[*] Missing/Non-Existing link: %s" %(tag['href'])
                continue

    print "\n[*] Total downloaded %d files" %(i+1)
    raw_input("[+] Press any key to exit ...")

except KeyboardInterrupt:
    print "[*] Exiting..."
    sys.exit(1)

except urllib2.URLError as e:
    print "[*] Could not get information from server!!"
    sys.exit(2)

except:
    print "I don't know the problem but sorry!!"
    sys.exit(3)