Cách AntiDebug chương trình

Sau vài hôm ngẫm nghĩ về bài học AntiDebug một chương trình thì đã hiểu ra được bài target của lão sinok, cái chương trình này lão đã sử dụng một antidebug nhằm để bảo vệ chương trình tránh khỏi crack. Hôm nay mình xin thực hành vấn đề này. Ok Let go

À quên những ai chưa hiểu về cách antidebug thì có thể tham khảo link này : RE6: AntiDebug | WhiteHat.vn

1 Khởi động cho nóng khi lâm trận

Tôi load target vào và kiểm tra xem nó có pack gì không, nếu như pack thì giải quyết nó trước đã rồi tính sau nhé 🙂

Có vẻ như nó không bị pack, cái chương trình này của lão sinok được code bằng c++ và biên dịch trên dev-c, bây giờ tui load vào x64 dbg xem có gì trong này.

vào màn hình tại tab CPU -> cilck phải chọn serachfor -> Chọn Current region -> string

Có vẻ như đến đây tôi nhìn nó rất là mê li không thấy mặt trời vẻ như ta đang không có chút gì ở đây cả nhưng đây tôi thấy một chuỗi là OnlyDBG hmm không biết có gì ở đây hay, nhưng tôi thử click vào chuỗi đó.

Tới được đây

00401587 | C70424 00104400 | mov dword ptr ss:[esp],crackme.441 | 441000:”OllyDBG”

có vẻ từ địa chỉ 0x 00401587 đến 004015D8 là phần bị antidebug , khi tôi cố găng debug nó như thường thì nó sẽ thoát chương trình có thể đoán chương trình này đã cài debug rồi xem ta có thể giải quyết xem nó bằng cách nào

Như ta có thấy thì chỗ địa chỉ 40157A thì có lời gọi tại địa chỉ 4015a6 có nghĩa sẽ là đoạn ở trên nữa

ta train tới 0x401546 xem

Như nó giống hệt dưới cũng có thêm một lời gọi hàm nữa ta thử train tiếp xem

Train tiếp cũng gặp y chang vậy bây giờ ta train tiếp cho đến khi nào tới entrypoint

Điểm cuôi cùng đến entrypoint rồi, đây là nơi chương trình thực thi.

lệnh move eax drword ptr ds:[444014] lệnh này có nghĩa tại vùng nhớ 0x444014 chứa được password ta nhập vào tiếp

lệnh lea edx , dword ptr ds[eax+eax] có lẽ tính toán gia trị ta nhập vào là bao nhiêu sẽ lưu vào edx

Ở đây tôi nhập 123 vào trong thanh ghi edx của tôi là 7b nghĩa là 0x7b là 123

Train tới lệnh so sánh thì nó so sánh cmp so sánh 2 thành ghi là edx và eax

edx=F6 ‘ö’ // đây là sau khi tính toán bởi lệnh eax + eax lưu vào edx

eax=5BA3BCE // đây là gia trị tạo vùng nhớ 440000

Và ta thấy pass fake này làm cho lệnh nhảy này nhảy vậy làm thế nào để không nhảy ok ta có công thức để giải mã crackme của lão sinok này

số 123 pass fake đổi sang hệ hex là 0x 7b + 0x7b = 0xf6 x 2 = 0x1ec

Vậy nếu tính pass thật sẽ là

pass_x = hex_x x 2 = giá trị thanh ghi eax = 5ba3bce

hex_x = 5ba3bce / 2 = 2DD 1DE7

Ok ta đổi cái hex_x ra xem sao có phải là pass không đổi ra thập phân

Ok đã xong được cách tìm pass rồi

Write_up CTF learn

Challenge 1 : Reykjavik 

Good beginning Reversing challenge - jump into gdb and start looking for the flag!Reykjavik.zip 

Step 1 :

Kiểm tra loại file ở đây thì ta thấy đây là file ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2

và ta có thể chú ý được là tham số ta truyền vào khi chạy chương trình.

Ví dụ: ./ tên file => là 1 tham số

Ta có thể thấy được dòng lệnh trên là ta thực thi 1 chương trình, để ý 1 chút ta có thể thấy được khi ta chạy chương trình này thì sẽ có 1 thông báo lỗi "Usage: Reykjavik CTFlearn{flag}" có nghĩa là tham số bị lỗi format cho nên ta cần nhập theo định dạng là CTFlearn{flag} .

