You are on page 1of 236

INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

I. Lời nói đầu :

Một lần nữa gửi lời chào tới toàn thể anh em trong REA. Tình cờ qua bên site của lão
Ricardo Narvaja thấy được bộ tut này khá hay và rất cơ bản cho tất cả những ai muốn
tìm hiểu về cracking thông qua sự trợ giúp của chương trình debugger đã trở nên quá nổi
tiếng, đó chính là Ollydbg. Tôi rất khoái các tut bên Cracklatinos nhưng ngặt nỗi toàn là
tiếng TBN, nhưng thấy bộ tut này hay nên máu quá , quyết định trans từ TBN qua English,
rồi từ Eng lại hì hục viết lại theo cách mình hiểu để truyền đạt những gì mình biết cho anh
em. Ý tưởng chính của loạt tut này theo như tác giả của nó nói là nhằm cung cấp những
kiến thức cơ bản nhất cho tất cả những ai chuẩn bị bắt đầu bước vào tìm hiểu nghệ thuật
cracking với sự trợ giúp của Ollydbg. Mặc dù tiêu đề của tut là Introduction (tức là chỉ giới
thiệu thôi) nhưng thực chất bộ tuts này sẽ cung cấp cho chúng ta một kiến thức nền tảng
vững chắc để có thể đọc và hiểu được các tuts dành cho những người có trình độ advanced
và đặc biệt là những tut sắp được giới thiệu trên C racklatinos (hehe tác giả của nó quảng
cáo ác quá), đồng thời thông qua loạt tuts này nó còn giúp chúng ta có khả năng áp dụng
các kĩ thuật mới trong việc cracking.

II. Tại sao lại là Ollydbg ?

Tham gia vào REA điều đầu tiên có lẽ chúng ta thấy nhiều nhất đó là sự xuất hiện của
“Ollydbg”, vậy tại sao lại là Ollydbg mà không phải là một công cụ nào khác. Ở đây chúng
ta sẽ không bàn luận đến việc tạo ra một công cụ khác hay hơn, mạnh hơn Ollydbg cũng
như không để cập tới việc chỉnh sửa lại một chương trình đã quá nổi tiếng từ lâu là SoftIce,
chỉ đơn giản là những tín đồ cuồng tín của SoftIce đang dần dần chuyển qua xài Ollydbg
bởi tính dễ dùng, không gây crash máy bất thình lình như SoftIce, được hỗ trợ bởi nhiều
teams trên thế giới thông qua các Plugins cũng như các bản Ollydbg được mod lại nhằm
chống lại các cơ chế anti-debug cũng như anti-Ollydbg, và vì một lý do đơn giản khác nữa
đó là loạt tuts này dành riêng để nói vể Ollydbg ☺.

III. Nhiệm vụ đầu tiên

Hì nhiệm vụ đầu tiên của chúng ta bây giờ là gì ? Do đây là tut viết về Olly nên việc chúng
ta phải làm là đi tìm Olly ở đâu để còn load về mà xài. Thứ nhất bạn có thể lên home site
của Olly là ollydbg.de để download, còn không thì trong REA có đưa rất nhiều link để
download Ollydbg. Riêng bản thân tôi cũng sưu tầm được có lẽ gần chục bản Olly khác
nhau, hic hic có lẽ là đợi ver 2.0 của Olly thôi ☺

1
Khi download được Olly về rồi thì rất đơn giản chỉ việc extract nó ra rồi sử dụng, tôi khuyên
bạn nên để chung tất cả công cụ liên quan đến RE, Cracking vào 1 thư mục, ví dụ như của
tôi trên hình minh họa, như thế ta dễ dàng quản lý hơn. Okie coi như bạn đã có Ollydbg,
chúng ta chỉ việc Run cái file OLLYDBG.exe là Olly hoạt động liền, không phức tạp về mặt
cài đặt cũng như sử dụng như SoftIce. Giao diện của Ollydbg như sau :

Đây là bản Ollydbg của tôi, đã được chỉnh sửa cũng như cấu hình lại. Nếu như các bạn
download bản Ollydbg trên home site hoặc từ các nguồn khác có thể sẽ khác của tôi, và để
có thể hiện thị menu Plugins thì các bạn làm như sau :

2
C họn như hình trên hoặc vào Options > Appearance , chọn tab Directories và chỉnh lại
đường dẫn tới thư mục Plugins và thư mục UDD.

Sau đó nhấn Ok và chạy lại Olly thì sẽ thấy được menu Plugins. Phần tiếp theo, tôi sẽ giới
thiệu tới các bạn chi tiết các cửa số chính trong Ollydbg và để minh họa cho các phần sau
của bài viết, tôi sẽ sử dụng một Crackme rất nổi tiếng đó là : CRACKME.EXE của tác giả
CRUEHEAD. Để load crackme này vào trong Olly ta nhấn chuột vào biểu tượng sau hoặc
vào File > Open (or F3) :

Sau đó chúng ta sẽ chọn chính xác crackme mà chúng ta dùng để minh họa cho bài viết
này.

Kết quả sau khi load vào Olly chúng ta có được như sau :

3
C hắc các bạn nhìn vào sẽ cảm thấy choáng ngợp, không biết phải bắt đầu từ đâu. Hic ngày
đầu tiên khi tôi load một target vào trong Olly, nhìn ngược nhìn xuôi cũng không hiểu gì
hết luôn hehe, cứ ngồi ngắm mãi vì chẳng biết làm gì hơn. Nhưng không sao mọi thứ đều
có cách giải quyết, khi chưa biết thì phải tìm tài liệu mà đọc, khi đọc mà không hiểu lúc đấy
hẵng đi hỏi. Nhưng hỏi cũng phải biết đường mà hỏi, nếu không sẽ chẳng bao giờ bạn nhận
được câu trả lời mà có khi còn khiến người khác cảm thấy bực mình. Tôi sẽ cùng các bạn
tìm hiểu từng cửa sổ một của Olly. Như các bạn nhìn thấy ở trên màn hình chính của Olly
được phân ra làm 5 cửa sổ chính, mỗi cửa sổ có một nhiệm vụ và một tên riêng :

4
Ở đây chúng ta thấy có 4 cửa sổ lớn :

- The Disassembler Window : Ở cửa sổ này các bạn có thể nhìn thấy các đoạn
code của chương trình ở dạng ngôn ngữ asm, và đồng thời tại cửa sổ này các bạn
cũng có thể chú thích cho từng từng dòng mã asm .

- The Registers Window : Đây là cửa số chứa thông tin chi tiết về các thanh ghi
như eax, ebx, ecx v….v…..Các cờ trạng thái cũng được quản lý tại cửa sổ này

- The Dump Window : Tại cửa sổ này bạn có thể xem hoặc chỉnh sửa theo 2 dạng
là hex và Ascii bộ nhớ của chương trình mà bạn muốn debug

- The Stack Window : Một cửa sổ không kém phần quan trọng , mọi thứ trước khi
được thực hiện phải được nạp vào Stack.

C uối cùng có một cửa sổ nằm bên dưới cửa sổ Disassembler Window : C húng ta gọi nó
là The Tip Window . Đây không phải là tên gọi của nó nhưng với tôi, tôi thích gọi như vậy
☺ .Khi bạn đang ở tại một dòng code nào đó trong quá trình debug , Olly sẽ cho bạn thấy
thông tin chi tiết về dòng code đó . Lấy ví dụ đơn giản như sau : nếu bạn debug tới dòng
lệnh “ mov eax , dword ptr [123]” . Thì cửa sổ này sẽ cho bạn biết được giá trị hay con số
nào đang được lưu giữ tại [123] . Và còn nhiều điều thú vị khác nữa mà cửa sổ này sẽ
mang lại cho chúng ta .

Trên đây là những gì tổng quan nhất mà các bạn nên biết. Phần dưới đây tôi sẽ đi vào giới
thiệu về chức năng của từng cửa sổ một thông qua các hình minh họa, tất nhiên không thể
giới thiệu chi tiết hết được, chúng ta sẽ tìm hiểu dần dần trong từng trường hợp cụ thể ở
5
các loạt tuts sau thêm vào đó các bạn cũng nên chủ động tự mình tìm hiểu, đừng nên quá
lệ thuộc vào bài viết này.

1. The DISASSEMBLER Window :

Đây là cửa sổ chính đầu tiên của Olly và là cửa sổ rất quan trọng, chúng ta sẽ làm việc rất
nhiều trên cửa sổ này. Khi bạn muốn debug một chương trình, bạn load file thực thi của
chương trình đó vào trong Olly.Các chương trình mà bạn load vào Olly là những chương
trình có thể được code bằng những ngôn ngữ khác nhau như : VB, VC++, Borland Delphi
hay MASM nhưng tại cửa sổ này toàn bộ code của chương trình sẽ được list ra dưới dạng
các mã ASM. Theo mặc định của Olly thì bất cứ chương trình nào mà bạn load vào Olly sẽ
được Olly tiến hành phân tích toàn bộ code chính của chương trình đó và đưa ra các
comment thích hợp. Bạn có thể tùy biến chức năng này thông qua hình minh họa dưới
đây :

Nếu như bạn chọn sử dụng chức năng này của Olly thì những gì xuất hiện trên cửa sổ bạn
sẽ giống với những hình minh họa trước. C òn nếu như bạn không chọn, chúng ta sẽ thấy
ngay được sự khác biệt, Olly sẽ không tự động phân tích chương trình nữa công việc phân
tích này chúng ta sẽ phải thực hiện một cách manual sau khi chương trình được load vào
trong Olly. Okie, tôi thử bỏ chọn và load lại C rackme vào trong Olly, ta sẽ được như sau :

6
Như các bạn thấy trên hình trên, nếu như chúng ta không chọn chức năng tự động phân
tích của Olly thì sẽ thấy các thông tin trong phần Comment đã bị lược bỏ đi khá nhiều,
điều này dẫn đến việc khó khăn trong quá trình debug chương trình. Tuy nhiên không phải
lúc nào chức năng này cũng hoạt động một cách hiệu quá, nhiều khi chúng ta để cho Olly
tự động phân tích sẽ lại dấn đến một kết quả hoàn toàn ngược lại, đoạn code được phân
tích và thể hiện ra không được chính xác, ví dụ như trường hợp dưới đây chúng ta sẽ nhận
được đoạn code toàn chứa DB :

Trong trường hợp như thế này chúng ta có thể thực hiên một cách manual để remove
những gì mà Olly đã tiến hành phân tích chỉ đơn giản bằng cách nhấn chuột phải tại màn
hình này và chọn Analysis > Remove analysis from module

7
Và kết quả là chúng ta có được đoạn code chính xác như sau :

Do đó trong quá trình làm việc với Olly các bạn nên linh hoạt trong quá trình sử dụng chức
năng này. Ngoài ra còn một phần khác cũng không kém phần quan trọng, như các bạn
thấy trên hình minh họa Olly của tôi các câu lệnh được phân biệt màu sắc một cách rõ ràng,
có thể các bạn không chú trọng đến vấn đề này nhưng theo tôi việc chúng ta phân biệt
cũng như tinh chỉnh lại màu sắc trong Olly sẽ khiến cho chúng ta nhận biệt các câu lệnh dễ
dàng hơn cũng như phần nào thể hiện năng khiếu thẩm mĩ của bạn ☺. Để tinh chỉnh lại
màu sắc trong Olly các bạn vào các Tabs sau :

8
2. The REGISTERs Window :

Một cửa sổ quan trọng tiếp theo, đó chính là cửa sổ Register. Như đã nói đây là cửa sổ
chứa thông tin chi tiết về các thanh ghi như eax, ebx, ecx v…v… Các cờ trạng thái cũng
được quản lý tại cửa sổ này.

C ửa số này sẽ cung cấp cho chúng ta rất nhiều thông tin trong quá trình chúng ta làm việc
cùng Olly. Nếu như chỉ nhìn vào hình minh họa ở trên các bạn chắc cũng sẽ như tôi cảm
thấy rằng nó sẽ không có ý nghĩa nhiều lắm, nhưng kì thực đây là nơi cung cấp nhiều thông
tin rất hữu ích.

3. The STACK Window :

Trước tiên chúng ta sẽ đi tìm hiểu sơ qua về Stack. Đây là nơi lưu trữ tạm thời các dữ liệu
và địa chỉ, nó là một cấu trúc dữ liệu một chiều. C ác phần tử được cất vào và lấy ra từ một
đầu của cấu trúc này, tức là nó được xử lý theo phương thức “vào trước, ra sau” (LIFO :
Last In First Out). Phần tử được cất vào cuối cùng gọi là đỉnh của Stack. Các bạn có thể
hình dung Stack như là một chồng đĩa, chiếc đĩa được đặt lên cuối cùng sẽ nằm trên đỉnh
và chỉ có nó mới có thể được lấy ra đầu tiên. Hai thanh ghi chính làm việc với Stack là ESP
và EBP. Theo mặc định trong Olly, Stack được biểu diễn theo thanh ghi ESP tuy nhiên
chúng ta có thể luân chuyển qua lại giữa ESP và EBP bằng cách nhấn chuột phải và chọn
như hình sau :

9
4. The DUMP Window :

Đây là cửa số hiện thị nội dung của bộ nhớ hoặc file. Ta có thể chọn nhiều định dạng khác
nhau để biểu diễn nội dung của memory trong cửa số này : byte, text, integer, float,
address, disassembly hoặc PE Header. C ửa sổ này cho phép chúng ta tìm kiếm cũng như
thực hiện các chức năng chỉnh sửa, thiết lập các Break points v..v...

Vậy là chúng ta đã dạo qua 1 vòng các cửa sổ chính của Olly, tuy nhiên bên cạnh đó Olly
còn có rất nhiều cửa sổ khác mà chúng ta không nhìn thấy một cách trực tiếp như các cửa
sổ trên được.C húng ta phải truy cập vào các cửa sổ đó thông qua Menu như hình minh họa
dưới đây :

C húng ta sẽ lướt qua chức năng của từng cửa sổ một.

_ Nút L dùng để mở cửa sổ Log của Olly, cửa sổ này cho chúng ta thấy những thông tin mà
Olly ghi lại. Theo mặc định thì cửa số này sẽ lưu các thông tin về các module, import library
hoặc các Plugins được load cùng chương trình tại thời điểm đầu tiên khi ta load chương
trình vào Olly. Bên cạnh đó cửa sổ này cũng ghi lại các thông tin về các Break points mà
chúng ta đặt trong chương trình. Trong trường hợp crackme của chúng ta, ta có được thông
tin như sau :

10
Một tính năng nữa của cửa sổ này là khi chúng ta muốn lưu lại nhưng thông tin về Log cửa
số này cũng cung cấp cho chúng ta khả năng ghi ra file.

_ Nút E dùng để mở cửa sổ Executables, cửa sổ này sẽ đưa ra danh sách những file có khả
năng thực thi được chương trình sử dụng như file exe, dlls, ocxs , v..v..

Tại cửa sổ này nếu như bạn click chuột phải sẽ thấy có rất nhiều tùy chọn khác nhau, trong
khuôn khổ có hạn của bài viết không thể nói hết được. Sẽ có những phần tiếp theo đề cập
đến chúng.

_ Nút M dùng để mở cửa sổ Memory, cửa sổ này sẽ cho chúng ta thông tin về bộ nhớ đang
được sử dụng bởi chương trình của chúng ta và còn nhiều thông tin bổ ích khác nữa :

11
Tại cửa sổ này chúng ta cũng có thể sử dụng tính năng Search để tìm kiếm thông tin về các
strings, các đoạn hexa cụ thể hay unicode v..v.. thêm vào đó nó còn cung cấp cho chúng ta
những kiểu thiết lập Break points khác nhau tại các Sections. Việc thiết lập các BPs là tùy
thuộc vào yêu cầu và mục đích của chúng ta.

_ Nút T dùng để mở cửa sổ Threads, cửa sổ này liệt kê các Threads của chương trình :

_ Nút W dùng để mở cửa sổ Windows

_ Nút H dùng để mở cửa sổ Handles

_ Nút C thì khỏi nói , bạn cứ nhấn vào là khắc biết ngay ☺

_ Nút / để mở cửa sổ Patches, cửa sổ này sẽ cho chúng ta các thông tin về những gì mà
chúng ta đã edit trong chương trình.

_Nút K để mở cửa sổ Call Stack, hiển thị một danh sách các lệnh call mà chương trình của
chúng ta đã thực hiện khi chúng ta Run bằng F9 và dùng F12 để tạm dừng chương trình.

_ Nút B để mở cửa sổ Break Points, cửa sổ này sẽ hiển thị tất cả các BPs mà chúng ta đặt
trong chương trình. Tuy nhiên nó chỉ hiện thị các BPs được set bằng cách nhấn F2 thôi, còn
các dạng BPs khác như : hardware breakpoint hoặc memory breakpoints thì không được
liệt kê ra ở đây:

_ Nút R để mở cửa sổ References, cửa sổ này là kết quả cho những gì chúng ta thực hiện
chức năng Search trong Olly, kết quả sẽ được hiện ra ở đây :

12
Phù khá nhiều cửa sổ phải không các bạn, tôi sẽ không đi vào chi tiết thêm nữa bởi vì
chúng ta sẽ còn gặp lại trong các tuts tiếp theo, 1 yêu cầu rất quan trọng ngoài việc bạn
biết sử dụng Olly ra thì bạn còn phải biết về Asm language, nếu không biết về nó thì hii các
bạn nên dành thời gian để tìm hiểu một số kiến thức cơ bản trước khi đọc tiếp các phần sau
của bài viết. Ngoài ra để các bạn dễ làm quen hơn trong các phần sau tôi sẽ cố gắng hệ
thống lại ☺.

IV. Cấu hình Olly thành JIT (Just-in-time debugging)

Khi một số chương trình thực thi và nó tạo ra Exception, Windows có thể gọi Registered
Debugger (các debuggers được cấu hình thành JIT) và attach nó vào chương trình. Tính
năng này được gọi là Just-in-time debugging.

Một vài JIT debuggers dừng lại tại System breakpoint. Ollydbg thì tiếp tục thực thi cho đến
khi nó đi đến câu lệnh đã tạo ra Exception.

Để cấu hình Ollydbg trở thành 1 JIT bạn làm như sau :

Nếu như bạn không muốn sử dụng tính năng này thì bạn có thể Restore lại.

13
V. Một số phím cơ bản để làm việc với Olly :

F7 : Khi bạn nhấn F7 sẽ thực thi từng dòng lệnh 1. Nếu trong quá trình Trace mà gặp lệnh
Call thì sẽ đi vào trong lòng của lệnh Call đó và thực thi từng câu lệnh trong lệnh Call này
cho đến khi gặp lệnh Retn để trở lại chương trình chính, tức là câu lệnh tiếp theo sau lệnh
Call.

F8 : C ũng tương tự như F7 nhưng có 1 điểm khác biệt là khi Trace code, nếu như gặp lệnh
Call nó bỏ qua không cần quan tâm các lệnh bên trong lệnh C all mà thực thi luôn lệnh Call
đó và dừng lại tại câu lệnh tiếp theo dưới lệnh Call.

F2 : Đặt một Break point trong chương trình. Vậy Break point là gì , đơn giản nó chỉ là việc
chúng ta tạo 1 điểm ngắt trong chương trình theo một điều kiện nào đó để khi thực thi
chương trình, nếu thỏa điều kiện mà chúng ta đặt ra thì chương trình sẽ dừng lại tại vị trí
mà chúng ta đã đặt BP. Ví dụ, trong hình minh họa dưới đây :

Bây giờ tôi muốn đặt một BP tại hàm C all gọi tới API: LoadIconA. Tức là khi tôi thực thi
chương trình, chương trình gọi tới hàm này thì ngay lập tức nó sẽ dừng lại tại đây.Việc tiếp
theo là tôi có thể tùy biến lại hàm này theo mục đích của tôi, chẳng hạn tôi NOP nó để
chương trình không còn gọi đến hàm này nữa v..v.. Để làm được điều này bạn nhấn chuột
tại vị trí cần Set BP, sau đó nhấn F2. Chỗ chúng ta Set BP sẽ được đánh dấu màu đỏ :

Để bỏ BP mà chúng ta đã set thì chỉ việc chọn vị trí đánh dấu màu đỏ và nhấn F2.

F9 : C ho phép thực thi chương trình trong chế độ Debug, tương tự như việc chúng ta nhấp
đúp chuột vào chương trình để thực thi nó. Tuy nhiên khác với việc nhấp đúp chuột, nếu
chúng ta nhấn F9 thì Olly sẽ tìm xem có BP nào được Set hay không, chương trình có tung
ra các Exception gì không, hay nếu chương trình có cơ chế chống Debug thì nó sẽ
terminate ngay lập tức. Nếu như không có bất kì cản trở nào thì chương trình sẽ Run hoàn
toàn và trên status bar của Olly sẽ báo cho chúng ta biết điều này :

14
F12 : Tạm dừng chương trình lại.

VI. Lời kết :

Trên đây là những gì tổng quan nhất về Olly, như đã nói các bạn không nên quá lệ thuộc
vào bài viết này của tôi, các bạn có thể tự mình tìm hiểu thêm những tính năng khác của
Olly. Các phần sau của loạt tuts này làm việc trên C rackme của tác giả CRUEHEAD, để tiện
cho các bạn đỡ mất công tìm kiếm tôi đã kèm luôn target cùng với bài viết này. Hi vọng
những gi tôi đã viết ở trên đã giúp cho các bạn phần nào hiểu được tại sao Ollydbg đang
ngày càng trở nên phổ biến.

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, C omputer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQC rker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongC hauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v.. các
bạn đã đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy ☺

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I like
your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienbigmummy[at]gmail.com

15
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

I. Lời nói đầu

Chào mọi người, sau tut đầu tiên của tôi giới thiệu tới các bạn về Ollydbg, bẵng đi một thời
gian do công việc bận rộn tôi đành gác bút chưa thể viết tiếp được. Bây giờ mọi việc có vẻ
ổn định rồi, tôi sẽ dành chút thời gian để tiếp tục bộ tut này. Mặc dù có bạn đã làm tiếp
công việc của tôi là dịch và viết đến tut thứ 16, nhưng tôi sẽ vẫn viết lại theo cách viết và
phong cách của tôi. ðây vừa là những bài viết mà tôi chia sẻ đến các bạn cũng đồng thời là
việc tôi đúc kết và lưu trữ những gì mình đã làm được. Ở phần trước sau khi các bạn đã có
một cái nhìn tổng quan nhất về công cụ Ollydbg về các thành phần cũng như chức năng
chính của nó, thì trong phần thứ hai này tôi sẽ đề cập đến việc sử dụng các hệ thống số
trong Olly, thêm vào đó là một chút kiến thức cơ bản về Stack. Okie, L3t’s G0!!

II. Các hệ thống số

Có ba hệ thống số được sử dụng nhiều nhất đó là Hệ nhị phân, Hệ mười và cuối cùng là hệ
thập lục phân.Chúng ta sẽ đi lần lượt định nghĩa về từng hệ thống này.

Hệ nhị phân : Trong hệ đếm nhị phân cơ số là 2 và nó chỉ có hai chữ số là 0 và 1.

Hệ mười (thập phân) : Có thể nói đây là một hệ thống được chúng ta sử dụng nhiều nhất
trong đời sống hàng ngày.Hệ này bao gồm mười chữ số bắt đầu từ 0 đến 9. Hệ đếm này là
hệ đếm mà chúng ta quen thuộc nhất.

Hệ mười sáu : Các số dưới dạng nhị phân thường là dài và khó nhớ. Việc chuyển đổi các
số thập phân sang nhị phân thường khó. Khi chúng ta viết chương trình hợp ngữ chúng ta
thường sử dụng cả hai hệ đếm là : nhị phân và thập phân, và cả một hệ đếm thứ ba là hệ
16 hay còn gọi tắt là số hex. Số hex cho phép chúng ta chuyển đổi một cách dễ dàng sang
số ở hệ nhị phân và ngược lại.

Note : ðể đổi số hex sang số nhị phân chúng ta chỉ việc biểu diễn các chữ số của nó dưới
dạng nhị phân. Còn đổi số nhị phân sang số hex, thì ta nhóm 4 chữ số của số nhị phân lại
theo thứ tự lần lượt từ phải qua trái. Sau đó chuyển thành số hex tương ứng.

Hệ đếm hex là hệ đếm có cơ số 16 cho nên các chữ số của nó là : 0-9, A-F. (Vì hết các kí
hiệu chữ số để biểu diễn nên người ta dùng thêm các chữ cái để biểu diễn: các chữ cái từ A
– F tương ứng biểu diễn các số từ 10 – 15).

Khi bạn muốn làm quen với công việc debug trong Olly thì điều đầu tiên tôi khuyên bạn nên
làm quen với các hệ thống số ở trên, Olly chủ yếu sử dụng hệ 16. Bên cạnh đó các bạn
cũng phải học các phương pháp chuyển đổi đơn giản giữa các hệ số với nhau để tiện cho
quá trình bạn làm việc. Có thể các bạn sẽ cho lời tôi nói là thừa bởi vì ngày nay có quá
1
nhiều công cụ hỗ trợ cho chúng ta làm việc này, nhưng theo tôi đây vẫn là những kiến thức
tiên quyết vì công cụ chỉ là hỗ trợ để chúng ta làm việc nhanh chóng mà thôi, còn muốn
hiểu sâu, rộng thì chúng ta không nên bỏ qua những chi tiết dù là vụn vặt nhất.

Ở đây trong bài viết này, tôi coi như các bạn đã tự mình trang bị những kiến thức cơ bản
rồi. Do đó để dễ dàng hơn cho chúng ta khi làm việc với các hệ thống số, Windows cung
cấp cho chúng ta một công cụ khá mạnh mà đôi khi ít người để ý mà thậm chí có khi còn
không biết là nó hỗ trợ cho chúng ta các tính năng liên quan đến việc chuyển đổi ☺, đó
chính là tiện ích Calculator. Có nhiều cách thức để mở chương trình này nhưng cách nhanh
nhất là vào menu Run và gõ Calc.exe (thậm chí chỉ cần gõ Calc cũng mở được).

Như bạn thấy trên hình sau khi chúng ta gõ Calc thì ngay lập tức công cụ Calculator sẽ
hiện ra dưới dạng một máy tính chuẩn hệt như cái máy tính bình thường mà bạn hay sử
dụng. ðể có thể chuyển sang sử dụng các tính năng chuyên nghiệp hơn liên quan tới các số
hệ nhị phân và hệ 16 cũng như các phép tính liên quan tới hai hệ số này, bạn làm như trên
hình vẽ (View > Scientific). Ta có được như sau :

2
Trong hình minh họa bên trên, bạn thấy hệ thống số được sử dụng mặc định là hệ 10
(Dec).Tại sao nó lại mặc định như vậy? Một câu trả lời rất đơn giản là vì từ lúc cha sinh mẹ
đẻ chúng ta tới giờ chúng ta sử dụng hệ 10, hệ đếm chuẩn của loài người ☺ nên chương
trình để default như vậy là hoàn toàn hợp lý. Các bạn có thể luân chuyển sang các hệ khác
rất đơn giản thông qua các tùy chọn. Lấy một ví dụ, tôi muốn chuyển một con số từ hệ 10
sang hệ 16 thì tôi làm thế nào? Tại màn hình Calculator bạn chọn Dec và gõ vào một con
số bất kì, ví dụ : 1111)

ðể chuyển sang hệ Hex bạn chỉ việc nhấp chọn vào tùy chọn Hex tại cửa màn hình của
Calculator, ngay lập tức số ở hệ 10 của bạn sẽ được chuyển sang số ở hệ 16 một cách
chính xác.

3
Trên hình trên bạn đã thấy khi ở hệ 10 thì các chữ cái từ A – F đều bị disable. Khị bạn chọn
chuyển sang hệ hex thì các chữ cái này sẽ được enable lên để phục vụ cho các bạn làm việc
ở hệ hex. Việc chuyển đôi qua lại các hệ số khác cũng làm tương tự như trên, qua đó bạn
thấy công cụ này đã đơn giản hóa cho chúng ta rất nhiều các công việc liên quan đến việc
chuyển đổi bằng tay.Tất cả những gì bạn phải làm là gõ số và nhấn chọn khà khà ☺.

III. Số có dấu trong hệ 16

Phần cứng của máy tính cần giới hạn kích thước của các số để có thể lưu nó trong các
thanh ghi hay các ô nhớ. Trong hệ hex vấn đề sẽ nảy sinh khi chúng ta muốn biểu diễn một
số âm ví dụ như -1 chẳng hạn, chúng ta không thể làm bằng cách thêm một dấu trừ ở phía
trước con số giống như ở trong hệ 10 được.Vì nếu làm thế thì đơn giản quá rồi, đâu cần
phải đề cập đến vấn đề này làm gì và vì hệ thống máy tính mà chúng ta đang sử dụng chỉ
làm việc với hai số 0 và 1 mà thôi, cho nên để biểu diễn một số có dấu phải có qui định
khác.

Do chúng ta đang làm việc với hệ thống 32 bít cho nên dải số của nó sẽ được biểu diễn ở
hệ hex là từ 00000000 – FFFFFFFF.Dải này sẽ được cắt nửa ra, một nửa dùng để biểu diễn
số dương và một nửa dùng để biểu diễn số âm. Vậy số dương sẽ bắt đầu từ 00000000 và
kết thúc là 7FFFFFFF, còn số âm sẽ bắt đầu từ 80000000 và kết thúc là FFFFFFFF. Vậy làm
thế nào để nhận biết đâu là số âm và đâu là số dương? Các bạn hãy để ý đến một bit đặc
biệt, đó là bit nằm ở tận cùng bên trái hay còn được gọi với một cái tên khác là bit có trọng
số nặng nhất (MSB - Most significant bit). Tương tự như vậy ta cũng có một bit có trọng
số thấp nhất hay còn gọi là bít nhẹ nhất đó là số nằm ở tận cùng bên phải (LSB – Least
Significant bit).

Nếu như bit có trọng số cao nhất là 0 thì số đó được hiểu là số dương. Còn nếu như bít có
có trọng số cao nhất là 1 thì số được được hiểu là số âm. Bằng 0 hay bằng 1 là khi chúng ta
biểu diễn số đó dưới dạng nhị phân. Các số âm trong máy tính được lưu ở dạng số bù 2
(Note: số bù 2 có được bằng cách đảo bít của một số nguyên và cộng với 1).

Theo đó ta có được dải biểu diễn như sau :

SỐ DƯƠNG :

00000000h hệ 16 – 0 hệ 10
00000001h hệ 16 – 1 hệ 10
4
…………………………………………..
7FFFFFFFh hệ 16 – 2147483647 hệ 10 (Số dương lớn nhất)

SỐ ÂM :

FFFFFFFFh hệ 16 - -1 hệ 10
FFFFFFFEh hệ 16 - -2 hệ 10
………………………………………….
80000000h hệ 16 - -2147483647 hệ 10 (Số âm nhỏ nhất)

Tôi sẽ làm một ví dụ chuyển đổi sang số bù 2 để các bạn thấy được một cách trực quan
nhất. Giả sử tôi có số dương là 1 , giờ tôi muốn biểu diễn số -1 tôi sẽ làm thế nào. ðể đơn
giản tôi chỉ làm mẫu với số 16 bit.

_ ðầu tiên ta tìm số bù 1 của 1 (có được bằng cách đảo bít) :
1. Biểu diễn 1 ở dạng nhị phân : 0000 0000 0000 0001
2. Tìm số bù 1 của 1 : 1111 1111 1111 1110
_ Tìm số bù 2 của 1 bằng cách lấy bù 1 đem cộng với 1 :
1. Theo kết quả ở trên, bù 1 của 1 : 1111 1111 1111 1110
2. Cộng với 1 : +1
3. Kết quả là số bù 2 : 1111 1111 1111 1111
ðem số bù hai này chuyển qua hệ Hex các bạn sé có được là : FFFFh

Trong Olly chúng ta có thể giải quyết mọi vấn đề liên quan thông qua Plug-in : Command
Bar. ðể sử dụng nó cũng rất đơn giản, bạn làm như hình minh họa dưới đây :

Rất trực quan và dễ hiểu, bạn không biết giá trị ở hệ 10 của 7FFFFFFFh là bao nhiêu. Trong
Plug-in Command Bar bạn chỉ việc gõ ? và theo sau là biểu thức hay giá trị mà bạn cần
biết thông tin. Ta thử thực hiện phép chuyển đổi với giá trị 80000000h xem sao? Như ta
biết ở trên, giá trị 80000000h biểu diễn một số âm, nhưng khi sử dụng Command Bar để
chuyển đổi thì kết quả ta có được không như những gì chúng ta mong đợi, đây là một bug
của Plug-in Command Bar.

Chúng ta có thể giải quyết vấn đề này thông qua cửa số Register. Giả sử tại cửa số này tôi
có giá trị thanh ghi EAX là 80000000h. Tôi muốn xem giá trị của nó ở hệ mười thì phải làm
thế nào và giá trị âm dương của nó ra sao?

ðể làm được điều này, nhấn chuột phải lên thanh ghi EAX và chọn Modify.Như hình minh
họa dưới đây :

5
Cửa sổ Modify sẽ hiện ra cho phép chúng ta muốn thay đổi thanh ghi EAX thế nào tùy thích
☺. Trong trường hợp này kết quả của 80000000h đúng như những gì chúng ta trông đợi đó
là -214783648.

Chúng ta thử sửa giá trị 80000000 đi và thay vào đó là một giá trị khác xem thế nào :

Ok, sau khi chỉnh sửa các bạn có thể lưu lại giá trị mà bạn đã chỉnh hoặc bỏ bằng cách
nhấn Cancel.

IV. Bảng mã ACSII

Không phải mọi số liệu mà máy tính xử lý đều là các con số, các thiết bị ngoại vi như màn
hình, bàn phím, máy in đều có xu hướng làm việc với kí tự.Cũng như tất cả mọi loại dữ liệu
khác, các kí tự cần phải được biểu diễn thành dạng nhị phân để máy tính có thể xử lý
chúng. Một kiểu mã hóa thông dụng nhất cho các kí tự đó là mã ASCII. Khi làm việc trong
Ollydbg bắt buộc bạn cũng phải tìm hiểu sơ qua về bảng mã này. Bạn phải hiểu nó để có
thể làm các bước chuyển đổi giữa kí tự ở dạng hex sang kí tự cũng như những symbols
tương ứng. Dưới đây là bảng mã ACSII mà bạn có thể tham khảo :

6
Một ví dụ với sự giúp đỡ của Plug-in Command Bar sẽ cho bạn thấy được kết quả trực
quan :

Ngoài ra cửa sổ Dump trong Olly cũng giúp bạn có được những thông tin quan trọng trong
quá trình bạn Debug target :

7
V. STACK

Như trong phần đầu tiên tôi đã nói sơ quan vế STACK, nó là một vùng của bộ nhớ dùng để
lưu trữ tạm thời các dữ liệu và địa chỉ. Stack làm việc theo nguyên lý LIFO (Last In, First
Out), tức là phần tử nào được cất vào cuối cùng trong stack sẽ là phần tử được lấy ra đầu
tiên. Bạn cứ tưởng tượng như bạn đang xếp một chồng đĩa, thì chiếc đĩa cuối cùng mà bạn
xếp sẽ nằm trên cùng, tức là đỉnh của Stack nó sẽ là chiếc đĩa được lấy ra đầu tiên nếu như
bạn muốn lấy tiếp chiếc đĩa thứ hai bên dưới nó. Cấu trúc dữ liệu làm việc theo kiểu LIFO
này là ý tưởng cho việc lưu trữ những dữ liệu tạm thời, hoặc những thông tin không cần
thiết phải được lưu trữ trong một thời gian dài. Stack thường là nơi lưu trữ các local
variables, những lời gọi hàm (function calls) và các thông tin khác được sử dụng để dọn
dẹp stack sau khi một hàm hay một thủ tục được gọi.

Một tính năng quan trọng khác của stack là nó grows down theo không gian địa chỉ: có
nghĩa là càng nhiều dữ liệu được thêm vào trong stack, nó được thêm vào tại các giá trị địa
chỉ thấp hơn theo cơ chế tăng dần. Xem hình minh họa về sơ đồ không gian bộ nhớ :

Làm việc với Stack có 2 thanh ghi chính là ESP và EBP, và các câu lệnh PUSH và POP.
Trong Ollydbg bạn có thể quan sát thấy cửa sổ Stack rất trực quan :

Okie vậy là phần hai trong loạt bài viết về Olly đến đây là hết, trong phần tiếp theo tôi sẽ
giới thiệu tới các bạn về các thanh ghi cũng như những tính năng của từng thanh ghi. Tôi
sẽ cố gằng viết xong trong thời gian sớm nhất! ☺
8
Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v.. các
bạn đã đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy ☺

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I like
your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

9
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

I. Lời nói đầu

Hà Nội trời lạnh nhưng cũng không thể át được không khí hừng hực lửa tại triển lãm Giảng
Võ.Hàng nghìn con người hò hét, lắc giật xé tan bầu không khí lạnh lẽo. Sau một đêm
“phê” cùng R0ck, toàn thân mệt nhoài, cổ đau đến hôm nay mới đỡ tôi lại tiếp tục dành
thời gian để hầu tiếp các bạn phần ba trong loạt tut về Ollydbg. Phần ba này sẽ tập trung
giới thiệu tới các bạn ý nghĩa của các thanh ghi, các cờ thường được sử dụng trong quá
trình crack hay reverse chương trình. Tôi sẽ cố gắng đúc kết lại sao cho các bạn dễ dàng
tiếp cận nhanh nhất có thể… 0k13! L3t’s R0ck w1th m3 ☺

