Cracking part 51

Chia sẻ: Dqwdasdasd Qwdasdasdasd | Ngày: | Loại File: PDF | Số trang:6

0
26
lượt xem
3
download

Cracking part 51

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Trên đây là quá trình tạo Stack Frame và căn phòng được với không gian là 48 bytes dành cho việc lưu trữ các biến cục bộ. Windows yêu cầu rằng một vài thanh ghi khác ngoài ESP và EBP

Chủ đề:
Lưu

Nội dung Text: Cracking part 51

  1. Trên đây là quá trình tạo Stack Frame và căn phòng được với không gian là 48 bytes dành cho việc lưu trữ các biến cục bộ. Windows yêu cầu rằng một vài thanh ghi khác ngoài ESP và EBP cũng cần được bảo vệ trong suốt quá trình của một Callback function, đó là những thanh ghi EBX, ESI và EDI. Chúng được lưu trữ một cách an toàn trên Stack, và sẵn sàng để khôi phục lại đúng vị trí trước khi rời khỏi hàm.Điều này cho phép sự tự do khi sử dụng những thanh ghi này bên trong một hàm. Đã có quá trình lưu giữ thanh ghi thì cũng phải có quá trình phục hồi chúng, điều này được thực hiện nhờ vào các câu lệnh rất đơn giản. Và nhìn vào đó ta biết ngay nó làm gì : .00412348: 5F pop edi .00412349: 5E pop esi .0041234A: 5B pop ebx .0041234B: 8BE5 mov esp,ebp .0041234D: 5D pop ebp .0041234E: C3 retn Đầu tiên 3 thanh ghi được khôi phục từ stack của chúng ta. Sau đó Stack được phục hồi lại trạng thái của nó sau khi hàm đã được gọi và khi gặp câu lệnh Return. Chú ý rằng chúng ta không thể khôi phục Stack trước khi khôi phục 3 thanh ghi được, bởi vì các thanh ghi của chúng đã được lưu trên Stack.Chuyển tất cả đoạn code trên sang C là rất dễ dàng. Bây giờ chúng ta biết rằng đây có thể là một hàm, bởi vì dựa vào Stack Frame cũng như việc lưu trữ và phục hồi các thanh ghi, v..v.. : void SomeFunction() { //…code… } Bây giờ tôi giả sử rằng đây là một void function, bởi vì không hề có bất kì một sự thay đổi nào trong thanh ghi EAX trước khi Return. Điều đó không có nghĩa là EAX đã không bị thay đổi. Nhưng cho đến bây giờ, chúng ta sẽ giả sử giá trị trong thanh ghi EAX bị lờ đi. Tiếp theo chúng ta sẽ tiếp tục với thân của hàm này : .004122F9: C745F800000000 mov d,[ebp][-08],000000000 ;" .00412300: EB09 jmps .00041230B -----¯ (1) .00412302: 8B45F8 mov eax,[ebp][-08] .00412305: 83C001 add eax,001 ;"J" .00412308: 8945F8 mov [ebp][-08],eax
  2. .0041230B: 8B4508 mov eax,[ebp][08] .0041230E: 50 push eax .0041230F: FF1584A34300 call lstrlenA ;KERNEL32.dll .00412315: 3945F8 cmp [ebp][-08],eax .00412318: 7D2E jge .000412348 -----¯ (2) Chúng ta hãy để ý tới giá trị được tham chiếu đến : d,[ebp][-08] == dword ptr[ebp-08] (in another notation) Như tôi đã nói, bời vì nó nằm dưới thanh ghi EBP của chúng ta (thanh ghi EBP đang được lưu trên Stack), vì vậy hàm đang lưu trữ một biến cục bộ ở đó. Chúng ta biết được rằng nó có kích thước là DWORD và nó có thể là một giá trị có dấu (signed value), bởi nó được đem đi so sánh với kết quả của hàm lstrlenA, mà kết quả của hàm này là một signed int). Trên nền tảng win32, thì giá trị signed dword trong C là (signed) int. Chúng ta hãy đổi tên của nó thành int_locall để cho việc đọc hiểu trở nên dễ dàng hơn : .004122F9: mov int_local1, 000000000 .00412300: jmps .00041230B -----¯ (1) .00412302: mov eax, int_local1 .00412305: add eax,001 .00412308: mov int_local1, eax .0041230B: mov eax,[ebp][08] .0041230E: push eax .0041230F: call lstrlenA ;KERNEL32.dll .00412315: cmp int_local1,eax .00412318: jge .000412348 -----¯ (2) Okie đã thấy sáng sủa hơn một chút, tuy nhiên các bạn hãy cẩn thận ở đây, đừng nhầm lần giữa [ebp][08] với [ebp][-08] . Mặc dù là nhìn thoáng qua ta cũng thấy nó giống nhau đấy chứ, tuy nhiên đây lại là những địa chỉ hoàn toàn khác nhau. Biến tại địa chỉ [ebp][08]thì luôn luôn là một tham số đầu tiên được truyền vào hàm của chúng ta. Chính vì lí do đó chúng ta sẽ đổi tên của giá trị này thành dw_param1. Khà khà sau một hồi phân tích chúng ta đã xác định được biến cục bộ, và làm sáng tỏ được một số vấn đề , bây giờ chúng ta sẽ thử chuyển nó sang một đoạn mã giả C : int_local1 = 0; goto label_41230B; eax = int_local1; eax = eax + 1; int_local1 = eax; label_41230B: eax = dw_param1;
  3. eax = lstrlenA(eax); //lstrlenA returns its result in eax if( int_local1 >= eax) goto label_412348; Vậy là phần nào chúng ta đã có một cái nhìn dễ dàng hơn với đoạn code trên, tuy nhiên đây mới chỉ là điểm khởi đầu.Việc tiếp theo chúng ta phải dùng tư duy của mình để tối ưu hóa lại đoạn code này, hãy nhìn lại 3 dòng sau : eax = int_local1; eax = eax + 1; int_local1 = eax; Chúng ta sẽ thấy rằng đoạn code trên là hơi thừa nó có thể được đơn giản hóa lại như sau : int_local1++; Điểm khác biệt duy nhất giữa hai cách thể hiện này là thanh ghi EAX không xuất hiện trong cách biểu diễn thứ hai. Chúng ta cần phải cẩn thận quan sát, vì rất có thể giá trị của thanh ghi EAX sẽ lại được sử dụng ở phía bên dưới thì sao J. Tiếp theo ta đến dòng kế tiếp : eax = dw_param1; Điều này có nghĩa là những gì chúng ta làm ở trên là đúng bởi vì thanh ghi EAX đã được thay đổi bằng cách được gán 1 giá trị mới. Phần tiếp theo : eax = dw_param1; eax = lstrlenA(eax); // lstrlenA returns its result in eax if( int_local1 >= eax) goto label_412348; Với đoạn code này chúng ta hoàn toàn có thể làm cho nó trở nên dễ dàng hơn, chúng ta có thể kết hợp những câu lệnh trên lại như sau : if( int_local1 >= lstrlenA(dw_param1) ) goto label_412348; Một lần nữa chúng ta phải quan sát xem thành ghi EAX có được sử dụng trong các đoạn code bên dưới không, để từ đó chúng ta không bỏ sót vị trí nơi mà giá trị của thanh ghi này đang được sử dụng. Trong các câu lệnh sau đó, giá trị của EAX bị thay đổi, do đó chúng ta không cần quan tâm về những thay đổi của chúng ta. Bởi vì chúng ta biết rằng
  4. hàm lstrlenA sẽ lấy đầu vào là một con trỏ trỏ tới một chuỗi, do đó chúng ta sẽ thay đổi tham số này thành pString , cuối cùng ta có được như sau : int_local1 = 0; goto label_41230B; int_local1++; label_41230B: if( int_local1 >= lstrlenA(pString)) goto label_412348; Quan sát toàn bộ đoạn code tiếp theo trong hàm này chúng ta thấy được dòng sau : .00412346: EBBA jmps .000412302 ----- (3) Đây là một câu lệnh nhảy và nó nhảy trở về vị trí có câu lệnh int_local1++; , điều này chứng tỏ đây là một vòng lặp. Nếu như bạn đã quen thuộc với lập trình C, bạn có thể minh họa được cấu trúc này.Đây dường như là một vòng lặp for. Chúng ta sẽ cố gắng để biểu diễn lại nó, bằng cách thay đổi biến int_local1thành i. Chúng ta sẽ viết lại dưới ngôn ngữ C như sau : for(i = 0; i < lstrlenA(pString); i++) { //…rest of code… } Mọi việc đang dần dần được rõ ràng J. Giờ chúng ta đã biết hàm này có một vòng lặp, với số lần lặp bắt đầu từ 0 cho tới chiều dài của chuỗi có được thông qua tham số đầu tiên (lstrlenA(pString)). Tiếp theo chúng ta cần biết những gì đang diễn ra bên trong thân vòng lặp : .0041231A: mov eax, pString .0041231D: add eax,i .00412320: mov cl,[eax] .00412322: mov [ebp][-01],cl .00412325: movzx eax,b,[ebp][-01] .00412329: cmp eax,061 ;"a" .0041232C: jl .000412346 -----¯ (1) .0041232E: movzx eax,b,[ebp][-01] .00412332: cmp eax,07A ;"z" .00412335: jg .000412346 -----¯ (2) .00412337: movzx eax,b,[ebp][-01] .0041233B: sub eax,020 ;" " .0041233E: mov ecx, pString
  5. .00412341: add ecx, i .00412344: mov [ecx],al Trong đoạn code này chúng ta lại thấy có một biến cục bộ khác được sử dụng. Nó xuất hiện dưới kiểu unsigned char , bởi vì nó có kích thước là byte ( byte ptr) và được sử dụng nhưng là unsigned (bởi câu lệnh movzx). Trong đoạn mã giả C, ta có thể viết lại như sau : eax = pString; eax = eax + i; cl = *(eax); ch_local2 = cl; eax = (DWORD) ch_local2; if(eax < 0x61) // “a” goto label_412346; eax = (DWORD) ch_local2; if(eax > 0x7A) // “z” goto label_412346; eax = (DWORD) ch_local2; eax = eax – 0x20; ecx = pString; ecx = ecx + i; *(ecx) = al; Bây giờ tiếp tục, chúng ta sẽ làm cho đoạn code của chương trình rõ ràng hơn, tôi đổi tên kí tự thành c cho nó ngắn gọn : c = pString[i]; if((c < ‘a’) || (c > ‘z’)) goto label_412346; pString[i] = c-0x20; Để ý rằng địa chỉ tại 412346 chỉ đơn giản là vị trí kết thúc vòng lặp, vì vậy chúng ta có thể thay thế ‘goto label_412346’ bằng ‘continue;’, hoặc chúng ta có thể đảo conditional jumps. Chúng ta nhận thấy rằng chương trình kết thúc vòng lặp nếu (c‘z’), vậy thì nó sẽ không kết thúc vòng lặp nếu ta đổi thành (c>=’a’)&&(c
  6.  
Đồng bộ tài khoản