Step 2:

Ta đã nhập theo định dạng của bước trước 1 và ta có thêm 1 thông báo nữa
"Sorry Dude, 'CTFlearn{flag}' is not the flag :-(" . Có nghĩa là password not đúng :(

Step 3:

Tới đây ta sẽ sử dụng 1 trình gỡ lỗi là IDA 64 bit để load file này vào.

Như ta thấy được tại địa chỉ 0x10c1 -> 0x10DC là nơi chuỗi này xuất hiện, theo ta phân tích thì rất có khả năng tại đây chứa flag :) thử xem nào test lại ct trên như b1.

Ồ quả nhiên có chút khác như trên và nó hiện ra thông báo là "You found the false flag Dude!:'CTFlearn{Is_This_A_False_Flag?}' nghĩa là mật khẩu bạn sai. Vậy ta có thể biết tại đây nó đúng dạng flag theo fromat ct cho ta nhưng nó chưa phải mật khẩu.

Tiếp tuc phân tích lại IDA

Ta kéo xuống dưới tí thì có 1 khối màu xanh này mình đã đánh dấu nó vì khả nghi ở đây là mk đã được mã hóa. Thử bấm theo mình để xem mã giả xem nó làm gì.

Ok đây là đoạn mã giả trong IDA

int __cdecl main(int argc, const char **argv, const char **envp)
{
const char *v3; // rbp
int v4; // er12
__int64 v6[3]; // [rsp+0h] [rbp-38h] BYREF
char v7; // [rsp+18h] [rbp-20h]
char v8; // [rsp+19h] [rbp-1Fh]
char v9; // [rsp+1Ah] [rbp-1Eh]
char v10; // [rsp+1Bh] [rbp-1Dh]

if ( argc == 1 ) // tham số đầu vào nếu là 1
{
v4 = 1;
puts(“Usage: Reykjavik CTFlearn{flag}”); // hiển thị ra
}
else
{
v3 = argv[1];
__printf_chk(1LL, “Welcome to the CTFlearn Reversing Challenge Reykjavik v2: %s\n”, v3);
puts(“Compile Options: ${CMAKE_CXX_FLAGS} -O0 -fno-stack-protector -mno-sse\n”);
if ( !strcmp(v3, “CTFlearn{Is_This_A_False_Flag?}”) ) // tại đây so sanh chuỗi nhập là v3 vơi chuỗi chứa với flag fake
{
v4 = 2;
__printf_chk(1LL, “You found the false flag Dude!:’%s’\n\n”, “CTFlearn{Is_This_A_False_Flag?}”);
}
else // khúc này là ngược lại cái trên đoán tại đây có khả cao 98 % là mk của ct
{
v10 = 0;
v6[0] = data ^ 0xABABABABABABABABLL;
v6[2] = qword_4020 ^ 0xABABABABABABABABLL;
v6[1] = qword_4018 ^ 0xABABABABABABABABLL;
v7 = byte_4028 ^ 0xAB;
v8 = byte_4029 ^ 0xAB;
v9 = byte_402A ^ 0xAB;
v4 = strcmp((const char *)v6, v3);
if ( v4 )
{
v4 = 4;
__printf_chk(1LL, “Sorry Dude, ‘%s’ is not the flag :-(\n\n”, v3);
}
else
{
__printf_chk(1LL, “Congratulations, you found the flag!!: ‘%s’\n\n”, (const char *)v6);
}
}
}
return v4;
}

Step 4:

Chỗ này ta sẽ code đảo ngược nó để giải mã ra

v10 = 0;
v6[0] = data ^ 0xABABABABABABABABLL;
v6[2] = qword_4020 ^ 0xABABABABABABABABLL;
v6[1] = qword_4018 ^ 0xABABABABABABABABLL;
v7 = byte_4028 ^ 0xAB;
v8 = byte_4029 ^ 0xAB;
v9 = byte_402A ^ 0xAB;

Ta xem thử cái data này chứa gì trong bộ nhớ stack

Ta thấy rằng các tên data,qword,byte đều chứa một số byte ta sẽ đem giá trị từng byte này đi so với 0xAB xem ra những gì.

Sau khi code keygen trên ta được chương trình giải mã cờ ra.

Ta chạy thử ra chương trình không.Qủa nhiên là ra đươc một cái flag thử xem nó đúng với pass ta đang tìm không

Step 5:

Qủa nhiên đùng rồi :)))