II. Giới thiệu chung

Thông tin được lưu giữ bên trong bộ vi xử lý trong các thanh ghi. Các thanh ghi được phân
loại theo chức năng của chúng. Bộ vi xử lý dựa vào sự trợ giúp của các thanh ghi để thực
thi một chương trình. Các thanh ghi được phân loại như sau : thanh ghi dữ liệu chứa dữ liệu
cho một thao tác, thanh ghi địa chỉ chứa địa chỉ của lệnh hay của dữ liệu và thanh ghi
trạng thái lưu trạng thái hiện thời của bộ vi xử lý. ðối với bộ xử lý 8086 có bốn thanh ghi
dữ liệu công dụng chung, các thanh ghi địa chỉ được chia ra làm các thanh ghi đoạn, thanh
ghi con trỏ, thanh ghi chỉ số; thanh ghi trạng thái còn được gọi là các cờ. Khi mới làm quen
với các thanh ghi tôi khuyên bạn không nên học thuộc hết các chức năng của các thanh ghi
liền một lúc, các bạn nên làm quen với các thanh ghi dần dần trong quá trình học cũng như
trong lúc thực hành với Ollydbg.

III. Chi tiết về các thanh ghi và công dụng

1. Thanh ghi ESP :


Thanh ghi đầu tiên mà tôi muốn giới thiệu tới các bạn đó chính là thanh ghi ESP (con trỏ
ngăn xếp – Stack pointer). Thanh ghi này luôn trỏ tới đỉnh hiện thời của ngăn xếp. Các
bạn xem hình minh họa dưới đây :

1
Như các bạn thấy trên hình, giá trị của thanh ghi ESP là 0x0013FFC4h, quan sát tại cửa
sổ Stack các bạn sẽ thấy giá trị này đang nằm tại đỉnh của Stack.

Thanh ghi ESP trỏ tới địa chỉ vùng nhớ nơi mà thao tác stack tiếp theo sẽ được thực hiện.

2. Thanh ghi EIP :


ðể truy cập đến các lệnh, 8086 sử dụng thanh ghi EIP (Instruction Pointer). ðây là
một thanh ghi rất quan trọng, nó được cập nhật mỗi khi có một lệnh được thực hiện để sao
cho nó luôn trỏ đến lệnh tiếp theo. Khác với các thanh ghi khác EIP không thể bị tác động
trực tiếp bởi các lệnh, do đó trong một lệnh chúng ta sẽ thấy thường không có mặt thanh
ghi EIP như một toán hạng. Ví dụ quan sát cửa sổ Registers trong Olly chúng ta thấy như
sau :

2
Chúng ta thấy rằng thanh ghi EIP mang giá trị là 0x00401000h, điều này có nghĩa là địa
chỉ 0x00401000h chính là địa chỉ của câu lệnh tiếp theo sẽ được thực hiện. Chúng ta quan
sát trên cửa sổ CPU sẽ thấy được câu lệnh tại địa chỉ trên là câu lệnh gì :

Tại cửa sổ CPU, chúng ta nhấn F8 để thực hiện câu lệnh đầu tiên tại địa chỉ 0x00401000h
và quan sát trên cửa sổ Register xem thanh ghi EIP sẽ thay đổi giá trị như thế nào ? Chúng
ta sẽ thấy được như sau :

Oh, giá trị thanh ghi đã thay đổi thành 0x00401002h, đó chính là địa chỉ của câu lệnh tiếp
theo sẽ được thực hiện khi bạn quan sát trong màn hình CPU.

3. Thanh ghi EBP :


ðây cũng là một thanh ghi không kém phần quan trọng, thanh ghi EBP (Con trỏ cơ sở -
Base Pointer) chủ yếu được sử dụng để truy nhập dữ liệu trong ngăn xếp. Tuy nhiên khác
với thanh ghi ESP, thanh ghi EBP còn được sử dụng để truy nhập dữ liệu trong các đoạn
khác. Thanh ghi EBP thường được kết hợp với ESP khi chúng ta bắt gặp một lời gọi hàm, thì
trước khi hàm này được thực hiện địa chỉ trở về của chương trình (tức là địa chỉ của câu
lệnh tiếp theo dưới lời gọi hàm) sẽ được cất vào Stack, và bên trong thân hàm giá trị hiện
thời của thanh ghi EBP sẽ được đẩy vào Stack, bởi vì giá trị của thanh ghi EBP phải được
thay đổi để có thể tham chiếu tới các giá trị trên Stack.

3
4. Các thanh ghi dữ liệu EAX, EBX, ECX, EDX:
ðây là 4 thanh ghi đa năng 32 bit, điều đặc biệt là khi cần chứa dữ liệu 16 bit ta có các
thanh ghi sau AX, BX, CX, DX và đặc biệt hơn khi ta cần chữa dữ liệu 8 bit thì các thanh ghi
AX, BX, CX, DX này có thể phân tách ra thành 2 thanh ghi 8 bit cao và thấp để làm việc
độc lập, đó là các thanh ghi AH và AL, BH và BL, CH và CL, DH và DL. Bốn thanh ghi này
ngoài ý nghĩa là những thanh ghi công dụng chung thì nó còn mang những ý nghĩa và chức
năng đặc biệt sau :

• Thanh ghi EAX (thanh ghi chứa) : thường được sử dụng trong các lệnh số học, logic
và chuyển dữ liệu. Trong các thao tác nhân và chia thường sử dụng đến thanh ghi
này.
• Thanh ghi EBX (thanh ghi cơ sở) : thanh ghi này cũng đóng vai trò là thanh ghi địa
chỉ.
• Thanh ghi ECX (thanh ghi đếm) : thanh ghi này thường được sử dụng như một bộ
đếm số lần lặp. Ngoài ra nó cũng được sử dụng như là biến đếm trong các lệnh dịch
hay quay các bit.
• Thanh ghi EDX (thanh ghi dữ liệu) : thanh ghi này cùng với thanh ghi EAX tham gia
vào thao tác của phép nhân hoặc phép chia. Bên cạnh đó nó cũng thường được sử
dụng trong các thao tác vào ra.

5. Các thanh ghi chỉ số ESI, EDI :


Hai thanh ghi ESI (chỉ số nguồn) và EDI (chỉ số đích) thường được sử dụng trong các
thao tác làm việc với chuỗi hoặc mảng.

Trong Ollydbg như các bạn đã làm quen trong các bài trước có một cửa sổ cho chúng ta
quan sát trạng thái hiện thời của tất cả các thanh ghi, đó chính là cửa sổ Registers:

4
Những thanh ghi này với chữ cái E ở đầu cho chúng ta biết được chúng là những thanh ghi
32 bits. Trong hình minh họa này các bạn thấy Ollydbg biểu diễn nội dung các thanh ghi ở
dạng Hexa. Lấy thanh ghi EAX làm ví dụ, ta thấy giá trị của nó là 0x00000000h đây là giá
trị nhỏ nhất của một thanh ghi, giá trị lớn nhất mà thanh ghi này có thể lưu trữ là
0xFFFFFFFFh, nếu như chúng ta chuyển nó sang dạng nhị phân thì chúng ta sẽ có được như
sau :

Chúng ta thấy rằng khi chuyển sang dạng nhị phân sẽ biểu diễn đúng 32 bits, 32 bits này
sẽ có thể mang một trong hai giá trị 0 hoặc 1. Tuy nhiên trong lập trình ASM không phải
lúc nào chúng ta cũng sử dụng hết 32 bits, để tránh lãng phí chúng ta có thể thao tác, tính

5
toán chỉ trên một phần của các thanh ghi này, trong trường hợp này của tôi tôi có thể chia
nhỏ thanh ghi EAX ra. Ta sẽ làm một ví dụ cụ thể : Giả sử thanh ghi EAX tôi muốn thay đổi
giá trị của nó thành là 0x12345678h. ðầu tiên ta load crackme vào trong Ollydbg, sau khi
analyse xong chúng ta sẽ dừng lại tại EP (Entry Point) của chương trình. Bây giờ tôi sẽ thay
đổi giá trị của thanh ghi EAX, chuột phải tại thanh ghi này và chọn Modify :

Chỉnh sửa lại giá trị của thanh ghi EAX như hình dưới đây :

Kết quả sau khi chỉnh sửa :

6
Khi bạn thay đổi giá trị của một thanh ghi thì kết quả chỉnh sửa sẽ được đánh dấu màu đỏ.
Như tôi đã nói ở trên nhiều khi chúng ta không sử dụng hết 32 bits trong quá trình tính
toán mà ta chỉ cần một phần của nó thôi. Thông thường người ta thường sử dụng thanh ghi
AX (16 bits) - một phần của thanh ghi EAX. Do AX là thanh ghi 16 bits nên nó chiếm ½
trên tổng số bits, vậy ta có giá trị của thanh ghi AX là 0x5678h. ðể biết được kết quả này
có chính xác hay không, chúng ta sẽ sử dụng Command Bar :

ðúng như những gì chúng ta đã lập luận ở trên, giá trị của AX là 0x5678h. Tuy nhiên bản
thân thanh chi AX cũng lại được phân tách thành các thanh ghi AH (8 bits cao) và AL (8
bits thấp). Ta thử quan sát giá trị của thanh ghi AL :

Tổng kết lại ta có một hình ảnh minh họa trực quan như sau :

Tất cả những thanh ghi đa năng khác cũng sẽ được phân tách tương tự như thanh ghi EAX.

6. Thay đổi giá trị của những thanh ghi :


Ở phần trên, các bạn đã quan sát thấy quá trình thay đổi giá trị của một thanh ghi , ví dụ
như thanh ghi EAX diễn ra rất đơn giản, gọn nhẹ. Cách thức thay đổi giá trị bằng cách nhấp
chuột phải tại thanh ghi đó và chọn Modify.
Chúng ta sẽ làm thêm một ví dụ nữa, như các bạn đã biết thanh ghi EIP được sử dụng để
trỏ tới lệnh tiếp theo sắp được thực hiện, giờ đây tôi muốn thay đổi nội dung của thanh ghi
này thì phải làm thế nào ? Giả sử khi ta load crackme vào trong Olly thì ta có được như
sau :

7
Trong hình minh họa này thì thanh ghi EIP mang giá trị là 0x00401000h, điều này có nghĩa
là câu lệnh tại địa chỉ đó sẽ được thực hiện. Nhưng nếu ta muốn thay đổi giá trị EIP để cho
chương trình sẽ thực hiện một câu lệnh ở địa chỉ khác chứ không phải là câu lệnh tại địa chỉ
0x00401000h thì làm thế nào? Rất đơn giản, chúng ta chỉ việc chọn dòng lệnh đó nhấn
chuột phải và chọn New origin here, ngay lập tức giá trị của EIP sẽ thay đổi theo :

IV. Các cờ (Flags) hay được sử dụng

Trong phần tiếp theo của bài viết này, chúng ta sẽ làm quen với các cờ. Trong cửa sổ
Registers thì các cờ sẽ nằm bên dưới các thanh ghi ☺

8
Trong hình trên bạn quan sát sẽ thấy có các cờ sau : C, P, A, Z, S, T, D và O.Thêm vào đó
các bạn cũng thấy là các cờ này chỉ có 1 bit mà thôi do đó giá trị của nó chỉ có thể là 0
hoặc 1. Các cờ này được đặt trong thanh ghi cờ và chúng được phân chia ra thanh hai loại
là cờ trạng thái và cờ điều khiển. Cờ trạng thái phản ánh kết quả của các phép tính. Cờ
điều khiển được sử dụng để cho phép hoặc không cho phép một thao tác nào đó của bộ vi
xử lý. Nói tóm lại là mỗi một thao tác của CPU đều dựa vào các cờ để ra quyết định. Chúng
ta sẽ đi vào xem xét từng cờ một.

a. Cờ trạng thái :
Cờ tràn (Overflow Flag):
Cờ OF = 1 khi xảy ra hiện tượng tràn, thường là khi kết quả là một số bù hai vượt ra ngoài
giới hạn biểu diễn dành cho nó. ðể minh họa về cờ OF các bạn mở Ollydbg và load crackme
vào. Sau đó tiến hành sửa giá trị của thanh ghi EAX = 0x7FFFFFFFh (giá trị của số dương
lớn nhất), ta có được như sau :

Bây giờ chúng ta sẽ thực hiện cộng thêm 1 vào thanh ghi EAX, chúng ta sẽ nghĩ ngay đến
rằng giá trị của thanh ghi EAX sau khi cộng một sẽ là 0x80000000h (giá trị này tương
đương với số âm). ðể thực hiện được phép cộng này ta sẽ làm như sau : Chuột phải tại
lệnh mà bạn muốn thay đổi và chọn Assemble.

9
Ta có được như sau :

Thay câu lệnh Push 0 thành câu lệnh Add EAX, 1.

Sau khi thay đổi xong chúng ta quan sát kết quả thay đổi trên cửa sổ CPU.

Trước khi tôi và các bạn thực thi câu lệnh ADD EAX,1 – chúng ta sẽ quan sát giá trị của của
cờ OF. Ta có được kết quả như sau :

Okie, lúc này giá trị của cờ tràn O vẫn đang là 0. Chúng ta sẽ thử thực thi câu lệnh Add
EAX,1 xem thế nào. Nhấn F8 để thực thi lệnh và quan sát cửa sổ Registers :

10
Note: nhận xét về tràn với số có dấu là nếu cộng 2 số cùng dấu mà kết quả có dấu ngược
lại thì có tràn xảy ra. Khi ta cộng hai số khác dấu thì không bao giờ có tràn.

Cờ chẵn lẻ (Parity Flag):


Cờ này phản ánh tính chẵn lẻ của tổng số bit 1 có trong kết quả. Cờ PF = 1 khi tổng số bit
1 trong kết quả là chẵn – parity chẵn.Nó bằng không trong trường hợp ngược lại.Lấy ví dụ
cụ thể như sau. Chúng ta có thanh ghi EAX = 0x0h,cờ PF lúc đầu bằng 1, chúng ta sẽ thực
hiện lệnh cộng EAX với 1 và xem kết quả giá trị trên cờ PF.

Sau khi thực hiện lệnh ta có được như sau :

Ok chúng ta thấy rằng PF đã bằng 0 bởi vì giá trị thanh ghi EAX = 1, mà tổng số bit 1 trong
thanh ghi EAX lúc này là 1, vậy theo định nghĩa thì giá trị PF = 0 là hoàn toàn chính xác.
Quay trở lại vấn đề, lúc này ta chuột phải tại địa chỉ 0x00401000 và chọn New Origin.
Nhấn F8 để thực hiện lại câu lệnh. Chúng ta có được kết quả như sau :

11
Ta vẫn thấy cờ PF giữ nguyên kết quả. ðó là bởi vì thanh ghi EAX có giá trị là 0x02 (tổng số
bit 1 là lẻ). Lại làm như trên và thực hiện lại câu lệnh add EAX,1. Quan sát hình minh họa
dưới đây :

Cờ Zero (Parity Flag):


Cờ này được thiết lập 1 khi kết quả bằng không và ngược lại. Cờ này khá quan trọng đối với
việc crack. ðể minh họa cho cờ này chúng ta vẫn sẽ sử dụng lệnh Add EAX, 1 nhưng lần
này chúng ta sẽ thay lại giá trị của thanh ghi EAX thành 0xFFFFFFFF (-1).

Nhấn F8 để thực hiện câu lệnh add, ta sẽ có được thông tin như sau :

Khà khà, do kết quả của phép cộng thì thanh ghi EAX có giá trị là 0x0h cho nên cờ Z sẽ
được bật lên thành 1.

Cờ dấu (Sign Flag):


Cờ SF được thiết lập là 1 khi bít msb của kết quả bằng 1 có nghĩa là kết quả âm nếu bạn
muốn làm việc với số có dấu. Tôi sẽ minh họa về cờ SF như sau, trong Olly chúng ta thay
giá trị của thanh ghi EAX thành 0xFFFFFFF8 (=-8). Thực hiện câu lệnh add eax, 1 để tính
lại giá trị của thanh ghi EAX.

12
Thực thi lệnh, kết quả của thanh ghi EAX sẽ là 0xFFFFFFFF9 (=-7) :

Cờ nhớ(Carry Flag):
Cờ CF được thiết lập 1 khi có nhớ hoặc mượn từ bit msb.

b.Cờ điều khiển


Có 3 cờ được sử dụng trong việc điều khiển đó là cờ T. I và cờ D. Cờ T(cờ bẫy) bằng 1 thì
CPU làm việc ở chế độ chạy từng lệnh –chế độ này thường được dùng khi cần tìm lỗi trong
chương trình.)
Cờ I (cờ ngắt) , cờ này bằng 1 thì CPU cho phép các yêu cầu ngắt được tác động.
Cờ D (cờ hướng), cờ này bằng 1 khi CPU làm việc với chuỗi kí tự theo tứ tự từ phải sang
trái.

Okie vậy là phần 3 đến đây là kết thúc, trong phần này tôi có tham khảo thêm một số tài
liệu liên quan tới lập trình ASM. Các bạn có thể tham khảo thêm các tài liệu liên quan để có
được một cái nhìn sâu hơn.

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v.. các
bạn đã đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy ☺
13
I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I like
your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

14
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

I. Lời nói đầu

Hà Nội trời lạnh quá, ngoài trời mưa phùn, quàng khăn đi găng tay cộng thêm cái mũ mà
vẫn thấy lạnh. ðêm nay rảnh rỗi tôi lại tiếp tục phần bốn trong loạt tut về Ollydbg như đã
hứa với các bạn. Trong bài viết trước tôi đã tập trung giới thiệu ý nghĩa của các thanh ghi,
các cờ thường được sử dụng trong quá trình crack hay reverse chương trình, cũng như
quan sát thấy các cờ thay đổi trạng thái như thế nào khi ta thực thi một câu lệnh có tác
động đến cờ. Trong phần bốn này sẽ đề cập tới những câu lệnh Asm cơ bản, cách thức
chúng thi hành. Như những gì chúng ta đã làm trong các phần trước, sẽ không có gì dễ
hiểu hơn là khi tìm hiểu về một công cụ chúng ta tiến hành thực hành luôn trên công cụ đó
để kiểm nghiệm những kiến thức mà chúng ta tiếp thu được trong quá trình đọc tài liệu. Tôi
sẽ cố gắng đúc kết lại sao cho các bạn dễ dàng tiếp cận nhanh nhất có thể… 0k13! L3t’s
R0ck w1th m3 ☺

II. Giới thiệu chung

Tập lệnh của bộ vi xử lý có đến hơn trăm lệnh, trong đó có các lệnh được thiết kế dành
riêng cho các bộ vi xử lý cao cấp. Trong bài viết này tôi chỉ đề cập đến những câu lệnh hay
dùng nhất, chung nhất mà thôi. Việc cung cấp tất cả các lệnh vượt quá khuôn khổ cho
phép của bài viết, cũng như tôi cũng không đủ sức để mà thực hiện điều này. Do đó việc
tham khảo thêm các nguồn tài liệu khác để bổ sung thêm kiến thức là điều hết sức cần
thiết cho các bạn.

III. Chi tiết về các câu lệnh ASM hay dùng

1. NOP (No Operation) :


Cái tên của nó đã cho bạn thấy được ý nghĩa. Lệnh này không thực hiện một công việc gì
cả ngoại trừ việc tăng nội dung của thanh ghi EIP, nó không gây ra bất kì thay đổi nào
trong thanh ghi, stack hoặc memory. Chính vì ý nghĩa này của nó mà câu lệnh này thường
được dùng vào mục đích hủy bỏ bất kì câu lệnh nào (không cho lệnh đó thực hiện), bằng
cách ta thay thế câu lệnh sắp thực hiện bằng lệnh NOP chương trình sẽ vẫn thực thi nhưng
thay vì thực thi câu lệnh gốc thì giờ đây do được thay thế bằng NOP nên nó sẽ không làm gì
cả. ðó là lý do tại sao các bạn hay thấy người ta sử dụng NOP (ví dụ như : tôi muốn loại bỏ
một thông báo nào đó, để làm được điều này tôi thay thế lệnh Call đến thông báo bằng
lệnh NOP, vậy là thông báo đó sẽ biến mất ☺ ). Okie, mở Cruehead crackme trong Olly, ta
có như sau :

1
Trong hình trên, mới đầu khi load vào Olly ta sẽ có được đoạn code gốc của chương trình
đã được Olly phân tích sang ASM. Bây giờ chúng ta sẽ thay thế câu lệnh PUSH 0 như trên
hình minh họa bằng lệnh NOP. Các bạn để ý vùng tôi khoanh đỏ, lệnh Push này có 2 bytes
mà trong khi lệnh NOP chỉ có 1 byte mà thôi, vậy cho nên khi ta thay thế lệnh PUSH bằng
lệnh NOP chúng ta sẽ thấy trên màn hình Olly xuất hiện 2 lệnh NOP. ðể có thể thay đổi
một câu lệnh trong Olly, chúng ta làm như sau : chuột phải trên lệnh cần thay đổi và chọn
Assemble(hoặc nhấn Space Bar).

Ngay lập tức một cửa sổ bật ra thông báo cho chúng ta biết chúng ta đang chuẩn bị thay
đổi lệnh ở địa chỉ nào, và một textbox để cho phép ta nhập lệnh mà chúng ta muốn thay
đổi :

Như các bạn thấy trên hình, bây giờ ta muốn thay lệnh PUSH 0 bằng lệnh NOP. Rất đơn
giản ta xóa PUSH 0 đi và gõ vào NOP và nhấn Assemble.

Ở đây chúng ta nhận thấy rằng Olly ngoài việc sẽ thay thế bằng lệnh NOP, chương trình
này còn nhận biết được rằng lệnh PUSH 0 trước khi thay thế là một câu lệnh 2 bytes cho
nên nó sẽ tự động điền thêm một lệnh NOP ở địa chỉ 0x00401001 cho vừa đủ. So sánh lại
với hình trước thì các bạn thấy rằng lệnh PUSH 0 đã hoàn toàn được thay thế bằng 2 lệnh
NOP, 2 lệnh này sẽ không thực hiện bất kì công việc gì. ðể kiểm chứng bạn nhấn F8 để
trace lần lượt qua 2 lệnh NOP này và quan sát các cửa sổ xem có sự thay đổi gì không.Oh,
các thanh ghi không thay đổi, stack cũng không biến chuyển, các cờ vẫn bình thường chỉ có
mỗi một thay đổi xảy ra đó là với thanh ghi EIP (điều này là hiển nhiên rồi vì thanh ghi EIP
sẽ luôn trỏ tới câu lệnh tiếp theo được thực hiện).

Tiếp theo chúng ta sẽ quan sát sự thay đổi của 2 bytes này trong cửa sổ Dump, để tìm
chúng ta sẽ tìm kiếm theo địa chỉ chứa hai lệnh này. Như các bạn thấy ở trên đó là
0x00401000 và 0x00401001. Chúng ta tới cửa sổ DUMP, chuột phải và chọn như sau :
2
Một cửa sổ hiện ra, tại đây ta gõ vào : 00401000 và nhấn OK.

Kết quả ta có được như sau :

Olly sẽ biểu diễn những gì chúng ta thay đổi bằng màu đỏ, trong hình trên chúng ta thấy có
2 mã lệnh 90 90 tương đương với 2 lệnh NOP NOP. Tiếp theo đó là E8 FF .. tương đương
với câu lệnh CALL như các bạn quan sát thấy trong hình bên trên.

Có một câu hỏi nhỏ đặt ra : Tôi có thể loại bỏ những gì tôi vừa thay đổi và quay trở lại
đoạn code gốc được không ? Hoàn toàn có thể được, Olly hỗ trợ cho chúng ta chức năng
Undo.ðể làm điều này thì trong cửa sổ Dump hoặc cửa số CPU chúng ta chỉ việc đánh dấu
những bytes mà chúng ta đã thay đổi, nhấn chuột phải và chọn như trong hình dưới đây :

Sau khi làm đúng như trên, bạn sẽ có được lệnh PUSH 0 ban đầu :

3
Quan sát tại cửa sổ DUMP, chúng ta có được như sau :

Y34h! Với lệnh NOP thế là quá đủ! Chúng ta chuyển sang các lệnh liên quan đến STACK.

2. Các lệnh liên quan đến STACK :


Trong các phần trước chúng ta đã tìm hiểu về chức năng cơ bản của STACK rồi, phần này
tôi sẽ đề cập đến các lệnh làm việc với STACK mà cụ thể ở đây là lệnh PUSH (đẩy dữ liệu
vào Stack) và POP (lấy dữ liệu ra khỏi Stack).

2.a. Lệnh PUSH


Về cơ bản lệnh PUSH được dùng để thêm/cất 1 từ (Word (letters hoặc value)) vào trong
ngăn xếp. Như các bạn thấy trong Olly câu lệnh đầu tiên của Cruehead crackme là PUSH,
cụ thể trong trường hợp này là PUSH 0.Khi chúng ta thực hiện câu lệnh này thì điều gì sẽ
xảy ra, nó sẽ đẩy 0 vào đỉnh của Stack sau đó giảm thanh ghi ESP tuy theo kích thước của
toán hạng.
Quan sát cửa số Stack trước khi chúng ta thực thi câu lệnh PUSH.Lưu ý giá trị của thanh
ghi ESP có thể khác nhau tùy theo từng máy.

Okie, ban đầu khi chưa thực hiện câu lệnh gì thì cửa sổ Stack của tôi giống như hình minh
họa ở trên.ðây là những giá trị khởi tạo ban đầu của Stack do đó trên máy của bạn có thể
khác máy của tôi chứ không nhất thiết phải giống nhau hoàn toàn.Bây giờ tôi sẽ thực hiện
câu lệnh PUSH bằng cách nhấn F8 để trace qua câu lệnh này, ngay lập tức các bạn sẽ thấy
được sự thay đổi :

4
Như các bạn thấy giá trị tại đỉnh của Stack đã thay đổi là 0x0013FFC0 và tại đây lưu trữ giá
trị 0x0 do câu lệnh PUSH thực hiện. Bạn hãy tưởng tượng như chúng ta có 1 chồng đĩa có
sẵn, giờ ta muốn cất thêm một cái đĩa lên trên chồng đĩa này thì ta phải tịnh tiến chồng đĩa
đi để dành ra một khoảng không gian cho ta đặt cái đĩa mới, sau khi có được khoảng không
gian vừa đủ ta chỉ việc đặt cái đĩa mới lên trên. Vậy là khi chúng ta muốn lấy đĩa ra thì cái
đĩa mới được cất vào sẽ được lấy ra đầu tiên.
Thanh ghi liên quan trực tiếp đến Stack là ESP, thanh ghi này luôn trỏ vào đỉnh của Stack.
Quan sát tại cửa sổ Registers chúng ta thấy được như sau :

Có nhiều cách thức để đẩy dữ liệu vào Stack chứ không đơn thuần như chúng ta thấy ở
trên. Ví dụ nếu như tôi thực hiện câu lệnh PUSH EAX, thì lệnh này sẽ đẩy giá trị của thanh
ghi EAX vào đỉnh Stack. Chúng ta sẽ tìm hiểu thêm sự khác nhau giữa câu lệnh PUSH và
PUSH [].

Giá sử tôi có câu lệnh PUSH 401008. Khi thực hiện câu lệnh này nó sẽ đẩy 401008 vào đỉnh
của Stack. Quan sát hình minh họa dưới đây :

Thực hiện lệnh PUSH, quan sát trên stack :

Tuy nhiên nếu như tôi thực hiện câu lệnh PUSH [401008] thì điều gì sẽ xảy ra trên Stack?
Lệnh này sẽ đẩy nội dung của bộ nhớ tại 401008 vào đỉnh của Stack, chúng ta sẽ quan sát
cửa sổ DUMP xem tại 401008 lưu trữ giá trị gì.

5
Chúng ta thấy được giá trị là CA 20 40 00. Khi cất vào stack nó sẽ được đảo ngược lại
thành 004020CA, giống như dòng Comment như bạn quan sát thấy ở hình bên trên. Nhấn
F8 để thực hiện lệnh PUSH và quan sát kết quả trên Stack.

2.b. Lệnh POP


Lệnh POP có ý nghĩa hoàn toàn ngược lại với lệnh PUSH.Nó được sử dụng để lấy ra phần tử
(giá trị) từ đỉnh của Stack và đặt vào một nơi mà chúng ta chỉ đỉnh để nhận giá trị được lấy
ra.Lấy ví dụ, ta thực hiện câu lệnh POP EAX, điều này có nghĩa là chúng ta sẽ lấy giá trị tại
đỉnh của Stack và lưu nó vào thanh ghi EAX, đồng thời giá trị tại đỉnh của Stack sẽ được
thay đổi để trỏ tới phần tử tiếp theo. Lấy một ví dụ minh họa, ta thay thế lệnh PUSH 0
bằng lệnh POP EAX :

Giá trị tại đỉnh của Stack trước khi thực hiện lệnh POP :

Giá trị của thanh ghi ESP đang trỏ vào đỉnh của stack, giá trị của thanh ghi EAX lúc chưa
thực hiện POP :

6
Bây giờ chúng ta nhấn F8 để trace và thực hiện lệnh POP EAX.Quan sát cửa số Stack và
cửa sổ Registers chúng ta có được kết quả như sau :

Ok, như vậy là các bạn đã có cái nhìn tổng quan về 2 lệnh PUSH và POP.Ta chuyển sang
lệnh khác đó là hai lệnh PUSHAD và POPAD, đây là hai lệnh không kém phần quan trọng.
Tại sao ta phải lưu ý tới câu lệnh này, lý do đơn giản đó là hai câu lệnh này thường được sử
dụng để nhận biết các packers có cơ chế thực hiện gần giống với một Packer nổi tiếng mà
có thể các bạn đã biết hoặc đã từng nghe tới đó là : UPX.

2.c. Lệnh PUSHAD


Lệnh PUSHAD khi thực hiện sẽ lưu tất cả nội dung của các thanh ghi vào trong Stack. Vì
vậy có thể nói lệnh PUSHAD sẽ tương đương với một loạt các câu lệnh Push như sau : PUSH
EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI. Chúng ta sẽ quan sát câu lệnh này trong Olly,
load crackme vào và thay câu lệnh Push 0 bằng lệnh PUSHAD.

Quan sát cửa sổ Stack và cửa sổ Registers trước khi thực hiện lệnh :

7
Nhấn F8 để thực hiện lệnh, đồng thời quan sát cửa sổ Stack các bạn sẽ thấy được như
sau :

Theo hình minh họa trên các bạn thấy rằng các thanh ghi lần lượt được đẩy vào Stack theo
thự tự từ EAX cho tớ EDI. Vậy giá trị của EDI sẽ nằm ở đình của Stack và lúc này ESP sẽ có
giá trị là đỉnh của Stack : 0x0013FFA4.

2.d. Lệnh POPAD


Lệnh POPAD thực hiện nhiệm vụ ngược lại với những gì lệnh PUSHAD đã thực hiện.Nó sẽ
lấy giá trị tại Stack và cất vào các thanh ghi theo thứ tự từ EDI về EAX. Chính vì vậy câu
lệnh này sẽ tương đương với : POP EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX. Quan sát
minh họa bằng Olly sẽ cho bạn thấy một cách trực quan :

8
Các giá trị tại Stack :

Nhấn F8 để thực hiện lệnh POPAD. Quan sát tại cửa sổ Registers chúng ta thấy được giá trị
của các thanh ghi đã được phục hồi :

Qua đây ta có thể rút ra một kết luận nho nhỏ là cặp lệnh PUSHAD và POPAD thường đi
cùng với nhau. Nếu như ta thấy ở đâu đó trong mã của chương trình xuất hiện lệnh
PUSHAD thì có nghĩa là đâu đó ở bên dưới chắc chắn sẽ có câu lệnh POPAD.

3. Câu lệnh MOV


Lệnh MOV được sử dụng để chuyển dữ liệu giữa các thanh ghi, giữa một thanh ghi và một ô
nhớ hoặc chuyển trực tiếp một số vào một thanh ghi hay ô nhớ.Một ví dụ minh họa : MOV
EAX, EBX. Khi câu lệnh này thực thi nó sẽ chuyển dữ liệu của thanh ghi EBX tới thanh ghi
EAX, quan sát trên Olly các bạn sẽ thấy như sau :

9
Trên cửa sổ Registers chúng ta quan sát thấy giá trị của 2 thanh ghi EAX và EBX trước khi
thực hiện lệnh như sau :

Okie, ta nhấn F8 để thực hiện câu lệnh MOV EAX, EBX và quan sát sự thay đổi giá trị của
thanh ghi EAX tại cửa sổ Registers :

ðiều này khiến bạn liên tưởng tới ngôn ngữ lập trình bậc cao khi chúng ta thực hiện một
câu lệnh gán A:=B. Ở đây EAX được gán cho giá trị của EBX. Ở ví dụ này các bạn sẽ thấy
EAX lưu trữ dữ liệu giống hệt EBX, tuy nhiên trong một vài trường hợp đặc biệt tôi chỉ
muốn lấy một phần giá trị thôi thì thế nào? Câu lệnh MOV cũng hỗ trợ các bạn thực hiện
việc này. Lấy ví dụ cụ thể, tôi thực hiện cậu lệnh MOV AL, CL :

Nhấn F8 thực hiện câu lệnh MOV AL, CL. Quan sát cửa sổ Registers bạn sẽ thấy như hình
minh họa dưới đây :

Ngoài việc chuyển dữ liệu qua lại giữa các thanh ghi như những gì các bạn đã nhìn thấy và
quan sát ở trên chúng ta còn có lệnh MOV dùng để chuyển nội dung của một ô nhớ vào
một thanh ghi.Chẳng hạn chúng ta sẽ thực hiện câu lệnh bên dưới đây :
10
Trong trường hợ này thì nội dung của 405000 sẽ được chuyển vào thanh ghi EAX.Cụm từ
DWORD như các bạn nhìn thấy ở trên có nghĩa là toàn bộ 4 bytes tại ô nhớ trên sẽ được
chuyển vào EAX.Bây giờ chúng ta vào cửa sổ DUMP và quan sát xem tại 405000 có giá trị
như thế nào :

Như ta thấy, tại 405000 là 00 10 00 00, khi thực hiện câu lệnh MOV thì EAX sẽ giữ giá trị là
00001000. Nhấn F8 thực thi lệnh và kiểm tra kết quả :

Bây giờ chúng ta thử thực hiện ngược lại và chuyển dữ liệu của một thanh ghi vào ô nhớ
xem thế nào.Giả sử tôi muốn thực hiện lệnh : MOV DWORD PTR DS:[40500], ECX.

11
F8 thực hiện lệnh MOV, ặc chương trình bị terminate ngay lập tức. Không có lý do gì mà
câu lệnh này không thể thực hiện được? Vậy tại sao lại thế ?

Câu trả lời hết sức đơn giản là chúng ta không có quyển ghi tại ô nhớ đó. ðể kiểm tra xem
có đúng không ta nhấn Alt + M để mở cửa sổ memory và thấy được như sau :

Vây là đã rõ tại 405000 chúng ta chỉ có quyển Read mà thôi, chính vì vậy khi chúng ta thực
hiện lệnh MOV liền bị terminate chương trình ngay lập tức ☺.

Nếu như tôi muốn chuyển 2 bytes hay 1 bytes dữ liệu của một ô nhớ vào một thanh ghi thì
ta có thể dùng WORD và BYTE trong câu lệnh MOV. Ví dụ tôi có lệnh sau đây :
MOV AX, WORD PTR DS:[405008]

Tại sao ở đây chúng ta không sử dụng thanh ghi EAX đó là vì ở đây chúng ta chỉ muốn lấy
2 bytes (16 bit) thôi nên phải sử dụng thanh ghi AX là thanh ghi 16 bits. ðiều này cũng đã
được qui định bởi lệnh MOV : toán hạng đích và gốc có thể tìm được theo các chế độ địa chỉ
khác nhau nhưng phải có cùng độ dài và không được phép đồng thời là 2 ô nhớ hoặc 2
thanh ghi đoạn. Ok ta chuyển qua cửa sổ DUMP và xem nội dung của ô nhớ 405008 :

Nhấn F8 để thực hiện câu lệnh MOV và quan sát thanh ghi AX ta có được kết quả như sau :

Giờ chúng ta muốn lấy 1 bytes thì thay thế thanh ghi AX bằng thanh ghi AL. Do đó câu lệnh
MOV sẽ là như sau : MOV AL, BYTE PTR DS:[405008]

Vậy khi thực hiện lệnh MOV thanh ghi AL sẽ nhận giá trị như hình minh họa dưới đây :
12
4. Câu lệnh MOVSX
Câu lệnh này sẽ thực hiện sao chép nội dung của toán hạng thứ hai, có thể là thanh ghi
hoặc ô nhớ (với điều kiện toán hạng thứ hai phải có độ dài nhỏ hơn toán hạng thứ nhất)
vào toán hạng thứ nhất đồng thời sẽ điền đầy các bit bên trái của toán hạng thứ nhất bằng
bít có trọng số cao nhất của toán hạng thứ hai.Chúng ta sẽ lấy ví dụ cụ thể để minh họa,
giả sử trong Olly chúng ta bắt gặp lệnh sau :

