Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux

1865
13-06-2018
Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux

Mở đầu

Trọng tâm chính của blog này Bizfly Cloud là để mang lại cho người mới bắt đầu một khởi đầu chủ động trong lĩnh vực kỹ thuật đảo ngược. Vì đây là thời kỳ của x64 nên tôi đã bỏ qua cấu trúc x86 và sẽ chỉ tập trung vào x64 assembly. Tuy nhiên, tất cả các ví dụ sẽ được viết trong C và cũng có thể được biên dịch thành x86, nhưng tôi sẽ để nó cho các bạn. Tuy nhiên, nếu bạn không có kinh nghiệm assembly thì cũng không thành vấn đề. Điều duy nhất mà bạn sẽ yêu cầu trong suốt blog của tôi là logic và một chút hiểu biết cơ bản về ngôn ngữ lập trình. 

Để bắt đầu, chúng tôi sẽ viết một chương trình C đơn giản sẽ gợi nhắc nhập mật khẩu. Nó sẽ tiếp tục kiểm tra nếu mật khẩu phù hợp, nếu có phù hợp, nó sẽ đánh dấu nhắc chính xác, nếu không sẽ đánh dấu nhắc không chính xác. Lý do chính tôi lấy ví dụ này là bởi vì điều này sẽ cung cấp cho bạn sự hiểu biết qua về jump, if else và điều kiện tương tự khác làm việc trong hợp ngữ. 

Một lý do khác nữa là hầu hết các chương trình có hardcoded key có thể bị bẻ khóa theo cách tương tự ngoại trừ có một chút lập trình toán học hơn, và đây cũng là cách mà hầu hết các nhà phân phối vi phạm bản quyền crack phần mềm hợp pháp và truyền đi các key.

Trước tiên, hãy hiểu chương trình C mà chúng tôi đã viết. Tất cả các mã sẽ được lưu trữ trong profile Github của tôi: -

https://github.com/paranoidninja/ScriptDotSh-Reverse-Engineering

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 1.

Mã ở đây khá đơn giản. Chương trình của chúng tôi lấy một đối số làm input về cơ bản là password. Nếu tôi không nhập bất kỳ mật khẩu nào, nó sẽ in lệnh trợ giúp. Nếu tôi chỉ định một mật khẩu, nó sẽ được lưu trữ như một char với 10 byte và sẽ gửi mật khẩu đến hàm check_pass (). Mật khẩu mã hóa của chúng tôi là PASSWORD1 trong hàm check_pass (). 

Ở đây, mật khẩu của chúng tôi được so sánh với mypass biến mật khẩu thực tế với hàm strcmp(). Nếu mật khẩu khớp, nó trả về Zero, nếu không nó sẽ trả về One. Quay trở lại hàm chính của chúng tôi, nếu chúng tôi nhận được One, nó in mật khẩu sai, nếu không nó sẽ in mật khẩu chính xác.

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 2.

Bây giờ, hãy lấy mã này trong trình gỡ lỗi GDB của chúng tôi. Chúng tôi sẽ thực thi nhị phân với GDB và trước tiên chúng tôi sẽ thiết lập một điểm ngắt trên phần chính trước khi chúng tôi gửi đối số. 

Thứ hai, chúng tôi sẽ cho phép thời gian di chuyển trên GDB của chúng tôi, để nếu chúng tôi bằng cách nào đó đi trước một bước do nhầm lẫn, chúng tôi có thể đảo ngược điều đó và trở lại một bước nữa. Điều này có thể được thực hiện với lệnh sau: target record-fullreverse-stepi/nexti

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 3.

Đừng sợ nếu bạn không hiểu bất kỳ thứ gì trong đây. Chỉ cần tập trung vào phần gdb$ và như bạn có thể thấy ở trên, tôi đã đưa ra một mật khẩu không chính xác như pass123 sau khi đưa ra điểm ngắt với break main. Mã được biên dịch của tôi nên in một mật khẩu không chính xác như đã thấy trước đó, nhưng khi chúng tôi tiếp tục, chúng tôi sẽ tìm hai cách để bỏ qua mã; một là bằng cách lấy ra mật khẩu thực tế từ bộ nhớ và thứ hai là bằng cách sửa đổi giá trị jump và in ra mật khẩu là chính xác.