Challenge 2: Basic Android RE 1 

A simple APK, reverse engineer the logic, recreate the flag, and submit!BasicAndroidRE1.apk 

Step 1:

Đây là file apk nó tương đương với file .java, nếu bạn chương hiểu thì lên gg xem file apk là gì.

Step 2:

Tại đây mình sử dụng phần mền jad-GUI-Java để mở soruce code file này ra xem

Step 3:

thấy thây tại đoạn code tại hàm này kiểm pass trước khi ta bấm submit

public void submitPassword(View view) {
EditText editText = (EditText) findViewById(R.id.editText2); // lây chuỗi ta nhập thông qua edit text
if (DigestUtils.md5Hex(editText.getText().toString()).equalsIgnoreCase(“b74dec4f39d35b6a2e6c48e637c8aedb”)) { // so sanh chuỗi ta nhập + chuỗi mã hóa md5
((TextView) findViewById(R.id.textView)).setText(“Success! CTFlearn{” + editText.getText().toString() + “_is_not_secure!}”);
}
}

Step 4:

Ta sẽ coppy chuỗi md5 74dec4f39d35b6a2e6c48e637c8aedb và ta giải mã nó ra bằng trang web giải mã này MD5 Online | Free MD5 Decryption, MD5 Hash Decoder

Sau khi giả mã ta được chuỗi này  Spring2019

Vậy ta lấy chuỗi này với từ CTFlearn{ Spring2019 _is_not_secure!} đây là password.

Challenge 3

Riyadh  10 points Easy

Another entry level Reversing challenge, if you are new to Reversing you probably want to try my Reyjkavik challenge before attempting this challenge. Good Luck! The flag is hidden inside the Riyadh program. Solve the Challenge, get the flag, and I have included the encrypted sources used to create the challenge in the Riyadh.zip file. If you do to the work of solving the Challenge, I’m providing the Challenge source code (C++ and Python) if you are interested in studying the sources after solving the challenge. I think this is a great way to improve your Reversing skills when learning. Please don’t share the sources or flag after you solve the challenge.

Step 1:

Kiểm tra loại file đây là loại file 64 bit được phát triển trên linux

Chạy trương trình và kiểm tra và pass chương trình không đúng .

Step 2:

Load vào IDA để phân tích

Kiếm hàm mgs5 để giải mã

char __fastcall Msg5(char *a1)
{
unsigned __int64 v2; // rdi
__int64 i; // rax

*(_QWORD *)a1 = 0LL;
v2 = (unsigned __int64)(a1 + 8);
*(_QWORD *)(v2 + 240) = 0LL;
memset((void *)(v2 & 0xFFFFFFFFFFFFFFF8LL), 0, 8 * (((unsigned int)a1 – (v2 & 0xFFFFFFF8) + 256) >> 3));
if ( (unsigned __int64)(a1 + 7 – (char *)&xormask) <= 0xE || (unsigned __int64)(a1 + 7 – (char *)&fmsg) <= 0xE )
{
for ( i = 0LL; i != 31; ++i )
a1[i] = *((_BYTE *)&xormask + i) ^ *((_BYTE *)&fmsg + i);
}
else
{
*(_QWORD *)a1 = xormask ^ fmsg;
*((_QWORD *)a1 + 1) = qword_4168 ^ qword_4078;
*((_QWORD *)a1 + 2) = qword_4170 ^ qword_4080;
*((_DWORD *)a1 + 6) = qword_4178 ^ dword_4088;
*((_WORD *)a1 + 14) = WORD2(qword_4178) ^ word_408C;
LOBYTE(i) = BYTE6(qword_4178) ^ byte_408E;
a1[30] = BYTE6(qword_4178) ^ byte_408E;
}
return i;
}

Step 3:

Đoạn code trên là của hàm mgs5

Ta sẽ bấm vào mgs5 🙂

Nhìn code trên nhìn chán nản hỉ :)) nhưng không sao ta sẽ đi phân tích nào

Đi vào xormask xem sao