ðể biết nội dung của 2 thanh ghi EAX và BX trước khi thực hiện câu lệnh trên sẽ như thế
nào ta có thể nhờ cậy đến cửa sổ Tip Window.Cửa sổ này sẽ cho chúng ta thông tin chi
tiết :

OK thanh ghi EAX là 0x0 còn BX là 0xF000.Bây giờ chúng ta nhấn F8 để thực hiện lệnh và
quan sát trên cửa sổ Registers :

Như trên ta thấy rằng nội dung của BX đã được sao chép sáng AX và điền phần còn lại với
giá trị là FFFF, đó là bởi vì thanh ghi BX nếu xét cụ thể thì nó biểu diễn cho số âm, mà số
âm thì bít có trọng số cao nhất sẽ là 1. Do đó số 1 này sẽ được điền hết vào trong thanh
ghi EAX như các bạn đã thấy trên hình. Nếu như thanh ghi BX biểu diễn một số dương
chẳng hạn 0x1234 thì thanh ghi EAX sẽ có giá trị như sau : 0x00001234. ðể chứng mình ta
giả sử thanh ghi EBX biểu diễn một số dương là 0x7FFF vậy khi thực hiện lệnh MOV ta sẽ
được như sau :

13
Nếu BX là 0x8000 thì thanh ghi EAX sẽ có giá trị là 0xFFFF8000.

5. Câu lệnh MOVZX


Lệnh này cũng tương tự như lệnh MOVSX, nhưng thay vì phụ thuộc vào bít dấu thì phần
bên trái luôn luôn được điền đầy bằng những con số 0. Bạn tự kiểm chứng trong Olly nhé ☺.

6. Câu lệnh LEA


Lệnh này cũng tương tự như lệnh MOV nhưng khác ở chỗ toán hạng đầu tiên thường là các
thanh ghi công dụng chung còn toán hạng thứ hai là một ô nhớ.Câu lệnh này thực sự rất
hữu dụng khi ô nhớ này tương ứng với một phép tính toán trước đó. Lấy một ví dụ trực
quan trong Olly :

Quan sát cửa sổ Registers để thấy được giá trị hiện thời của các thanh ghi khi chưa thực
hiện lệnh :

Trong trường hợp tại máy của tôi thì giá trị thanh ghi ECX là 0x0013FFB0, mà trong lệnh
trên tôi cho thanh ghi ECX + 38 vậy tức là tôi sẽ có giá trị = 0x0013FFE8. Nếu hiểu như
lệnh MOV bạn sẽ nghĩ là nó sẽ chuyển dữ liệu tại ô nhớ có giá trị ở trên vào thanh ghi EAX
nhưng ở đây thì không phải như thế. Nó sẽ nạp giá trị của ECX + 38 vào thanh ghi EAX, kết
quả cuối cùng là thanh ghi EAX sẽ có giá trị là 0x0013FFE8. Lập luận là như vậy, bây giờ ta
thử nhấn thử F8 để thực hiện lệnh và kiểm tra kết quả xem có chính xác hay không ☺

Trong quá trình làm việc nhiều với các chương trình các bạn sẽ hiểu rõ hơn về lệnh LEA.

14
7. Câu lệnh XCHG
Câu lệnh này còn được gọi là lệnh tráo đổi nội dung của hai toán hạng. Lệnh XCHG được
dùng để hoán chuyển nội dung của hai thanh ghi, thanh ghi và một ô nhớ.Chúng ta thử
kiểm tra bằng ví dụ trong Olly, tôi có một lệnh đơn giản như sau :

Nhìn vào câu lệnh trên các bạn hoàn toàn có thể suy ra ngay được kết quả của câu lệnh
này sau khi thực hiện ☺. Thanh ghi EAX sẽ mang giá trị của ECX và ngược lại.

Cũng tương tự trong trường hợp câu lệnh MOV, bạn cũng không thể thực hiện lệnh XCHG
giữa thanh ghi và một ô nhớ nếu như ô nhớ đó không có quyền ghi mà chỉ có quyển đọc.

Tôi thử thực hiện câu lệnh XCHG ở trên, câu lệnh này không thực hiện được và tôi nhận
được một Exception :

Okie tôi nghĩ đến đây là đã đủ cho một bài viết và phần 4 về Ollydbg xin được kết thúc tại
đây, trong phần này tôi có tham khảo thêm một số tài liệu liên quan tới lập trình ASM. Tôi
tin là với những ví dụ minh họa trực quan như ở trên các bạn sẽ nắm được vấn đề nhanh
hơn.Tuy nhiên câu lệnh của ASM không phải chỉ có thế,các bạn có thể tham khảo thêm các
tài liệu liên quan để có được một cái nhìn sâu hơn. Hẹn gặp lại các bạn trong phần 5 của
loạt bài viết về Olly, By3 By3!! ☺

15
Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v.. các
bạn đã đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy ☺

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I
like your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

16
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

I. Lời nói đầu

Khà khà lâu quá rồi tí nữa thì quên mất cái pr0j3ct về Olly còn đang dang dở. Cũng lâu quá
rồi nên chẳng nhớ những bài trước mình viết những gì và viết đến đâu, hôm nay lục lại thì
thấy mình mới viết đến bài thứ tư , chà chậm quá. Tối nay rỗi rãi và cũng muốn tránh
tình trạng Pending quá dài, tôi viết tiếp phần 5 trong loạt tuts về Ollydbg mà tôi ấp ủ.
0k13! L3t’s R0ck w1th m3 ☺

II. Giới thiệu chung

Trong phần trước của bài viết tôi đã đề cập đến những câu lệnh hay dùng nhất, chung nhất
khi chúng ta làm quen với Olly. Trong phần 5 này tôi sẽ tiếp tục với các câu lệnh liên quan
tới việc tính toán cũng như các lệnh logic, nói tóm lại chưa có gì đặc biệt hơn và có thể gây
nhàm chán với những anh em nào đã quá Pr0 khà khà ☺. Xin nhắc lại một lần nữa việc
cung cấp tất cả các lệnh vượt quá khuôn khổ cho phép của bài viết, cũng như tôi cũng
không đủ sức để mà thực hiện điều này. Do đó việc tham khảo thêm các nguồn tài liệu
khác để bổ sung thêm kiến thức là điều hết sức cần thiết cho các bạn.

III. Các lệnh dùng trong việc tính toán

1. Lệnh INC và DEC :

INC (Increment) được dùng để cộng thêm 1 vào nội dung của một thanh ghi hay một ô nhớ.
DEC (Decrement) thực hiện công việc ngược lại, trừ 1 từ nội dung của một thanh ghi hay ô
nhớ. ðể minh họa cho hai câu lệnh này bạn load crackme vào trong Olly và edit như sau :

Chuyển qua cửa sổ Register và quan sát giá trị của thanh ghi EAX trước khi chúng ta thực
hiện câu lệnh trên là bao nhiêu :

1
Vậy khi chúng ta thực hiện lệnh INC EAX thì tức là tương được với việc ta thực hiện EAX =
EAX + 0x1.Nhấn F7 để trace qua câu lệnh INC EAX ta có được kết quả như sau :

Rất dễ hiểu phải không ? Tiếp tục với lệnh DEC, tôi edit lại lệnh NOP thành DEC EAX :

Nhấn F7 để trace qua lệnh này, quan sát cửa sổ Registers sau khi thực hiện lệnh ta sẽ có
được kết quả của EAX. Kết quả này tương đương với việc ta thực hiện EAX = EAX - 0x1.

Như các bạn thấy ở trên là những ví dụ đối với thanh ghi, tiếp theo tôi sẽ lấy ví dụ với ô
nhớ.Trong Olly các bạn sửa thành lệnh sau :

Trong phần 4 tôi có để cập đến quyền truy cập tại section có địa chỉ 0x405000, do nó không
có quyền ghi cho nên khi ta thực hiện câu lệnh INC đối với nội dung của nó sẽ thì sẽ không
thực hiện được và chúng ta sẽ dính exception trong Olly :

Nhưng nếu như tôi gán lại quyền cho section này và thực hiện câu lệnh trên thì kết quả sẽ
ra sao? Trước tiên ta cần xem xét nội dung tại [405000] đã :

2
Vậy là giá trị tại ô nhớ này là 0x00001000, theo lý thuyết nếu ta thực hiện lệnh INC thì kết
quả sẽ là 0x00001001. Ok bây giờ kiểm tra lại trong Olly :

Kết quả trong Olly đúng như những gì chúng ta đã tính toán trên lý thuyết. ðây là ví dụ
thực hiện với DWORD, bạn có thể tự thực hành thêm các ví dụ với WORD hoặc BYTE :

2. Lệnh ADD :

Lệnh này được sử dụng để cộng nội dung của hai thanh ghi, một thanh ghi và một ô nhớ
hoặc cộng một số vào một thanh ghi hay một ô nhớ, kết quả sẽ được lưu vào toán hạng
đầu tiên. Lấy một ví dụ như sau :
ADD WORDX, EAX

Lệnh này sẽ thực hiện “cộng EAX vào WORDX”, tức là cộng nội dung của thanh ghi EAX với
nội dung của ô nhớ WORDX và chứa tổng cuối cùng trong WORDX và EAX không bị thay đổi.
Vậy nếu ta có câu lệnh ADD EAX, 1 thì sẽ tương đương với INC EAX. Ta thực hiện một ví dụ
nhỏ trong Olly :

Giá trị hai thanh ghi EAX và ECX trên máy tôi có thể sẽ khác với máy của các bạn. Nhấn F7
để thực hiện lệnh ADD và quan sát trên cửa sổ Registers, ta thấy như sau :

Kết quả sau phép cộng EAX lưu giá trị cuối cùng là tổng và thanh ghi ECX vẫn giữ nguyên
không thay đổi.
Thực hiện thêm một ví dụ minh họa nữa, lần này là cộng nội dung thanh ghi với nội dung ô
nhớ :

3
Nhấn F7 để thực hiện lệnh ADD ta có được giá trị của EAX như sau :

3. Lệnh ADC

Lệnh này tạm dịch là lệnh cộng có nhớ, tức là Cờ nhớ được cộng vào tổng của toán hạng
nguồn và toán hạng đích. Nếu cờ CF=1 thì toán hạng đích = toán hạng nguồn + toán hạng
đích + 1. Còn nếu CF=0 thì toán hạng đích = toán hạng nguồn + toán hạng đích. Ví dụ
minh họa :

Ta thấy rằng lúc này cờ C đang là 0, thanh ghi EDX lúc này mang giá trị là 0x21(giá trị của
DL là 0x21). Ta sẽ thực hiện lệnh ADC DL, 0xEB tức là DL = DL + 0xEB = 0x21 + 0xEB.
Nhấn F7 để thực hiện lệnh, rõ ràng trong quá trình cộng sẽ có nhớ lên bit MSB cho nên cờ
C sẽ được set là 1 :

Ok tiếp tục thực hiện 1 lệnh nữa như sau :

4
Lúc này giá trị của DL đang là 0xC, cờ C đang được thiết lập là 1. Nếu ta thực hiện lệnh
ADC DL,1 tức là DL = DL + 1 + 1 = 0xE và cờ C lại được set lại thành 0 ☺.

4. Lệnh SUB

Lệnh này thực hiện công việc ngược lại của lệnh ADD. Ví dụ minh họa :

Nhấn F7 để thực hiện lệnh SUB EAX,2. Theo tính toán thông thường của chúng ta thì 0 – 2
sẽ cho kết quả là -2. Giá trị của -2 được biểu diễn ở dạng Hexa là : 0xFFFFFFFE

Các bạn hoàn toàn có thể thực hiện thêm các ví dụ như trừ 2 thanh ghi : SUB EAX, ECX

5
, trừ thanh ghi và ô nhớ : SUB EAX, DWORD PTR DS:[405000]

5. Lệnh SBB

Là lệnh trừ có nhớ, lệnh này thực hiện trừ toán hạng đích cho toán hạng nguồn và nếu
CF=1 thì trừ kết quả nhận được đi 1. Kết quả chứa trong toán hạng đích. Tôi lấy một ví dụ
nhỏ để minh họa :

Cờ C lúc này đang có giá trị là 0, do đó khi ta thực hiện lệnh SBB thì sẽ tương đương với
EDX = EDX – 3. Kết quả ta có được :

Ngược lại nếu ta set cờ C có giá trị 1 thì kết quả sẽ là như sau :

6. Câu lệnh MUL

Nhân số không dấu, trong trường hợp này toán hạng gốc là số nhân. Tùy theo độ dài của
toán hạng gốc mà ta có ba trường hợp để tổ chức phép nhân :

1. Nếu gốc là số 8 bit: AL * Gốc


Số bị nhân phải là số 8 bit để trong AL.
6
Sau khi nhân : AX <- tích
2. Nếu gốc là số 16 bit: AX * Gốc
Số bị nhân phải là số 16 bit để trong AX
Sau khi nhân : DX AX <- tích
3. Nếu gốc là số 32 bit: EAX * Gốc
Số bị nhân phải là số 32 bit để trong EAX
Sau khi nhân : EDX EAX <- tích

Ta lấy một ví dụ minh họa như sau :

Câu lệnh MUL ECX sẽ thực hiện nhân ECX với EAX sau đó kết quả thu được sẽ được lưu vào
EDX:EAX và không quan tâm tới dấu của các toán hạng. Bây giờ ta giả sử giá trị của các
thanh ghi EAX, ECX và EDX như sau :

Trước khi xem kết quả thu được trong Olly chúng ta hãy tính toán thử đã. Sử dụng
calculator của Windows, ta lấy 0xFFFFFFF7 * 0x9 được kết quả như sau :

Như vậy bạn thấy kết quả ở đây vượt quá sự biểu diễn của thanh ghi EAX do đó nó sẽ được
lưu một phần vào thanh ghi EXD. Vậy kết quả cuối cùng sẽ là thanh ghi EDX lưu giá trị 0x8
còn EAX sẽ là 0xFFFFFFAF. Trong Olly ta trace qua lệnh để xem kết quả :

Các bạn tự mình tìm hiểu thêm trong các tài liệu về lệnh này ☺.

7. Câu lệnh IMUL

Nhân số có dấu, cách thức thì cũng tương tự như lệnh MUL. Ta lấy 2 ví dụ như sau :

a. IMUL EBX : Câu lệnh này sẽ tương đương với việc lấy EAX * EBX và kết quả sẽ được lưu
vào EDX:EAX tương tự như lệnh MUL nhưng trong đó dấu của toán hạng được quan tâm
đến.

7
b. 696E74020080FF imul ebp, dword ptr [esi+74], FF800002 : [ESI+74] x FF800002
- > EBP
Trong ví dụ thứ hai này chúng ta sẽ thấy có 3 toán hạng và nó thực hiện như sau, lấy nội
dung của [ESI+74] nhân với FF800002 kết quả được bao nhiêu lưu vào EBP.Ta sẽ thử thực
hiện câu lệnh này trong Olly :

Ta sửa lại giá trị của thanh ghi ESI thành 0x401000 để chúng ta chắc chắn rằng giá trị của
[ESI+74] là có và thể đọc được nội dung của nó.

Ok sau khi đổi chúng ta xem nội dung của nó là gì :

Ta nhấn thử F7 để thực hiện câu lệnh IMUL :

Nếu ta tính toán trong calculator của windows ta sẽ được như sau :

8
8. Câu lệnh XADD

Câu lệnh này đồng thời thực hiện lần lượt hai lệnh XCHG và ADD. Ví dụ : XADD EAX, ECX
thì lúc này giá trị của ECX được thay thế bằng giá trị của EAX còn giá trị của EAX = EAX +
ECX. Minh họa :

Thực hiện lệnh và quan sát kết quả :

9. Câu lệnh NEG

Lệnh này thực hiện việc lấy bù hai của một toán hạng hay còn gọi là đảo dấu của một toán
hạng. ðiều này sẽ tương đương với công việc đảo bít của toán hạng và cộng với 1. Ví dụ :

9
Chúng ta thực hiện lệnh NEG và quan sát kết quả của EAX :

IV. Các lệnh Logic

Trong phần này sẽ giới thiệu về các lệnh AND, OR, XOR, NOT. Các lệnh này có thể sử dụng
để xóa, thiết lập và kiểm tra từng bit trong các thanh ghi hay các biến, khả năng thao tác
với từng bit riêng biệt chính là một trong những ưu điểm của hợp ngữ.
Chúng ta có thể thay đổi từng bit trong máy tính bằng các lệnh logic. Các giá trị nhị phân 0
và 1 được xem như là các giá trị logic TRUE hoặc FALSE một cách tương ứng.

1. Lệnh AND

Kết quả của lệnh AND là 1 nếu như hai bit là 1, ngược lại là 0 :

1 and 1 = 1
1 and 0 = 0
0 and 1 = 0
0 and 0 = 0

Minh họa bằng Olly lệnh : AND EAX, ECX

Dạng binary của EAX: 0x3500 11010100000000


Dạng binary của ECX: 0x2400 10010000000000
AND EAX, ECX 10010000000000

10
Lệnh AND có thể được dùng để xóa các bit nhất định của toán hạng đích trong khi giữ
nguyên những bit còn lại. Bit 0 của mặt nạ xóa bit tương ứng, còn bit 1 của mặt nạ giữ
nguyên bit tương ứng của toán hạng đích
2. Lệnh OR :

1 or 1 = 1
1 or 0 = 1
0 or 1 = 1
0 or 0 = 0

Lệnh OR có thể được dùng để thiết lập các bit xác định của toán hạng đích trong khi vẫn
giữ nguyên những bit còn lại. Bit 1 của mặt nạ sẽ thiết lập bit tương ứng trong khi bit 0 của
nó sẽ giữ nguyên bit tương ứng trong toán hạng đích.

3. Lệnh XOR :

1 xor 1 = 0
1 xor 0 = 1
0 xor 1 = 1
0 xor 0 = 0

Lệnh XOR có thể được dùng để đảo các bit xác định của toán hạng đích trong khi vẫn giữ
nguyên các bit còn lại. bit 1 của mặt nạ làm đảo bit tương ứng còn bit 0 của mặt nạ giữ
nguyên bit tương ứng của toán hạng đích.

4. Lệnh NOT :
Thực hiện việc đảo bít :

not 1 = 0
not 0 = 1

Ví dụ : not 0110 = 1001.


Giả sự ta có thanh ghi EAX mang giá trị là 0x1200:

Biểu diễn ở dạng Bin 00000000000000000001001000000000


Thực hiện đảo bit 11111111111111111110110111111111
ðưa về dạng Hexa FFFFEDFF

Kết quả sau khi thực hiện lệnh :

Okie tôi nghĩ đến đây là đã đủ cho một bài viết và phần 5 về Ollydbg xin được kết thúc tại
đây, trong phần này tôi có tham khảo thêm một số tài liệu liên quan tới lập trình ASM. Tôi

11
tin là với những ví dụ minh họa trực quan như ở trên các bạn sẽ nắm được vấn đề nhanh
hơn.Tuy nhiên câu lệnh của ASM không phải chỉ có thế,các bạn có thể tham khảo thêm các
tài liệu liên quan để có được một cái nhìn sâu hơn. Hẹn gặp lại các bạn trong phần 5 của
loạt bài viết về Olly, By3 By3!! ☺

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v.. các
bạn đã đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy ☺

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I
like your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

12
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

I. Giới thiệu chung

Trong phần 5, tôi đã đề cập tới các câu lệnh liên quan tới việc tính toán cũng như các lệnh
logic, nói tóm lại chưa có gì đặc biệt hơn và có thể gây nhàm chán với những anh em nào
đã quá Pr0 khà khà ☺. Trong phần 6 của loạt tuts này tôi xin giới thiệu tới các bạn về các
câu lệnh so sánh và các lệnh nhảy có điều kiện. ðây là những kiến thức nền tảng cơ bản và
quan trọng để có thể đi tiếp các phần tiếp theo. Xin nhắc lại một lần nữa việc cung cấp tất
cả các lệnh vượt quá khuôn khổ cho phép của bài viết, cũng như tôi cũng không đủ sức để
mà thực hiện điều này. Do đó việc tham khảo thêm các nguồn tài liệu khác để bổ sung
thêm kiến thức là điều hết sức cần thiết cho các bạn.

II. Các lệnh so sánh và các lệnh nhảy có điều kiện

Thông thường, khi chúng ta thực hiện việc so sánh là chúng ta so sánh giữa hai đối tượng
trở lên và rồi đi đến một quyết định vào đó. Lấy một ví dụ vui : Người A béo hơn người B
do đó suy ra người A ăn nhiều hơn người B ☺.

Trong Cr@cking, khi chúng ta thực hiện so sánh giữa hai toán hạng thì kết quả của việc so
sánh này sẽ quyết định rằng chương trình có thực hiện câu lệnh nhảy bên dưới hay là
không. Và đây cũng là những kiến thức cơ bản luôn luôn được đề cập đến trong các bài viết
hướng dẫn dành cho Newbie (những người mới bắt đầu làm quen với Crack).

Chúng ta biết rằng khi một chương trình yêu cầu ta phải nhập Serial để đăng kí, thì bản
thân chương trình đó sẽ quyết định xem liệu rằng cái dãy serial mà chúng ta nhập vào kia
có thỏa mãn (đúng) hay không thỏa mãn thông qua việc tính toán và tiến hành các câu
lệnh so sánh. Dựa trên kết quả của việc so sánh này chương trình sẽ đưa ra quyết định có
thực hiện lệnh nhảy hay là không, điều này tùy thuộc vào chúng ta có nhập serial không,
serial của chúng ta nhập vào đúng hay sai ?

1. Lệnh CMP :

ðây là câu lệnh so sánh rất thường gặp trong quá trình chúng ta phân tích chương trình,
các điều kiện nhảy thường được cung cấp bởi lệnh CMP này. Tổng quát câu lệnh CMP có
dạng như sau :

CMP ðích, Nguồn

Lệnh này thực hiện việc so sánh toán hạng ðích với toán hạng Nguồn bằng cách lấy toán
hạng ðích trừ đi toán hạng Nguồn. Có thể nói lệnh này tương đương với lệnh SUB nhưng nó
khác với lệnh SUB ở chỗ kết quả không được lưu lại (tức là toán hạng đích không bị thay
đổi). Tác dụng chủ yếu của lệnh CMP là tác động lên các cờ. Một điểm chú ý khác nữa là

1
các toán hạng của lệnh CMP không thể cùng là các ô nhớ. Vậy tổng kết lại lệnh này thường
được dùng để tạo cờ cho các lệnh nhảy có điều kiện.

Dưới đây là bảng trích dẫn các cờ chính theo quan hệ ðích và Nguồn khi so sánh 2 số
không dấu :

CF ZF SF
ðích = Nguồn 0 1 0
ðích > Nguồn 0 0 0
ðích < Nguồn 1 0 1

Ta lấy ví dụ trực quan trong Olly :

a) CMP EAX, ECX

Ở đây tôi giả sử giá trị của 2 thanh ghi EAX và ECX là bằng nhau, kết quả so sánh (kết quả
của phép trừ) sẽ không làm thay đổi giá trị của EAX mà nó sẽ tác động lên các cờ, trong đó
cờ được thiết lập sẽ là cờ Z. Ok , trong Olly chúng ta làm như sau :

Bây giờ tôi nhấn F8 để trace qua lệnh CMP, quan sát tại cửa sổ Register thì ta thấy rằng giá
trị của hai thanh ghi EAX và ECX không hề thay đổi. Tuy nhiên cờ Z được thiết lập.

Mở rộng vấn đề ra một chút, nếu bên dưới của câu lệnh so sánh trên tôi có một lệnh nhảy
vậy thì sẽ có hai khả năng xảy ra. Câu lệnh nhảy này sẽ được thực hiện hoặc không thực
hiện phụ thuộc vào trạng thái của cờ (mà cụ thể ớ đây là cờ Z). Trong trường hợp ví dụ
trên tôi giả sử bên dưới là lệnh JZ, lệnh nãy sẽ thực hiện nhảy nếu như cờ Z được thiết lập

2
là 1 và không nhảy nếu như cờ Z được thiết lập là 0. Cũng với ví dụ trên tôi giả sử serial
mà tôi nhập vào được lưu vào thanh ghi EAX, còn Serial do chương trình tính toán ra được
đặt trong thanh ECX. Nếu EAX = ECX, vậy tức là câu lệnh CMP sẽ làm cho cờ Z được bật
lên thành 1 và câu lệnh JZ sẽ nhảy tới vùng code dành cho người dùng đã đăng kí hợp
pháp, còn ngược lại nếu EAX không bằng ECX thì lúc này lệnh CMP sẽ thiết lập cờ Z là 0 và
như vậy chúng ta sẽ bị đưa đến vùng code mà sẽ bắn ra Nag thông báo!! 

Ngoài việc có tác động lên cờ Z thì lệnh CMP còn tác động lên cả cờ S. Tôi lấy một ví dụ cụ
thể như sau :

b) CMP EAX, ECX trong đó EAX lớn hơn ECX

Bây giờ chúng ta nhấn F8 để thực hiện lệnh CMP và quan sát xem giá trị của các cờ thay
đổi ra sao.

Ta thấy cờ Z đã được thiết lập là 0 lý do là vì EAX không băng ECX, đồng thời cờ S cũng
được thiết lập là 0 đó là vì EAX lớn hơn ECX (EAX-ECX cho chúng ta kết quả là một số
dương). Vậy trong trường hợp EAX nhỏ hơn ECX thì sao, tôi lấy thêm một ví dụ minh họa
nữa :

c) CMP EAX, ECX trong đó EAX nhỏ hơn ECX

3
Giờ chúng ta thực hiện lệnh và quan sát sự thay đổi :

Cờ S lúc này được bật lên thành 1 đó là vì kết quả của EAX – ECX sẽ cho chúng ta một số
âm.

Vậy chúng ta thấy rằng việc quyết định có thực hiện lệnh nhảy hay không sẽ phụ thuộc vào
trạng thái của các cờ.Bên cạnh lệnh so sánh giữa hai thanh ghi, thì CMP còn cho phép
chúng ta thực hiện so sánh giữa thanh ghi và một ô nhớ (DWORD, WORD hoặc BYTE). Lấy
ví dụ minh họa như sau :

Thực hiện lệnh so sánh và quan sát kết quả, ta sẽ thấy rằng lệnh so sánh này sẽ lấy giá trị
của EAX trừ đi giá trị tại ô nhớ [405000] là 1000. Kết quả của phép trừ này sẽ là âm và do
đó cờ S sẽ được thiết lập là 1.
4
2. Lệnh TEST :

Cũng giống như lệnh CMP, lệnh TEST thực hiện thao tác giữa toán hạng ðích và Nguồn mà
không làm thay đổi các toán hạng, kết quả cũng không được lưu giữ. Nó khác với lệnh CMP
ở chỗ lệnh này sử dụng phép AND, lệnh TEST sẽ tác động tới các cờ SF, ZF và PF. Các cờ
được tạo ra sẽ được dùng làm điều kiện cho các lệnh nhảy có điều kiện. Tổng quát về lệnh
TEST như sau :

TEST ðích, Nguồn

Trong đó toán hạng ðích và Nguồn phải chữa dữ liệu cùng độ dài và không được phép đồng
thời là hai ô nhớ.
Lấy ví dụ để minh họa: tôi có lệnh TEST EAX, EAX. Câu lệnh TEST này sẽ kiểm tra xem EAX
có bằng không hay không ? Trong Olly chúng ta sửa lại như sau :

Giả sử rằng giá trị của thanh ghi EAX lúc này đang là 0x0 và cờ Z cũng đang có giá trị 0.

Trong phần trước tôi đã cung cấp cho các bạn bảng tính toán giữa các bit của phép AND rồi,
do đó phần này không nhắc lại nữa. Nhấn F8 để trace qua lệnh TEST và quan sát kết quả :

5
Ồ cờ Z đã được bật lên, đó là vì kết quả của phép AND giữa hai toán hạng (ở đây là EAX) có
giá trị 0x0 sẽ cho ta là 0x0. Khi kết quả bằng 0x0 thì cờ Z của chúng ta sẽ được bật lên.

Tôi lặp lại ví dụ này, nhưng thay vào đó EAX sẽ mang một giá trị khác 0x0. Ví dụ :

Ok, nhấn F8 và quan sát cờ Z sẽ thay đổi thế nào :

Cờ Z không được bật lên, điều này là hiển nhiên bởi vì kết quả của phép AND cho chúng ta
một giá trị khác 0x0. Chúng ta thử tính toán xem thế nào, ta đổi giá trị 0x390 sang dạng
Binary (1110010000)và thực hiện phép AND.

Vậy như các bạn thấy ở trên kết quả sau khi tính toán sẽ là khác 0x0 cho nên cờ Z không
được bật lên, và một điều đặc biệt ở trên là kết quả sau khi tính toán giống hệt với hai toán
hạng của chúng ta.

6
3.Các lệnh nhảy :

Bảng tổng hợp các lệnh nhảy (chi tiết về các lệnh nhảy sẽ được đề cập ờ bên dưới) :

Lệnh JMP

ðây là lệnh nhảy trực tiếp hay nếu dịch sát nghĩa ra thì nó là lệnh nhảy không điều kiện
(tức là lệnh nhảy này luôn luôn thực hiện mà không cần bất kì điều kiện nào). Lấy ví dụ
trong Olly như sau :

Như quan sát trên hình, khi lệnh JMP thực hiện thì chương trình sẽ chuyển hướng thực thi
tới địa chỉ 0x00401031 và thực hiện câu lệnh tiếp theo bắt đầu tại địa chỉ này. Cũng trong

7
hình minh họa trên, các bạn thấy xuất hiện một mũi tên màu đỏ, mũi tên này chỉ cho ta nơi
mà lệnh nhảy sẽ nhảy tới. ðể có thể thấy được mũi tên này thì các bạn cấu hình trong Olly
như sau :

Bây giờ tôi nhấn F8 để thực thi câu lệnh JMP, lúc này giá trị thanh ghi EIP của tôi sẽ thay
đồi thành 0x00401031. ðơn giản là bởi vì thanh ghi EIP luôn luôn trỏ tới câu lệnh được thực
hiện tiếp theo :

Lệnh JE / JZ

Về ý nghĩa thì JE : Nhảy nếu bằng nhau / JZ : Nhảy nếu kết quả bằng không – là hai lệnh
nhảy biểu diễn cùng một thao tác nhảy có điều kiện tới một vị trí định trước nếu như cờ ZF
= 1. Tôi xét một ví dụ như sau :

Tôi cho giá trị của hai thanh ghi EAX và ECX bằng nhau, và ZF lúc này = 0 :

8
Do 2 thanh ghi có giá trị bằng nhau nên khi thực hiện lệnh CMP cho ra kết quả bằng 0 nên
lúc này cờ ZF sẽ được bật thành 1. Lệnh JE lúc này sẽ dựa vào trạng thái của cờ ZF để
quyết định có thực hiện hay không, do lúc này cờ ZF = 1 nên lệnh nhảy này sẽ được thực
hiện :

Lặp lại ví dụ ở trên nhưng lần này giá trị của EAX và ECX sẽ khác nhau, cờ ZF lúc này là 1 :

Nhấn F8 để trace qua lệnh CMP, do thanh ghi EAX có giá trị lớn hơn ECX nên kết quả của
việc thực hiện lệnh CMP sẽ cho ta một giá trị khác 0 dẫn đến cờ ZF sẽ được thiết lập lại là 0.
Lúc này lệnh JE thấy cờ ZF bị “tắt” cho nên nó không thực hiện lệnh nhảy nữa :

9
Khi mà lệnh nhảy JE tại địa chỉ 0x00401002 không được thực hiện thì lệnh tiếp theo sau nó,
tức là lệnh NOP tại địa chỉ 0x00401004 sẽ là lệnh tiếp theo được thực thi.
Nhiều lúc trong quá trình làm việc với Olly bạn không muốn can thiệp vào giá trị các thanh
ghi để từ đó thay đổi giá trị các cờ. Vậy có cách nào để chúng ta ép chương trình thực hiện
lệnh nhảy mà không cần can thiệp vào giá trị thanh ghi để tạo cờ hay không ? Xin thưa, vô
cùng đơn giản ☺.
Bạn lặp lại ví dụ trên và trace qua lệnh CMP. Ở đây bạn muốn làm sao cho lệnh nhảy dưới
lệnh CMP sẽ thực hiện, lẽ ra bạn sẽ phải tính toán và chỉnh lại giá trị các thanh ghi để sao
cho khi thực hiện lệnh CMP thì cờ ZF được bật lên thành 1 và lệnh nhảy sẽ được thực hiện.
Tuy nhiên ở đây tôi không cần quan tâm các thanh ghi chứa giá trị thế nào, việc đơn giản
nhất mà tôi làm là nhấn đúp chuột vào cờ mà tôi muốn thiết lập / hủy thiết lập. Cụ thể hơn,
các bạn nhìn vào hình trên thì thấy lệnh nhảy sẽ không được thực hiện và cờ Z lúc này
đang là 0. ðể cho lệnh nhảy sẽ được thực thi tôi nhấn đúp chuột lên cờ ZF, lúc này cờ ZF sẽ
được bật lên thành 1 và quan sát cửa sổ CPU các bạn sẽ thấy :

Lệnh JNE / JNZ

Hai lệnh nhảy này là ngược lại của hai lệnh nhảy JE và JZ, ý nghĩa cụ thể của nó là Nhảy
nếu không bằng nhau / Nhảy nếu kết quả không bằng không. Chúng biểu diễn cùng một
thao tác nhảy có điều kiện tới một vị trí nếu như cờ ZF = 0. Một ví dụ nhỏ để minh họa :
10
Trace qua lệnh CMP, do EAX khác ECX nên cờ ZF được thiết lập lại thành 0. Lệnh JNZ nhận
thấy cờ ZF là 0 nên sẽ quyết định thực thi lệnh nhảy.

Lệnh JS

ðây là lệnh nhảy được thực hiện nếu kết quả âm, tức là lệnh nhảy có điều kiện tới một vị
trí định trước nếu SF = 1. ðiều này có nghĩa là nếu kết quả âm sau khi thực hiện tính toán
các phép toán với các số có dấu thì cờ SF sẽ được thiết lập là 1 và lệnh JS sẽ được thực thi.
Ví dụ minh họa :

11
Trace qua lệnh CMP, do EAX < ECX do đó cờ SF sẽ được thiết lập là 1 và lệnh nhảy sẽ được
thực thi :

Lệnh JP / JPE

ðây là hai lệnh nhảy biểu diễn cùng một thao tác nhảy có điều kiện tới một vị trí định trước
nếu PF = 1 (PF là cờ Parity). Ví dụ minh họa :

Giá trị của EAX = 0x20, ECX = 0x18. Ta trace qua lệnh CMP thì thấy cờ PF vẫn giữ nguyên
trạng thái là PF = 0.

Do thanh ghi EAX = 0x20 > ECX = 0x18, cho nên khi thực hiện lệnh CMP ta sẽ có được kết
quả là 0x2. Mà kết quả này nếu đem đi biểu diễn dưới dạng binary là 10. Theo lý thuyết về
cờ PF thì tổng số bit 1 trong kết quả này là lẻ cho nên cờ PF không được thiết lập thành 1
và do đó lệnh JPE cũng sẽ không được thực hiện.
Ta cũng lấy ví dụ như trên nhưng lúc này ta cho giá trị của ECX là 0x17. Trace qua lệnh
CMP ta có được kết quả như hình minh họa dưới đây :
12
Ta thấy cờ PF lúc này đã được bật lên thành 1.ðơn giả là vì kết quả của lệnh CMP là 0x3,
biểu diễn dưới dạng nhị phân là 11.Vậy tổng số bit 1 trong kết quả có được là chẵn cho nên
cờ PE được bật lên thành 1 và lệnh JPE lúc này sẽ thực thi :

Lệnh JNP / JNPE

Hai lệnh này có điều kiện nhảy ngược với hai lệnh nhảy ở trên, tức là nó chỉ thực hiện khi
mà cờ PF mang giá trị 0.

Lện JO

ðây là lệnh nhảy có điều kiện tới vị trí định trước nếu OF = 1, tức là xảy ra tràn sau khi
thực hiện các phép toán với các số có dấu. Ví dụ minh họa :

Trace qua lệnh ADD và quan sát cửa sổ CPU các bạn sẽ thấy cờ JO được bật lên :

13
Lệnh JNO

Lệnh này là ngược lại với lệnh JO.

Lệnh JB

Lệnh này sẽ thực hiện nếu cờ CF = 1. Lấy ví dụ :

Giá trị của EAX ở đây tôi cho nhỏ hơn giá trị của ECX.Trace qua câu lệnh CMP, kết quả là
một giá trị < 0 và cờ CF được thiết lập là 1.

14
Ngược với lệnh JB là lệnh JNB (các bạn tự tìm hiểu thêm về lệnh này).

Lệnh JBE

Nhảy nếu thấp hơn hoặc bằng, lệnh này sẽ được thực hiện nếu cờ CF = 1 hoặc cờ ZF = 1.
Tức là nếu ta có EAX = ECX thì lệnh nhảy sẽ được thực hiện hoặc nếu EAX < ECX thì lệnh
nhảy cũng sẽ được thực hiện. Ví dụ :

Nếu ta cho EAX bằng ECX :

Trace qua lệnh CMP, kết quả của CMP là 0 cho nên cờ ZF được thiết lập là 1 :

Nếu ta cho EAX < ECX :

15
Trace qua lệnh CMP, lúc này cờ CF sẽ được bật thành 1 ☺.

Lệnh JL