Tháo gỡ

Bước tiếp theo là tháo gỡ toàn bộ mã và cố gắng tìm hiểu những gì thực sự đang diễn ra:

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 4.

Điểm chính của chúng tôi về intereset trong toàn bộ mã được tháo rời sẽ là một vài điều sau đây:

1. je - je có nghĩa là nhảy đến một địa chỉ nếu nó bằng với một giá trị nào đó. Nếu không, hãy tiếp tục với flow.

2. call - gọi một hàm mới. Hãy nhớ rằng sau khi tải xong, mã được tháo rời sẽ thay đổi từ hàm tháo gỡ chính sang mã tháo gỡ của hàm mới.

3. test - kiểm tra xem hai giá trị có bằng nhau không

4. cmp - so sánh hai giá trị với nhau

4. jne - jne có nghĩa là nhảy đến và đề địa chỉ nếu nó không bằng với một giá trị nào đó. Nếu không, tiếp tục với flow.

Một số người có thể đặt câu hỏi tại sao chúng tôi có test trong khi mà chúng tôi đã có cmp có thể làm điều tương tự. Câu trả lời có thể được tìm thấy ở đây và đã được giải thích đáng hài lòng: -

https://stackoverflow.com/questions/39556649/linux-assembly-whats-difference-between-test-eax-eax-and-cmp-eax-0

Và do đó, nếu chúng ta đã thấy mã tháo gỡ như ở trên thì chúng tôi biết nếu chạy nhị phân mà không có mật khẩu hoặc đối số, nó sẽ in trợ giúp, hoặc sẽ tiến hành kiểm tra mật khẩu. Vì vậy, cmp này sẽ là phần giúp kiểm tra xem chúng ta có đối số hay không. Nếu không có đối số nào tồn tại, nó sẽ tiếp tục với việc in trợ giúp, nếu không nó sẽ jump đến <main 70>

Nếu bạn thấy các con số bên cạnh các địa chỉ ở phía bên tay trái, chúng ta có thể thấy rằng tại < 70>, chúng ta đang di chuyển một cái gì đó vào thanh ghi rax. Vì vậy, những gì chúng tôi sẽ làm là thiết lập một điểm ngắt tại je, bằng cách xác định địa chỉ của điểm ngắt 0x0000000000400972 và sau đó sẽ xem liệu điểm ngắt này có nhảy đến < 70> bằng cách yêu cầu tiếp tục với c hay không . Lệnh GDB c sẽ tiếp tục chạy nhị phân cho đến khi nó chạm đến điểm ngắt khác.

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 5.

Và bây giờ nếu bạn dùng một stepi là bước lặp lại, nó sẽ bước một lần lặp lại của quá trình thực thi và đưa bạn đến < 70> - nơi mà nó di chuyển một Quad Word vào trong thanh ghi rax.

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 6.

Do đó, logic của chúng tôi cho đến thời điểm hiện tại là chính xác nên hãy tiếp tục cùng chúng tôi chuyển sang điều thú vị tiếp theo mà chúng ta thấy, đó là phần call (gọi). Và nếu bạn đã thấy đứng bên cạnh nó, nó nói một cái gì đó đại loại như <_Z10check_passPc> đó  chính xác là hàm check_pass(). Hãy bắt đầu bằng cách sử dụng stepi và xem những gì nằm bên trong hàm đó.

Đôi khi, bạn nhảy vào hàm check_pass() và tháo gỡ nó, bạn sẽ thấy một bộ mã mới được tách rời, đó là mã của chính hàm check_pass(). Và ở đây, có bốn dòng assembly code thú vị ở đây:

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 7.

Phần đầu tiên là nơi giá trị của thanh ghi rdx được chuyển sang rsirax và lại được chuyển sang rdi. Phần tiếp theo là hàm strcmp() được gọi là hàm so sánh chuỗi của C . Tiếp đó, chúng tôi có test so sánh hai giá trị, và nếu các giá trị bằng nhau, chúng tôi nhảy (je) đến <_Z10check_passPc 77> mà sẽ di chuyển giá trị Zero trong thanh ghi eax