Cái này như thể là các nội của các giá trị được xor như trên mã giả là ở đây ( ý tưởng tại đây ta thử lấy các thông tin trong mã giải này.

*(_QWORD *)a1 = xormask ^ fmsg;
*((_QWORD *)a1 + 1) = qword_4168 ^ qword_4078;
*((_QWORD *)a1 + 2) = qword_4170 ^ qword_4080;
*((_DWORD *)a1 + 6) = qword_4178 ^ dword_4088;
*((_WORD *)a1 + 14) = WORD2(qword_4178) ^ word_408C;
LOBYTE(i) = BYTE6(qword_4178) ^ byte_408E;
a1[30] = BYTE6(qword_4178) ^ byte_408E;

Viết lại code keygen xem tiến trình hoạt động ra sao

xormask = [0x4B, 0x7A, 0xB1, 0x7E, 0x11, 0x80, 0x46, 0x9A]fmsg = [0x25, 0x08, 0xD0, 0x1B, 0x7D, 0xC6, 0x12, 0xD9]qword_4168 = [0xEA, 0x14, 0x1B, 0xB0, 0xAC, 0xF3, 0xBE, 0x01]qword_4170 = [0x5B, 0xF2, 0x48, 0xF3, 0x9C, 0x3F, 0xAD, 0x27]qword_4178 = [0xE7, 0x01, 0x8E, 0xA8, 0x42, 0x63, 0x7E, 0xFC]
qword_4078 = [0xB5, 0x7F, 0x7A, 0xDD, 0xDF, 0x92, 0xF3, 0x7A]qword_4080 = [0x28, 0x81, 0x2D, 0x81, 0xE8, 0x4D, 0xC2, 0x61]dword_4088 = [0x74, 0x5B, 0x4F, 0xA3]
word_408C = [0xF3, 0x9D]
flag = ”for i in range(len(xormask) – 1, -1, -1):    flag += chr(xormask[i] ^ fmsg[i])
for i in range(len(qword_4168) – 1, -1, -1):    flag += chr(qword_4168[i] ^ qword_4078[i])
for i in range(len(qword_4080) – 1, -1, -1):    flag += chr(qword_4080[i] ^ qword_4170[i])
flag1 = ”for i in range(len(dword_4088)):    flag1 += chr(dword_4088[i] ^ qword_4178[i + 4])flag += flag1[::-1]
flag += chr(qword_4178[3] ^ word_408C[1]) + chr(qword_4178[2] ^ word_408C[0])
print(flag)

Code keygen và chạy ra được flag : CTFlearn{Masmak_Fortress_1865}

Step 4:

Check lại chương trình

Ok thành công rồi

Chllenge 4

10 points Easy

This is a beginners Reversing Challenge. It is build with the optimization level set to 0 so that the assembler is more readable. If you are new to reversing, please remember that to solve Reversing challenges you probably need to know some C/C++, Assembler and also some experience with gdb (the gnu debugger). And maybe Ghidra. So this challenge is a great place to start Reversing, but unfortunately it’s only 10 points because it’s easier than other reversing challenges. It probably requires more skills than solving a 10 point Forensics problem like RubberDuck. If you solve the challenge you can use the flag to decrypt the sources and see how the challenge is created.

Step 1:

Kiểm tra file và chạy thử ct như thử thách trước

Step 2:

Load vào IDA và phân tích

Mã giả IDA

Tìm hàm check flag

Step 2:

Trong hàm check flag có data ta thử click vào xem có gì

Cũng không có gì thử bấm phím x xem có nơi là chứa nội dung này không

Ok ta đã nhảy đến chỗ hàm Intdata

click vào theo mình

Có một mớ dữ liệu byte ở đây

Step 3

Keygen chương trình

import numpy as np

data = [0x13693, 0x6b2c0, 0x11a9f9, 0x157000, 0x1cb91, 0x1bb528, 0x1bb528, 0xded21, 0x144f38, 0xfb89d, 0x169b48, 0xd151f, 0x8b98b, 0x17d140, 0xded21, 0x1338c0, 0x1338c0, 0x11a9f9, 0x1b000, 0x144f38, 0x1734eb]

s = ""
for d in data:
	i = round(np.cbrt(d))
	s+=chr(i)
	
print(s)

# Flag +Lip1zzaner_Stalli0ns