Lệnh này thực hiện khi mà cờ SF và cờ OF khác nhau. Một ví dụ minh họa với trường hợp
EAX và ECX là hai số dương và EAX lớn hơn ECX.

Trace qua lệnh CMP, quan sát sẽ thấy lệnh Jmp không được thực hiện bởi vì EAX lớn hơn
ECX, kết quả của CMP là một số dương do đó các cờ S và O không bị tác động.

Ngược lại nếu tôi lấy giá trị của EAX < ECX và lặp lại ví dụ trên :

Thực hiện CMP , quan sát kết quả ta thấy như sau :

16
SF != OF, cho nên lệnh nhảy JL sẽ được thực hiện.

Okie tôi nghĩ đến đây là đã đủ cho phần 6 về Ollydbg , bài viết xin được kết thúc tại đây
mặc dù còn một số lệnh nhảy tôi chưa trình bày (cái này để dành cho các bạn tự tìm
hiểu).Trong phần này tôi có tham khảo thêm một số tài liệu liên quan tới lập trình ASM. Tôi
tin là với những ví dụ minh họa trực quan như ở trên các bạn sẽ nắm được vấn đề nhanh
hơn.Tuy nhiên câu lệnh của ASM không phải chỉ có thế,các bạn có thể tham khảo thêm các
tài liệu liên quan để có được một cái nhìn sâu hơn. Hẹn gặp lại các bạn trong phần 7 của
loạt bài viết về Olly, By3 By3!! ☺

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v.. các
bạn đã đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy ☺

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I
like your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

17
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

Công việc bề bộn và ngập đầu trong dự án nhưng tôi vẫn ở đây, vẫn dành trọn tình cảm
cho những đam mê của riêng mình. Vẫn muốn đóng góp thật nhiều cho dù là nhỏ bé nhất
cho ngôi nhà REA thân yêu. Trong sáu phần trước tôi đã tập trung giới thiệu một cách tổng
quan những câu lệnh cơ bản và thường được sử dụng nhất. Tuy nhiên vẫn còn rất nhiều các
câu lệnh khác nhưng trong khuôn khổ có hạn của bài viết không thể giới thiệu hết được, và
thiết nghĩ việc liệt kê hết ra sẽ rất nhàm chán cho nên chi tiết về các câu lệnh sẽ được đề
cập tới khi chúng ta gặp phải trong quá trình làm việc với Olly. Trong phần 7 của loạt tuts
này sẽ tập trung giới thiệu tới các bạn về lệnh CALL và RET. Xét một cách tổng quan thì
đây là 2 lệnh đơn giản, tuy nhiên khi đi vào chi tiết nhiều người thường khó hiểu đặc biệt là
những bạn mới làm quen với ASM. Chính vì lý do này mà phần 7 sẽ đi sâu vào giải quyết 2
lệnh này.

II.CALL và RET

Trước tiên chúng ta mở Olly lên và load crackme vào. Tại cửa sổ CPU, bạn nhấn chuột phải
và chọn như sau (hoặc nhấn Ctrl + G) :

Tại cửa sổ vừa mới xuất hiện bạn gõ vào địa chỉ như sau : 0x401245 và nhấn OK

1
Olly sẽ đưa chúng ta đến địa chỉ mà chúng ta vừa gõ. Tại đây chúng ta sẽ thấy một lệnh
CALL :

ðây là lệnh CALL mà tôi dùng để thực hành trong bài viết này. ðể có thể thực thi được lệnh
CALL này thì chúng ta phải thiết lập lại thanh ghi EIP trỏ đúng tới địa chỉ 0x401245. ðiều
này được thực hiện rất đơn giản bằng cách nhấn chuột phải lên lệnh CALL và chọn New
origin here như sau :

Quan sát thanh ghi EIP các bạn sẽ thấy nó thay đổi (xem lại về thanh ghi EIP ở phần
trước) :

2
Ok, giờ quay trở lại lệnh CALL của chúng ta :

Về bản chất thì lệnh CALL được dùng để gọi một thủ tục (chương trình con). Có hai kiểu gọi
thủ tục đó là gọi trực tiếp và gọi gián tiếp. Cú pháp của lệnh gọi thủ tục trực tiếp :

CALL Name (trong đó Name là tên của thủ tục)

Cú pháp của lệnh gọi thủ tục gián tiếp :

CALL addr_expresstion (trong đó addr_expression là một thanh ghi hay ô nhớ chứa địa chỉ
của thủ tục)

Note : Xem thêm hình minh họa về lệnh CALL trong file CaLL_stack.gif.

Lệnh CALL dùng để chuyển hoạt động của bộ vi xử lý từ chương trình chính sang chương
trình con. Có nghĩa là khi chúng ta trace qua một lệnh CALL trong Olly thì các câu lệnh bên
trong của câu lệnh CALL này sẽ được thực hiện, điều này giống như việc các bạn lập trình
trên các ngôn ngữ bậc cao bằng cách tạo ra các thủ tục hay các hàm. Khi thực hiện chương
trình thì ở đâu có lời gọi hàm hay thủ tục thì sẽ thực hiện các lệnh bên trong hàm/thủ tục
đó đã rồi mới trả lại quyền điều khiển cho chương trình chính. Một ví dụ minh họa để hiểu
rõ vấn đề :

Câu lệnh CALL CRACKME.00401362 có nghĩa là câu lệnh tiếp theo sẽ được thực thi bắt đầu
tại địa chỉ 0x00401362 và sau khi thực hiện xong chương trình con (thủ tục/hàm) bắt đầu
từ địa chỉ đó, nó sẽ trở về (trả lại quyền điều khiển cho chương trình chính) thực thi câu
lệnh tiếp theo bên dưới lệnh CALL. Trong ví dụ của chúng ta thì sau khi thực hiện các lệnh
bên trong lệnh CALL CRACKME.00401362 xong thì nó sẽ trở về lệnh JMP SHORT
CRACKME.004011E6 tại địa chỉ 0x0040124A và thực thi câu lệnh này theo đúng trình tự thực
hiện của chương trình chính. Vậy trong Ollydbg hỗ trợ cho tôi chức năng gì để tôi có thể
làm việc với lệnh CALL?
Nếu như tôi muốn xem nội dung của lệnh CALL và muốn trace để debug các lệnh bên trong
lệnh CALL thì Ollydbg hỗ trợ cho tôi tính năng Step Into (F7). Tức là tại bất kì câu lệnh
CALL nào bạn chỉ việc nhấn F7 thì bạn sẽ chui vào trong lòng lệnh CALL đó để xem các lệnh.
Tuy nhiên, nếu lệnh CALL nào cũng nhấn F7 thì e rằng nhiều lúc thực sự không cần thiết vì
tôi chỉ muốn có cái nhìn tổng quan về lệnh CALL đó mà chưa cần quan tâm đến nội dung
bên trong lệnh CALL có những gì, về mặt này Olly hỗ trợ cho chúng ta tính năng Step Over
(F8). Tính năng này giúp ta thực thi luôn lệnh CALL mà không cần phải chui vào thực hiện
3
từng lệnh bên trong lệnh CALL như chúng ta nhấn F7, sau khi thực hiện xong lệnh CALL nó
sẽ đưa chúng ta thẳng tới lệnh tiếp theo bên dưới lệnh CALL.
Vậy từ đây ta đi tới kết luận, khi ta đứng tại một lệnh CALL bất kỳ ta sẽ có hai lựa chọn :

1. Nếu như lệnh CALL đó là quan trọng và chúng ta muốn quan sát cách hành xử bên
trong lệnh CALL đó thì chúng ta sử dụng chức năng Step Into.

2. Nếu như lệnh CALL đó không có gì để ta phải quan tâm và ta chỉ cần kết quả trả
về của nó mà không cần biết bên trong nó làm những gì thì ta sử dụng chức năng
Step Over.

Tuy nhiên hai chức năng này vẫn phải thực thi các lệnh, nhưng ở đây tôi chỉ muốn quan sát
bên trong lệnh CALL có những lệnh gì mà không muốn phải thực thi bất kì lệnh nào thì Olly
có tính năng hỗ trợ không?? Với một lệnh CALL mà ta quan tâm, Olly hỗ trợ cho chúng ta
chức năng Follow. Nhấn chuột phải lên lệnh CALL và chọn Follw, xem hình minh họa dưới
đây :

Tính năng này chỉ đơn giản là cho phép ta xem câu lệnh tiếp theo sẽ được thực hiện mà
bản thân nó không hề thực thi bất kì câu lênh nào của chương trình. Nó cũng không làm
thay đổi thanh ghi EIP, quan sát hình minh họa dưới đây :

Khi tôi Follow theo lệnh CALL tại địa chỉ 0x00401362 tôi sẽ quan sát được các lệnh bên
trong lệnh CALL này và rõ ràng rằng địa chỉ của lệnh tiếp theo sẽ được thực thi sẽ bắt đầu
tại 0x00401362. Kết thúc lệnh CALL này để trở vể chương trình chính, các bạn quan sát sẽ
thấy có một lệnh đặc biệt đó chính là RET/ RETN. Lệnh RET thường được đặt ở cuối chương
trình con để bộ vi xử lý lấy lại địa chỉ trở về (địa chỉ của lệnh tiếp theo bên dưới lệnh CALL),
4
địa chỉ này được tự động cất vào stack mỗi khi có lời gọi đến một chương trình con. Theo
như ví dụ của chúng ta thì sau khi thực hiện lệnh RET tại 0040137D \. C3 RETN ta sẽ
trở về địa chỉ 0x0040124A.
ðây là những kiến thức rất quan trọng các bạn cần phải nắm được về lệnh CALL. Ở trên các
bạn mới chỉ làm những công việc là nhìn và quan sát những gì bên trong lệnh CALL mà
chưa thực thi bất kì một câu lệnh nào. Phần tiếp theo dưới đây chúng ta sẽ áp dụng các
chức năng Step Into và Step Over. Ok, quay trở lại ví dụ chúng ta đang dừng lại tại lệnh
CALL :

Bây giờ chúng ta nhấn F7 để đi vào trong lệnh CALL, khà khà nhưng trước tiên chúng ta
cần quan sát cửa sổ Stack trước khi thực hiện nhấn F7. Cửa sổ Stack sẽ cung cấp cho
chúng ta một thông tin rất quan trọng đó là địa chỉ trở về (địa chỉ của lệnh bên dưới lệnh
CALL), địa chỉ này sẽ được cất vào Stack để từ đó chương trình sẽ biết được nơi mà nó cần
trở về khi thực hiện câu lệnh RET.

Lưu ý giá trị trên Stack của tôi có thể khác với máy của các bạn và điều này không quan
trọng.Bây giờ chúng ta nhấn F7 để chui vào trong lệnh CALL đông thời quan sát cửa sổ
Stack xem có gì xảy ra :

Khác với chức năng Follow ở trên lúc này thanh ghi EIP sẽ thay đổi và điều này có nghĩa là
chúng ta đang thực thi chương trình con :

Cửa số Stack lúc này thay đổi như sau :

5
Như bạn thấy trên hình minh họa thanh ghi ESP trỏ lên đỉnh của Stack đã được giảm đi
thành 0x0013FEA0 và địa chỉ của câu lệnh tiếp theo sau lệnh CALL (địa chỉ trở về) được
đẩy vào đỉnh của Stack.Và đây chính là cơ sở cho lệnh RET thoát khỏi chương trình con để
quay trở về chương trình chính ☺. Olly cũng đã cung cấp cho chúng ta thông tin : RETURN
to CRACKME.0040124A from CRACKME.00401362

Quay trở lại công việc chúng ta đang làm, các bạn nhấn tiếp F7 để thực hiện lệnh tại địa chỉ
0x00401362 đó là :

00401362 /$ 6A 00 PUSH 0 ; /BeepType = MB_OK

Lệnh PUSH 0 được thực thi tức là đẩy giá trị 0 vào đỉnh của Stack. Lúc này địa chỉ trở về sẽ
được đầy lùi xuống nhường chỗ cho giá trị 0x0 :

Chương trình có thể kiểm soát hàng nghìn câu lệnh bên trong một chương trình con, bản
thân bên trong chương trình con có thể thực hiện hàng nghìn lệnh PUSH và POP nhưng khi
đã ở tại câu lệnh RET thì lúc đó trên stack sẽ chỉ có địa chỉ trở về (chương trình gọi tới
chương trình con), để từ đó câu lệnh RET sẽ căn cứ vào địa chỉ trở về này để quay về lệnh
tiếp theo dưới lệnh CALL. Tiếp theo ví dụ trên, chúng ta nhấn F8 để thực hiện các lệnh tiếp
theo cho tới khi chúng ta dừng lại tại câu lệnh RET.

Thông tin trên cửa sổ Stack :

Như chúng ta đã đề cập về lệnh RET ở phía trên, khi ta thực hiện lệnh RET thì nó sẽ căn cứ
vào địa chỉ trở về trên Stack để quay về lệnh tiếp theo dưới lệnh CALL. ðồng thời thêm vào

6
đó nó sẽ xóa địa chỉ trở về này khỏi Stack vì giá trị này không còn hữu ích nữa. OK ta nhấn
F7 để thực hiện lệnh RETN, ta sẽ được đưa tới địa chỉ 0x0040124A :

Tuy nhiên, trong một số trường hợp ta có thể thực thi lệnh RET mà không cần phải có lệnh
CALL. Một ví dụ như sau :

PUSH 401256
RET

Trong ví dụ trên, lệnh PUSH sẽ đẩy giá trị 0x401256 vào đỉnh của Stack và bên dưới lệnh
PUSH này là một lệnh RET. Theo như lý thuyết thì lệnh RET sẽ căn cứ vào địa chỉ trở về
được cất trên Stack để quay trở về vậy cho nên khi thực hiện lệnh RET chúng ta sẽ được
đưa tới địa chỉ của lệnh tiếp theo sẽ được thực hiện là 0x401256. Qua ví dụ này ta rút ra
một nhận xét là cặp lệnh PUSH và RET tương đương với lệnh JMP ☺.

Bây giờ quay trở lại ví dụ chính của chúng ta, tôi sẽ minh họa một trường hợp khác, trong
Olly nhấn Ctrl + G và gõ vào địa chỉ 0x401364. Ta sẽ ở đây trong Olly :

Quá trình này không làm thay đổi thanh ghi EIP, nhấn F2 để đặt một BP tại địa chỉ trên.
Mục đích của việc đặt BP là tôi muốn chương trình sau khi thực thi sẽ dừng lại tại nơi mà tôi
đã đặt BP.

Sau khi đặt BP giống như trên xong, lúc này ta nhấn F9 để Run chương trình :

7
Tại Crackme v1.0, ta nhấn Help và chọn Register :

Cửa sổ Register sẽ hiện ra yêu cầu ta nhập thông tin :

Ta nhập thông tin vào :

Nhấn OK, ngay lập tức chúng ta sẽ dừng tại điểm mà chúng ta đặt BP trong Olly :
8
Lúc này quan sát cửa sổ Stack ta có được như sau :

Như các bạn quan sát thấy trên cửa sổ Stack lúc này cố một số dòng “RETURN TO…”,
nhưng theo lý thuyết mà chúng ta đã lập luận ở trên thì dòng nào ở vị trí cao nhất trong tất
cả các dòng sẽ chính là nơi chứa địa chỉ trở về chương trình chính khi chương trình con thực
hiện câu lệnh RET bên trong nó. Vì khi chúng ta ở tại câu lệnh RET thì dòng “RETURN TO…”
cao nhất sẽ được đẩy lên đỉnh của Stack và lúc này địa chỉ trở về sẽ là 0x0040124A.

Ta đang dừng lại tại BP đã thiết lập, bây giờ nhấn F8 để trace tới lệnh RET.Tuy nhiên bạn
để ý trên hình minh họa trước khi tới được lệnh RET thì sẽ phải đi qua một lệnh CALL :

00401378 |. E8 BD000000 CALL MP.&USER32.MessageBoxA> ; \MessageBoxA

Ta không cần quan tâm bên trong nó ra sao chỉ cần biết rằng khi trace over qua nó sẽ hiện
ra một thông báo :

Nhấn Ok để tiếp tục, lúc này chúng ta sẽ dừng lại tại câu lệnh RETN và chuẩn bị thực hiện
câu lệnh này :

9
Quan sát trên cửa sổ Stack, ta sẽ có được thông tin của địa chỉ trở về :

ðiểm khác biệt của lần phân tích này so với lần phân tích ở trên chính là việc thay đổi
thanh ghi EIP, và việc chúng ta thực hiện một câu lệnh CALL (là một phần của chương
trình) mà không phải là toàn bộ chương trình.Thanh ghi EIP thay đổi thông qua việc thực
thi chương trình và dừng lại tại điểm mà chúng ta đặt BP. Nếu chúng ta tiếp tục thực thi
chương trình bằng việc nhấn F9 thì nó sẽ hoàn toàn chạy một cách bình thường như không
có gì xảy ra ☺.
Tuy nhiên điều mà tôi muốn nhấn mạnh ở đây đó là công dụng của cửa sổ Stack, khi chúng
ta đang thực thi chương trình và bị dừng lại vì một lý do nào đó thì thông tin mà cửa sổ
Stack cung cấp cho chúng ta sẽ cho ta biết được nơi mà thủ tục được gọi cũng như địa chỉ
mà nó sẽ trở về. Tuy nhiên các chương trình thường sử dụng các lệnh CALL lồng nhau thì
qua cửa sổ Stack này chúng ta cũng có được các thông tin để lần ngược về nơi gọi.

Phần tiếp theo tôi sẽ lấy một ví dụ minh họa khác, nhấn Ctrl+F2 để restart Olly và edit lại
như hình minh họa dưới đây :

Nhấn Enter để Follow vào quan sát nội dung bên trong lệnh CALL :

10
Như quan sát ở trên thì sau khi chúng ta sửa đổi lúc này câu lệnh đầu tiên sẽ được thực
hiện sẽ bắt đầu tại địa chỉ 0x00401245 và kết thục tại câu lệnh RETN tại địa chỉ 0x00401288
(mà ở đây chúng ta thấy là lệnh RETN 10 hơi khác một chút với lệnh RETN).

Tại địa chỉ mà chúng ta vừa mới Follow tới là 0x00401245 ta nhấn “-“ để quay về nơi phát
sinh ra lời gọi tới nó, sau đó chúng ta nhấn F7 để trace into vào trong lệnh CALL, lú đó
thành ghi EIP sẽ thay đổi :

ðồng thời trên cửa sổ Stack ta sẽ quan sát thấy địa chỉ trờ về sau khi thực hiện xong :

Chúng ta nhìn thấy giá trị là 0x00401005, điều này là rất đúng và hợp lý. Tuy nhiên ở đây
tôi không khẳng định rằng sau khi thực hiện xong Ollydbg sẽ đưa chúng ta trở về đúng nơi
mà chúng ta đã thấy ở trên.Lý do là vì chúng ta đã sửa lại hướng thực thi của cả chương
trình ☺ điều này chẳng khác gì trong một cỗ máy đang hoạt động trơn tru bị bạn làm thay
đổi qui trình hoạt động của nó.
ðể có thể fix được nó thì trong cửa sổ CPU nhấn chuột phải và chọn :

11
Hoặc có thể nhấn phím tắt là Ctrl + A. Sau khi analyze xong quan sát cửa sổ Stack :

Ok nó thông báo cho chúng ta như sau :

0013FFC0 00401005 RETURN to CRACKME.<ModuleEntryPoint>+5 from


CRACKME.00401245

ðiều này chính là giá trị 0x00401000 (EntryPoint) + 0x5 = 0x00401005. Rõ ràng là
thông tin sau khi Olly analyze mang lại đầy đủ ý nghĩa hơn là thông tin ban đầu mà chúng
ta có được. Sau khi nhấn F7 chúng ta sẽ ở đây trong Olly :

Tại đây chúng ta nhấn tiếp F7 để trace vào bên trong lệnh :

00401245 $ E8 18010000 CALL CRACKME.00401362

Quan sát trên cửa sổ Stack ta có được như sau :

12
Thông qua hình minh họa ở trên ta thấy rằng trước khi đi vào mỗi lệnh CALL địa chỉ của
lệnh tiếp theo (dưới lệnh CALL) đều được đẩy lên đỉnh của Stack _ đó chính là địa chỉ trở về.
ðiều này sẽ giúp cho chúng ta hiểu được cơ chế quản lý khi có các lệnh CALL lồng nhau.
Trong ví dụ trên, ta đang ở tại địa chỉ 0x00401362 và đây chính là nơi mà lệnh tiếp theo
được thực hiện.Sau khi thực hiện toàn bộ các lệnh bên trong và tới lệnh RETN tại địa chỉ
0x0040137D, khi ta thực hiện lệnh RETN này nó sẽ căn cứ vào địa chỉ trở về nằm trên Stack
để quay ra ngoài, và lúc này địa chỉ trở về đó là 0x0040124A. Thực hiện lệnh RETN ta sẽ ở
đây theo đúng lý thuyết đã lập luận :

Và trên cửa sổ Stack ta có thông tin giống như hình minh họa ở trên, điều này có nghĩa là
ta vẫn đang nằm trong lòng lệnh CALL (00401000 >/$ E8 40020000 CALL
CRACKME.00401245) và địa chỉ trở về sẽ là 0x00401005 bên dưới lệnh CALL này ☺. Tuy
nhiên như tôi nói ở trên nếu bạn tiếp tục thực hiện các lệnh tiếp theo thì chương trình sẽ
không return về đúng địa chỉ, đó là bởi vì chúng ta đã phá vỡ cấu trúc của chương trình.
Nếu bạn cố tình thực hiện thì sẽ crash đó, ráng chịu!! ☺.

Okie tôi nghĩ đến đây là đã đủ cho phần 7 về Ollydbg, bài viết xin được kết thúc tại đây.
Trong phần này tôi có tham khảo thêm một số tài liệu liên quan tới lập trình ASM nhưng có
thế không tránh khỏi những sai sót trong quá trình viết, rất mong các bạn góp ý để tôi
chỉnh sửa lại. Tôi tin là với những ví dụ minh họa trực quan như ở trên các bạn sẽ nắm
được vấn đề nhanh hơn. Ngoài ra các bạn có thể tham khảo thêm các tài liệu liên quan để
có được một cái nhìn sâu hơn. Hẹn gặp lại các bạn trong phần 8 của loạt bài viết về Olly,
By3 By3!! ☺

Best Regards
_[Kienmanowar]_

13
--++--==[ Greatz Thanks To ]==--++--
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v.. các
bạn đã đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy ☺

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I
like your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

14
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

ðợt rồi bận quá, mải cài đặt và config hệ thống để phục vụ cho dự án upgrade, xém chút
nữa thì quên mất viết tiếp bộ tut về Olly. Trong phần 7 tôi đã tập trung giới thiệu tới các
bạn về lệnh CALL và RET. Xét một cách tổng quan thì đây là 2 lệnh đơn giản, tuy nhiên khi
đi vào chi tiết nhiều người thường khó hiểu đặc biệt là những bạn mới làm quen với ASM.
Hôm nay, chúng ta tiếp tục với phần 8 của loạt tuts này, phần này tập trung vào giới thiệu
về vòng lặp và các câu lệnh liên quan tới chuỗi. Bài viết sẽ không sa đà vào giải thích cặn
kẽ từng cấu trúc của vòng lặp mà sẽ đi nhanh và tập trung nhấn mạnh vào những phần
quan trọng. Phần 8 này cũng là phần kết thúc việc giới thiệu các lệnh cơ bản, các phần tiếp
theo sẽ tập trung vào những chủ đề, khía cạnh thú vị hơn.

II. Giới thiệu về vòng lặp

Một vòng lặp là một chuỗi các lệnh được lặp lại. Số lần lặp có thể đã được xác định trước
hoặc phụ thuộc vào điều kiện. Thông thường trong Asm thì bộ đếm vòng lặp thường là
thanh ghi ECX, nó được khời tạo bằng số lần lặp. Sau khi thực hiện xong các lệnh bên trong
vòng lặp giá trị của thanh ghi ECX sẽ tự động giảm đi 1. Nếu như giá trị của ECX còn khác
0 thì các lệnh trong vòng lặp còn tiếp tục được thực hiện , còn nếu như ECX bằng 0 thì sẽ
thoát khỏi vòng lặp và thực hiện các lệnh tiếp theo bên dưới vòng lặp. Lấy ví dụ minh họa:

XOR ECX, ECX\ ðoạn lệnh này thực hiện nhiệm vụ khởi gán cho thanh ghi
ADD ECX, 15 / ECX.Số lần lặp lúc này sẽ là 15 và ñược lưu trong thanh ghi ECX.
LOOP:
DEC ECX // Giá trị của thanh ghi ECX sẽ ñược giảm ñi 1
……………… \ Thực hiện các lệnh trong thân vòng lặp
……………… /
TEST ECX, ECX \ Chừng nào giá trị của ECX còn khác 0
JNE LOOP / thì còn tiếp tục thực hiện

Minh họa ví dụ trên trong Olly như sau :

1
Vùng mà tôi khoanh vàng ở trên hình đó chính là vòng lặp, các lệnh trong vòng lặp này sẽ
được thực hiện lặp lại cho tới khi nào thanh ghi ECX có giá trị 0. Các câu lệnh bắt đầu từ
0x00401008 cho tới 0x0040100C chính là thân của vòng lặp. Do chỉ mang tính chất minh
họa nên tôi để toàn lệnh NOP, các bạn có thể thay thế bằng các lệnh khác. Hiện tại chúng
ta đang ở tại câu lệnh XOR ECX, ECX , nhấn F7 để trace và quan sát giá trị của thanh ghi
ECX .

Lệnh XOR ECX, ECX sẽ xóa thanh ghi ECX về 0 :

Lệnh ADD ECX, 15 tương đương với việc gán ECX = 0x15 :

Nhấn F7 và trace qua lệnh DEC ECX. Giá trị của ECX lúc này sẽ đươc giảm đi 1 (ECX = ECX
-1 = 0x15 – 0x1 = 0x14) :

Tiếp tục thực hiện cho tới khi chúng ta dừng lại tại lệnh TEST ECX, ECX, câu lệnh này sẽ
kiểm tra xem giá trị của ECX đã bằng 0 chưa ? Nếu bằng 0 thì cờ Z sẽ được bật lên. Tuy
nhiên lúc này giá trị ECX đang là 0x14, do đó khi trace qua lệnh TEST thì cờ Z không được
active và vì vậy lệnh JNZ ở bên dưới sẽ nhảy lại về vị trí 0x00401007 (nơi bắt đầu của vòng
lặp)

2
Trace tiếp để thực hiện các lệnh cho tới khi giá trị của thanh ghi ECX =0x0, lúc này lệnh
TEST kiểm tra thấy giá trị của ECX = 0x0 cho nên nó sẽ active cờ Z. Khi cờ Z được active
nên câu lệnh JNZ sẽ dựa vào cờ Z và đưa ra quyết định sẽ không nhảy về vị trí 0x00401007.

Các bạn sẽ dễ dàng nhận thấy mũi tên tại lệnh JNZ đã chuyển sang màu xám, điều đó có
nghĩa là lệnh nhảy sẽ không được thực hiện. Còn nếu như mũi tên này có màu đỏ như hình
bên trên thì tức là lệnh nhảy sẽ được thực hiện. Do mũi tên đã chuyển sang màu xám cho
nên khi ta tiếp tục trace, chúng ta sẽ thoát ra khỏi vòng lặp và thực hiện các lệnh tiếp theo
bên dưới. ðây chỉ là một ví dụ minh họa rất đơn giản để các bạn hình dùng về vòng lặp,
các cấu trúc lặp như For, While và Repeat các bạn có thể đọc thêm trong các tài liệu về lập
trình ASM.

Lệnh LOOP :

Câu lệnh này thường được sử dụng để thực hiện vòng lặp FOR. Nó có dạng như sau :

LOOP Nhãn

Bộ đếm vòng lặp được khởi tạo trong thanh ghi ECX. Mỗi lần thực hiện lệnh LOOP, thanh
ghi ECX sẽ tự động được giảm đi 1, nếu thanh ghi ECX khác 0 thì điều khiển được chuyển
tới Nhãn (tức là lặp lại lệnh bắt đầu từ vị trí của Nhãn). Nếu ECX = 0, lệnh tiếp theo sau
lệnh LOOP sẽ được thực hiện. Với câu lệnh LOOP này ta có thể thay thế các lệnh đã minh
họa ở mục trước như sau :

3
Như đã nói, vì chỉ mang tính chất minh họa cho nên tôi để toàn lệnh NOP cho đơn giản và
dễ hiểu. Tượng tự như ở trên ta thực hiện lệnh XOR và lệnh ADD để khởi tạo giá trị cho
thanh ghi ECX. Sau đó ta trace cho tới câu lệnh LOOP, giá trị của ECX lúc này đang là 0x15.

Bây giờ ta trace để thực hiện lệnh LOOP, ngay lập tức thanh ghi ECX sẽ được giảm xuống
(trừ đi 1) và quyền điều khiển được chuyển tới Nhãn (địa chỉ 0x401007).

Tiếp tục thực hiện cho tới khi giá trị của thanh ghi ECX được giảm xuống còn 0x1, và trace
tới lệnh LOOP. Lúc này khi ta thực hiện lệnh LOOP, ECX sẽ được giảm xuống là 0x0, quyển
điều khiển sẽ không được chuyển cho Nhãn nữa mà chuyển cho câu lệnh bên dưới lệnh
LOOP.
Ngoài lệnh LOOP trên các bạn có thể tham khảo thêm về các lệnh LOOPE/LOOPZ,
LOOPNE/LOOPNZ trong các tài liệu.

III. Các lệnh liên quan đến chuỗi

Lệnh MOVS :

Câu lệnh này sẽ sao chép nội dung dữ liệu được định địa chỉ bởi DS:ESI đến vùng dữ liệu
được định địa chỉ bởi ES:EDI. Nội dung của chuối gốc không bị thay đổi. Sau khi chuối được
chuyển cả hai thanh ghi ESI và EDI đếu được tự động tăng lên 1 nếu như cờ DF = 0 hay
giảm đi nếu DF = 1.

Nếu DF = 0, ESI và EDI được xử lý theo chiều tăng của các địa chỉ trong bộ nhớ : từ trái
qua phải trong chuỗi. Ngược lại nếu DF = 1, ESI và EDI được xử lý theo chiều giảm dần các
địa chỉ bộ nhớ : từ phải qua trái trong chuỗi.

Lệnh MOVS thường không cần bất kì tham số nào, tuy nhiên khi viết trong Olly chúng ta
phải chỉ rõ ra như sau : MOVS DWORD PTR IS:[EDI], DWORD PTR DS:[ESI]. Lấy một ví dụ
nhỏ để minh họa :

4
Câu lệnh đầu tiên sẽ khời tạo giá trị cho ESI và nội dung dữ liệu sẽ được đọc ra từ đó. EDI
cũng được khởi tạo một giá trị, và tại đó dữ liệu sẽ được copy vào. Chúng ta có thể xem nội
dung tại hai địa chỉ trên bằng cách vào cửa sổ Dump, nhấn Ctrl+G và gõ vào địa chỉ cần
xem nội dung hoặc tại cửa sổ CPU, chuột phải chọn Follow in Dump > Immediate
Constant :

OK vậy là ta đã biết được nội dung của chuỗi gốc và chuối đích (Chuỗi gốc là nơi mà ta đọc
dữ liệu ra và chuỗi đích là nơi mà ta copy dữ liệu vào) Bây giớ nấn F7 để trace qua lệnh
MOVS, quan sát cửa sổ dump ta sẽ thấy được 4bytes của chuối gốc được copy vào chuỗi
đích :

5
Các bạn tự tìm hiểu thêm các lệnh MOVSB và MOVSW.

Lệnh REP :

Không giống như lệnh MOVS chỉ chuyển một doubleword tại địa chỉ DS:(E)SI tới địa chỉ
ES:(E)DI, lệnh REP cho chúng ta chuyển cả chuỗi . ðể chuyển cả chuỗi đầu tiên chúng ta
phải khởi tạo thanh ghi (E)CX với số N bằng số doubleword trong chuỗi nguồn và thực hiện
lệnh như sau :

REP MOVS

Lệnh REP có tác dụng làm cho MOVS đươc thực hiện N lần. Sau mỗi lệnh MOVS thì (E)CX
được giảm đi 1 cho đến khi nó bằng 0. Tôi lấy ví dụ minh họa như sau :

Ta quan sát nội dung tại 0x0040365C , nơi chứa chuỗi gốc :

Trong đoạn code trên, bạn đế ý thấy ECX được khởi tạo giá trị là 4. Vậy tức là sẽ có 4 lần
copy từ chuỗi nguồn vào chuỗi đích, mỗi lần copy một doubleword. Bây giờ ta Trace từ từ
tới lệnh REP :

Các thông tin hiện ra trong Tip Window rất đầy đủ, giờ ta nhấn F7 và quan sát nội dung tại
chuỗi đích, tức là tại 0x0040369C. Tại sao lại nhấn F7 mà không phải là F8, vì nếu các bạn
nhấn F8 lệnh REP MOVS sẽ copy thẳng một mạch toàn bộ 4 doubleword từ chuỗi gốc sang
chuỗi đích,đồng thời thanh ghi ECX sẽ được giảm về 0. Ta sử dụng F7 để quan sát từng lần
copy một :

6
Như quan sát trên hình minh họa, ta thấy 4 bytes đầu tiên được chuyển tới và thanh ghi
ECX lúc này bị giảm đi 1 (ECX = 0x4 -0x1 = 0x3). Thêm vào đó 2 thanh ghi ESI và EDI
được tăng thêm 4 để trỏ vào vị trí tiếp theo :

Tiếp tục nhấn F7 và quan sát :

Cuối cùng nhấn F7 cho tới khi ECX = 0x0, lúc này toàn bộ chuỗi gốc đã được copy sang
chuỗi đích. Rất rõ ràng và dễ hiểu!

Lệnh LODS :

Lệnh LODS nạp vào EAX một double word do ESI chỉ ra trong đoạn DS, sau đó ESI tự động
tăng/ giảm để chỉ vào phần tử tiếp theo tùy theo cờ hướng DF. Ví dụ minh họa :

Trace từ từ đến lệnh LODS và quan sát :

7
Nhấn F7 để thực hiện lệnh LODS, kết quả ta sẽ có được như sau :

Lệnh STOS :

Lệnh này ngược lại với lệnh LODS, có tác dụng chuyển nội dụng của thanh EAX đến vị trí đã
được đĩnh nghĩa bởi ES:EDI. Sau khi thực hiện xong thì EDI tự động tăng/giảm để chỉ vào
phần tử tiếp theo tùy theo cờ hướng. Ví dụ :

Trace tới lệnh STOS và quan sát cửa sổ TIP :

Sau khi thực hiện lệnh STOS, kết quả ta có được như sau :

8
Lệnh CPMS :

Cú pháp : CPMS Chuỗi ñích, Chuỗi gốc


Lệnh này dùng để so sánh nội dung của ESI với nội dung của EDI. Lệnh này chỉ tạo cờ,
không lưu kết quả so sánh, sau khi so sánh các toán hạng không bị thay đổi.

Ta trace tới lệnh CMPS và quan sát :

Về bản chất của lệnh CPMS là lệnh này trừ dw tại địa chỉ DS:ESI cho dw tại địachỉ ES:EDI
và thiếp lập cờ. Nếu kết quả của phép trừ bằng 0x0 thì cờ Z được bật cũng đồng nghĩa hai
chuỗi này giống nhau :

Ok như vậy qua 8 phần có thể nói tôi đã chỉ cho các bạn đã phần nào nắm được các lệnh cơ
bản và quan trọng trong quá trình làm việc với Olly.Các phần tiếp theo của loạt tuts này sẽ
tập trung vào các vấn đề khác, do đó các bạn tự tìm hiểu thêm về các lệnh trong các tài
liệu về lập trình ASM.

Các chế độ địa chỉ

DIRECT (Trực tiếp) :

Trong chế độ địa chỉ trực tiếp, một toán hạng chứa địa chỉ lệch của ô nhớ dùng chứa dữ liệu
còn toán hạng kia chỉ có thể là thanh ghi (không được là ô nhớ). ðây là cách chung được sử
dụng để tham chiếu tới một địa chỉ trong bộ nhớ, một số ví dụ minh họa :

mov dword ptr [00513450], ecx


mov ax, word ptr [00510A25]
mov al, byte ptr [00402811]
CALL 452200
JMP 421000

9
Trong trường hợp này chúng ta sẽ không gặp vấn đề gì trong việc biểu diễn địa chỉ cũng
như biết được nơi mà lệnh nhảy sẽ nhảy tới v..v... Chúng ta chỉ việc chỉ rõ các địa chỉ này
trong các lệnh mov, lệnh jmp và cả lệnh Call.

INDIRECT (Gián tiếp) :

Thường được gọi là chế độ địa chỉ gián tiếp qua thanh ghi, trong chế độ địa chỉ này một
toán hạng là một thanh ghi được sử dụng để chứa địa chỉ lệch của ô nhớ chứa dữ liệu, còn
toán hạng kia chỉ có thể là thanh ghi mà không được là ô nhớ.

mov dword ptr [eax], ecx


CALL EAX
JMP [ebx + 4]

Như các ban thấy với cơ chế đánh địa chỉ như trên chúng ta sẽ gặp khó khăn trong việc xác
định vị trí, không biết được vị trí mà câu lệnh nhảy sẽ nhảy đến, đoạn routine nào sẽ được
gọi bởi lệnh call. Chỉ có sử dụng Olly để debug thì chúng ta mới biết được chính xác thông
qua việc xem xét các giá trị của các thanh ghi.