Nếu các giá trị không bằng nhau, hàm sẽ tiếp tục tiến hành tại < 70> và di chuyển giá trị One trong thanh ghi eax. Bây giờ, đây chỉ là giá trị trả về mà chúng tôi đã chỉ định trong hàm check_pass () trước đó. Vì chúng tôi đã nhập mật khẩu không hợp lệ, giá trị trả lại sẽ được gửi là One. Nhưng nếu chúng tôi có thể sửa đổi giá trị trả về thành Zero, nó sẽ in ra là "Mật khẩu chính xác".

Ngoài ra, chúng tôi có thể tiếp tục và kiểm tra những gì đang được chuyển vào thanh ghi rsirdi. Vì vậy, hãy đặt một điểm ngắt ở đó và nhảy thẳng đến điểm này.

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 8.

Như bạn có thể thấy từ hình trên, tôi đã sử dụng lệnh x/s $rdxx/s $rax để lấy các giá trị từ thanh ghi. x/s có nghĩa là kiểm tra thanh ghi và hiển thị nó như một chuỗi. Nếu bạn muốn nhận bằng byte, bạn có thể chỉ định x/b hoặc nếu bạn muốn ký tự, bạn có thể chỉ định x/c và cứ thế. 

Tuy nhiên, có nhiều biến thể. Bây giờ phần đầu tiên của chúng tôi nhận được mật khẩu ở đây. Tuy nhiên, hãy tiếp tục và xem cách chúng tôi có thể sửa đổi giá trị trả về tại <_Z10check_passPc 70> thành Zero. Vì vậy, chúng ta sẽ chạy qua stepi và nhảy tới bước lặp đó.

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 9.

Lời kết

Như bạn có thể thấy ở trên, hàm đã di chuyển 0x1 đến eax trong nhị phân, nhưng trước khi nó có thể thực hiện je, chúng tôi đã sửa đổi giá trị thành 0x0 trong eax bằng cách sử dụng set $eax = 0x0 và sau đó tiếp tục hàm với c như bên dưới và Voila !!! Chúng tôi có một giá trị được trả về là Correct Password (Mật khẩu chính xác)!

Kỹ thuật dịch ngược x64 cho người mới bắt đầu - Linux - Ảnh 10.

Học Assembly không thực sự khó đúng không. Chỉ cần bỏ ra một lượng thời gian vừa đủ, nó sẽ trở nên dễ hiểu và vô cùng dễ dàng.  

Đây mới chỉ là một ví dụ đơn giản để giúp bạn bắt đầu với assembly và kỹ thuật đảo ngược. Bây giờ khi chúng ta đi sâu hơn, chúng ta sẽ thấy các hàm socket, mã hóa runtime, mã hóa các tên miền ẩn, v.v.... Toàn bộ quá trình này có thể được thực hiện bằng cách sử dụng x64dbg trong Windows cũng là thứ mà tôi sẽ hiển thị trong blogpost tiếp theo của tôi.

Còn bây giờ, chính là nó. Hãy bình luận bên dưới hoặc tweet cho tôi @NinjaParanoid nếu bạn có bất kỳ thắc mắc hay nghi ngờ gì :).

Cảm ơn các bạn đã theo dõi!

Link gốc: http://niiconsulting.com/checkmate/2018/04/reverse-engineering-x64-for-beginners-linux/

Theo Bizfly Cloud chia sẻ

>> Có thể bạn quan tâm: Kỹ thuật đảo ngược cho người mới bắt đầu - Mã hóa XOR - Windows x64 

BizFly Cloud là nhà cung cấp dịch vụ điện toán đám mây với chi phí thấp, được vận hành bởi VCCorp.

BizFly Cloud là một trong 4 doanh nghiệp nòng cốt trong "Chiến dịch thúc đẩy chuyển đổi số bằng công nghệ điện toán đám mây Việt Nam" của Bộ TT&TT; đáp ứng đầy đủ toàn bộ tiêu chí, chỉ tiêu kỹ thuật của nền tảng điện toán đám mây phục vụ Chính phủ điện tử/chính quyền điện tử.

Độc giả quan tâm đến các giải pháp của BizFly Cloud có thể truy cập tại đây.

DÙNG THỬ MIỄN PHÍ và NHẬN ƯU ĐÃI 3 THÁNG tại: Manage.bizflycloud

SHARE