Rất nhiều chương trình sử dụng cơ chế địa chỉ này để ngăn cản hay hạn chế quá trình phân
tích chương trình của của cracker/reverser. Lấy một ví dụ để dễ hiểu, khi bạn cho Olly phân
tích một chương trình bằng cách load target vào trong Olly, bạn sẽ gặp câu lệnh tương tự
như sau :

PUSH DWORD PTR SS:[EBP+8] ; |hWnd

Nếu như bạn không tiến hành debug chương trình, thì thử hỏi khi bạn nhìn vào lệnh trên
bạn làm cách nào để biết được nội dung gì sẽ được đẩy lên Stack ?

Câu trả lời như sau, để biết được nội dung gì sẽ được đẩy lên Stack bạn có thể debug trong
Olly bằng cách trace từ từ tới câu lệnh trên hoặc đặt một Break point tại câu lệnh này và
thực thi chương trình để chương trình dừng tại chỗ mà chúng ta đã set BP. Qua đó chúng ta
sẽ quan sát được sự thay đổi và giá trị của thanh ghi EBP, dựa vào thông tin thu được ta sẽ
xác định được nôi dung của ô nhớ [EBP + 8].Cụ thể như sau :

Nhấn F9 để run chương trình, ngay lập tức chúng ta sẽ break tại chỗ mà ta vừa set BP.
Quan sát trên cửa sổ Registers, ta thấy được giá trị của EBP là 0x0013FFF0, vậy EBP + 8 sẽ
là 0x0013FFF8. Cửa sổ tip sẽ cho ta biết nội dung tại ô nhớ 0x0013FFF8 là gì :

10
Vậy tóm lại lệnh PUSH [EBP+8] sẽ PUSH nội dung của 0x0013FFF8 lên Stack. Nếu cẩn thận
các bạn có thể vào cứa sổ DUMP, nhấn Ctrl + G, nhập địa chỉ trên vào để quan sát và kiểm
tra :

Giờ ta nhấn F7 để thực hiện lệnh Push, đồng thời quan sát cửa sổ Stack để thấy được kết
qủa :

Okie tôi nghĩ đến đây là đã đủ cho phần 8, bài viết xin được kết thúc tại đây. Trong phần
này tôi có tham khảo thêm một số tài liệu liên quan tới lập trình ASM nhưng có thế không
tránh khỏi những sai sót trong quá trình viết, rất mong các bạn góp ý để tôi chỉnh sửa lại.
Tôi tin là trải qua 8 bài viết vừa qua tôi đã cung cấp cho các bạn những kiến thức cơ bản
nhất để các bạn có thể hiểu và làm việc với Olly. Mặc dù 8 phần này có vẻ hơi nhàm chán
với những ai đã có kinh nghiệm trong lập trình ASM tuy nhiên nó lại là những viên gạch đầu
tiên cho những người mới làm quen. Những phần tiếp theo của loạt tuts này hứa hẹn sẽ
mang đến cho bạn nhiều thông tin bổ ích hơn nữa.Hẹn gặp lại các bạn trong các phần tiếp
theo, By3 By3!! ☺

Best Regards
_[Kienmanowar]_

11
--++--==[ Greatz Thanks To ]==--++--
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina, QHQCrker,
the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN, HacNho, RongChauA,
Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend, and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl v..v.. các
bạn đã đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy ☺

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially haggar),
Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on crackmes.de, thank
to all members of unpack.cn (especially fly and linhanshi). Great thanks to lena151(I
like your tutorials). And finally, thanks to RICARDO NARVAJA and all members on
CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

12
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

Vậy là chúng ta ñã trải qua tám bài viết trong loạt bài viết về OllyDbg, trong tám bài viết này tôi
ñã hoàn thành phần việc ñầu tiên là giới thiệu và giải thích sơ bộ về các lệnh asm thường ñược sử
dụng nhất khi chùng ta làm việc với OllyDbg. Trong các phần tiếp theo tới ñây chúng ta sẽ dần
dần tiếp cận những kiến thức mới mẻ hơn, sẽ có nhiều ñất ñể cho chúng ta tìm tòi, học hỏi và thực
hành. Chúng ta sẽ tìm hiểu dần dần từng phần một một cách chậm rãi, song song với việc ñọc lý
thuyết thì chúng ta sẽ thực hành luôn những gì chúng ta ñã tìm hiểu ñược và tự bổ sung những
mảng mà chúng ta còn khiếm khuyết. Bài viết này tôi sẽ trình bày tới các bạn một số thuật ngữ cơ
bản, cách thức làm việc với các hàm APIs, cách patch thông qua các cờ và cuối cùng là các edit
trực tiếp code của chương trình. N0w….L3t’s G0!!!!!!!!!

II. Thuật ngữ cơ bản, làm việc với APIs và patch thông qua cờ

Trong phần 9 này chúng ta vẫn tiếp tục sử dụng crackme của CRUEHEAD ñể demo, Load
crackme vào trong Olly chúng ta dừng lại tại entrypoint của Crackme. Vậy entrypoint nó là cái gì?
Có khá nhiều câu hỏi của các bạn liên quan ñến nó, tôi không phải là dân lập trình chính gốc nên
tôi hiểu thế nào sẽ giải thích cho các bạn.

Về cơ bản thuật ngữ EntryPoint (EP) ám chỉ ñiểm bắt ñầu của một chương trình nơi mà tại ñó trở
ñi chương trình sẽ ñược thực thi một cách bình thường. Không nên bị nhầm lẫn giữa EP và OEP
(Original Entry Point), OEP là một thuật ngữ khác mà chúng ta sẽ tìm hiểu ở các phần tiếp theo
sau của bộ tuts này. Sau khi chúng ñã open một chương trình trong Olly, ñợi cho quá trình phân
tích kết thúc thì Olly sẽ ñưa chúng ta dừng lại tại EntryPoint của chương trình ñó.
Cụ thể trong trường hợp của chúng ta, crackme này có EP là 0x401000 và Olly cũng ñã chỉ cho
chúng ta thấy sau khi analyze crackme trên nó ñang dừng lại tại EP như hình minh họa mà các bạn
ñã thấy ở trên. Hầu hết tất cả các chương trình (tức là khoảng 99% các trường hợp) khi chúng ta
load nó bằng Olly thì ñều dừng lại tại EP của chương trình ñó, ngoài trừ một số trường hợp ñặc
biệt có sự “can thiệp” khiến cho sau khi load chươn trình vào Olly ta lại không dừng lại tại EP, ñây
cũng là mà thủ thuật ñặc biệt mà chúng ta có thể sẽ có dịp tìm hiểu sau này. Còn trong lúc này nó
mới chỉ là khái niệm mà thôi ☺, chúng ta còn nhiều thời gian ñể mò mẫm lắm!

Tiếp theo là một khái niệm khác nữa mà chúng ta cũng cần xem xét ñến ñó chính là các hàm
Application Programming Interface (APIs) và thư viện DLL.

Lý thuyết cũng như kiến thức về API và DLL các bạn có thể tham khảo quyển PE File Format mà
tôi ñã dịch hoặc các nguồn từ Internet. Theo như hình minh họa ở trên các bạn thấy chỗ khoanh ñỏ
chính là một lời gọi tới hàm API .

CALL LoadIconA

Có thể nói nôm na về API như sau, hệ ñiều hành Windows xây dựng nên một tập hợp rất nhiều các
hàm/thủ tục, những hàm/thủ tục này sẽ giúp bạn thực hiện những công việc mà bạn phải lặp ñi lặp
lại hàng ngày, rất nhàm chán trong quá trình coding. Tập hợp những hàm/thủ tục mà Windows xây
dựng ñược ñặt cho cái tên chung là API, với sự có mặt của API các lập trình viên không phải phí
công sức cho những công việc vốn ñã ñược xây dựng sẵn. Các API này tuy theo nhóm công việc,
mục ñích thực hiện sẽ ñược tập hợp vào trong một file thư viện DLL ñể khi cần ñến người lập
trình chỉ cần tra từ thư viện ñó xem hàm ñó có nằm trong thư viện ñó không, nếu có thì chỉ việc
gọi ra và sử dụng mà thôi.
Nhìn vào hình minh họa ở trên, các bạn thấy Olly ñã chỉ cho ta thấy hàm LoadIconA nằm trong
Dll là User32.dll.

Ta lấy một ví dụ ñơn giản với hàm MessageBoxA như sau, tôi không hề biết hàm này nằm ở thư
viện dll nào và cũng chẳng biết ñịa chỉ của nó là gì? Vậy tôi làm thế nào ñây ñể có ñược thông tin
về hàm này, rất ñơn giản Olly ñã hỗ trợ cho chúng ta khả năng tìm kiếm ñịa chỉ theo tên hàm. Tại
chỗ Command Bar của Olly ta gõ tên hàm vào như sau :
Wow, ngay lập tức Olly tìm cho ta ngay ñịa chỉ của hàm MessageBoxA, bây giờ ta ñi tới ñịa chỉ
này ñể xem hàm mà chúng ta tìm nằm trong thư viện nào. Tại Olly, nhấn chuột phải và chọn Go to
> Expression :

Nhập ñịa chỉ ñã tìm ñược vào textbox và nhấn OK :

Olly sẽ ñưa ta tới ñịa chỉ của hàm MessageBoxA :

Theo như hình trên thì ta thấy ngay rằng hàm MessageBoxA thuộc về thư viện Dll là User32.dll.
Hàm này bắt ñầu tại 0x7e45058a và kết thúc bằng lệnh Retn 10 tại 0x7e4505d0.
Cũng có một cách khác nữa giúp cho chúng ta tìm thấy hàm MessageBoxA, cách tương tự như
trên nhưng thay vì gõ ñịa chỉ hàm thì ta gõ thẳng tên của hàm vào và nhấn OK :

Như bạn thấy ở trên việc tìm ra hàm MessageBoxA có vẻ rất dễ dàng, tuy nhiên không phải lúc
này cũng ñơn giản như thế. Với 2 phương pháp trên bắt buộc bạn phải nhớ chính xác từng chữ cái
cũng như cú pháp chữ hoa chữ thường trong tên hàm ñó. Vậy trong trường hợp ta chỉ nhớ mang
máng tên hàm và không nhớ viết ñúng tên hàm theo ñúng form thì thế nào, Olly ñã hỗ trợ cho ta
một cách khác ñể tìm ñến hàm ñó. Ok, ñể thực hiện, ta quay lại chỗ EP của chương trình (ñơn giản
bằng cách bấm phím ‘–‘ trên bàn phím vì lúc này bạn ñang ở tại ñ/c của MessageBoxA), sau ñó
thực hiện như hình dưới (phím tắt là Ctrl + N) :

Ngay lập tức một loạt các hàm ñược sử dụng trong module hiện tại ñược liệt kê ra như các bạn
thấy ở hình sau :
Nhìn như trên thì rối quá ta không biết phải mò ra MessageBoxA ở ñâu trong một rừng tên như thế
này, ñể tìm kiểm ñược ñúng hàm cần tìm trước tiên tại chính cửa sổ trên ta gõ chữ cái ñầu của tên
hàm mà cụ thể ở ñây là chữ M. Olly sẽ ñưa chúng ta ñến vị trí của những hàm bắt ñầu bằng chữ M

Tiếp tục gõ những chữ cái tiếp theo trong tên hàm Olly sẽ ñưa ta ñến ñúng vị trí cần tìm :
Tại hàm tìm ñược ta nhấn chuột phải và chọn Follow import in Disassembler :

Ok, vậy là chúng ta ñã trải qua một số phương pháp khác nhau ñể tìm kiếm thông tin về một hàm
API, bây giờ chúng ta tiếp tục trở lại với phần tiếp theo của bài viết. Sau khi tìm kiếm ñược thông
tin về hàm MessageBoxA như hình minh họa ở trên, ta tiến hành ñặt một ñiểm ngắt hay còn gọi
với một thuật ngữ là Break Point (BP) . Ta làm như sau :

Việc thiết lập BP như trên cũng tượng tự với cách làm khác như sau, tại cửa sổ Command Bar ta
gõ vào : Bp MessageBoxA
Ok ta vừa mới ñặt BP, giờ ta kiểm tra xem kết quả ta ñặt như thế nào. Chuyển qua cửa số BP bằng
cách nhấn phím tắt (Alt + B) :

Như bạn thấy ở trên, tôi ñã ñặt một BP tại ñịa chỉ bắt ñầu của hàm MessageBoxA, bây giờ khi tôi
cho thực thi crackme này trong Olly nếu như có bất kì một thông báo nào bắn ra thì ta sẽ dừng lại
tại vị trí mà ta ñã ñặt BP. ðể kiểm nghiệm ñiều này, ta tiến hành thực thi crackme bằng cách nhấn
F9 :

Vào menu Help và chọn Register, cửa sổ yêu cầu nhập User Name và Serial hiện ra :

Ta nhập thử Fake info vào những text box, sau ñó nhấn Ok. Ngay lập tức Olly sẽ dừng lại và dừng
ñúng chỗ mà chúng ta ñặt BP :
Vậy ta ñoán ngay lúc ta nhấn Ok sẽ có một thông báo bắn ra, tuy nhiên ta ñã cho Olly bắt hành
ñộng này nên Olly ñã dừng lại tại ñầu hàm. Bây giờ ta chuyển qua cửa sổ Stack ta sẽ có ñược
những thông tin sau :

Theo thông tin mà hình cung cấp các bạn có thể thấy rằng mỗi hàm Api trước khi chuẩn bị ñược
gọi thì các tham số của hàm sẽ ñược ñẩy lên Stack. Các tham số này bạn có thể tham khảo tại file
Help là Win32.hlp. Ok giờ tại cửa sổ Stack ta chọn như sau :

Ta sẽ quay lại cửa sổ code của chương trình và dừng tại vị trí sau :
Theo như lý thuyết về hai lệnh CALL và RET mà tôi ñã giới thiệu ở phần trước thì chúng ta sẽ
không ngạc nhiên lắm khi ta Follow theo ñịa chỉ trên thì Olly lại ñưa ta ñến lệnh Ret mà không
phải là lệnh Call.

Ok vậy là như các bạn ñã thấy, khi thông tin về User name và Serial mà chúng ta nhập vào không
ñúng thì chúng ta sẽ nhận ñược một thông báo với nội dung như sau :

004013AD |. 6A 30 push 30 ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL


004013AF |. 68 60214000 push 00402160 ; |Title = "No luck!"
004013B4 |. 68 69214000 push 00402169 ; |Text = "No luck there, mate!"
004013B9 |. FF75 08 push dword ptr [ebp+8] ; |hOwner
004013BC |. E8 79000000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA

Giờ ta quay trở lại chỗ ñặt BP ñể kiểm chứng thông tin mà ta vừa nói ở trên.

Ta ñặt một BP tại lệnh Ret 10 :

Sau ñó nhấn F9 ñể thực thi chương trình, chúng ta nhận ñược thông báo xong :
Khà khà ñúng như thông tin mà ta có ñược ở trên, giờ ta nhấn OK ngay lập tức sẽ dừng lại tại lệnh
Ret 10 :

Lệnh Ret 10 này cho ta biết ta ñang ở ñiểm kết thúc của hàm API MessageBoxA, khi lệnh này
ñược thực thì thi ta sẽ quay trở lại ñoạn code chính của chương trình. Nhưng trước khi thực hiện
lệnh này, ta nhìn qua cửa sổ Stack sẽ có ñược thông tin ñịa chỉ mà khi thực hiện lệnh Ret 10 ta sẽ
quay về ñó :

ðịa chỉ mà tôi khoanh ñỏ ở trên chính là ñịa chỉ của lệnh bên dưới lời gọi tới hàm MessageBoxA.
Ta nhấn F7 ñể trace qua lệnh Retn 10, khi ñó ta sẽ trở về ñịa chỉ 0x004013C1 nhưng ñồng
thời khi ta thực hiện lệnh này thì thanh ghi Esp cũng tự ñộng ñược cộng thêm 0x10 vào, tức là
ESP =ESP + 0x10 = 0x0013FE90 + 0x10 = 0x0013FEA0. Ok, sau khi nhấn F7
như ñã nói ta sẽ tới ñây :

ðể ý cửa sổ Stack :

Như hình trên ta ñang ở 0x004013C1, bên trên nó là một lời gọi tới hàm MessageBoxA, hình
này cho chúng ta biết ñược chúng ta ñã nhập thông tin về Name và Serial bị sai cho nên thông báo
“No luck…” sẽ bắn ra!! Bây giờ ta tiếp tục nhấn F9 thêm một lần nữa :
Bùm…ta lại break tại MessageBoxA, tiếp tục dòm qua cửa sổ Stack :

Chuột phải tại dòng ñầu tiên và chọn Follow in Disassembler :

Olly ñưa ta ñến ñịa chỉ 0x0040137D, bên trên tại 0x00401378 tiếp tục là một lời gọi tới hàm
MessageBoxA :

Như vậy, tổng kết lại chúng ta thấy rằng có hai ñoạn code ñều Show ra cái Nag là “No luck…”,
vậy ta phỏng ñoán rằng vậy chúng ta sẽ có hai ñoạn check liên quan ñển UserName và Serial nhập
vào. Có thể cái Nag ñầu tiên mà chúng ta nhận là cái Nag liên quan tới việc Check Name, còn cái
Nag tiếp theo mà chúng ta thấy ở trên hình là cái Nag liên quan ñến check Serial . Chà chà có vẻ
mệt ñây!!

Tại vị trí trên, dịch lên một chút bạn sẽ thấy có thêm một lời gọi tới hàm MessageBoxA nữa :

Hình trên sẽ cho ta biết có 2 Nag liên quan ñến việc nhập Serial, nếu ta nhập ñúng thì hiện thông
báo ở chỗ ñược tô vàng, nếu nhập sai thì sẽ hiện thông báo ở chỗ ñược tô xanh. ðể ý trong hình
trên ta thấy ñược có dấu ‘$’, dấu này thông báo cho chúng ta biết ta ñang ở trong thân của một lời
gọi hàm/thủ tục, vậy ñể biết ñược lời gọi này xuất phát ở ñâu chúng ta chỉ việc chọn dòng có chứa
dấu $ và nhìn xuống cửa sổ bên dưới :

Vậy là Olly ñã giúp chúng ta biết ñược ñịa chỉ nơi mà có lời gọi gọi tới ñoạn code trên ñó chính là
tại 0x00401245, nhấn chuột phải tại dòng tô màu xanh ở trên và chọn Go to Call from
00401245 :
Hmm, có vẻ như chúng ta ñang ñứng tại vị trí chứa ñoạn code so sánh. Vậy ta lập luận như sau,
nếu kết quả so sánh là ñúng thì chúng ta sẽ nhảy tới ñịa chỉ 0x0040124C và thực hiện lời gọi
hàm tại ñịa chỉ này, mà theo hình trên thì lời gọi này sẽ hiện thông báo “Greate work…”, còn
ngược lại nếu kết quả so sánh là sai thì ta sẽ ñi tới lời gọi tại 0x00101245 và thực hiện lời gọi
hàm hiện thông báo “No luck …” . Ta ñặt thử một BP tại lệnh JE :

Xóa hết các BP liên quan ñến API MessageBoxA ñi, mở cửa sổ Break Point (Alt + B) :

Ta loại bỏ hai BP mà ta ñặt tại Module User32 ñi chỉ ñể lại BP mà ta ñặt tại lệnh JE, ñể loại bỏ
một BP thì chỉ việc nhấn chuột phải tại BP ñó và chọn Remove hoặc nhấn phím tắt Del.

Sau khi remove BP chỉ ñể lại một BP duy nhất như hình trên, ta nhấn F9 ñể thực thi chương trình.
Lúc này cái Nag “No luck…” sẽ xuất hiện, lý do là vì lúc trước ta set BP tại MessageBoxA nhưng
ta vừa bỏ ñi rồi nên nhận cái Nag ñó là ñúng thôi ☺. Nhấn Ok, sau ñó tiến hành nhập lại thông tin
về Name và Serial, lần này ta nhập thử một cái name khác thử xem :
Nhấn OK, ta sẽ dừng lại tại BP. Oh… như vậy kết luận sơ bộ ban ñầu của tôi về việc crackme này
có tới hai chỗ check liên quan tới Name và Serial là ñúng. Vì nếu như bạn nhập Name như tôi
nhập lần ñầu ở trên thì khi chúng ta nhấn Ok chúng ta sẽ nhận Nag “No luck…” trước khi chúng ta
break tại ñiểm ñặt BP. Sau khi chúng ta nhấn Ok tại Nag thì chúng ta mới dừng lại tại BP mà ta ñã
set :

Chúng ta thấy rằng dựa theo kết quả so sánh ở lệnh CMP, nếu như giá trị của eax không bằng giá
trị của ebx thì lệnh nhảy sẽ không ñược thực hiện. Khi lệnh nhảy không ñược thực hiện thì lệnh
Call bên dưới nó tại ñịa chỉ 0x00401245 sẽ ñược thực hiện tiếp theo, và chúng ta biết rằng lệnh
CALL 401362 chính là hàm show ra Nag là “No luck..”, nếu như bạn không nhớ thì bạn chọn
lệnh Call ñó và nhấn Enter ñể Follow :

Như chúng ta thấy lệnh JE không ñược thực hiện vì Serial mà chúng ta nhập vào là sai. Ngoài ra ta
biết rằng lệnh nhảy JE này phụ thuộc vào cờ Z, vậy muốn cho lệnh này thực hiện thì ta có một
mẹo nhỏ là thay ñổi giá trị của cờ bằng cách nhấp ñúp vào cờ Z :
Theo hình trên thì cờ Z ñã chuyển thành 1, ñiều này ñồng nghĩa với việc là giá trị của thanh ghi
eax bằng giá trị của thanh ghi ebx, cũng ñồng nghĩa với nếu như thực hiện lệnh Cmp thì lệnh này
sẽ thực hiện phép trừ hai toán hạng bằng nhau cho ra kết quả là 0. Mà khi kết quả bằng 0 thì cờ Z
ñược bật lên ☺ và chúng ta cùng “nhảy” lolz … như hình minh họa dưới ñây :

Vậy là nếu ta nhấn F8 ñể trace thì lệnh JE sẽ ñưa chúng ta tới lệnh tiếp theo tại ñịa chỉ
0x0040124C. Ta biết rằng lệnh Call tại ñịa chỉ này chính là show Nag “Great work …” , nếu bạn
không nhớ hãy thử Follow tại lệnh Call này bằng cách nhấn Enter :

Nào ta cùng thử xem có ñúng không nhé, nhấn F9 ñể run và bùm :

Vậy tại ñây chúng ta có thể khẳng ñịnh lệnh Cmp eax, ebx chính là lệnh so sánh liên quan ñến
Serial, phụ thuộc vào kết quả ñầu ra tức là (eax = ebx?) mà lệnh nhảy sẽ quyết ñịnh việc show Bad
boy hay Show good boy. Cũng từ ñây ta kết luận crackme này có hai ñoạn check riêng biệt, một
ñoạn liên quan ñến Name và một ñoạn liên quan ñến Serial. Vì nếu chúng ta nhập Name mà trong
Name nhập vào có số thì chúng ta sẽ nhận Nag luôn. Ok ta kiểm tra thử nhé :
Nhấn Ok ñể xác nhận thông tin nhập vào và …:

Ta nhấn Ok một lần nữa và lần này ta mới dừng lại tại BP mà ta ñã thiết lập ở trên :

Nếu như ta bypass nột ñoạn check trên thì mới vượt qua ñược Nag cuối cùng của Crackme này,
tức là khúc này sẽ check serial, ñúng thì sẽ hiện “Greate work…” mà sai thì tiếp tục hiện “No
luck..”. Ok, giờ ta quay lại khúc mà ta break khi ta ñặt BP tại hàm api MessageBoxA :
Quan sát ta thấy ñịa chỉ trở về là 0x004013C1, follow theo ñịa chỉ này

Tại ñây, chúng ta thấy rằng Olly chỉ cho ta biết ñoạn routine này bắt ñầu từ 0x0040137E và kết
thúc tại 0x004013C1. ðể ý một chút chúng ta cũng thấy rằng tại ñịa chỉ 0x004013AC có một
dấu “>”. Kí hiệu này sẽ chỉ cho ta biết lệnh nhảy ở vị trí nào nhảy tới nó, ñể biết chi tiết ta chỉ việc
chọn vị trí có dấu trên và quan sát cửa sổ Tip Window :
Lại một lần nữa chúng ta ñể ý thấy rằng có một lệnh so sánh và một lệnh nhảy phụ thuộc vào kết
quả so sánh, vậy ta ñặt một BP tại lệnh nhảy tại ñịa chỉ 0x0040138B :

Ok nhấn F9 ñể run chương trình và nhập thông tin như lúc trước ta nhập :

Sau ñó nhấn Ok, ta sẽ break tại chỗ ta vừa set BP :

Sau khi break, ta quan sát thấy rằng lần ñầu tiên break lệnh nhảy này sẽ không nhảy. Lý do là vì nó
sẽ kiểm tra dần dần từng kí tự của chuỗi Name ta nhập vào, nếu có chứa chữ số thì nó mới nhảy.
Giờ ta nhấn F9 thêm 4 lần nữa lúc này ta quan sát thấy rằng nó kiểm tra ñến kí tự thứ 5, vị trí này
chính là số “4” cho nên lệnh nhảy sẽ ñược thực thi :

Quan sát các giá trị của các cờ ta thấy rằng cờ C ñược bật lên :
Chọn giá trị của cờ C và nhấn ñúp ñể set về giá trị 0, quan sát sang cửa sổ CPU ta thấy lệnh nhảy
không còn hiệu lực nữa :

Ta tiếp tục nhấn F9 và bypass tương tự cho hai số tiếp theo. Sau khi vượt qua ñoạn check này
chúng ta sẽ break tại ñây :

Tiếp tục sử dụng tiểu xảo ñể active lệnh nhảy bằng cách nhấp ñúp chuột tại cờ Z ☺ :
Cuối cùng ta nhấn F9 thêm một lần nữa và lần này là những gì chúng ta mong ñợi :

Như các bạn thấy răng ñể ñến ñược cái thông báo Greate work như trên chúng ta ñã thực hiện bằng
cách thay ñổi các cờ, tuy nhiên các bạn biết rằng các cờ này thay ñổi liên tục do ñó ta không có
cách nào ñể lưu lại những gì chúng ta làm ñược. Vì vây, ñể có thể ép chương trình của chúng ta
chấp nhận bất kì username và serial nào mà chúng ta nhập vào thì ta buộc phải thay ñổi code của
chương trình!! Ta sẽ làm như thế nào?

III. Patch bằng cách sửa code

ðầu tiên ta xử lý cái lệnh nhảy ở chỗ check liên quan ñến Name nhập vào ñể nó chấp nhận trong
Name có số :

Hehe giờ ta sẽ không thay ñổi cờ nữa mà edit lại code luôn, tại ñịa chỉ 0x0040138B chứa lệnh
nhảy ta nhấn phím Space bar :

Thay bằng lệnh NOP :


Sau ñó nhần Assemble ta có kết quả như sau :

Ok như vậy chúng ta ñã loại bỏ ñược lệnh nhảy này, giờ ta nhấn F2 ñể bỏ việc thiết lập BP tại vị
trí trên :

Tiếp theo ta ñi tới chỗ lệnh nhảy tại chỗ kiểm tra Serial :

Tại ñây ta cũng không cần tác ñộng cờ Z ñể active lệnh nhảy nữa. Ta nhấn Space Bar và thay bằng
lệnh sau :

Thay bằng jmp tức là ta ép cho nó luôn nhảy dù có ñúng hay sai ñi nữa, ok sau khi edit ta bỏ BP
tại vị trí trên. Nhấn F9 ñể run và kiểm tra kết quả :
Chọn Ok và khà khà :

Như các bạn thấy vừa rồi tôi ñã hướng dẫn các bạn cách edit lệnh trực tiếp trong Olly, nhưng nếu
chúng ta restart chương trình thì những thay ñổi này sẽ không còn tác dụng có nghĩa là nó ko lưu
lại những gì ta ñã làm. Vậy ñể lưu các thay ñổi vừa rồi trước khi ñóng Olly bạn làm như sau :

Nhấn chuột phải sau ñó chọn Copy to executable > All modifications , một cửa sổ bật ra :
Ta chọn Copy all ñể lưu lại toàn bộ những gì ta ñã thay ñổi :

Một cửa sổ khác bật ra như trên, tại ñây chúng ta nhấn chuột phải và chọn : Save file
ðặt cho file mà chúng ta Save dưới một tên mới, ví dụ Crackme_fixed.exe và chọn Save. ðóng
Olly lại và test thử kết quả bằng cách run file mới :

Nhập thông tin ñể ñăng kí :


Nhấn Ok ☺ :

Khà khà vậy là file mới mà ta vừa save hoạt ñộng rất tốt!! Quá khỏe, giờ ta nhập loạn tùng phèo nó
cũng nói là “Greate work …”

Phụ lục

Phần phục lục này ta tìm hiểu thêm một cách ñặt BP ñể dò ra tử huyệt, ñầu tiên load crackme vào
Olly và nhấn Ctrl + N. Tìm ñến hàm MessageBoxA, nhấn chuột phải và chọn như sau :

Cửa sổ References sẽ xuất hiện :


Nhấn chuột phải tại vị trí bất kì và chọn :

Sau khi ñã ñặt BP như trên, tiến hành nhấn F9 ñể run crackme và nhập thông tin :

Sau ñó nhần Ok, ta sẽ break tại ñây :

Khà khà vậy là ñúng chỗ ta cần tìm rồi nhé, chỉ việc lần theo lệnh Retn là ta biết ñược nơi sẽ gọi
tới ñoạn code này. Lúc này ta làm tương tự như những gì mà tôi ñã viết ở trên.
Ok vậy là phần 9 của loạt tuts về Ollydbg ñến ñây là kết thúc, bài viết này ñã hướng dẫn sơ bộ các
cách cơ bản ñể bạn tìm một hàm API, cách thiết lập BP, cách edit các cờ và hơn cả là patch
chương trình bằng cách edit code.ðây mới chỉ là những gì cơ bản nhất thôi, phía trước còn nhiều
ñiều thú vị lắm. Hi vọng trong thời gian tới tôi sẽ gặp lại các bạn trong các phần tiếp theo, By3
By3!! ☺

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina,
QHQCrker, the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN,
HacNho, RongChauA, Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend,
and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl,
moth, XIANUA, nhc1987, 0xdie v..v.. các bạn đã đóng góp rất nhiều cho REA. Hi
vọng các bạn sẽ tiếp tục phát huy ☺

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially
haggar), Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on
crackmes.de, thank to all members of unpack.cn (especially fly and linhanshi).
Great thanks to lena151(I like your tutorials). And finally, thanks to RICARDO
NARVAJA and all members on CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

Chào các bạn, các bạn còn nhớ loạt tuts này chứ….Kể từ lúc hoàn thành xong phần 9 tôi khá bận
với dự án cho nên chưa tập trung vào để dịch và viết tiếp các phần tiếp theo được. Lý do một phần
cũng là bởi tôi ngại đọc và trans từ TBN của English quá, vì khi trans chỉ là word by word cho nên
lắm khi phải nhìn vào cái tut bằng tiếng TBN để hiểu xem ý nó là gì và mình viết lại theo cách của
mình, thêm nữa tôi cũng lười viết lách . Trong phần 9 các bạn đã được làm quen với các phương
pháp cơ bản để tìm một hàm API, cách đặt BP, cách edit các cờ và cuối cùng là patch chương trình
bằng cách edit code. Ở phần 10 này sẽ đi sâu hơn một chút về quá trình làm việc với BreakPoint
trong OllyDbg, việc hiểu rõ quá trình cũng như cách thức đặt BreakPoints sẽ giúp đỡ chúng ta rất
nhiều trong việc dừng sự thực thi của một chương trình tại nơi mà chúng ta mong muốn. Thêm vào
đó chúng ta cũng tìm hiều thêm về một số cách đặt Breakpoint, target trong phần này vẫn là
Crackme mà các bạn làm việc từ đầu đến giờ, điều thú vị đang nằm ở phía trước…. N0w….L3t’s
G0!!!!!!!!!

II. BreakPoints in OllyDbg

1.Common Breakpoint or BPX :

Đây có thể nói là phương pháp đặt breakpoint phổ biến mà chúng ta đã làm việc ngay từ các phần
trước của bộ tuts này, nó còn được gọi là BPX bởi vì nó có nhiều điểm tương đồng với lệnh BPX
của SoftIce (ai đã từng dùng qua SoftIce thì chắc là biết còn tôi chỉ đụng SoftIce đúng một lần duy
nhất ), thay vì phải viết dài dòng là BreakPoint thì để tránh rườm rà trong quá trình làm việc
thông qua Command Line, tác giả đã rút gọn lại là BPX, tuy nhiên trong Olly chữ “X” thường
được sử dụng trong việc đặt BP với các hàm API (liên quan tới version của Windows) cho nên tác
giả của Olly đã rút gọn lại và thêm một command khác mà ta hay dùng đó là BP (vừa có thể đặt
BP tại API và address). Thông thường, đối với một câu lệnh nào đó mà chúng ta muốn đặt BPX
lên nó thì đơn giản nhất ta chỉ việc chọn dòng lệnh mà ta muốn và nhấn F2, nếu nhấn F2 một lần
nữa tức là ta remove BP khỏi câu lệnh.

Giải thích như trên có thể khiến các bạn bị rối, tóm lại nếu muốn đặt BP tại một dòng lệnh bất kì
các bạn chỉ cần nhớ là bấm F2 tại dòng lệnh đó. Giờ ta load Crackme vào Olly, chúng ta sẽ dừng
lại tại Entry Point của crackme :

1
Các bạn có thể thấy trên hình minh họa, tại địa chỉ 00401018 khi tôi bấm F2 thì ngay lập tức địa
chỉ này được tô sáng lên bằng màu vàng (của các bạn có thể là màu đỏ hay bất kì màu nào do bạn
cấu hình Olly), điều này có nghĩa là tôi đã đặt BP tại 00401018 |. 0BC0 or eax, eax .
Ngay lúc này, bạn chuyển qua cửa sổ quản lý các Breakpoints bằng cách nhấn chữ B (hoặc vào
Menu: Windows -> BreakPoints) :

Các bạn sẽ thấy BP mà chúng ta vừa đặt đã được liệt kê tại cửa sổ này, ta tìm hiểu qua về cửa sổ
quản lý BreakPoints này một chút :

Chúng ta quan sát thấy tại cột Active thì trạng thái của BP ta đặt luôn là Always điều này có nghĩa
là BP này sẽ luôn được thực thi hay nói cách khác là nó sẽ được kích hoạt khi ta thực thi chương
trình. Khi ta chọn và nhấn chuột phải lên dòng lệnh ta sẽ nhận được một menu ngữ cảnh như sau :

 Remove : loại bỏ breakpoint ra khỏi danh sách các điểm đặt BP mà cửa sổ này quản lý.
 Disable : tạm thời disable bp của chúng ta mà không loại nó khỏi danh sách, khi cần ta lại
active nó lên.
 Edit Condition : khi chọn chức năng này là ta đang muốn chuyển đổi bp của chúng ta sang
một dạng khác là conditional bp, kiểu đặt bp này sẽ được bàn tới ở dưới.
 Follow in Disassembler : Với một danh sách dài các bp thì chúng ta khó có thể nhớ được
nó liên quan tới đoạn code nào, tính năng này cho phép chúng ta tìm tới điểm mà chúng ta
đặt bp tại cửa sổ code.
 Disable all : tương tự như tính năng Disable tuy nhiên có khác là nó sẽ disable hết toàn bộ
các bp có trong cửa sổ Breakpoints.

2
 Copy to clipboard : sao chép thông tin về bp vào clipboard. Khi chọn tính năng này sẽ
xuất hiện thêm một số chức năng con đi kèm.

Ta thử chọn chức năng Copy to Clipboard -> Whole line, tính năng này sẽ copy nguyên dòng mà
chúng ta chỉ định. Còn Whole table sẽ copy toàn bộ tất cả những danh sách bp hiện có trong cửa sổ
Breakpoints. Đây là kết quả khi ta chọn Whole line :

Br3akp0ints, item 0
Address=00401018
Module=CRACKME
Active=Always
Disassembly=or eax, eax

OK, như trên chúng ta đã đặt một bp tại 0x00401018, bây giờ chúng ta cần kiểm tra xem bp mà
chúng ta đặt có hoạt động đúng như chúng ta mong muốn hay không? Nhấn F9 để thực thi chương
trình, ngay lập tức các bạn sẽ thấy ta đã dừng lại tại nơi mà ta đặt bp :

Dòm qua thanh status ta thấy như sau :

Bây giờ chúng ta sẽ tìm hiểu xem điều gì đã thực sự xảy ra? Có sự thay đổi nào không khi ta thiết
lập BP tại lệnh mà chúng ta muốn.Ok, chuột phải tại 0x00401018 và chọn :

3
Quan sát nội dung tại cửa sổ Dump ta có như sau :

So sánh thông tin ở cửa sổ Dump với thông tin ở cửa sổ CPU ta thấy không có gì thay đổi cả, ở
cửa sổ Dump các bạn thấy các bytes 0B C0 tương đương với câu lệnh or eax, eax tại cửa sổ
CPU. Điều này khiến chúng ta không khỏi thắc mắc, nếu như không có sự thay đổi gì thì tại sao
khi tôi run chương trình thì nó lại dừng lại tại điểm mà tôi đặt BP? Để kiểm chứng xem có sự thay
đổi hay không, các bạn hãy restart lại Olly (Ctrl+F2) và chắc chắn rằng chúng ta vẫn đang đặt BP
tại địa chỉ 0x00401018 . Sau khi Restart lại Olly, ta sẽ dừng lại tại EP của chương trình, tiến hành
edit một đoạn code như sau tại EP :

Mục đích của đoạn code này chỉ đơn giản là đọc ra nội dung tại địa chỉ 0x401018 và lưu vào thanh
ghi eax. Để dễ hiểu hơn bạn nhìn vào cửa sổ Tip :

Nhìn vào cửa sổ Dump ta sẽ biết được đây là những bytes gốc ban đầu, chưa bị thay đổi gì.Nhưng
tôi lấy làm ngờ vực , tôi thử nhấn F7 để trace và kết quả là thanh ghi EAX đã có sự thay đổi rất
thú vị :

4
Để ý cửa sổ Dump bạn thấy các bytes vẫn được giữ nguyên như ban đầu, nhưng ở thanh ghi EAX
thì ta lại thấy giá trị đã khác là : 0x0174C0CC. Điều này được giải thích sơ bộ như sau: khi tôi đặt
một BP tại địa chỉ 0x401018 thì Olly sẽ tiến hành thay thế byte đầu tiên mà ở đây là giá trị 0B
bằng một giá trị khác là 0xCC. Nếu như bạn quy đổi byte CC này sang lệnh asm thì nó là int3,
đây là một câu lệnh đặc biệt (nó còn được gọi là Trap to Debugger) nó sẽ gây ra một exception
khi chúng ta cố gắng thực thi chương trình. Các bạn đọc thêm thông tin sau :

“So generally it is complex to set a breakpoint in an arbitrary place of the program. The debugger
should save the current value of the memory location at the specified address, then write the code
0xCC there. Before exiting the debug interrupt, the debugger should return everything to its
former place, and should modify IP saved in the stack so that it points to the beginning of the
restored instruction. (Otherwise, it points to its middle.)”

Hơi lằng nhắng một chút nhưng hi vọng các bạn cũng thấm vào đầu được ít nhiều , ngoài việc
đặt BP thông qua việc chọn câu lệnh và nhấn F2 thì ta còn một cách đặt BP khác nữa như sau, tìm
địa chỉ cần đặt BP và gõ lệnh tại Command Bar plugin :

Giờ ta tìm hiểu một chút về cách đặt BP cho hàm API. Như ở trên tôi đã nói lệnh BPX thường
được sử dụng cho việc đặt BP tại các hàm API của chương trình, thêm nữa nó lại phụ thuộc vào
phiên bản Windows mà bạn đang sử dụng. Đối với những ai sử dụng Windows NT/2000/XP/2003
thì việc đặt BP tại một API function cụ thể rất đơn giản, chỉ việc gõ BP [tên của hàm] trong
Command Bar như sau :

Bạn nhớ gõ đúng chữ hoa chữ thường trong tên hàm nhé!! Trên Windows 98 thì ngược lại, việc
đặt BP tại 1 hàm API cụ thể không được hỗ trợ mà thay vào đó là việc đặt BP tới những nơi có lời
gọi tới hàm API mà chúng ta cần. Ví dụ :

Kết quả ta có được như sau :

5
Vậy là ta đã thấy được sự khác biệt giữa BPX và BP, BPX không thiết lập một breakpoint tại một
địa chỉ cụ thể đã được chỉ định như BP đã làm mà nó chỉ đặt BP tại những câu lệnh tham chiếu tới
địa chỉ đó mà thôi. Lý thuyết phải đi kèm thực tế, các bạn đặt liền một lúc cả BP và BPX tại API
MessageBoxA và quan sát cửa sổ Breakpoints :

Ngoài việc hỗ trợ đặt BP thông qua phím F2 và thông qua command line, Olly còn hỗ trợ cho
chúng ta việc đặt bp thông qua việc nhấn đúp chuột. Để thực hiện việc đặt bp tại một địa chỉ, bạn
chỉ việc chọn cột Hex Dump tại cửa sổ CPU và nhấp đúp chuột lên đó.Nếu nhấp đúp chuột một lần
nữa thì sẽ loại bỏ BP :

Tiếp theo ta sẽ tìm hiểu về Memory BreakPoint.

2.Breakpoints on Memory (Memory Breakpoint) :

Ở phần trên các bạn đã tìm hiểu về việc đặt breakpoint thông qua BP và BPX, tuy nhiên việc đặt
bp này là đối với những câu lệnh hay những opcodes không bị thay đổi trong suốt quá trình thực
thi chương trình. Còn ở phần này chúng ta sẽ tìm hiểu về việc đặt bp trên memory(nơi mà dữ liệu
thường xuyên thay đổi). Tại một thời điểm Olly chỉ cho phép duy nhất một memory breakpoint.
Olly hỗ trợ cho chúng ta hai kiểu đặt bp trên memory là : Breakpoint Memory on access và
Breakpoint memory on write.Vậy hai cách đặt BP này có gì khác nhau :
 BreakPoint Memory on access: Với kiểu đặt bp này lên một vùng nhớ sẽ cho phép chúng
ta dừng sự thực thi của chương trình khi có bất kì một sự thực thi, đọc hay ghi lên vùng
nhớ mà ta đã đặt bp.
 BreakPoint Memory on write: Khác một chút với kiểu đặt bp ở trên, kiểu này cho phép
chúng ta dừng sự thực thi của chương trình khi có bất kì dữ liệu nào được ghi lên vùng nhớ
mà ta đặt bp.

Lý thuyết là như thế , chúng ta sẽ thực hành một chút để hiểu thêm nhé :
Chúng ta đã load crackme vào Olly và đang dừng lại tại EP của crackme.

6
Chuyển xuống cửa sổ Dump và nhấn chuột phải chọn Goto > Expression hay nhấn phím tắt là
Ctrl+G và gõ vào địa chỉ như sau :

Olly sẽ đưa ta tới đây :

Ok chúng ta đã tới vùng nhớ để thực hành đặt bp, tôi sẽ tiến hành đặt một bp là Memory on access
lên 4 bytes tại 4020CA, sau đó tiến hành thực thi chương trình và hi vọng rằng chương trình sẽ
dừng quá trình thực thi lại nếu như có một đoạn code nào đó đọc 4 bytes tại 4020CA, hoặc ghi vào
4 bytes tại 4020CA hay thực thi lệnh tại 4020CA. Để đặt bp tại 4 bytes tôi làm như sau, dùng chuột
bôi đen 4 bytes :

Tiếp theo nhấn chuột phải và chọn như hình :

7
Một điểm đáng lưu ý là không giống như việc đặt với lệnh BP hay BPX , việc đặt bp tại memory
sẽ không được lưu giữ thông tin tại cửa sổ Breakpoint vì vậy ta phải tự ghi nhớ xem mình đã đặt
ở đâu, nếu chúng ta muốn remove breakpoint đã đặt thì nhấn chuột phải và chọn :

Như đã nói ở trên, Olly chỉ cho phép tại một thời điểm có một memory bp duy nhất, nếu bạn đặt
một bp khác thì bp đã đặt trước đó sẽ tự động bị loại bỏ . Ok, sau khi đã đặt bp theo hướng dẫn
như trên, các bạn cho thực thi chương trình bằng cách nhấn F9,chương trình ngay sau đó sẽ dừng
lại tại đoạn code bên dưới EP chút xíu :

Thông tin ở Status Bar đã cho chúng ta biết được tại sao Olly lại break, đó là bởi vì câu lệnh tại địa
chỉ 0x00401007 chuẩn bị ghi giá trị của thanh ghi eax vào nội dung của địa chỉ 4020CA, việc này

8
sẽ gây ra một exceptions khiến cho dừng sự thực thi của chương trình.Giờ ta nhìn qua cửa sổ
Register để xem giá trị của eax là gì :

Ta nhấn F7 để trace qua đoạn code mov dword ptr [4020CA], eax và quan sát giá trị tại
của sổ dump :

Như vậy là giá trị 0x00400000 được lưu giữ tại [4020CA], tiếp tục một lần nữa ta nhấn F9 để thực
thi chương trình để xem chuyện gì sẽ xảy ra :

Chà, một lần nữa Olly lại break và lần này là tại 0x401045, nhìn xuống thanh Status Bar ta thấy
được lý do tại sao lại dừng sự thực thi của chương trình. Đó chính là do đoạn code tại 0x401045
đang cố gắng đọc nội dung tại 4020CA và lưu vào thanh ghi eax. Nội dung tại 4020CA là gì thì ta đã
biết ở trên, giờ ta nhấn F7 để trace và quan sát thanh ghi eax :

9
Giá trị 0x400000 lại được đưa trả về cho thanh ghi eax. Lại tiếp tục nhấn F9 thêm lần nữa :

Như vậy là các bạn đã hiểu về Memory on Access và cách thức để có thể đặt một bp Memory on
access rồi nhé. Việc đặt bp Memory on Write cũng tương tự như những gì tôi đã làm ở trên, các
bạn tự thực hành để rút ra kết luận nhé.
Ngoài việc đặt bp như trên, Olly còn cho phép chúng ta đặt Memory bp lên các section của file. Để
thực hiện được điều này các bạn mở cửa sổ Window -> Memory map hoặc nhấn phím tắt là Alt +
M:

Ta chọn đại lấy một section để làm ví dụ, ở đây để đơn giản tôi chọn section CODE và đặt một
Memory bp lên nó. Chỉ việc chọn section, nhấn chuột phải và chọn như hình dưới đây để thiết lập
một bp :

10
Sau khi đặt xong bp, nhấn F9 để thực thi chương trình :

Việc quá trình thực thi bị dừng lại là hoàn toàn chính xác, đó là vì ta đang thực thi lệnh tại
[401002]. Giờ ta thử đặt BP lên section của một module khác mà không phải là section của file exe
mà ta đang làm việc, ở đây tôi chọn là kernel32 :

Nhấn F9 để thực thi chương trình, ta không cần remove memory bp đã đặt ở trước đơn giản là vì
khi ta đặt một memory bp khác thì bp trước sẽ bị remove luôn :

11
Nhìn sang cửa sổ Stack ta sẽ biết là ta đang dừng tại hàm API nào :

Như vậy là chương trình đã dừng lại khi thực thi lệnh của kernel32.dll, nhìn ở cửa sổ Stack ở hình
trên và kết hợp với lý thuyết về Stack mà tôi đã giới thiệu qua ở phần trước thì có thể nhận thấy
rằng địa chỉ 0x401007 là địa chỉ trở về của lệnh bên dưới lời gọi hàm Call GetModuleHandleA
tại địa chỉ 0x401002. Thử nhấn chuột phải và chọn Follow in Disassembler để kiểm chứng lại :

Đây là cách nhanh nhất để quay về địa chỉ của lệnh bên dưới, còn một cách khác cũng hay được áp
dụng nữa là khi ta đang dừng tại hàm API như hình mình họa ở trên, ta nhấn chọn Menu Debug >
12
Execute till User code hoặc nhấn phím tắt là Alt+F9. Olly sẽ đưa chúng ta về đúng nơi như
những gì ta vừa mới thực hiện ở trên (tuy nhiên chú ý là phải bỏ Bp trên memory trước rồi mới
thực hiện nhấn Alt+F9) :

Mở rộng vấn để ra một chút, ở phần trước tôi đã thực hiện việc phân tích sơ bộ chương trình và
các bạn cũng đã biết rằng khi chúng ta nhập sai thông tin về UserName và Serial thì ta sẽ nhận
được một thông báo lỗi. Bây giờ tôi muốn đặt BP tại hàm MessageBoxA (vd: Bp MessageBoxA),
nhưng vì một lý do nào đó chương trình sử dụng cơ chế anti-bp và phát hiện ra rằng có CC (tức
int3) được sử dụng ngay lập tức nó sẽ terminate Olly của ta. Vậy không lẽ ta phải chịu vậy sao và
không thể đặt bp tại API MessageBoxA. Xin thưa với các bạn, đến lúc này việc đặt Memory Bp
mới có tác dụng và hiệu quả. Để tìm địa chỉ của hàm MessageBoxA tôi làm như sau trong Olly :

Vậy là địa chỉ hàm MessageBoxA của tôi là ở 0x7E45058A (trên máy các bạn có thể khác), lúc
này tôi chỉ việc qua cửa sổ CPU và nhấn Ctrl+G, gõ địa chỉ này vào hoặc thay vào đó tôi gõ trực
tiếp tên hàm vào và nhấn Ok, Olly sẽ đưa tôi đến đúng nơi cần tìm :

13
Bây giờ việc đặt bp hết sức đơn giản, thực hiện như hình minh họa dưới đây :

Giờ ta test thử xem việc đặt bp có hoạt động đúng như ta mong đợi không nhé. Nhấn F9 để run
chương trình, sau đó nhập fake info gì là tùy bạn :

Nhẹ nhàng bấm OK xem thế nào  :

14
Khà khà Olly đã break đúng chỗ rồi, quan sát cửa sổ Stack :

Giờ tôi muốn quay trở về code chính của chương trình thì thế nào nhỉ? Quá đơn giản, bạn remove
memory bp đi và nhấn Alt+F9, chương trình sẽ thực thi và show nag. Ta nhấn Ok để chấp nhận,
sau đó Olly sẽ đưa chúng ta tới đây :

Ok vậy là phần 10 của loạt tuts về Ollydbg đến đây là kết thúc, qua bài viết này tôi đã giới thiệu sơ
qua về cách thiết lập BP, các thao tác thông qua command bar để đặt các bp với các lệnh BP và
BPX, cung cấp thông tin về việc đặt memory bp và cách xử lý để có thể đặt bp nếu như chương
trình sử dụng cơ chế anti-bp. Trong vài viết tiếp theo về loạt tuts này hi vọng tôi sẽ cùng các bạn
khám phá thêm về Hardware BP, Message breakpoint và Conditional breakpoint …. chắc sẽ có
nhiều điều thú vị lắm.Hẹn gặp lại các bạn trong các phần tiếp theo, By3 By3!! 

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina,
QHQCrker, the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN,
HacNho, RongChauA, Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend,
and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl,
moth, XIANUA, nhc1987, 0xdie, Unregistered!, akira v..v.. các bạn đã đóng góp rất
nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy 

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially
haggar), Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on
crackmes.de, thank to all members of unpack.cn (especially fly and linhanshi).

15
Great thanks to lena151(I like your tutorials).Thanx to Orthodox, kanxue, TiGa and
finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

16
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

Chào các bạn, chúng ta lại gặp nhau trong phần 11 của loạt bài viết về OllyDbg. Lần trước, khi
release phần 10 trên hai site : REA(reaonline.net) và HVA(hvaonline.net) nhận thấy lượng
download rất nhiều, chứng tỏ rằng các bài viết của tôi vẫn được các bạn quan tâm và ủng hộ. Đó
chính là nguồn động viên lớn cho tôi để tôi tiếp tục viết tiếp các phần tiếp theo.Tiện đây tôi cũng
xin lan man một chút, trước đây tôi cũng đã từng có một thời gian tham gia việc training và được
quen biết với những đồng nghiệp mà sau này vẫn là những anh em tốt của tôi, lúc đó mặc dù công
việc của chúng tôi là giảng dạy kiến thức cho người khác nhưng người sếp (người anh cả của
chúng tôi) đã định hướng cho chúng tôi rằng: “Chúng ta đứng trên bục giảng không có nghĩa
chúng ta tự coi mình là thầy của người khác, không có nghĩa chúng ta là người hiểu biết hơn
những người đang ngồi nghe chúng ta nói, mà chúng ta chỉ là những người truyền đạt lại những
kiến thức mà chúng ta biết, khơi gợi cho học viên khả năng tự tìm tòi và tự nghiên cứu.Quan hệ
giữa học viên và giảng viên là quan hệ hoàn toàn bình đẳng, mọi vấn đề được đem ra trao đổi
thẳng thắn theo phương pháp phản biện như thế mới tạo tâm lý thoải mái cho người học, khiến
cho buổi học không phải là nơi truyền đạt kiến thức theo kiểu một chiều như những gì chúng ta
thấy trên các trường lớp ở Việt Nam”.
Qua loạt tuts này cũng vậy, kiến thức tôi truyền tải cho các bạn chưa chắc đã đúng 100%, đó chỉ là
những gì cá nhân tôi tích lũy được và truyền tải lại cho các bạn, cho nên nếu trong quá trình các
bạn đọc thấy có những kiến thức nào tôi viết sai hoặc chưa đúng thì cứ góp ý thẳng thắn, vì như
thế mới chứng tỏ các bạn thật sự quan tâm tới bộ tài liệu này. Ở phần trước tôi đã giới thiệu sơ qua
về cách thiết lập BP, các thao tác thông qua command bar để đặt các bp với các lệnh BP và BPX,
cung cấp thông tin về việc đặt memory bp và cách xử lý để có thể đặt bp nếu như chương trình sử
dụng cơ chế anti-bp. Trong phần 11 này các bạn sẽ tìm hiểu thêm về các dạng Break Points khác
như Hardware Breakpoints, Conditional và Message BreakPoints, những điều thú vị đang nằm
ở phía trước…. N0w….L3t’s G0!!!!!!!!!

II. BreakPoints in OllyDbg

1.Hardware Breakpoints :

Hardware Breakpoint là gì nhỉ? Tự nhiên nếu có ai hỏi tôi một câu hỏi như vậy chắc tôi cũng
không biết phải giải thích thế nào. Ngay cả trong bài viết của lão làng Ricardo Navarja cũng không
giải thích chi tiết về nó. Vậy là phải tự mình tìm hiểu rồi, đọc trong help file của Olly thì chỉ nhận
được một chút thông tin như sau :

Hardware breakpoint (available only when running Debugger under Windows ME, NT, 2000 or
XP). 80x86-compatible processors allow you to set 4 hardware breakpoints. Unlike memory

1
breakpoint, hardware breakpoints do not slow down the execution speed, but cover only up to 4
bytes. OllyDbg can use hardware breakpoints instead of INT3 when stepping or tracing through
the code.

Điều đầu tiên ta thu thập được qua đoạn này là Hardware breakpoint (viết tắt HWBP) không thể sử
dụng được nếu như bạn dùng Olly trên môi trường Windows 98. Điều thứ hai là chúng ta được
phép thiết lập tới 4 HWBP, so với Memory BP là quá đã rồi vì như ta đã biết tại một thời điểm
Olly chỉ cho phép có duy nhất một memory bp. Thêm vào đó HWBP không làm châm quá trình
thực thi của chương trình. Điều cuối cùng ta nhận được là HWBP không sử dụng INT3, vậy thì nó
sử dụng lệnh gì để dừng sự thực thi của chương trình?? Chúng ta tiếp tục tìm hiểu thêm vậy . Đi
lòng vòng một hồi tôi cũng có thêm được một chút thông tin: HWBP được hỗ trợ trực tiếp bởi
CPU, sử dụng một số thanh ghi đặc biệt hay còn được gọi là debug registers. Có bốn thanh ghi đó
là : DR0, DR1, DR2, DR3, bốn thanh ghi này sẽ được sử dụng để lưu giữ những địa chỉ mà ta
thiết lập HWBP. Điều kiện của mỗi break points để cho dừng sự thực thi của chương trình lại được
lưu trong một thanh ghi đặc biệt khác là CPU register, đó là thanh ghi DR7. Khi bất kì một điều
kiện nào thỏa mãn (TRUE) thì processor sẽ quăng một exception là INT1 (khà khà vậy là nó dùng
INT1 nhé) và quyền điều khiển lúc này sẽ được trả về cho trình Debug của chúng ta. Có bốn khả
năng để dừng sự thực thi của một chương trình :

1. Khi một câu lệnh được thực thi.


2. Khi nội dung của memory có thay đổi (modified).
3. Khi một ví trí memory được đọc ra hoặc được cập nhật(updated).
4. Khi một input-output port được tham chiếu tới. (cái này tôi cũng chưa tìm hiểu).

Khả năng của tôi cũng chỉ biết giải thích đến như thế, các bạn muốn tìm hiểu thêm vui lòng tìm
đọc các tài liệu khác. Bây giờ là phần thực hành, mở Olly lên và load crackme vào nào :

Ta sẽ thực hành lần lượt với các kiểu HWBP là : HardWare Breakpoint on Execution, HWBP
on Write và HWBP on Access.

Việc đặt HWBP on Execution cũng gần tương tự như cách ta đặt BP thông thường tại một câu
lệnh, chỉ có một điều hơi khác là HWBP không có thay đổi code do đó khiến cho việc phát hiện
HWBP trở nên khó khăn hơn. Mặc dù vậy vẫn có những chương trình có khả năng sử dụng một số
tricks để xóa HWBP, những kĩ thuật như vậy và cách thức chống lại nó chúng ta sẽ tìm hiểu trong
các phần tiếp theo. Bây giờ quay trở lại vấn đề, ta muốn đặt một HWBP tại địa chỉ 0x00401013 thì
làm như thế nào? Câu trả lời cực kì đơn giản, ta chọn địa chỉ đó nhấn chuột phải và chọn như sau :

2
Hoặc một cách khác là thực hiện thông qua command line:

Chà ta đặt HWBP rồi mà chẳng thấy có dấu hiệu gì chứng tỏ là ta đã đặt cả. Có cách gì kiểm
chứng không nhỉ? Xin thưa là có , Olly hỗ trợ cho chúng ta một cửa sổ đặc biệt dùng để quản lý
các HWBP, để mở cửa sổ này bạn làm như sau :

Ta sẽ nhận được một cửa sổ như sau :

3
Không cần giải thích nhiều chắc các bạn cũng hiểu được ý nghĩa từng thành phần của cửa sổ
HWBP. Giờ để tìm tới chỗ ta vừa đặt HWBP ta chỉ việc nhấn vào nút Follow là Olly sẽ di chuyển
vệt sáng tới chỗ ta đặt BP. Bây giờ ta nhấn F9 để thực thi chương trình :

Bùm…Olly đã stop tại chỗ mà ta đặt BP. Ta thấy nó chẳng khác gì với việc ta đặt BP như ở phần
10, giờ ta kiểm chứng xem nó có thay đổi code gì không nhé. Để kiểm chứng ta làm hệt như
những gì tôi đã hướng dẫn các bạn ở phần trước :

Chúng ta edit lại đoạn code như trên, dòm xuống cửa sổ Tip và cửa sổ Dump ta có được thông tin
như sau :

Giờ ta nhấn F7 để trace và quan sát thanh ghi EAX :

4
Ta thấy được gì nào, thanh ghi eax vẫn giữ nguyên giá trị được mov vào mà không thấy có thay
đổi , vậy chứng tỏ một điều HWBP không có change code. Giờ ta kiểm chứng một điều khác
nữa, ở phần trước khi ta restart chương trình thì memory bp cũng theo đó mà mất luôn , vậy
HWBP có như thế không? Thử cái biết liền, ta nhấn Ctrl+F2 để restart chương trình sau đó vào
cửa sổ HWBP để kiểm tra xem còn lưu lại BP không :

Oh vẫn y nguyên nhé!! Giờ ta xóa HWBP này đi, sau đó đặt một HWBP tại MessageBoxA như ta
thực hiện bằng lệnh BPX.

Kiểm tra chắc chắn xem bp đã đặt được chưa :

Chắc các bạn cũng đoán ra được ý đồ vì sao tôi lại đặt HWBP tại MessageBoxA rồi chứ. Đơn
giản, tôi muốn các bạn tự kiểm chứng xem khi ta cho thực thi chương trình, sau đó nhập

5
UserName và Serial vào và nhấn OK thì Olly sẽ dừng lại tại MessageBoxA, tương tự như những
gì ta đã thực hiện ở các phần trước. Các bạn tự thực hành nhé .

Tiếp theo ta tìm hiểu tiếp về HWBP on Write và HWBP on Access. Hai kiểu HWBP này cho
phép thiết lập với Byte, Word, Dword (tương ứng 1, 2 hoặc 4 bytes). Không khó để thực hiện hai
kiểu hwbp này, đơn giản bạn chỉ việc qua cửa sổ Dump, sau đó đánh dấu vùng bytes tương ứng và
đặt BP. Ta thực hành luôn nhé, giờ bạn xóa hết các HWBP đã đặt đi, sau đó chúng ta sẽ thử đặt
HWBP on Access tại địa chỉ 4020CA tại cửa sổ Dump. Ta chuyển qua cửa sổ Dump, nhấn Ctrl+G
và nhập vào :

Ta tới đây :

Giờ ta đánh dấu 4 bytes như hình dưới đây :

Nhấn chuột phải và chọn như sau :

6
Như các bạn nhìn thấy trên hình, vùng mà chúng ta đánh dấu cho phép chúng ta thiết lập HWBP
tại 1 byte hoặc 2 bytes (word). Mặc dù chúng ta đánh dấu chọn 4 bytes nhưng ở đây tùy chọn
Dword không xuất hiện trong danh sách của HWBP on Access. Thực hiện tương tự với byte tiếp
theo và lần này ta chỉ thấy có tùy chọn Byte xuất hiện :

Thử tiếp tục với byte kế tiếp, lần này ta thấy tùy chọn Dword đã xuất hiện :

Quay trở lại vấn đề chính, chúng ta đang muốn giám sát vùng nhớ tại 4020CA khi có bất kì một sự
thực thi, đọc hay ghi lên vùng nhớ mà ta đã đặt bp. Để làm điều này ta đặt HWBP như sau :

Trong cửa sổ quản lý HWBP ta thấy xuất hiện như sau (size bằng 1 tương ứng với 1 byte) :

7
Ok, đặt xong hwbp rồi giờ ta run thử chương trình xem thế nào :

Oh, chúng ta đã dừng lại khi có sự tác động vào vùng nhớ 4020CA. Quan sát Olly các bạn thấy
dòng Hardware breakpoint 1 at…, số “1” ở đây tương ứng với số thứ tự của Hwbp được liệt kê
trong cửa sổ quản lý Hwbp như các bạn thấy ở hình trên. Ngoài ra các bạn để ý là vệt sáng đang
dừng lại tại 0040100C |. 6A 00 push 0 ; /Title = NULL,chứ không dừng lại tại lệnh
tác động vào vùng nhớ [4020CA]: 00401007 |.A3 CA204000 mov dword ptr [4020CA], eax.
Đây là điểm khác biệt giữa Hwbp và Memory Bp, giờ ta quan sát xem nội dung của 4020CA đã
thay đổi như thế nào :

Tương tự, các bạn hãy tự thực hành với cách đặt Hardware Breakpoint on Write. Phần tiếp ta tìm
hiều về Conditional Breakpoint.

2.Conditional Breakpoints :

Conditional Breakpoint là gì? Thử tra help của Olly xem có thông tin gì không, tôi có được như
sau :

Conditional breakpoint (shortcut Shift+F2) is an ordinary INT3 breakpoint with associated


expression. Each time Debugger encounters this breakpoint, it estimates expression and, if result
is non-zero or expression is invalid, stops debugged program. Of course, the overhead caused by
false conditional breakpoint is very high (mostly due to latencies of the operational system). On
PII/450 under Windows NT OllyDbg processes up to 2500 false conditional breakpoints per
second. An important case of conditional breakpoint is break on Windows message (like
WM_PAINT). For this purpose you can use pseudovariable MSG together with proper
interpretation of arguments. If window is active, consider message breakpoint described below.

8
Về mặt khách quan thì nó cũng giống như bp thông thường, tức là nó cũng dùng lệnh Int3 để dừng
sự thực thi của chương trình, thêm nữa Condtional bp cũng được quản lý thông qua cửa sổ
Breakpoints(B). Tuy nhiên, điểm khác biệt nằm ở chỗ điều kiện dừng phải thỏa một điều kiện đã
được thiết lập từ trước (Các biểu thức điều kiện như thế nào mời các bạn đọc thêm Help file, phần
expression được tôi đánh dấu đỏ ở trên) . Điểm quan trọng khác của conditional bp là nó hay được
sử dụng để “tóm” các Windows Message (Ví dụ như: WM_CLOSE, WM_PAINT v..v..). Window
Message là gì, chắc tôi không cần giải thích vì nếu các bạn học về lập trình hay muốn nghiên cứu
RE thì các bạn phải biết về nó . Bây giờ chúng ta xem xét một ví dụ nhỏ để dễ hiểu và dễ hình
dung hơn, chúng ta đang ở tại Entry point của Crackme :

Xóa hết các Hwbp đã đặt trước đó đi. Tiếp theo ta sẽ đặt một Conditional BP tại 0x0040100E, ta
làm như sau :

Hoặc đơn giản hơn ta chọn dòng cần đặt Conditional bp và nhấn phím tắt Shift+F2, một cửa sổ
xuất hiện cho phép ta đặt điều kiện :

Giả sử, tôi muốn dừng sự thực thi của chương trình khi giá trị của thanh ghi eax=0x400000. Tôi
nhập điều kiện như sau :

9
Sau khi nhập điều kiện xong, ngay lập tức ta thấy địa chỉ 0x0040100E được tô sáng thành màu
hồng :

Sau khi đặt xong bp, nhấn F9 để thực thi chương trình và quan sát :

Nhìn sang cửa sổ Registers, ta xem giá trị của EAX lúc này đang là bao nhiêu :

Vậy là ta thấy giá trị của EAX đang là 0x400000, giá trị này thỏa với điều kiện mà ta đã thiết lập
để đặt BP, do đó chương trình dừng lại và quyền điều khiển được trả về cho trình debug. Ta thử
đặt lại Conditional bp nhưng với điều kiện Eax==0x500000 xem thế nào :

Nhấn F9 để run chương trình và quan sát, khà khà lần này chẳng thấy nó Olly break gì cả mà lại
thấy chương trình chạy vù vù. Điều này chứng tỏ điều kiện ta đặt ra không thỏa .

10
3.Conditional Log Breakpoints :

Conditional logging breakpoint (Shift+F4) is a conditional breakpoint with the option to log the
value of some expression or arguments of known function each time the breakpoint is encountered
or when condition is met. For example, you can set logging breakpoint to some window procedure
and list all calls to this procedure, or only identifiers of received WM_COMMAND messages, or
set it to the call to CreateFile and log names of the files opened for read-only access etc. Logging
breakpoints are as fast as conditional, and of course it's much easier to look through several
hundred messages in the log window than to press F9 several hundred times. You can select one of
several predefined interpretations to your expression.

Bp này cũng là một dạng conditional bp tuy nhiên cao cấp hơn một chút. Nó có thêm tùy chọn cho
phép ta lưu “vết” giá trị của biểu thức hoặc các tham sổ của function mỗi khi xảy ra bp hoặc khi
thỏa mãn điều kiện mà ta đặt ra. Những thông tin này được lưu lại trong cửa sổ Log(L) của Olly.
Thực hiện một ví dụ để minh họa, trước tiên chúng ta restart lại Olly cái đã. Sau đó nhấn Ctrl+G
và tìm tới hàm MessageBoxA :

11
Sau khi tới vị trí tương tự như hình trên, ta tiến hành đặt một Conditional Log BP như sau :

Hoặc đơn giản chỉ việc nhấn phím tắt Shift+F4, cửa sổ Conditional Log BP xuất hiện với rất nhiều
tùy chọn :

12
Trong trường hợp này của tôi, tôi không muốn dừng sự thực thi tại hàm MessageBoxA mà đơn
giản tôi chỉ muốn ghi lại các giá trị mà tôi cần quan tâm, tôi đặt diều kiện như sau :

13
Những gì tôi giải thích trên hình minh họa chắc các bạn cũng hiểu phần nào mục đích của việc đặt
BP. Tôi xin nói chi tiết lại như sau, trong phần Expresstion tôi nhập vào là [esp] có nghĩa là tôi
muốn đọc ra nội dung của thanh ghi Esp. Phần Pause program tôi chọn là Nerver, có nghĩa là tôi
không muốn dừng sự thực thi của chương trình lại. Hai thành phần tiếp theo là Log value of
expression và Log function arguments tôi chọn là Always, có nghĩa là tôi muốn ghi lại nội dung
của biểu thức mà cụ thể ở đây là giá trị của thanh ghi esp, đồng thời tôi cũng muốn ghi lạ các tham
số truyền vào cho function mà cụ thể ở đây là hàm MessageBoxA. Giải thích vậy các bạn đã hiểu
chưa . Sau khi thiết lập như trên xong, nhấn Ok ta có được như sau :

Tiếp theo ta chuyển qua cửa sổ Log :

14
Tại cửa sổ Log ta clear hết các thông tin đi để tiện theo dõi :

Clear xong ta nhấn F9 để run chương trình, tiến hành nhập các thông tin mà chương trình yêu cầu :

Sau đó nhấn OK, ta sẽ nhận được Nag thông báo. Lúc này để ý cửa sổ Log ta thấy như sau :

15
Nhìn vào thông tin trên các bạn thấy dòng màu đỏ đầu tiên COND: 0040137D chắc cũng đoán
được đây là giá trị của thanh ghi ESP. Còn các dòng tiếp theo chắc tôi không cần giải thích chắc
các bạn cũng đoán ra đó chính là các tham số truyền vào cho hàm MessageBoxA. Để kiếm chứng
giá trị của thanh ghi ESP bạn có thế nhìn vào cửa sổ Stack :

Giá trị 0x0040137D chính là địa chỉ trở về sau khi thực hiện xong hàm MessageBoxA :

Khà khà mọi thứ đều rõ ràng quá . Tiếp theo chúng ta thử đặt một Conditional Log BP khác xem
thế nào, quay trở lại hàm MessageBoxA và nhấn Shift+F4 để sửa lại như sau :

16
Với Conditional Log bp này tôi thêm điều kiện là [esp]==0x40137D và cho dừng sự thực thi của
chương trình khi thỏa điều kiện đã đặt ra.Sau khi sửa xong nhấn Ok để chấp nhận những thay
đổi.Qua cửa sổ Log và clear hết thông tin cũ. Nhấn F9 để thực thi chương trình và nhập thông tin
theo yêu cầu :

Sau đó nhấn OK, ngay lập tức Olly sẽ break tại chỗ ta đặt BP. Ta chuyển qua cửa sổ Log để quan
sát kết quả thu được :

17
Để ý kĩ ta thấy có khác với lần đặt BP trước là sự thực thi của chương trình đã dừng lại và có thêm
dòng thông báo : Conditional breakpoint at user32.MessageBoxA. Điều đó chứng tỏ là điều kiện
đặt bp đã thỏa cho nên chương trình mới dừng lại. Giờ ta kiểm tra cửa sổ Stack xem giá trị của Esp
bây giờ có đúng là 0x0040137D hay không .

Ok vậy là phần 11 của loạt tuts về Ollydbg đến đây là kết thúc, qua bài viết này tôi đã giới thiệu
cho các bạn biết thêm về hai dạng BP nữa là : Hardware Breakpoints và Conditional
Breakpoints cũng như các cách thiết lập cho hai dạng BP này. Trong phần này tôi vẫn còn nợ các
bạn một loại Breakpoint khác đó là Message Breakpoints, trong bài viết tiếp theo của loạt tuts
này chắc chắn tôi sẽ cùng các bạn khám phá thêm về nó….sẽ có nhiều điều thú vị lắm.Hẹn gặp lại
các bạn trong các phần tiếp theo, By3 By3!! 

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina,
QHQCrker, the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN,
HacNho, RongChauA, Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend,
and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl,
moth, XIANUA, nhc1987, 0xdie, Unregistered!, akira, mranglex v..v.. các bạn đã
đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy 

18
I want to thank Teddy Roggers for his great site, Reversing.be folks(especially
haggar), Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on
crackmes.de, thank to all members of unpack.cn (especially fly and linhanshi).
Great thanks to lena151(I like your tutorials).Thanx to Orthodox, kanxue, TiGa and
finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

19
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

Chào các bạn, trong phần bài viết trước ở phần 11 tôi đã hướng dẫn các bạn tìm hiểu về hai dạng
Break Points là Hardware Breakpoints và Conditional Breakpoints, cũng như các cách thiết lập
cho hai dạng BP này. Lẽ ra trong phần 11 tôi cũng định giới thiệu luôn về dạng Message
BreakPoints, nhưng thiết nghĩ nếu gộp luôn vào trong phần 11 sẽ khiến các bạn quá tải và dẫn
đến “tẩu hỏa” mất . Cho nên tôi cắt riêng phần Message Breakpoints ra và quyết định giới thiệu
về nó trong phần 12 này. Rất nhiều điều thú vị đang nằm ở phía trước…. N0w….L3t’s G0!!!!!!!!!

II. BreakPoints in OllyDbg

1.Message Breakpoints :

Message Breakpoint là gì nhỉ? Sao lại lắm lọai BP đến thế . Khi gặp bất kì những vấn đề nào
mới, trong đầu tôi luôn xuất hiện những câu hỏi liên quan đến vấn đề đó. Sau đó, tôi tìm cách tiếp
cận thông tin để giải quyết cho những câu hỏi của tôi. Trước tiên, tôi chẳng biết Message
Breakoint nó là cái gì, cho nên tôi tra help của Olly trước, hi vọng sẽ tìm ra chút thông tin nào đó
về nó. Đọc trong help file của Olly thì chỉ nhận được một chút thông tin như sau :

Message breakpoint is same as conditional logging except that OllyDbg automatically generates
condition allowing to break on some message (like WM_PAINT) on the entry point to window
procedure. You can set it in the Windows window

Thông tin đầu tiên gợi mở cho tôi là thằng Message breakpoint này gần tương tự như Conditional
Log BP ngoài trừ việc khác ở chỗ Olly hoàn toàn tự động tạo ra các điều kiện cho phép dừng lại
tại các Message. Mà cái Message ở đây chính là các Windows Message. Tôi không phải là dân
chuyên lập trình cho nên tôi tìm hiểu tiếp các thông tin khác trên Net về Windows Message :

“The messages in Windows are used to communicate most of the events, at least in the basic
levels. If you want a window or control (which is a specialized window) does something, you must
send a message to him. If another window wants you do something, then it sends a message to you.
If an event occurs, such as when the user moves the mouse, presses the keyboard, etc… the system
sends a message to the affected window. This window receives the message and acts suitably.”

-Message là một trong những phương tiện giao tiếp quan trọng nhất trong môi trường Windows.
-Lập trình trong Windows chủ yếu là đáp ứng lại những sự kiện.
-Message có thể báo hiệu nhiều sự kiện gây ra bởi người sử dụng, hệ điều hành, hoặc chương trình
khác.

1
-Có hai lọai message: window message và thread message.

Window Message:
-Tất cả các message đều được trữ trong một Message Queue(một nơi trong bộ nhớ). Những
message này sau đó sẽ được luân chuyển giữa các ứng dụng.

Message Loop:
-Bạn có thể gọi những message bằng cách tạo ra một Message Queue.
-Message Loop là một vòng lặp kiểm tra những message trong Message Queue.
-Khi một message được nhận, Message Loop giải quyết nó bằng cách gọi Message Handler (một
hàm được thiết kế để giúp Message Loop xử lý message)<hầu hết công việc lập trình của mình sẽ
tập trung vào đây>
-Message Loop sẽ kết thúc khi nhận được message WM_QUIT (lúc người dùng chọn File/Exit ||
click vào nút Close || bấm Alt+F4)
-Khi bạn tạo cửa sổ (ứng dụng) Windows sẽ tạo cho bạn một Message Handler mặc định. Bạn sẽ
vào đây để sửa chữa giúp ứng dụng phản hồi lại những sự kiện theo ý bạn muốn ->chương trình
của bạn.
-Tất cả những control chuẩn đều như thế. Lấy một button làm ví dụ: khi nó nhận WM_PAINT
message nó sẽ vẽ button; khi bạn click chuột trái lên nó sẽ nhận WM_LBUTTONDOWN message
và nó sẽ vẽ hình button bị nhấn xuống; khi buông chuột ra nó nhận WM_LBUTTONUP message
và sẽ vẽ lại button bình thường.
-Tên của window message thường có dạng WM_ và hàm để xử lý message đó thường có dạng On.
Ví dụ hàm xử lý WM_SIZE message là OnSize.
-Message thường có hai tham số lưu trữ thông tin về sự kiện(32 bit): lParam kiểu LONG và
wParam kiểu WORD. Ví dụ: WM_MOUSEMOVE sẽ trữ tọa độ chuột trong một tham số còn
tham số kia sẽ có cờ hiệu để ghi nhận trạng thái của phím ATL, Shift, CTRL và những nút trên
con chuột.
-Message có thể trả về một giá trị giúp bạn gửi dữ liệu ngược trở về chương trình gửi nó. Ví dụ:
WM_CTLCOLOR message chờ bạn trả về một HBRUSH (khi dùng AppWizard để tạo nhanh ứng
dụng bạn chú ý những hàm có dạng On... và nhận xét những kiểu trả về của nó, bạn sẽ hiểu hơn về
cơ chế liên kết giữa các thành phần ứng dụng với nhau)

Nguồn : http://www.eco-blue.net/index.php?showtopic=571&mode=threaded&pid=2527

Ok, qua những thông tin tổng hợp ở trên tôi chắc rằng tôi và các bạn cũng đã phần nào hiểu được ý
nghĩa và mục đích của Windows Message. Bây giờ chúng ta sẽ cùng nhau làm một ví dụ, như các
bạn đã đọc ở các phần trước, tôi đã hướng dẫn các bạn cách đặt BP tại các hàm APIs để dừng sự
thực thi của chương trình cũng như tìm ra những điểm mấu chốt để patch chương trình. Lần này ta
thực hành như sau : để tìm ra Serial của chương trình chúng ta muốn chương trình dừng sự thực
thi khi chúng ta tiến hành nhập fake Username và Serial và nhấn nút OK, cụ thể hơn có nghĩa là
sau khi ta nhấn nút OK thì chương trình sẽ dừng lại theo đúng mong muốn của ta. Chà nghe có vẻ
phức tạp quá phải không, vậy thì ta load crackme vào OllyDbg cái đã  :

2
Nhưng trước khi thực hiện phương pháp Message BP ta ôn lại phương pháp đặt BP tại APIs cái đã.
Lần này tôi không dùng hàm MessageBoxA nữa mà sẽ dùng hàm GetDlgItemTextA, hàm này có
nhiệm vụ như sau :

The GetDlgItemText function retrieves the title or text associated with a


control in a dialog box.

UINT GetDlgItemText
(
HWND hDlg, // handle of dialog box
int nIDDlgItem, // identifier of control
LPTSTR lpString, // address of buffer for text
int nMaxCount // maximum size of string
);

Mục đích của tôi là, thông qua hàm này tôi tìm ra nơi lưu thông tin mà tôi nhập vào để dùng cho
các quá trình xử lý tiếp theo trong chương trình. Vậy để đặt BP tại hàm GetDlgItemTextA tôi làm
như sau, trước tiên tôi tìm nó cái đã :

Các bạn còn nhớ cách tìm hàm API trong cửa sổ Names mà tôi đã hướng dẫn ở các phần trước
chứ, nếu không nhớ thì các bạn chỉ việc : tại cửa sổ Names gõ đúng tên hàm API cần tìm là Olly sẽ
đưa chúng ta đến đúng hàm ta cần. Tôi có được như sau :

Thực hiện đặt BP tại hàm này như sau :

3
Hoặc đơn giản hơn, tại cửa sổ Command Bar Plug-in ta gõ :

Đặt BP xong, cho thực thi chương trình bằng cách nhấn F9. Sau đó điền thông tin về UserName và
Serial vào :

Nhập xong ta nhấn OK, ngay lập tức Olly sẽ break tại API GetDlgItemTextA mà chúng ta đã đặt
BP ở trên.

4
Đảo mắt qua cửa sổ Stack để xem ta thu được những thông tin gì  :

Wow, như các bạn thấy thông tin các tham số truyền vào cho hàm GetDlgItemTextA là hết sức rõ
ràng, kết hợp với mô tả về hàm này ở trên các bạn sẽ thấy rằng tham số Buffer sẽ là nơi lưu đoạn
text mà chúng ta nhập vào, nhưng lúc này chúng ta chưa biết là vùng Buffer này sẽ lưu Name hay
Serial. Ta phỏng đoán theo thứ tự lần lượt từ trên xuống thì nó sẽ lấy UserName trước. Để xác
định chính xác ta làm như sau, chuột phải tại chỗ Buffer và chọn Follow in Dump hoặc chuyển
qua cửa sổ Dump, nhấn Ctrl + G và nhập vào địa chỉ của vùng Buffer là 0x0040218E :

Lúc này tại cửa sổ Dump các bạn nhận được kết quả là toàn byte 0x00. Đơn giản là vì ta đã thực
thi hàm đâu mà lấy được đoạn text nhập vào 

Bây giờ ta cho thực thi hàm GetDlgItemTextA và quan sát kết quả thu được tại cửa sổ Dump :

5
Ok đúng như ta phỏng đoán, chương trình sẽ lấy UserName nhập vào trước và lưu nó vào vùng
Buffer có địa chỉ là 0x0040218E. Tiếp theo ta lại cho thực thi chương trình bằng cách nhấn F9 :

Bùm, Olly một lần nữa lại Break tại hàm GetDlgItemTextA. Không cần nói chắc các bạn cũng có
thể đoán ra ngay được là nó sẽ lấy Serial mà ta nhập vào.Nhưng lúc này Serial sẽ được lưu vào
một vùng Buffer khác mà các bạn thấy ở trên, đó là 0x0040217E. Ta follow theo vùng Buffer này :

Cho thực thi hàm và kiểm tra kết quả có được tại vùng Buffer :
6
Hehe Serial mà chúng ta nhập vào kìa!! Như vậy là với việc đặt BP tại hàm GetDlgItemTextA tôi
đã dừng lại tại nơi lấy những thông tin mà tôi nhập vào, bao gồm UserName và Serial, bước tiếp
theo tôi sẽ trace dần dần từng đoạn code cho tới khi nào tôi có thể tìm ra một Serial hợp lệ. Nhưng
có lẽ tạm thời ta nên dừng lại tại đây để chuyển sang phần thực hành với Message BP, xem có thể
thu được những thông tin tương tự như những gì ta vừa mới làm với việc đặt BP tại hàm APIs hay
không? Trước khi thực hành ta xóa hết các BP đã đặt, vào cửa sổ BreakPoint và xóa hết :

Sau khi xóa xong, ta restart lại Olly và cho thực thi chương trình , tiến hành nhập thông tin mà
chương trình yêu cầu :

Không giống như đặt BP tại các hàm API là ta có thể đặt BP tại đầu hàm thì để đặt Message BP
chúng ta phải làm việc với cửa sổ Windows. Hiện tại chương trình của chúng ta đang thực thi,
chúng ta chuyển qua cửa sổ Window bằng cách nhấn vào nút W :

7
Sau khi bạn nhấn vào nút W thì cửa sổ Windows sẽ hiện ra. Nếu như bạn thấy nó trống trơn không
có gì cả thì nhấn chuột phải và chọn Actualize :

Kết quả ta có được như sau :

Như đã nói ở trên, mục đích của chúng ta là sau khi bấm Button Ok thì chương trình sẽ dừng lại.
Vậy quan sát trong cửa sổ Windows, ở phần Class ta thấy có dòng Button, sau đó nhìn qua phần
Title ta thấy được tên của Button là OK. Vậy đây chính là mục tiêu của chúng ta. Để đặt Message
BP ta làm như sau, chuột phải tại nơi của Button OK và chọn Message Breakpoint on ClassProc:

Cửa sổ cho phép ta thiết lập BP hiện ra :

8
Ở phần Messages là một danh sách liệt kê những dạng Messages mà chúng ta có thể thiết lập BP :

Như các bạn thấy, Olly hỗ trợ đủ loại Messages từ Text,Mouse, Keyboard v…v.. Song bên cạnh
đó nó còn hỗ trợ cho ta một loạt danh sách các Messages thông dụng nhất. Quay trở lại ví dụ của
chúng ta: ta mong muốn khi ta nhấn chuột vào nút OK thì chương trình sẽ dừng sự thực thi. Vậy ta
phân tích một chút, lúc ta bấm chuột mà cụ thể ở đây là chuột trái lên nút OK thì chương trình sẽ
gửi một thông điệp là WM_LBUTTONDOWN (L ở đây có nghĩa là Left, BUTTONDOWN có
nghĩa là ta bấm chuột xuống). Lúc ta nhả chuột thì chương trình cũng sẽ gửi một thông điệp là
WM_LBUTTONUP. Do vậy trong trường hợp cụ thể của ta, ta sẽ nhờ Olly bắt thông điệp
WM_LBUTTONUP khi ta nhả chuột khỏi nút OK . Trong phần Messages ta cuộn chuột xuống
và tìm thấy :

9
Ta chọn nó và cấu hình lại như sau :

Sau khi cấu hình như trên ta nhấn OK :

Ta sẽ thấy chỗ ClsProc của hai Button Cancel và OK được hightlight. Bạn sẽ đặt câu hỏi là tại sao
tôi đặt cho nút OK mà lại dính cả vào nút Cancel, đó là vì trong phần cấu hình BP ở trên bạn chọn
là Break on any window, nếu bạn chọn là Break on all windows with same title thì sẽ có kết
quả tương tự nhưng lúc đó điều kiện đặt BP sẽ khác, các bạn hãy tự mình khám phá thêm . Bây
giờ sau khi đặt BP như trên, ta nhấn nút OK để kiểm tra việc đặt BP :
10
Olly đã break ngay lập tức sau khi ta nhả nút OK, quan sát cửa sổ Stack bạn có được thông tin như
trên. Tại cửa sổ Log Window lúc này ta cũng có được các tham số truyền vào :

Ok vậy là quá trình thực thi của chương trình đã bị dừng lại và quyền điều khiển lúc này là của
Olly. Tuy nhiên,như các bạn thấy thông thường khi dừng lại tại các hàm API ta luôn muốn tìm
cách trở về đoạn code chính của chương trình, để rồi từ đó lần ra các manh mối tiếp theo. Vậy
trong trường hợp này ta làm cách nào để quay về? Rất đơn giản các bạn nhấn Alt + M để mở cửa
sổ Memory :

Các bạn biết rằng chương trình của chúng ta sẽ thực thi code tại section bắt đầu từ 0x00401000, do
đó để quay về làm việc với code của chương trình ta đặt một BP tương tự như sau :

11
Sau đó nhần F9 để thực thi chương trình và chúng ta sẽ dừng lại tại đây :

Đừng vội xóa bỏ Memory BP, ta tiếp tục nhấn F9 để thực thi chương trình. Bạn sẽ thấy lúc này
chương trình sẽ lần lượt thực thi từng lệnh một, sau khi thực thi xong lệnh retn 10 bạn sẽ tới đây:

12
Để ý bạn sẽ thấy rằng chúng ta đang ở tại chỗ sắp sửa thực thi hàm API GetDlgItemTextA, mà
hàm này sẽ lấy thông tin về UserName và Serial ta nhập vào để lưu vào vùng Buffer. Qua đây ta
thấy rằng không cần sử dụng đến phương pháp đặt bp tại hàm API ta cũng có thể thông qua
Messages BP để lần tới những điểm quan trọng.

Tuy nhiên, giả sử trong một trường hợp nào đó mà chương trình không sử dụng hàm API để lấy
text do ta nhập vào thì ta làm thế nào, lúc đó ta cần sử dụng đến Messages BP để tiếp cận mục tiêu.
Ta sẽ thực hiện một demo nhỏ, trước tiên xóa Memory BP và Message BP đã đặt trước đó đi :

Restart lại Olly và cho thực thi chương trình :

Ở đây tôi chưa nhập thông tin gì vội, chuyển qua cửa số Windows và chọn Actualize :

13
Tại lần minh họa này tôi thực hiện đặt một Message BP như sau :

Các bạn sẽ hỏi tại sao tôi chọn WM_KEYUP, đơn giản là vì khi tôi gõ một kí tự bất kì và nhả
phím thì sẽ có một thông điệp WM_KEYUP sinh ra. Tôi muốn Olly bắt lấy thông điệp này và
dừng sự thực thi của chương trình lại. Thông tin thêm về WM_KEYUP :

The WM_KEYUP message is posted to the window with the keyboard focus when a
nonsystem key is released. A nonsystem key is a key that is pressed when the
ALT key is not pressed, or a keyboard key that is pressed when a window has the
keyboard focus.

WM_KEYUP
nVirtKey = (int) wParam; // virtual-key code
lKeyData = lParam; // key data

14
Sau khi đặt BP như trên, tôi tiến hành gõ thử một kí tự vào Textbox Name tuy nhiên khi tôi nhả
phím thì chẳng thấy chương trình dừng lại gì cả . Đó là bởi vì chương trình mà chúng ta làm việc
không xử lý các Messages liên quan tới WM_KEYUP, nhưng qua đây ta cũng biết được một
hướng khác để tiếp cận mục tiêu.

Quay trở lại vấn đề chính, tôi muốn tìm hiểu xem thực sự Message BP là gì và hoạt động của nó.
Tôi tiến hành đặt lại BP tại Message 202 WM_LBUTTONUP :

Sau đó nhấn OK ta sẽ break :

Chuyển qua cửa sổ Breakpoint ta thấy như sau :

Chúng ta thấy rằng Message BP cũng được quản lý bởi cửa sổ BP, nhấn chuột phải vào BP này và
chọn :

15
Ồ.. vậy bản chất của Message BP thực ra là một Conditional Log BP, trong đó điều kiện để dừng
sự thực thì của chương trình là [ESP+8]==WM_LBUTTONUP (tức là [ESP+8]==202). Lúc này
ta để ý cửa sổ Stack :

Giá trị tại [esp + 8] đúng là 202, để cho rõ ràng hơn bạn nhấp đúp chuột tại cột chứa giá trị của
ESP sẽ có được như sau :

16
“$+8” ở đây chính là “ESP + 8”. Hehe qua đó tôi biết chắc một điều rằng, giá trị [esp + 8] sẽ
chứa giá trị của các Messages. Vậy đề dò các giá trị tôi sửa lại BP như sau :

Ý nghĩa của những thiết lập trong hình trên tôi không cần phải giải thích lại nữa . Sửa lại BP
xong tôi cho thực thi chương trình và nhập thông tin vào. Tiếp theo bấm OK và chuyển qua cửa sổ
Log để quan sát các giá trị mà tôi thu được :

17
Khà khà nhiều quá trời, để ý các bạn thấy là chương trình này xử lý hai Message là
WM_LBUTTONDOWN(201) và WM_LBUTTONUP(202), đồng thời ta cũng thấy là nó không
hề xử lý các Messages như WM_KEYUP hay WM_KEYDOWN .

Ngoài ra để kiểm soát toàn bộ các Message cho tất cả các chương trình chúng ta có thể đặt một BP
conditional log tại các hàm APIs chuyên kiểm soát các Messages. Hai hàm API đó là
TranslateMessage và DefWindowProcA. Ta thực hiện như sau, tại command bar gõ hai lệnh :

Mở cửa sổ quản lý BP, chọn BP đầu tiên, chuột phải và chọn FOLLOW IN DISSASSEMBLER :

18
Sau đó lại chuột phải tiếp và chọn :

Đặt một Conditional Log BP như sau :

Thực hiện tương tự với BP thứ hai :

19
Ok như vậy là ta đã chuyển hết hai BP sang dạng Conditional Log BP rồi :

Tiếp theo ta sẽ cấu hình cửa sổ Log để lưu toàn bộ thông tin vào một text file để tiện theo dõi.
Chuyển qua cửa sổ Log, clear hết Log cũ đi sau đó chuột phải và chọn :

Lưu với tên file bất kỳ mà bạn muốn, cuồi cùng ta cho thực thi chương trình :

20
Sau đó quan sát cửa sổ Log bạn sẽ thấy có rất nhiều Windows Message được xử lý . Đóng
chương trình lại và kiểm tra log file của chúng ta xem ta thu được gì nào :

Rất đầy đủ và chi tiết .

Ok vậy là phần 12 của loạt tuts về Ollydbg đến đây là kết thúc, qua bài viết này tôi đã giới thiệu
nốt cho bạn loại BP cuối cùng đó là Message Breakpoints, việc nằm được ý nghĩa và mục đích
của từng loại Windows Message sẽ giúp ta rất nhiều trong quá trình tiếp cận mục tiêu. Giả sử như
21
trong trường hợp ta làm việc với Nag mà xử lý Message WM_CLOSE thì ta có thể đặt một
Message BP liên quan tới WM_CLOSE để lần ra manh mối.Hi vọng qua bài viết này tôi đã
truyền tải tới các bạn những kiến thức mà có thể đến bây giờ bạn mới biết khi sử dụng OllyDbg .
Trong bài viết tiếp theo của loạt tuts này chắc chắn tôi sẽ cùng bạn hoàn thành nốt quá trình tìm ra
Serial cho cái Crackme mà chúng ta đã làm việc từ đầu tới giờ….sẽ có nhiều điều thú vị lắm.Hẹn
gặp lại các bạn trong các phần tiếp theo, By3 By3!! 

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina,
QHQCrker, the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN,
HacNho, RongChauA, Deux, tlandn, light.phoenix, dqtln, ARTEAM .... all my friend,
and YOU.

--++--==[ Thanks To ]==--++--


iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl,
moth, XIANUA, nhc1987, 0xdie, Unregistered!, akira, mranglex v..v.. các bạn đã
đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy 

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially
haggar), Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on
crackmes.de, thank to all members of unpack.cn (especially fly and linhanshi).
Great thanks to lena151(I like your tutorials).Thanx to Orthodox, kanxue, TiGa and
finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.

>>>> If you have any suggestions, comments or corrections email me:


kienmanowar[at]reaonline.net

22
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

Chào các bạn, hôm nay chúng ta lại gặp nhau ở phần 13 của loạt bài viết về Olly . Vẫn còn rất
nhiều phần khác nữa tới đây, chỉ sợ sức lực tôi có hạn không thể viết hết được thôi.. khà khà.
Trong toàn bộ 12 bài viết trước, tôi đã lần lượt giới thiệu cho các bạn về Ollydbg, các kiến thức cơ
bản về ASM, các câu lệnh thường được sử dụng, cách patch chương trình cũng như các kiểu BP từ
cơ bản đến nâng cao trong Olly và còn nhiều thông tin khác nữa.... Tôi hi vọng rằng qua 12 bài
viểt đó các bạn đã tự trang bị cho mình những kĩ năng cơ bản nhất để làm việc với Olly, cũng như
tích lũy được những kinh nghiệm để có thể làm việc tiếp với những bài viết chuyên sâu tiếp theo
của loạt tutor này. Vậy ở phần 13 này chúng ta sẽ làm gì nhỉ? Thực ra là phần 13 này không có
trong kịch bản của lão Rincardo đâu, mà là tự tôi viết. Vì trong phần 12 của lão, cuối bài lão có nói
lão sẽ xử lý Crackme Cruehead để tóm được Serial nhưng rồi lão lại không viết ở phần 13, thay
vào đó lão đi xử lý các crackme khác. Cho nên tôi quyết định tự tay xử lý Crackme này để phục vụ
các bạn . Rất nhiều điều thú vị đang nằm ở phía trước…. N0w….L3t’s F1nish H1M !!!!!!!

II. Let’s Finish Him 

Nói là xử lý nhưng chúng ta phải làm thế nào nhỉ? Người có kiến thức và kinh nghiệm thì bảo :
“Hãy kiểm tra chương trình trước xem có bị pack bởi packer nào không? Nếu bị pack thì giải
quyết packer trước rồi tính tiếp. Còn nếu không bị pack thì quá khỏe, chạy thử chương trình xem
nó hoạt động ra sao và tìm kiếm thông tin. Sau khi có được những thông tin quan trọng thì load
chương trình vào Olly, tìm các cách để tiếp cận, đặt BP ở những điểm mấu chốt, sau đó trace
code, comment những chỗ quan trọng, nếu fish được serial thì tốt, còn không thì tìm ra thuật toán
và code keygen v..v..Bạn hãy tự mình thực hành đi đã, nếu bị bí chỗ nào hãy post lên để hỏi!”

Những người biết thì thưa thớt nhưng lại thích khoe khoang cũng phán đại :”Thì load vào Olly,
tìm cái chuỗi liên quan đến Nag ấy, rồi đặt BP chứ còn làm gì nữa! Không làm được thì show
code lên đây tôi giúp cho v..v..”

Riêng cá nhân của tôi thì thấy rằng: “Phải tự mình đúc kết các kinh nghiệm trước khi lâm trận cái
đã, khi bạn chưa biết gì mà đã vội nhảy vào trận chiến thì chẳng khác nào lấy trứng chọi đá. Vậy
kinh nghiệm ở đâu ra? Kinh nghiệm có được khi bạn đọc những bài viết của người khác, có được
khi bạn thực hành với những trường hợp tương tự nhưng bạn thử nghiệm những hướng tiếp cận
khác ,kinh nghiệm có được khi bạn tham gia thảo luận một chủ đề kĩ thuật v..v.. Để rồi từ đó bạn
rút tỉa dần dần và tích lũy lại thành kinh nghiệm của riêng mình.Rồi sẽ đến một lúc nào đó, lại có
người muốn ta chia sẻ kinh nghiệm của mình. Không ai có đủ thời gian và kiên nhẫn để chỉ dạy
từng bước cho bạn, bạn phải tự mình tìm tòi và khám phá, khi nào bạn cảm thấy thực sự cần đến
sự giúp đỡ tôi nghĩ lúc đó sẽ có người sẵn sàng giúp bạn  ”

1
Quay trở lại phần chính của bài viết này là giải quyết crackme CrueHead để tỉm ra môt valid serial.
Một hướng tiếp cận cơ bạn sẽ như tôi trình bày bên dưới đây, đương nhiên không nằm ngoài khả
năng có những cách tiếp cận khác, điều đó nằm ở sự khám phá của các bạn .

1. Kiểm tra xem chương trình có bị pack hay không?

Pack file nghĩa là như thế nào? Tại sao phải kiểm tra xem có bị pack? Hiểu một cách đơn giản thì
pack file là nén file thực thi (PE file : .dll, .exe, .ocx, v..v..) để làm giảm kích thước của file, việc
nèn này ngoài việc nén code, data của chương trình thì trình packer còn thêm cả đoạn decompress
stub vào PE file để làm nhiệm vụ unpack chương trình trong memory. Việc nén này không nên
hiểu như ta dùng Winrar/Winzip để nén file, vì Winrar/Winzip sau khi nén file xong ta không thể
thực thi file đó được mà ta phải làm một bước là extract file, sau đó mới run file.

Khi một file không bị pack thì lúc ta load chương trình vào Olly ta sẽ dừng lại tại EP của chương
trình (hay còn gọi là OEP gốc). Còn nếu chương trình đã bị pack, khi ta load vào Olly ta sẽ dừng
lại tại EP của packer chứ không phải là EP của chương trình. Do đó nhiệm vụ của chúng ta là phải
unpack chương trình trước đã (tức là ta đi tìm lại OEP gốc), rồi mới thực hiện các hướng tiếp cận
khác. Đó chính là lý do tại sao ta phải kiểm tra chương trình. Vậy ta kiểm tra như thế nào? Tôi
thường sử dụng một số chương trình sau để check :

a) PeiD v0.94/v0.95 :

b) ExeInfo PE :

2
c) RDG Packer Detector:

d) PE Detective :

Kết quả như các bạn đã thấy, sau khi sử dụng một loạt các chương trình PE detector ta nhận được
kết quả là :
3
 Chương trình không bị pack bởi bất kì packer nào.
 Chương trình có thể được code bằng Masm32 hoặc Tasm32

Việc chương trình không bị pack cũng đồng nghĩa với việc ta không cần phải unpack chương trình
nữa, vậy là nhẹ được một bước.Ta chuyển qua bước kế tiếp 

2. Chạy thử chương trình để tìm kiếm mục tiêu cần tiếp cận.

Việc chạy thử chương trình nhằm mục đích giúp cho ta có một cái nhìn tổng quan về hoạt động
của chương trình, biết được nhưng mục tiêu mà ta cần giải quyết. Song song với đó ta sẽ tìm kiếm
các cách thức để tiếp cận mục tiêu. Ok giờ tôi chạy thử chương trình xem thế nào đã. Sau khi run
tôi thấy nó không show nag gì cả. Nhìn sơ qua cũng chưa biết là mục tiêu tiếp cận ở đâu. Nếu các
bạn để ý khi sử dụng các chương trình thì chức năng Register thường được đặt ở Menu Help. Do
đó tôi nhấn chuột thử vào menu Help xem thế nào, blah blah..tôi thấy có phần Register, nhấn vào
đó tôi nhận được :

Chà, tiếp theo làm gì nữa đây? Chúng ta nhập đại Name và Serial vào và hi vọng là nó đúng .
Sau khi nhập và nhấn OK tôi nhận được nguyên cái Nag!

Ok, thông qua việc thực thi chương trình và nhập thông tin đăng kí như trên ta rút ra được một số
mục tiêu tiếp cận như sau :

 Tiếp cận thông qua việc tìm kiếm chuỗi “No luck there, mate!”
 Tiếp cận thông qua hàm MessageBoxA.
 Tiếp cận thông qua việc nhận Name và Serial (thông qua GetDlgItemTextA)
 v..v…

4
Như vậy sơ sơ ta cũng đã có 3 hướng tiếp cận rồi, việc chọn cách nào là tùy ở bạn. Bạn cũng có
thể tự tìm ra một hướng khác với những hướng đã liệt kê ở trên. Ở đây tôi chọn cách thứ 3 là dụng
hàm GetDlgItemTextA để tiếp cận và giải quyết crackme này!

3. Dùng Olly + Brain để giải quyết bài toán

Sau hai bước 1 và 2 chúng ta đã thu lượm được những thông tin cần thiết cho việc giải quyết bài
toán. Ở bước 3 này chúng ta sẽ nhờ đến Ollydbg + Brain để giải quyết bài toán hóc búa này .
Tại sao lại là Olly và Brain nhi? Vì đơn giản Ollydbg chỉ là một công cụ phục vụ cho mục đích của
chúng ta, việc làm chủ và sử dụng thành thạo nó là kĩ năng tối thiểu và cần thiết khi chúng ta muốn
debug một chương trình. Còn việc phải làm ra sao, tìm các tuyệt chiêu thế nào, phương hướng tiếp
cận làm sao nhanh nhất có thể v..v.. lại nằm ở trí thông minh và sức sáng tạo của chúng ta. Quay
trở lại bài toán của chúng ta, load Crackme vào trong Olly đã :

Như đã nói ở trên, hướng tiếp cận của tôi lúc này là đi theo hàm GetDlgItemTextA. Thông tin về
hàm này như sau :

The GetDlgItemText function retrieves the title or text associated with a


control in a dialog box.

UINT GetDlgItemText(
HWND hDlg, // handle of dialog box
int nIDDlgItem, // identifier of control
LPTSTR lpString, // address of buffer for text
int nMaxCount // maximum size of string
);

Return Values
If the function succeeds, the return value specifies the number of characters
copied to the buffer, not including the terminating null character.

If the function fails, the return value is zero.

Trờ lại Olly, tôi tiến hành đặt BP tại hàm GetDlgItemTextA :

Chuyển tới cửa sổ Breakpoints ta thấy có hai BP được thiết lập, vậy ta phỏng đoán hai hàm này
tương ứng với hai lần Get Name và Get Serial :

5
Tiếp theo ta nhấn F9 để thực thi chương trình, nhập Name và Serial vào sau đó nhấn Ok và hi
vọng Olly sẽ break tại nơi ta vừa thiết lập BP.

Như các bạn thấy trên hình, ta đang dừng lại tại lời gọi tới hàm GetDlgItemTextA đầu tiên. Nhìn
sang cửa sổ Stack ta có thông tin sau :

Không cần giải thích chắc các bạn cũng hiểu các thông tin này, chúng tương ứng với các tham số
truyền vào cho hàm trước khi hàm được thực hiện. Ở đây chúng ta quan tâm tới vùng Buffer, vì
nếu hàm thành công thì đoạn text nhập vào sẽ được lưu tại vùng Buffer này. Ta chọn Buffer,
chuột phải và chọn Follow in Dump :

6
Bây giờ ta nhấn F8 để trace và thực hiện hàm GetDlgItemTextA, sau đó quan sát kết quả tại vùng
Buffer :

Như vậy là ta đã có được chuỗi Name rồi . Để ý một chút bên cửa sổ Register ta sẽ thấy thanh
ghi eax lưu độ dài của chuỗi Name (eax=00000007). Sau khi có được chuỗi Name như trên, tiếp
tục nhấn F9 để thực thi chương trình, ta sẽ Break tại lời gọi tới hàm GetDlgItemTextA tiếp theo :

Tiếp tục Follow in Dump tại vùng Buffer : 0x0040217E. Sau đó nhấn F8 để trace và thực hiện
hàm GetDlgItemTextA thứ hai :

Sau khi thu được hai chuỗi Name và Serial, ta tiếp tục nhấn F8 để trace code.Trace qua mấy đoạn
code ta tới đây :

00401284 |> /5F pop edi


00401285 |. |5E pop esi
00401286 |. |5B pop ebx
00401287 |. |C9 leave
00401288 |. |C2 1000 retn 10

7
Tiếp tục trace và thực hiện lệnh Retn 10, ta bị return tới vùng code không phải là code chính của
crackme :

Nếu các bạn tiếp tục trace tiếp thì sẽ vẫn luẩn quẩn trong đám code này, vậy để cho nhanh chóng
về vùng code chính của chương trình ta chọn :

Tại đây ta dừng lại một chút và suy nghĩ đã, quan sát đoạn code :

00401223 . 83F8 00 cmp eax, 0


00401226 .^ 74 BE je short 004011E6
00401228 . 68 8E214000 push 0040218E ; ASCII "manowar"
0040122D . E8 4C010000 call 0040137E (1)
00401232 . 50 push eax
00401233 . 68 7E214000 push 0040217E ; ASCII "1234567890"
00401238 . E8 9B010000 call 004013D8 (2)
0040123D . 83C4 04 add esp, 4
00401240 . 58 pop eax
00401241 . 3BC3 cmp eax, ebx (3)
00401243 . 74 07 je short 0040124C
8
00401245 . E8 18010000 call 00401362
0040124A .^ EB 9A jmp short 004011E6
0040124C > E8 FC000000 call 0040134D
00401251 .^ EB 93 jmp short 004011E6

Đầu tiên, để ý đến lệnh call 0040137E (1) trước nó là lệnh push chuỗi Name vào Stack. Vậy
ta đoán khả năng lệnh call này sẽ dùng chuỗi Name để tính toán gì đó với chuỗi Name. Kết quả
tính toán này sẽ được lưu vào thanh ghi eax vì ta thấy thanh ghi eax sau đó được lưu vào Stack và
được sử dụng lại trong quá trinh so sánh. Tiếp theo là lệnh call 004013D8 (2),trước nó là
lệnh push chuỗi Serial vào Stack, khả năng lệnh call này cũng tính toán gì đó với Serial , kết quả
sau đó chắc là được lưu vào thanh ghi ebx. Vì tay thấy rằng sau đó thanh ghi eax được đem so
sánh với thanh ghi ebx. Phụ thuộc vào kết quả so sánh này sẽ là một lệnh nhẩy đưa ta đến
Good/Bad boy .

Quá trình suy nghĩ và phân tích sơ bộ đã xong, giờ ta trace vào từng đoạn code để hiểu thêm xem
về cơ chế tính toán ra sao. Trước tiên ta làm việc với lệnh call 0040137E (1) :

Tôi phân tích từng phần một để các bạn dễ hiểu, đầu tiên là khúc tôi khoanh màu vàng. Nó có
nhiệm vụ như sau :

1. Đọc chuỗi Name từ Buffer và lưu vào thanh ghi esi.


2. Kiểm tra từng kí tự trong chuỗi Name xem có nằm trong khoảng từ ‘A’ – ‘Z’ không?
3. Nếu có kí tự nào có mã Ascii < 0x41 (‘A) thì sẽ show Nag (tức là Name không chứa chữ số
v..v.)
4. Nếu kí tự nào là chữ hoa thì thôi, nếu không là chữ hoa thực hiện convert sang chữ hoa
(call 004013D2).
5. Kết quả cuối cùng được lưu lại vào vùng Buffer.

Tiếp theo ta sẽ trace into vào lệnh call tại : 0040139D |. E8 20000000 call 004013C2,
mục đích để tìm hiểu xem lệnh call này sẽ tính toán gì tiếp theo với chuỗi buffer.

9
Đoạn code này làm nhiệm vụ cộng dồn toàn bộ các kí tự trong chuỗi Name lại vào lưu vào thanh
ghi edi, kết quả cuối cùng của thanh ghi edi đối với chuỗi Name mà tôi nhập vào là :

Chuyển giá trị này về dạng decimal xem là bao nhiêu :

Sau khi có được kết quả tại thanh ghi edi ta thực hiện lệnh 004013D1 \> \C3 retn để trở
về, ta tới đây :

Tại đoạn code này, giá trị của edi sau khi tính toán được ở trên được đem đi xor với một giá trị
mặc định của chương trình là 0x5678. Kết quả được bao nhiêu sẽ lưu lại vào thanh ghi eax. Sau đó
quay về main code của chương trình.

Vậy tổng kết lại ta có được quá trình tính toán liên quan tới chuỗi Name như sau :

1) Chuỗi Name nhập vào phải là các chữ cái trong khoảng ‘A’-‘Z’, ‘a’-‘z’.
2) Toàn bộ chuỗi sau đó sẽ được convert thành chữ in hoa.
10
3) Sau khi được convert, đem các kí tự trong chuỗi cộng dồn lại ở dạng hexa, và lưu vào edi.
4) Thanh ghi edi tiếp tục được xor với giá trị mặc định là 0x5678.
5) Cuối cùng được kết quả bao nhiêu sẽ lưu vào eax.

Sau khi trở về main code của crackme ta ở đây :

Nhìn vào hình trên ta thấy, thanh ghi eax lưu kết quả của quá trình tính toán liên quan đến chuỗi
Name sẽ được cất tạm vào Stack. Tiếp theo chương trình sẽ đẩy chuỗi Serial lên Stack và tính toán
gì đó với chuỗi này. Việc tiếp theo ta cần làm là tìm hiểu xem nó tính toán gì tại : call
004013D8 (2). Trace into vào lệnh call này ta tới đây :

Ngay đầu tiên ta đã thấy thanh ghi eax bị clear, chính vì thế các bạn thấy tác giả đã lưu lại thanh
ghi eax trước. Tổng thể toàn bộ đoạn code trên làm nhiệm vụ : chuyển chuỗi Serial về dạng hexa.
Trong ví dụ của tôi nhập vào là 1234567890, qua đoạn code trên nó sẽ được convert về thành giá
trị là 0x499602D2 và lưu vào thanh ghi edi :

Giá trị tại thanh ghi edi sau đó lại được đem xor với một giá trị mặc định khác là 0x1234 (hehe ở
trên thì là 0x5678). Kết quả được bao nhiêu sẽ được lưu lại tại thanh ghi ebx. Sau đó trở về main
code để tới quá trình so sánh tại :

00401241 . 3BC3 cmp eax, ebx (3)


00401243 . 74 07 je short 0040124C

Vậy là ta đã tìm hiểu xong phần tính toán liên quan đến chuỗi Name và Serial. Bây giờ ta cần phải
suy nghĩ và lập luận để tìm ra real serial cho chuỗi Name của chúng ta. Như các bạn thấy, chuỗi
Name của ta nhập vào được chuyển sang chữ hoa, sau đó cộng dồn, cuối cùng đem xor với 0x5678
để cho ra kết quả và lưu vào eax. Trong trường hợp của tôi giá trị sau khi tính toán là 0x0000546D,

11
chuyển giá trị này sang dạng decimal tôi có 21613. Tiếp theo tôi thấy rằng chuỗi Serial mà tôi
nhập vào cũng được convert thành dạng hexa (Giả sử nếu tôi nhập vào là 21613, thì tức là chuyển
giá trị 21613 về dạng hexa là 0x546D). Sau đó giá trị hexa này được đem đi xor với giá trị mặc
định là 0x1234. Mà tôi thì biết rằng lệnh XOR có ý nghĩa như sau :

Lệnh XOR có thể được dùng để đảo các bit xác định của toán hạng đích trong khi vẫn giữ nguyên
những bit còn lại. Bit 1 của mặt nạ làm đảo bit tương ứng còn bit 0 giữ nguyên bit tương ứng của
toán hạng đích.

Vậy từ đó ta kết luận rằng Serial của chúng ta sẽ là giá trị tính toán được của chuỗi Name và đem
xor với 0x1234. Trong trường hợp cụ thể của tôi thì real serial sẽ là : 0x546D xor 0x1234 =
0x4659 (chuyển sang decimal là : 18009). Thử kiểm chứng lại xem có đúng không nhé, tôi nhấn
F9 để run chương trình. Nhập Name và Serial như sau :

Nhấn Ok và trace tới đoạn code :

Ta dừng lại tại đoạn so sánh, để ý cửa sổ Tip Window ta sẽ thấy  :

Khà khà quá chuẩn rồi, nhấn F9 để thực thi chương trình các bạn sẽ nhận được good boy :

12
Như vậy các bạn đã thấy tầm quan trọng của việc phân tích và đọc hiểu code của chương trình sẽ
giúp chúng ta rất nhiều. Bên cạnh đó tính kiên nhẫn trong việc trace code cũng không thể thiếu
được khi ta làm việc với Olly. Sau khi phân tích được thuật toán của Crackme như trên, bạn hoàn
toàn có thể code một chương trình nhỏ làm nhiệm vụ Genkey từ chuỗi Name nhập vào, chương
trình đó người ta gọi là keygen hay keymaker . Công việc đó xin nhường lại cho các bạn tự mình
khám phá tiếp nhé, còn tôi thì mệt rồi!!

Ok vậy là phần 13 của loạt tuts về Ollydbg đến đây là kết thúc, qua bài viết này tôi đã hướng dẫn
các bạn cách kiểm tra xem file có bị pack hay không, cách tìm các điểm quan trọng để tiếp cận
mục tiêu, phân tích chi tiết hoạt động của Crackme CrueHead thông qua việc trace và analyze code
để từ đó tìm ra một real serial cho chuỗi Name nhập vào. Hi vọng qua bài viết này tôi đã truyền tải
tới các bạn những kinh nghiệm thực tế khi làm việc với một crackme đơn giản nhưng cũng sẽ là
tiền đề cho các bạn khi gặp các crackme hoặc các chương trình khác. Hẹn gặp lại các bạn trong các
phần tiếp theo của loạt tutor này, By3 By3!! 

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina,
QHQCrker, the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN,
HacNho, RongChauA, Deux, tlandn, light.phoenix, dump, dqtln, ARTEAM .... all my
friend, and YOU.
--++--==[ Thanks To ]==--++--
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl,
moth, XIANUA, nhc1987, 0xdie, Unregistered!, akira, mranglex v..v.. các bạn đã
đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy 

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially
haggar), Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on
crackmes.de, thank to all members of unpack.cn (especially fly and linhanshi).
Great thanks to lena151(I like your tutorials).Thanx to Orthodox, kanxue, TiGa and
finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.
>>>> If you have any suggestions, comments or corrections email me:
kienmanowar[at]reaonline.net

13
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

Khà khà, Giáng sinh rồi … có được chút thời gian rảnh rỗi tôi lại bắt tay vào viết tiếp bộ tutor này.
Hi vọng các bạn vẫn còn hứng thú để đọc những gì tôi viết . Ở phần 13 của loạt tuts về Ollydbg,
tôi đã hướng dẫn các bạn cách kiểm tra xem file có bị pack hay không, cách tìm các điểm quan
trọng để tiếp cận mục tiêu, phân tích chi tiết hoạt động của Crackme CrueHead thông qua việc
trace và analyze code để từ đó tìm ra một real serial cho chuỗi Name nhập vào. Như vậy, qua bài
viết đó tôi đã truyền tải tới các bạn những kinh nghiệm thực tế khi làm việc với một crackme đơn
giản nhưng cũng sẽ là tiền đề cho các bạn khi gặp các crackme hoặc các chương trình khác sau
này….Ở phần 14 này chúng ta sẽ quay lại làm việc với các target do lão Rincardo đưa ra, cụ thể
hơn là tập trung vào chủ đề Fishing Serial . N0w….L3t‟s G0 !!!!

II. Fishing Serial 

Chà Fishing Serial tức là gì nhỉ? Nghe như kiểu chúng ta đang đi câu cá, giữa một hồ cá rộng và
sâu, làm sao ta câu được một con cá ưng ý … trong ngữ cảnh của Cracking thì ý nghĩa cũng gần
như vậy. Fishing Serial ở đây có nghĩa là chúng ta đi câu Serial, mà phải là valid Serial nhé chứ
câu lung tung là mệt và dễ stress. Đối với những bạn mới vào nghề thì việc tìm được một valid
Serial luôn mang lại một cảm giác lâng lâng khó tả như tìm được một “kho báu” giữa lòng đại
dương . Hồi tôi chập chững lọ mọ đọc tutor và cặm cụi mò theo, cho đến khi tìm được serial hợp
lệ tự nhiên cảm thấy sướng khó tả, lúc đó nếu có ai ở bên cạnh chắc tôi sẽ kéo vào và chỉ trỏ để
khoe những gì mình đã làm, dù chắc gì người đó đã hiểu mình đang làm gì, có khi lại cho mình
đang bị chập lolz.

Trong phần 14 này tôi sẽ hướng dẫn các bạn làm việc với dạng Hardcoded Serial (đây là một dạng
cơ bản và đơn giản), có nghĩa là dạng Serial cố định không được tính toán dựa trên Name nhập
vào, cũng không thay đổi khi bạn chạy trên bất kì máy nào (tức là Serial đó valid trên mọi máy).
Có bạn sẽ cho rằng vậy thì dễ quá, viết làm gì? Nhưng xin thưa, phải có dễ thì mới có khó, phải đi
từ basic rồi mới tới advanced. Quan điểm của tôi là cứ từ từ mà tiến, không đi đâu mà phải vội
vàng. Ok giờ chúng ta vào thực hành luôn nhé, trong bài này ta sẽ làm việc với hai Crackme của
lão RedH@wk (lão này cũng là một thành viên trụ cột trong CrackLatinos).

1. LESSON 13 HARDCODED 1

Trước khi load vào Olly, ta chạy thử xem mặt mũi cái crackme này thế nào :

1
Chà thấy có mỗi cái Textbox cho phép nhập Serial vào, còn mấy cái nút ở dưới toàn tiếng TBN .
Nhưng chắc 1 cái dùng để kiểm tra tính hợp lệ của Serial nhập vào, cái còn lại chắc dùng để thoát
crackme.Ok, ta nhập đại một serial vào và nhấn thử nút Verificar :

Ặc thông báo bằng tiếng TBN, nhưng may cái Caption là Error, đủ để cho chúng ta biết rằng cái
Serial mà ta nhập vào là không hợp lệ. Vậy thì ta phải “đi câu” để túm được valid Serial nào .
Load cái crackme vào trong Olly :

Sau khi load vào Olly, ta dừng lại tại EP của crackme như các bạn thấy ở hình minh họa trên. Dòm
qua cái code thấy quá trong sáng, các bạn sẽ bắt gặp cái thông báo Error :

00401078 |. 68 35204000 push 00402035 ; |Text = "Mal Muy MAL"

và một cái thông báo khác, tôi đoán chắc là thông báo Serial hợp lệ :

2
0040108B |. 68 28204000 push 00402028 ; |Text = "Muy
BIEN",A1,"",A1,"",A1,"",A1,""

Vậy Serial này ở đâu? Vì nó là dạng HardedCode, tức là người code đã include nó vào trong
chương trình rồi, ta thử mò bằng cách tìm toàn bộ các String xem thế nào. Chuột phải và chọn như
sau :

Ta có được kết quả :

Ồ, kết quả có được cũng không nhiều, dòng thứ 3 thì ta đã biết được nó là thông báo lỗi rồi, còn
dòng thứ hai là gì nhỉ, thử đưa lên anh google nhờ anh ấy dịch hộ xem nó có nghĩa gì không  :

Khà khà kết quả là nó vẫn là chính nó lolz, vậy có thể nghi ngờ nó là valid Serial. Tuy nhiên đây
mới chỉ là nghi ngờ thôi, tôi không khuyến cáo các bạn áp dụng cách này để tìm Serial đơn giản vì
lý do sau :
“Do đây là crackme đơn giản cho nên tác giả đã code hết sức gọn nhẹ để chúng ta thực hành, cho
nên kết quả trả về cho việc tìm kiềm chỉ là hai dòng text duy nhất. Nhưng với các target phức tạp
khác, kết quả trả về có thể lên đến hàng trăm hoặc hàng nghìn dòng, việc dò và kiểm thử xem có
đúng hay không là điều khó thực hiện và mất thời gian.”

Giờ chúng ta đã có điểm nghi ngờ là dòng text thứ hai, nếu nhanh gọn các bạn có thể chạy
crackme và nhập vào để kiểm tra tính hợp lệ của nó. Tuy nhiên để chắc chắn hơn chúng ta cần
chứng minh đúng là nó chứ không phải dựa vào phán đoán nhất thời. Ta tiến hành tìm kiếm các
hàm API mà crackme này sử dụng :

3
Olly trả về kết quả cho chúng ta như sau :

Chà trong danh sách này có hai API mà chúng ta đã khá quen thuộc từ các bài viết trước rồi, ta
quan tâm nhất tới hàm user32.GetDlgItemTextA. Đặt BP tại hàm này như sau :

Kiểm tra xem BP đã được thiết lập chưa tại cửa sổ quản lý BP :

Ok, sau khi đặt BP xong ta run chương trình và tiến hành nhập Serial :

4
Sau khi nhập xong các bạn nhấn Verify, ngay lập tức Olly sẽ break :

Ta đang dừng lại tại GetDlgItemTextA, dòm qua cửa sổ Stack ta có thông tin như sau :

Ở đây ta cần quan tâm tới Buffer, đây sẽ là nơi nhận lưu Serial mà chúng ta đã nhập vào. Chuột
phải vào Buffer và chọn Follow in Dump :

Do hàm API của chúng ta chưa được thực hiện nên vùng buffer hiện thời vẫn còn trống :

Giờ chúng ta cho thực thi hàm API GetDlgItemTextA như sau :

5
Olly sẽ dừng lại tại lệnh RET, lúc này quan sát vùng Buffer ta có được kết quả như sau :

Không cần giải thích chắc các bạn cũng biết được đó là gì rồi! Giờ nhấn F8 để trace qua lệnh Ret
để trở về code chính của chương trình :

Ok, ta dừng lại quan sát và phân tích một chút. Để ý các bạn sẽ thấy có lệnh so sánh và lệnh nhảy,
phụ thuộc vào kết quả so sánh mà lệnh nhảy sẽ đưa chúng ta đến một trong hai thông báo :

1. Nếu sai chúng ta sẽ được nhận thông báo "Mal Muy MAL" ( «bad, very bad» - approx.
Ed.)
2. Nếu đùng chúng ta sẽ nhận thông báo "Muy BIEN" ( «very good »- Prim.per.).

Rõ ràng trong trường hợp của chúng ta chúng ta muốn nhận được thông báo “Very good”. Vậy ta
trace code để xem điều gì sẽ xảy ra tiếp theo. Đầu tiên ta sẽ thấy chương trình chuyển vào thanh
ghi edx một hardcoded string là FIACA :

00401061 |. BA 08304000 mov edx, 00403008 ; ASCII "FIACA"

Tiếp theo tại 0x00401066, ta thấy thanh ghi ebx sẽ nhận được giá trị từ vùng nhớ [403010], mà
theo phân tích ở trên thì đây chính là vùng Buffer nhận vào chuỗi Serial của chúng ta :
6
Trace qua lệnh này và quan sát thanh ghi EBX, kết quả như sau :

Sau khi trace qua lệnh 00401066 |. 8B1D 10304000 mov ebx, dword ptr [403010], ta sẽ
đến lệnh CMP. Ta thấy nội dung của thanh ghi ebx sẽ được đem đi so sánh với vùng chứa chuỗi
hardcoded.Ta follow in dump để quan sát giá trị :

Theo như hình trên thì các bạn có thể thấy rằng, không phải toàn bộ chuỗi Hardcoded sẽ được đem
đi so sánh với toàn bộ chuỗi serial mà ta nhập vào,mà ở đây chương trình chỉ lấy hai dword (tức là
4 chữ cái đầu tiên) đem so sánh với nhau. Nếu giống nhau thì quá tốt, còn không thì .Giờ tôi
trace qua lệnh CMP :

7
Đương nhiên là lệnh nhảy sẽ không thực hiện ví lý do Serial của tôi nhập vào không trùng khớp
với Serial mà chương trình đưa ra. Bây giờ tôi đã biết được Serial của chương trình là gì rồi, đó
chính là chuỗi “FIAC”, không cần phải đầy đủ hết cả chuỗi vì như tôi đã phân tích ở trên. Chúng
ta bỏ BP tại GetDlgItemTextA đi, sau đó đặt BP tại lệnh nhảy ở trên. Tiếp theo Restart Olly và
cho thực thi chương trình :

Nhập valid Serial vào, sau đó nhấn Verify. Olly sẽ break :

Khà khà Serial đã hợp lệnh, câu lệnh so sánh đã thành công và lệnh nhảy sẽ được thực hiện.Nhấn
F9 phát nữa nào :

Hola, thành công rồi. Crackme 1 đến đây là kết thúc.

8
2. LESSON 13 HARDCODED 2

Xử xong crackme1 rồi, giờ chúng ta chuyển qua crackme2. Chạy thử nó xem thế nào đã, đây là
một bước cần thiết để thu thập thông tin :

Nhập thử Serial và nhấn Verify :

Chà thông báo trên thấy quen quá . Giờ ta load Crackme vào Olly để tìm hướng giải quyết bài
toán.Trong Olly ta có được như sau :

Như các bạn thấy code trông giống hệt crackme1, ta thử search string xem có tìm được vàng
không nhé :

9
Ái chà, crackme2 này có vẻ khó hơn crackme1 rồi đây. Thông tin ta có được chỉ vẻn vẹn có mỗi
một dòng thông báo lỗi, vậy là đầu mối tìm kiếm này đã không có tác dụng. Quay trở vể cửa sổ
CPU của Olly, cuộn chuột xuống ta sẽ thấy đoạn code so sánh :

Tại đây ta cũng không thấy có dòng nào tương tự như crackme1, chẳng thấy có thông tin nào
tương tư như „FIACA‟ mà ta có được với crackme1 cả lolz . Do code của crackme2 tương tự
crackme1 cho nên phần phân tích tôi bỏ qua, ta đi thẳng vào vấn đề chính. Tôi đặt BP tại lệnh mov
bên dưới lời gọi tới hàm GetDlgItemTextA.

Nhấn F9 để thực thi crackme, sau đó nhập đại một cái Serial vào rồi nhấn Verify :

Olly sẽ break tại chỗ mà ta đặt BP, ta Follow in Dump để biết nội dung tại [40300C] là gì :

Ta thấy 4 bytes sẽ được đưa vào thanh ghi ebx. Quan sát thanh ghi :

10
Vậy là thanh ghi ebx đã giữ thông tin về 4 kí tự đầu tiên trong chuỗi Serial mà tôi nhập vào. Bây
giờ chúng ta đang dừng tại câu lệnh :

0040106A |. 8B15 4B204000 mov edx, dword ptr [40204B]

Không hiểu thanh ghi edx được mov thông tin gì vào nhỉ? Điểm nghi ngờ là ở đây, vì ở bên dưới
tôi thấy lệnh cmp đem hai thanh ghi ebx và edx so sánh với nhau. Vậy ta có thể khẳng định chắc
chắn rằng, vùng nhớ [40204B] đang nắm giữ một thông tin rất quan trọng, đó chính là valid Serial.
Ta Follow in dump để biết thông tin đó là gì :

Khà khà, vậy là Serial mà chúng ta cần tìm là : 9898. Quay lại cửa sổ code, bỏ BP đã đặt trước đó
đi, sau đó bạn đặt BP tại lệnh nhảy bên dưới lệnh cmp :

Restart lại Olly, sau đó nhấn F9 để run chương trình. Nhập valid Serial là 9898 vào và nhấn
Verify:

11
Hehe, như các bạn thấy lệnh nhảy tới Good boy sẽ được thực hiện sau khi so sánh.Vậy là việc
Fishing của chúng ta đã thành công, nhấn F9 để kiểm chứng kết quả cuối cùng :

Vậy là xong, crackme2 đã được xử lý nhẹ nhàng!!


Ok vậy là phần 14 của loạt tuts về Ollydbg đến đây là kết thúc, qua bài viết này tôi đã giới thiệu
tới các bạn thế nào là Fishing Serial và hướng dẫn các bạn thực hành với hai Crackme rất đơn
giản, ngoài ra trong phần 14 này cũng có thêm một target nữa của lão Detten để các bạn tự thực
hành để kiểm chứng kiến thức và khả năng của mình. Hi vọng qua bài viết này của tôi đã cung cấp
thêm một số kiến thức cơ bản giúp các bạn làm việc hiệu quả với Olly. Hẹn gặp lại các bạn trong
các phần tiếp theo của loạt tutor này, By3 By3!! 

Solution for Detten‟s crackme :

Best Regards
_[Kienmanowar]_

12
--++--==[ Greatz Thanks To ]==--++--
My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina,
QHQCrker, the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN,
HacNho, RongChauA, Deux, tlandn, light.phoenix, dump, dqtln, ARTEAM .... all my
friend, and YOU.
--++--==[ Thanks To ]==--++--
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl,
moth, XIANUA, nhc1987, 0xdie, Unregistered!, akira, mranglex v..v.. các bạn đã
đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy 

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially
haggar), Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on
crackmes.de, thank to all members of unpack.cn (especially fly and linhanshi).
Great thanks to lena151(I like your tutorials).Thanx to Orthodox, kanxue, TiGa and
finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.
>>>> If you have any suggestions, comments or corrections email me:
kienmanowar[at]reaonline.net

13
INTRODUCTION TO THE CRACKING WITH OLLYDBG

FROM CRACKLATINOS
(_kienmanowar_)

Một cái đầu lạnh để vững vàng, một trái tim đỏ lửa để yêu và làm việc hết mình!

I. Giới thiệu chung

Hi vọng trong mấy ngày vừa qua các bạn đã đọc và thực hành xong với những crackme trong phần
14, hôm nay chúng ta sẽ tiếp tục với phần 15. Trong phần 14 tôi đã cùng các bạn làm việc với
dạng Hardcoded Serial đơn giản, phần 15 này ta vẫn sẽ tiếp tục nhưng có khó hơn một chút. Lượn
qua site của lão Ricard để down tutor về (các tutor của lão tôi đã down cả và lưu trong CD rồi
nhưng ngại mở đĩa ), extract tutor và target ra thì lại đòi pass, sặc chẳng hiểu sao lão lại đặt pass
và tôi cũng chẳng biết pass để extract là gì  . Hehe google thử phát để tìm kiếm thông tin, hóa ra
pass để unrar là serial ta tìm được trong cái Detten‟s crackme. Chà ý tưởng của lão Rincar cũng
hay phết, lão muốn người đọc phải giải quyết được target của tutor này mới được xem bài viết ở
tutor tiếp theo. Ok nói chuyện vui thế đủ rồi, chúng ta đi vào phần chính luôn nhé . N0w….L3t‟s
G0 !!!!

II. Fishing Serial 

Trước tiên chúng ta lướt qua cách giải quyết Detten‟s crackme cái đã, vì có giải quyết được
crackme này tôi và các bạn mới extract được tutor 15 để đọc. Ta load crackme vào trong Olly :

Ta đang dừng lại tại EP của crackme, tiền hành tìm kiếm thông tin về các hàm APIs được sử dụng
trong crackme này :

1
Kết quả ta có được như sau :

Các bạn thấy có khá nhiều hàm API, tuy nhiên để ý sẽ thấy có 3 hàm API quan trọng (các hàm mà
tôi đã đánh dấu) có thể chọn làm đầu mối để tiếp cận mục tiêu.Trong 3 hàm này thì hàm
MessageBoxA các bạn đã quá quen thuộc rồi, chỉ còn hai hàm GetWindowTextA và lstrcmpA.
Ta sẽ lần lượt xem qua ý nghĩa của hai hàm này :

Đọc các thông tin cung cấp ở trên các bạn đã phần nào hiểu được mục đích sử dụng và ý nghĩa của
từng hàm API rồi chứ. Như vậy các bạn có thể đặt BP tại các hàm API này để giải quyết bài toán.
Giờ chúng ta tìm kiếm thử các String quan trọng :

2
Kết quả ta có được như sau :

Các String quan trọng show ra rõ như ban ngày . Ta nhấn đúp chuột tại ASCII "You entered the
right password!", Olly sẽ đưa ta tới đây :

Nhìn tổng thể toàn bộ đoạn code trên ta có thể đưa ra những nhận xét cơ bản như sau :
1. Chương trình sử dụng hàm API GetWindowTextA để copy chuỗi Serial mà ta nhập vào và
lưu vào vùng Buffer.
2. Sau đó chuỗi Fake serial này sẽ được đem đi so sánh với chuỗi Hardcoded serial thông qua
hàm API lstrcmpA.
3. Phụ thuộc vào kết quả so sánh mà quyết định hiển thị Good boy hay Bad boy.

Để kiếm chứng những gì chúng ta vừa nhận xét ở trên, tôi đặt bp tại GetWindowTextA, sau đó
nhấn F9 để run chương trình.Tiến hành nhập Fake Serial :
3
Sau khi nhập xong nhấn Check, Olly sẽ ice tại BP mà ta đã đặt. Lúc này quan sát cửa sổ Stack ta
có thông tin :

Ta chuẩn bị thực hiện hàm GetWindowTextA, vùng Buffer sẽ là nơi lưu Serial mà ta nhập vào.
Ta có được như sau :

Sau khi thực hiện hàm GetWindowTextA, ta dừng lại tại đây :

Khà khà vậy không còn nghi ngờ gì nữa, tới đây ta có thể hoàn toàn kết luận rằng chuỗi
Hardcoded Serial của crackme này là “cannabis”. Ta kiểm tra thử xem thế nào nhé :

Vậy là xong!! Tiếp theo chúng ta sẽ giải quyết một crackme khác..

4
LESSON 15 HARDCODED 1: crakmeeasy.exe

Không giống như các crackme trước, crackme này sẽ không thực hiện việc so sánh trực tiếp Fake
Serial với Real Serial mà sẽ thực hiện một số bước tính toán trước khi tiến hành thao tác so
sánh.Trước khi load vào Olly, ta chạy thử xem mặt mũi cái crackme này thế nào :

Ta thấy có mỗi cái Textbox cho phép nhập password và một button dùng để kiểm tra xem pass
nhập vào là đúng hay sai.Ok, ta nhập đại một password vào và nhấn nút Check :

Qua các thao tác trên chúng ta đã thu thập được một số thông tin cấn thiết cho việc tiếp cận để giải
quyết crackme này. Tiếp theo ta phải “đi câu” để túm được valid Serial . Load cái crackme vào
trong Olly :

Tiến hành tìm kiếm thông tin về các hàm APIs được sử dụng trong crackme này :

5
Quan sát thấy có hàm GetDlgItemTextA, chúng ta sẽ dùng hàm này để tiếp cận mục tiêu. Ta đặt
BP tại hàm này như sau :

Nhấn F9 để run chương trình, nhập Fake Serial và nhấn Check :

Olly sẽ dừng lại tại BP, quan sát cửa sổ Stack ta có thông tin như sau :

6
Chú ý vùng Buffer, đây sẽ là nơi lưu Fake serial mà ta nhập vào. Follow in Dump tại vùng Buffer
ta có được kết quả trước khi thực hiện hàm như sau :

Ok, ta nhấn F8 để thực hiện hàm GetDlgItemTextA và quan sát vùng Buffer. Kết quả sau khi
thực hiện sẽ có được như sau :

Như các bạn thấy lúc này vùng Buffer đã chứa chuỗi Serial mà chúng ta vừa nhập vào.Ta quay trở
lại cửa sổ Code, lúc này ta đang dừng lại tại đây :

7
Chà như các bạn thấy trên hình, chúng ta thấy rằng có một chuỗi mặc định gồm toàn chữ số tham
gia vào quá trình tính toán. Không biết nó có phải là Hardcoded serial không nhỉ? Để khẳng định
thì các bạn có thể nhập thử chuỗi đó vào và kiểm tra, còn tôi thì đã thử rồi khà khà . Các bạn để
ý sẽ thấy giá trị 0x00401222 được đẩy vào thanh ghi eax, mà địa chỉ này lại trỏ tới chuỗi mặc
định là "10445678951" , vậy tức là thanh ghi eax lúc này sẽ trỏ tới chuỗi mặc định :

Follow in Dump tại thanh ghi EAX :

Ở dòng lệnh tiếp theo ta sẽ thấy giá trị tại EAX được chuyển vào EDX :

0040130F . 8B10 mov edx, dword ptr [eax]

mà cụ thể ở đây tức là :

0040130F . 8B10 mov edx, dword ptr [401222]

Vậy kết luận là nội dung tại 0x401222 sẽ được chuyển vào thanh ghi EDX, cụ thể ở đây là
Dword tức là 4 bytes đầu tiên tại vùng nhớ 0x401222. Quan sát tại cửa sổ Tip ta sẽ thấy được
thông tin cụ thể như sau :

Ok phân tích xong ta nhấn F8 để thực hiện lệnh và quan sát thanh ghi EDX để kiểm chứng kết
quả:
8
Dòng lệnh tiếp theo sẽ lại chuyển giá trị của EDX vào vùng nhớ [EBP-30] :

Quan sát trên cửa sổ Tip ta sẽ biết được [EBP-30] là vùng nhớ nào và giá trị của nó tại cửa sổ
Dump đang là bao nhiêu :

Nhấn F8 để thực thi lệnh và quan sát cửa sổ Dump :

Thực hiện xong ta dừng tại lệnh :

00401314 . 8B50 04 mov edx, dword ptr [eax+4]

Lệnh này sẽ lấy 4 bytes tiếp theo tại 0x401222 và đẩy vào thanh ghi EDX :

9
Thực thi lệnh và quan sát thanh ghi EDX :

Tiếp theo giá trị của EDX được chuyển vào vùng nhớ [EBP-2C] :

Cuối cùng thực hiện copy nốt 4 bytes vào thanh ghi EAX. Sau đó giá trị của EAX lại được cất vào
vùng nhớ [EBP-28] :

Như vậy qua đây ta thấy rằng hai thanh ghi EAX và EDX được sử dụng làm trung gian để copy
toàn bộ chuỗi mặc định vào một vùng nhớ do chương trình định ra. Đoạn code tiếp theo chúng ta
sẽ thấy chương trình sử dụng hàm memset, quan sát ta thấy hàm này nhận vào 3 tham số :

Google thử thông tin về hàm này :

10
Hàm memset nhận vào 3 biến là s, c, n :

s is the starting address


n is the number of bytes that are going to fill
c is the value with which to fill this area

Qua những thông tin trên ta kết luận rằng, hàm memset sẽ tiến hành set 8 bytes của vùng nhớ tại
0x0240F9F0 thành giá trị 0x00. Follow in Dump tại vùng nhớ, sau đó nhấn F8 để thực hiện hàm
ta sẽ thấy kết quả như sau :

Trace tiếp xuống đoạn code bên dưới ta bắt gặp đoạn code sau :

Hàm strlen sẽ tính toán độ dài của chuỗi s, cụ thể ở đây là chuỗi s = "10445678951". Kết quả tính
toán được sẽ lưu tại thanh ghi EAX :

Như quan sát kết quả tại thanh ghi EAX ta thấy giá trị của nó là 0xB, tương ứng với 11 ở hệ mười.
Vậy tức là độ dài chuỗi mặc định là 11. Nhấn F8 để trace tiếp ta sẽ đến đây :
11
Qua thông tin trên các bạn chắc cũng đã hiểu được, độ dài của chuỗi mặc định được trừ đi 1 sau đó
chuyển vào thanh ghi EDX. Vậy EDX sẽ có giá trị là 0xA (tức là 10 ở hệ mười). Đoạn code bên
dưới ta sẽ thấy giá trị tại vùng nhớ [EBP-10] được đem so sánh với giá trị của EDX :

Mà giá trị tại vùng nhớ [EBP-10] là :

Kết quả so sánh 0x0 < 0xA, cho nên lệnh nhảy JB tại 0x00401357 sẽ thực hiện, chúng ta sẽ
chuyển tới đoạn code tại 0x00401360 :

Câu lệnh MOV tại 0x401360 sẽ chuyển Fake Serial mà ta nhập vào vào thanh ghi EAX :

12
Dòng lệnh tiếp theo sẽ mov giá trị tại [EBP-10] vào thanh ghi EDX, giá trị của [EBP-10] lúc
này đang là 0x0 :

Tiếp theo :

EAX hiện tại đang trỏ vào chuỗi Fake Serial, giá trị của EDX đang là 0x0. Điểu này làm ta liên
tưởng tới việc sẽ có một vòng lặp trong đó thanh ghi EAX giữ nguyên, thanh ghi EDX thay đổi từ
0x0 đến 0xA, vậy tức là sẽ lần lượt lấy ra từng kí tự trong chuỗi Fake Serial (vậy cũng kết luận là
chuỗi Serial mà ta nhập vào cũng phải có độ dài là 0xB). Điều này thể hiện ở đoạn code sau :

Lệnh MOVSX sẽ thực hiện copy giá trị từ nguồn vào đích, nguồn ở đây vùng nhớ chứa Fake
Serial, tính theo từng byte. Đích ở đây là thanh ghi EDX, tính theo Dword. Trong trường hợp cụ
thể của tôi là copy byte đầu tiên, tức là chữ cái “m” và thanh ghi EDX :

Dòng lệnh tiếp theo :

13
Ta thấy rằng, giá trị của EDX sau đó được trư đi 0x14, kết quả được bao nhiêu sẽ lưu vào thanh
ghi EAX. Cụ thể của tôi (0x6D – 0x14 = 0x59) :

Câu lệnh tiếp theo 0040136E .8D55 D0 lea edx, dword ptr [ebp-30], thanh
ghi EDX lúc này sẽ trỏ vào chuỗi mặc định :

Tiếp tục xem xét hai câu lệnh bên dưới :

00401371 . 8B4D F0 mov ecx, dword ptr [ebp-10]


00401374 . 0FBE1411 movsx edx, byte ptr [ecx+edx]

Lệnh đầu tiên thanh ghi ECX sẽ được gán giá trị tại [EBP-10] (hiện tại giá trị tại [EBP-10] =
0x0). Lệnh tiếp theo dùng để copy vào thanh ghi EDX từng kí tự trong chuỗi mặc định (do lúc này
thanh ghi ECX đang là 0x0 cho nên thanh ghi EDX sẽ chứa kí tự đầu tiên của chuỗi mặc định).
Vậy ta nhận thấy rằng việc di chuyển để copy kí tự tiếp theo trong chuỗi Fake Serial và chuỗi mặc
định sẽ phụ thuộc vào giá trị tại [EBP-10] :

14
Kết thúc quá trình lấy kí tự từ hai chuỗi Fake Serial và chuỗi mặc định, chúng ta sẽ tới đoạn code
so sánh :

Trong hình minh họa của tôi, các bạn thấy thanh ghi EAX đang có giá trị là 0x59, thanh ghi EAX
đang có giá trị là 0x31. Quay ngược lại một chút ta sẽ thấy rằng, giá trị 0x59 có được là do kí tự
đầu tiên của chuỗi Fake Serial là “m”, mã hexa là 0x6D trừ đi 0x14. Còn giá trị 0x31 là mã hexa
của kí tự đầu tiên trong chuối mặc định. Tôi viết lại cụ thể như sau :

cmp eax, edx  cmp (First byte of FS – 0x14), First byte of Constant string 
cmp 59, 31

Kết quả của việc so sánh này sẽ ảnh hưởng tới lệnh nhảy bên dưới . Tới đây chúng ta không cần
quan tâm tới đoạn code bên dưới nữa, chúng ta sẽ lập luận để tìm ra được Real Serial. Như các bạn
thấy chúng ta có công thức như sau :

CMP (FIRST BYTE OF MY CORRECT SERIAL - 14), 31

Ở đây là so sánh bằng vậy cho nên ta có :

FIRST BYTE OF MY CORRECT SERIAL – 0x14 = 0x31

Suy ra :

FIRST BYTE OF MY CORRECT SERIAL = 0x31 + 0x14

Khà khà vậy là ta đã tìm ra được kí tự đầu tiên của chuỗi Real Serial rồi, đó là kí tự „E’. Thực hiện
tiếp tục theo logic như trên ta sẽ có được chuỗi Real Serial hoàn chỉnh :

31 +14 = 45 is the letter E in ASCII

30 + 14 = 44 is the letter D in ASCII

34 + 14 = 48 is the letter H in ASCII

34 + 14 = 48 is the letter H in ASCII

35 + 14 = 49 is the letter I ASCII


15
36 + 14 = 4A is the letter J in ASCII

37 + 14 = 4B is the letter K in ASCII

38 + 14 = 4C is the letter L in ASCII

39 + 14 = 4D is the letter M in ASCII

35 + 14 = 48 is the letter I in ASCII

31 +14 = 45 is the letter E in ASCII

Hola, chuỗi serial cuối cùng của chúng ta là : EDHHIJKLMIE. Nhiệm vụ của Olly đã xong, ta
tạm thời close Olly, chạy thử crackme và test serial mà ta tìm được :

Ok vậy là phần 15 của loạt tuts về Ollydbg đến đây là kết thúc, qua bài viết này tôi và các bạn đã
cùng thực hành với một crackme với mức độ khó hơn một chút, chỉ là một chút thôi . Trong
phần tutor này còn có một target khác để các bạn thực hành đó là Splish crackme, có lẽ tôi cũng
bắt chiếc lão Ricard, tutor tiếp theo sẽ đặt pass là serial mà các bạn tìm được ở Splish crackme
l0lz. Hi vọng qua bài viết này của tôi đã cung cấp thêm một số kiến thức cơ bản giúp các bạn làm
việc hiệu quả với Olly. Hẹn gặp lại các bạn trong các phần tiếp theo của loạt tutor này, By3 By3!!

Best Regards
_[Kienmanowar]_

--++--==[ Greatz Thanks To ]==--++--


My family, Computer_Angel, Moonbaby , Zombie_Deathman, Littleboy, Benina,
QHQCrker, the_Lighthouse, Merc, Hoadongnoi, Nini ... all REA‘s members, TQN,
HacNho, RongChauA, Deux, tlandn, light.phoenix, dump, dqtln, ARTEAM .... all my
friend, and YOU.
--++--==[ Thanks To ]==--++--

16
iamidiot, WhyNotBar, trickyboy, dzungltvn, takada, hurt_heart, haule_nth, hytkl,
moth, XIANUA, nhc1987, 0xdie, Unregistered!, akira, mranglex v..v.. các bạn đã
đóng góp rất nhiều cho REA. Hi vọng các bạn sẽ tiếp tục phát huy 

I want to thank Teddy Roggers for his great site, Reversing.be folks(especially
haggar), Arteam folks(Shub-Nigurrath, MaDMAn_H3rCuL3s) and all folks on
crackmes.de, thank to all members of unpack.cn (especially fly and linhanshi).
Great thanks to lena151(I like your tutorials).Thanx to Orthodox, kanxue, TiGa and
finally, thanks to RICARDO NARVAJA and all members on CRACKSLATINOS.
>>>> If you have any suggestions, comments or corrections email me:
kienmanowar[at]reaonline.net

17

You might also like