Try   HackMD

Hack The Box - Reversing (Medium 3)

image

Ghi chú:

Difficulty: Medium

Challenge 13: Debugme

A develper is experiementing with different ways to protect their software. They have sent in a windows binary that is suposed to super secureand really hard to debug. Debug and see if you can find the flag.

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

Mở file trong IDA32, quan sát trong hàm mainCRTStartup_0 ta thấy chương trình sử dụng BeingDebugged và NtGlobalFlag field của PEB để kiểm tra chương trình có đang debug không.

image

Sau đó, thực hiện XOR các byte của hàm main() với opcode 0x5C để có thể thực thi được.

import ida_bytes
start = 0x00401620
end = 0x00401791
for i in range(start,end):
    tmp = ida_bytes.get_byte(i)
    ida_bytes.patch_byte(i,tmp^0x5C)

Ta được nội dụng hàm main() như sau:

image

Chương trình thực hiện lấy v11 XOR 0x4B rồi trả về kết quả tính được.

v11 = [0x277B391F, 0x2C252227, 0x3F250A14, 0x780F147A, 0x0C0C3E29, 0x3F14192E, 0x20282239, 0x14191431, 0x6A253E2D]
data = ""
for num in v11:
    hex_str = format(num, '08x')
    reversed_str = ''.join(reversed([hex_str[i:i+2] for i in range(0, len(hex_str), 2)]))
    data += reversed_str
print(data)
# 1f397b272722252c140a253f7a140f78293e0c0c2e19143f39222820311419142d3e256a

image

Flag: HTB{Tr0lling_Ant1_D3buGGeR_trickz_R_fun!}

Challenge 14: Iterative Virus

While cleaning up the workspace of a recently retired employee, we noticed that one of the core files of the very important programs they were working on didn't match up with the backups we have of it, could you check it out for us?

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

image

image

Tệp có 7 section, khi ta mở file trong PEBear, ta tìm thấy tệp có một section tên ivir. Đây là một section lạ. Đồng thời, ta lại thấy Timestamp = deadc0de.

image

Mở chương trình trong IDA64.

image

Trong hệ điều hành Windows, cấu trúc Thread Environment Block (TEB) sẽ chứa thông tin chi tiết cần thiết để quản lý luồng (thread) đang chạy. TEB là một thành phần quan trọng trong không gian người dùng của hệ điều hành, liên quan mật thiết đến việc thực thi và điều hành các chương trình.

Bên trong TEB, ta có ProcessEnvironmentBlock (PEB) nắm giữ thông tin môi trường chi tiết của quá trình mà luồng nằm trong. PEB cũng chứa thành viên Ldr – nó cung cấp quyền truy cập vào danh sách liên kết InMemoryOrderModuleList, nơi liệt kê tất cả các module đã được nạp theo đúng thứ tự trong bộ nhớ. Thông qua danh sách này, Ldr giúp quản lý các module khác nhau

Từng API trong module sẽ được tính checksum CRC32 và kiểm tra có bằng 0xBC553B82. Ta sẽ tìm được chương trình muốn gọi GetProcAddress

image

Hàm sub_14001C1A8 để xác định hành động cần thực hiện - sao chép tên các API để sử dụng GetProcAddress sau này gọi các API đó.

image

Từ đây, ta có thể thay đổi tên của các biến để chương trình rõ ràng và dễ hiểu hơn. Mục đích của nó để tải động các hàm từ kernel32.dll, sử dụng trong việc xử lý tệp và quản lý tiến trình.

image

Chương trình kiểm tra byte thứ năm từ EntryPoint có giá trị là 5 hay không. Nếu có, nó sẽ gọi một hàm hiện tại được mã hóa, nếu không, mã sẽ chọn và lưu trữ một số 64-bit sẽ được sử dụng sau này để giải mã. Khi chưa thực thi, giá trị byte đó là 1.

image

Chương trình sẽ kiểm tra qua các tệp có phần mở rộng exe. Nếu tìm thấy, nó tệp với tên đã có và cấp quyền truy cập (GENERIC_READ và GENERIC_WRITE). Nếu việc mở file thành công sẽ lấy kích thước của file. Sau đó, kích thước mới của file được tính bằng cách cộng thêm một giá trị cố định (0xD80) vào kích thước hiện tại của file, mục đích để ghi thêm một section mới.

Hàm này tạo ra một đối tượng file mapping. Khi một file được mapped, dữ liệu của nó có thể được xem như một mảng liên tục trong không gian địa chỉ của quá trình. Khi đã có một đối tượng file mapping, MapViewOfFile cho phép ánh xạ nó vào không gian địa chỉ của quá trình gọi hàm. Nó cũng cho phép bạn chỉ định cặp quyền truy cập và bảo vệ khi ánh xạ, như chỉ đọc, chỉ ghi, hoặc ghi đè.

Như ta đều đã biết, cấu trúc của một PE File bao gồm:

  1. DOS Header
  2. Rich Header
  3. NT Headers
  4. Data Directories (within the Optional Header)
  5. Section Headers
  6. Import Table
  7. Base Relocations Table

image

Đây là hình ảnh mô tả về phần DOS Header, DOS Stub and PE Header. Tại đây ta thấy, thành phần cuối cùng của DOS HeaderFile address of new exe header = 0xF8. Thành viên này rất quan trọng đối với trình tải PE trên hệ thống Windows vì nó cho trình tải biết nơi tìm PE Header.

image

Ta kết luận v25 = 0xF8 => v25 + 4 = 0xFCv25 + 8 = 0x100. Tương ứng với MachineTime Date Stamp. Biết v26 = v25 + 20 = 0x10Cv27 = v26 + 40 * Section Count = 0x224.

RVAFileOffset sẽ có giá trị là phần đầu của section.

Ở đây tôi đang ví dụ với tệp đề cho. Trên thực thế, nó không thể load chính nó được vì tệp được load sẽ bị chương trình take control một cách tuyệt đối. Không thể mở nó trong các chương trình khác.

Hiểu đến đây, ta sẽ sử dụng struct của PE header để sửa chương trình cho thuận tiện trong phân tích sau này.

struct _IMAGE_DOS_HEADER
{
    USHORT e_magic;                                                         //0x0
    USHORT e_cblp;                                                          //0x2
    USHORT e_cp;                                                            //0x4
    USHORT e_crlc;                                                          //0x6
    USHORT e_cparhdr;                                                       //0x8
    USHORT e_minalloc;                                                      //0xa
    USHORT e_maxalloc;                                                      //0xc
    USHORT e_ss;                                                            //0xe
    USHORT e_sp;                                                            //0x10
    USHORT e_csum;                                                          //0x12
    USHORT e_ip;                                                            //0x14
    USHORT e_cs;                                                            //0x16
    USHORT e_lfarlc;                                                        //0x18
    USHORT e_ovno;                                                          //0x1a
    USHORT e_res[4];                                                        //0x1c
    USHORT e_oemid;                                                         //0x24
    USHORT e_oeminfo;                                                       //0x26
    USHORT e_res2[10];                                                      //0x28
    LONG e_lfanew;                                                          //0x3c
};
struct _IMAGE_NT_HEADERS
{
    ULONG Signature;                                                        //0x0
    struct _IMAGE_FILE_HEADER FileHeader;                                   //0x4
    struct _IMAGE_OPTIONAL_HEADER OptionalHeader;                           //0x18
}; 

image

Chương trình thực hiện kiểm tra:

  • Kiểm tra xem vùng nhớ được ánh xạ không rỗng nhằm đảm bảo rằng việc ánh xạ file vào bộ nhớ đã thành công.
  • Kiểm tra signature của DOS header là "MZ"
  • Kiểm tra xem architecture của file có kiến trúc 64bit
  • Kiểm tra timestamp của file giá trị là 'THIS'
  • Kiểm tra xem kích thước của các phần header và section không vượt quá kích thước của header của tệp

image

Lấy giá trị của trường SizeOfHeaders từ Optional Header. Kiểm tra xem kích thước mới của section .ivir (0xD80) có phải là bội số của SizeOfHeaders không, nếu không thì bổ sung thêm. Tính toán con trỏ đến dữ liệu thô của section .ivir bằng cách cộng trường PointerToRawDataVirtualSize của section. Đặt các cờ của section .ivir với các quyền truy cập thích hợp. Cập nhật kích thước của image trong File HeaderTimestamp.

image

Lấy giá trị của các cờ của section .ivir gán với 0x60500060, ta đặt tên biến là IvirSectionFlag. Các thay đổi này tạo ra một section mới trong file thực thi và cập nhật các giá trị SizeOfCode Initialized DataUninitialized Data nếu cần thiết. Dựa trên những giá trị cài đặt của các cờ bit để điều chỉnh kích thước section trong file thực thi.

image

Nếu đủ vùng nhớ phần cho phần section mới, nó sẽ được ghi thêm section đó và section header được thêm và sửa đổi để đảm bảo chúng tuân thủ các quy tắc căn chỉnh và phần còn lại của quá trình chỉ là sao chép mã lây nhiễm và làm cho nó thay thế EntryPoint của injected file

image

image

Thiết lập để trỏ tới ký tự cuối cùng trong file có kích thước mới. Nếu vị trí con trỏ vượt qua giới hạn của vùng nhớ hiện tại, nó sẽ di chuyển dữ liệu cũ sang phía sau để tạo không gian cho dữ liệu mới. Sau đó, nó thực hiện việc sao chép dữ liệu mới từ vị trí bắt đầu của start vào vùng nhớ đã được làm trống. Sau khi hoàn thành việc xử lý dữ liệu, nó đóng tài nguyên bằng cách gọi hàm CloseHandle().

image

Phần cuối của chương trình thực hiện giải mã nhiều lần bằng cách sử dụng các khóa đã đề cập ở trên - start + 5. Lúc đầu nó có giá trị là 1, sau mỗi lần giải mã thì tăng 1 cho giá trị đó, túc là lặp lại 4 lần đến khi *(start + 5) = 5 thì gọi hàm byte_14001C7E4(). Ta viết đoạn mã để giải mã hàm này.

import ida_bytes
keys = [0x6E2368B9C685770B,0xEB7FD64E061C1A3D,0xCB8FF2D53D7505A1,0x0F1EF554206DCE4D]

for i in range(0x14001C7E4,0x14001C7E4+0x198,8):
    data = (ida_bytes.get_qword(i))
    for key in keys:
    	data = (data * key) & 0xFFFFFFFFFFFFFFFF
    ida_bytes.patch_qword(i,data)

Ta di chuyển đến và bôi đen từ 0x14001C7E4 đến 14001C971make code -> make function. Hãy chắc rằng bạn đã NOP bốn byte tại byte_14001C018. Ta sẽ nhận được các hàm sau.

image

Đoạn mã load một số hàm quan trọng từ thư viện kernel32.dll và user32.dll bằng cách sử dụng hàm GetFunction_v2, sau đó gọi một số hàm API của hệ thống như GetUserNameAMessageBoxA để thực hiện các tác vụ như hiển thị hộp thoại thông báo và lấy tên người dùng. Sau đó, mã kiểm tra xem tên người dùng có khớp với một giá trị cụ thể không. Nếu có thì tạo MessageBoxA và in ra flag

image

Flag: HTB{f1V3_it3RaTiOn_V1rus}

Challenge 15: Coffee Invocation

Our new crazy conspiracy theorist intern, has blocked everyone from the coffee machine because he saw that aliens were trying to steal the "out of the world" secret recipe. Your mission is to unveil the secrets that lie behind his profound madness and teach him a javaluable lesson.

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

Mở chương trình trong IDA64.

image

JNI (java native interface) là framework cho phép gọi các hàm java trong JVM(java virtual machine) từ các ngôn ngữ thấp hơn như C++, C, assembly Cocos2dx cung cấp 1 class singleton để có thể sử dụng JNI đó là JNIHelper. Để sử dụng JNI_CreateJavaVM, bạn cần bao gồm tệp jni.h trong chương trình C của mình. Hàm sẽ có cấu trúc như sau: JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);.

image

Khi chạy chương trình bình thường, nó sẽ thông báo thiếu thư viện libjvm.so. Ta thực hiện các bước sau:

  1. sudo apt update
  2. sudo apt install openjdk-17-jdk
  3. sudo gedit ~/.bashrc
    export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
  4. LD_LIBRARY_PATH=/usr/lib/jvm/java-17-openjdk-amd64/lib/server ./coffee_invocation

image

Ta đã biết thực chất đây là một chương trình C/C++
sử dụng JNI để chạy các hàm Java. Ta sẽ xây dựng struct của các function trong Java. Tôi đã tham khảo:

Ta viết đoạn struct có nội dung sau:

struct JNINativeInterface
{
  _QWORD NULL1;
  _QWORD NULL2;
  _QWORD NULL3;
  _QWORD NULL4;
  _QWORD GetVersion;
  _QWORD DefineClass;
  _QWORD FindClass;
  _QWORD FromReflectedMethod;
  _QWORD FromReflectedField;
  _QWORD ToReflectedMethod;
  _QWORD GetSuperclass;
  _QWORD IsAssignableFrom;
  _QWORD ToReflectedField;
  _QWORD Throw;
  _QWORD ThrowNew;
  _QWORD ExceptionOccurred;
  _QWORD ExceptionDescribe;
  _QWORD ExceptionClear;
  _QWORD FatalError;
  _QWORD PushLocalFrame;
  _QWORD PopLocalFrame;
  _QWORD NewGlobalRef;
  _QWORD DeleteGlobalRef;
  _QWORD DeleteLocalRef;
  _QWORD IsSameObject;
  _QWORD NewLocalRef;
  _QWORD EnsureLocalCapacity;
  _QWORD AllocObject;
  _QWORD NewObject;
  _QWORD NewObjectV;
  _QWORD NewObjectA;
  _QWORD GetObjectClass;
  _QWORD IsInstanceOf;
  _QWORD GetMethodID;
  _QWORD CallObjectMethod;
  _QWORD CallObjectMethodV;
  _QWORD CallObjectMethodA;
  _QWORD CallBooleanMethod;
  _QWORD CallBooleanMethodV;
  _QWORD CallBooleanMethodA;
  _QWORD CallByteMethod;
  _QWORD CallByteMethodV;
  _QWORD CallByteMethodA;
  _QWORD CallCharMethod;
  _QWORD CallCharMethodV;
  _QWORD CallCharMethodA;
  _QWORD CallShortMethod;
  _QWORD CallShortMethodV;
  _QWORD CallShortMethodA;
  _QWORD CallIntMethod;
  _QWORD CallIntMethodV;
  _QWORD CallIntMethodA;
  _QWORD CallLongMethod;
  _QWORD CallLongMethodV;
  _QWORD CallLongMethodA;
  _QWORD CallFloatMethod;
  _QWORD CallFloatMethodV;
  _QWORD CallFloatMethodA;
  _QWORD CallDoubleMethod;
  _QWORD CallDoubleMethodV;
  _QWORD CallDoubleMethodA;
  _QWORD CallVoidMethod;
  _QWORD CallVoidMethodV;
  _QWORD CallVoidMethodA;
  _QWORD CallNonvirtualObjectMethod;
  _QWORD CallNonvirtualObjectMethodV;
  _QWORD CallNonvirtualObjectMethodA;
  _QWORD CallNonvirtualBooleanMethod;
  _QWORD CallNonvirtualBooleanMethodV;
  _QWORD CallNonvirtualBooleanMethodA;
  _QWORD CallNonvirtualByteMethod;
  _QWORD CallNonvirtualByteMethodV;
  _QWORD CallNonvirtualByteMethodA;
  _QWORD CallNonvirtualCharMethod;
  _QWORD CallNonvirtualCharMethodV;
  _QWORD CallNonvirtualCharMethodA;
  _QWORD CallNonvirtualShortMethod;
  _QWORD CallNonvirtualShortMethodV;
  _QWORD CallNonvirtualShortMethodA;
  _QWORD CallNonvirtualIntMethod;
  _QWORD CallNonvirtualIntMethodV;
  _QWORD CallNonvirtualIntMethodA;
  _QWORD CallNonvirtualLongMethod;
  _QWORD CallNonvirtualLongMethodV;
  _QWORD CallNonvirtualLongMethodA;
  _QWORD CallNonvirtualFloatMethod;
  _QWORD CallNonvirtualFloatMethodV;
  _QWORD CallNonvirtualFloatMethodA;
  _QWORD CallNonvirtualDoubleMethod;
  _QWORD CallNonvirtualDoubleMethodV;
  _QWORD CallNonvirtualDoubleMethodA;
  _QWORD CallNonvirtualVoidMethod;
  _QWORD CallNonvirtualVoidMethodV;
  _QWORD CallNonvirtualVoidMethodA;
  _QWORD GetFieldID;
  _QWORD GetObjectField;
  _QWORD GetBooleanField;
  _QWORD GetByteField;
  _QWORD GetCharField;
  _QWORD GetShortField;
  _QWORD GetIntField;
  _QWORD GetLongField;
  _QWORD GetFloatField;
  _QWORD GetDoubleField;
  _QWORD SetObjectField;
  _QWORD SetBooleanField;
  _QWORD SetByteField;
  _QWORD SetCharField;
  _QWORD SetShortField;
  _QWORD SetIntField;
  _QWORD SetLongField;
  _QWORD SetFloatField;
  _QWORD SetDoubleField;
  _QWORD GetStaticMethodID;
  _QWORD CallStaticObjectMethod;
  _QWORD CallStaticObjectMethodV;
  _QWORD CallStaticObjectMethodA;
  _QWORD CallStaticBooleanMethod;
  _QWORD CallStaticBooleanMethodV;
  _QWORD CallStaticBooleanMethodA;
  _QWORD CallStaticByteMethod;
  _QWORD CallStaticByteMethodV;
  _QWORD CallStaticByteMethodA;
  _QWORD CallStaticCharMethod;
  _QWORD CallStaticCharMethodV;
  _QWORD CallStaticCharMethodA;
  _QWORD CallStaticShortMethod;
  _QWORD CallStaticShortMethodV;
  _QWORD CallStaticShortMethodA;
  _QWORD CallStaticIntMethod;
  _QWORD CallStaticIntMethodV;
  _QWORD CallStaticIntMethodA;
  _QWORD CallStaticLongMethod;
  _QWORD CallStaticLongMethodV;
  _QWORD CallStaticLongMethodA;
  _QWORD CallStaticFloatMethod;
  _QWORD CallStaticFloatMethodV;
  _QWORD CallStaticFloatMethodA;
  _QWORD CallStaticDoubleMethod;
  _QWORD CallStaticDoubleMethodV;
  _QWORD CallStaticDoubleMethodA;
  _QWORD CallStaticVoidMethod;
  _QWORD CallStaticVoidMethodV;
  _QWORD CallStaticVoidMethodA;
  _QWORD GetStaticFieldID;
  _QWORD GetStaticObjectField;
  _QWORD GetStaticBooleanField;
  _QWORD GetStaticByteField;
  _QWORD GetStaticCharField;
  _QWORD GetStaticShortField;
  _QWORD GetStaticIntField;
  _QWORD GetStaticLongField;
  _QWORD GetStaticFloatField;
  _QWORD GetStaticDoubleField;
  _QWORD SetStaticObjectField;
  _QWORD SetStaticBooleanField;
  _QWORD SetStaticByteField;
  _QWORD SetStaticCharField;
  _QWORD SetStaticShortField;
  _QWORD SetStaticIntField;
  _QWORD SetStaticLongField;
  _QWORD SetStaticFloatField;
  _QWORD SetStaticDoubleField;
  _QWORD NewString;
  _QWORD GetStringLength;
  _QWORD GetStringChars;
  _QWORD ReleaseStringChars;
  _QWORD NewStringUTF;
  _QWORD GetStringUTFLength;
  _QWORD GetStringUTFChars;
  _QWORD ReleaseStringUTFChars;
  _QWORD GetArrayLength;
  _QWORD NewObjectArray;
  _QWORD GetObjectArrayElement;
  _QWORD SetObjectArrayElement;
  _QWORD NewBooleanArray;
  _QWORD NewByteArray;
  _QWORD NewCharArray;
  _QWORD NewShortArray;
  _QWORD NewIntArray;
  _QWORD NewLongArray;
  _QWORD NewFloatArray;
  _QWORD NewDoubleArray;
  _QWORD GetBooleanArrayElements;
  _QWORD GetByteArrayElements;
  _QWORD GetCharArrayElements;
  _QWORD GetShortArrayElements;
  _QWORD GetIntArrayElements;
  _QWORD GetLongArrayElements;
  _QWORD GetFloatArrayElements;
  _QWORD GetDoubleArrayElements;
  _QWORD ReleaseBooleanArrayElements;
  _QWORD ReleaseByteArrayElements;
  _QWORD ReleaseCharArrayElements;
  _QWORD ReleaseShortArrayElements;
  _QWORD ReleaseIntArrayElements;
  _QWORD ReleaseLongArrayElements;
  _QWORD ReleaseFloatArrayElements;
  _QWORD ReleaseDoubleArrayElements;
  _QWORD GetBooleanArrayRegion;
  _QWORD GetByteArrayRegion;
  _QWORD GetCharArrayRegion;
  _QWORD GetShortArrayRegion;
  _QWORD GetIntArrayRegion;
  _QWORD GetLongArrayRegion;
  _QWORD GetFloatArrayRegion;
  _QWORD GetDoubleArrayRegion;
  _QWORD SetBooleanArrayRegion;
  _QWORD SetByteArrayRegion;
  _QWORD SetCharArrayRegion;
  _QWORD SetShortArrayRegion;
  _QWORD SetIntArrayRegion;
  _QWORD SetLongArrayRegion;
  _QWORD SetFloatArrayRegion;
  _QWORD SetDoubleArrayRegion;
  _QWORD RegisterNatives;
  _QWORD UnregisterNatives;
  _QWORD MonitorEnter;
  _QWORD MonitorExit;
  _QWORD GetJavaVM;
  _QWORD GetStringRegion;
  _QWORD GetStringUTFRegion;
  _QWORD GetPrimitiveArrayCritical;
  _QWORD ReleasePrimitiveArrayCritical;
  _QWORD GetStringCritical;
  _QWORD ReleaseStringCritical;
  _QWORD NewWeakGlobalRef;
  _QWORD DeleteWeakGlobalRef;
  _QWORD ExceptionCheck;
  _QWORD NewDirectByteBuffer;
  _QWORD GetDirectBufferAddress;
  _QWORD GetDirectBufferCapacity;
  _QWORD GetObjectRefType;
};
struct JNIEnv
{
  JNINativeInterface *function;
};

Trong IDA -> View -> Open subviews -> Local types -> Insert vào tạo struct như trên. Lưu ý, tôi đã dùng tên NULL1, NULL2, NULL3 ,NULL4 để tránh trùng tên khi xây dựng struct. Hãy chắc rằng bạn Set type cho _int64 a1 thành JNINativeInterface *env.

Từ đây ta phân tích chương trình bình thường.

image

Nếu số lượng tham số nhỏ hơn hoặc bằng 1, chương trình sẽ in ra một thông báo cảnh báo. Ngược lại, nếu có ít nhất một tham số truyền vào, chương trình sẽ gọi hàm sub_1FB9() với tham số thứ nhất của dòng lệnh.

image

Tại hàm sub_2121() chương trình sẽ hiển thị menu lựa chọn: Normal Coffee, Espresso, [REDACTED], Exit. Tất cả đều dẫn đến kết thúc chương trình

image

Hàm bắt đầu bằng việc gọi hai hàm khác check1check2 để kiểm tra quyền truy cập vào cà phê. Nếu bất kỳ một trong số hàm này trả về kết quả khác không (có nghĩa là không có quyền truy cập), hàm sẽ in ra thông báo "No coffee for you!" và trả về 1.

Nếu không có vấn đề gì với quyền truy cập, hàm sẽ in ra thông báo "Access granted." và tiếp tục với việc in ra danh sách cà phê có sẵn để lựa chọn. Sau khi in ra danh sách cà phê, hàm sẽ in ra thông báo "Enjoy!"flag.

Hàm check1():

Đầu tiên chúng ta cần vượt qua hàm check1.

__int64 __fastcall loadShutdownNativeFunctions(JNIEnv *env, __int64 a2)
{
  __int64 ShutdownClassObject; 

  qword_87D0 = a2;
  ShutdownClassObject = env->function->FindClass(env, "java/lang/Shutdown");
  return env->function->RegisterNatives(env,v3,halt0,2LL);
}

Tại hàm loadShutdownNativeFunctions, nó gọi RegisterNatives - cho phép ta thay đổi hàm tại halt0runAllFinalizers. Giải thích sơ qua về hai hàm.

  • halt0: thường được gọi sau khi hàm System.exit(status_code) được thực thi trong chương trình Java. Hàm này sẽ kết thúc Java Virtual Machine. Tuy nhiên, hàm register_shutdown sẽ chặn hàm halt0 và chuyển hướng nó đến hàm được trỏ bởi con trỏ on_halt. Điều này cho phép bạn thực hiện các hành động tùy chỉnh trước khi JVM kết thúc hoàn toàn.
  • runAllFinalizers: thường chạy tất cả các finalizer đã đăng ký trước khi JVM kết thúc. Finalizer là một phương thức được gọi tự động khi đối tượng không còn được tham chiếu bởi bất kỳ biến nào. Finalizer thường được sử dụng để giải phóng tài nguyên được cấp phát bởi đối tượng. Họ đã không đề cập gì về nó, nên không có thay đổi gì.
__int64 __fastcall set_bytes_to_var_in_jvm(JNIEnv *env, __int64 mangJNI1)
{
  ByteClassObject = env->function->FindClass(env, "java/lang/Byte");
  MethodID = env->function->GetStaticMethodID(env,ByteClassObject,"valueOf","(B)Ljava/lang/Byte;");
  FieldID = env->function->GetFieldID(env,ByteClassObject,"value","B");
  for ( index = 0; index <= 255; ++index )
  {
    byteObject = env->function->CallStaticObjectMethod(env, ByteClassObject, MethodID, index);
    env->function->SetByteField(env, byteObject, FieldID, (unsigned int)*(mangJNI1 + index);
  }
  return byteObject;
}

Thực hiện đặt các byte từ mangJNI1 vào một biến trong môi trường JVM

__int64 __fastcall set_short_to_var_in_jvm(JNIEnv *env, __int64 mangJNI2)
{
  ShortClassObject = env->function->FindClass(env, "java/lang/Short");
  MethodID = env->function->GetStaticMethodID(env,ShortClassObject,"valueOf","(S)Ljava/lang/Short);
  FieldID = env->function->GetFieldID(env,ShortClassObject,"value","S");
  for ( index = 0; index <= 255; ++index )
  {
    shortObject = env->function->CallStaticObjectMethod(env, ShortClassObject, MethodID, index);
    env->function->SetShortField(env,v8,FieldID,(unsigned int)*(mangJNI2 +index));
  }
  return shortObject;
}

Thực hiện đặt các short (2 byte) từ mangJNI2 vào một biến trong môi trường JVM

__int64 __fastcall check1(JNIEnv *env, __int64 password){
    // trả về hàm halt được lưu trong code dạng biến toàn cục
  loadShutdownNativeFunctions(env, (__int64)on_halt);
    // trỏ tới các mảng byte và short sẽ truyền cho biến của JVM - dùng để ánh xạ
  array1 = return_array_for_mapping(1);
  set_bytes_to_var_in_jvm(env, array1);
  array2 = return_array_for_mapping(2);
  set_short_to_var_in_jvm(env, array2);
    // tạo Java Class Object
  BufferContainClassData = get_verify_class(0, 0xCAFEBABE);
  Verify1ClassObject = env->function->DefineClass(env, "Verify1", 0LL, BufferContainClassData, 0XCAFEBABE);
    // tạo mảng cho vùng nhớ unk_3140 để lưu các mảng, nó là Java Array Object
  NewArrayObject = env->function->NewObjectArray;
  javaStringObject = env->function->NewStringUTF(env, &unk_3140);
    // tạo 2 Array Object để lưu trữ Password và Check_password_byte
  javaStringClass = env->function->FindClass(env, "java/lang/String");
  stringArrayObject = NewArrayObject(env, 2LL, javaStringClass, javaStringObject);
    // tạo Java Array Object từ Password
  NewPasswordStringObject = env->function->NewStringUTF(env, password);
  PasswordStringObjectClass = env->function->GetObjectClass(env,NewPasswordStringObject);
    // nhận ID của phương thức Substring
  SubstringMethod = env->function->GetMethodID(env,PasswordStringObjectClass,"substring","(II)Ljava/lang/String;");
    // Lấy giá trị Password từ 0->0x1A (vẫn là Array Object)
  SetObjectArrayElement = env->function->_SetObjectArrayElement;
  PasswordSubstring = env->function->CallObjectMethod)(env,NewPasswordStringObject,SubstringMethod,0LL,0x1A);
  SetObjectArrayElement(env, stringArrayObject, 0LL, PasswordSubstring);
    // Lấy mảng byte để kiểm tra mật khẩu (vẫn là Array Object)
  _SetObjectArrayElement = env->function->_SetObjectArrayElement;
  NewString = env->function->NewStringUTF(env, &check_password_byte);
  _SetObjectArrayElement(env, stringArrayObject, 1LL, NewString);
    // nhận ID của phương thức main() và thực hiện gọi (verify1.class,main(),password,unknown_byte)
  MethodString = env->function->GetStaticMethodID(env,Verify1ClassObject,"main","([Ljava/lang/String;)V");
  env->function->CallStaticVoidMethod(env,Verify1ClassObject,MethodString,stringArrayObject);
    // trả về ánh xạ bình thường
  v11 = return_array_for_mapping(0);
  set_bytes_to_var_in_jvm(env, (__int64)v11);
  v12 = return_array_for_mapping(0);
  set_short_to_var_in_jvm(env, (__int64)v12);
  return (unsigned int)dword_87F4;
}

Hãy đọc mô tả hoạt động của hàm check1() ở trong phần mô ta code ở trên, tôi đã comment khá kĩ.

Binwalk là một công cụ mạnh mẽ và linh hoạt cho phép bạn phân tích, trích xuất và khám phá nội dung ẩn trong các file binary. Ta dùng binwalk để lấy các file ẩn, với câu lệnh: binwalk -D='.*' ./coffee_invocation. Sau khi trích xuất được, ta dùng http://www.javadecompilers.com/ để decompile chương trình. Tôi dùng Bytecode Viewer để xem thêm thông tin về Bytecode Disassembler

public class Verify1 {
   private static boolean compareByte(Byte var0, Short var1) {
      return var0 == var1;
   }

   public static void main(String[] var0) {
      if (var0 != null && var0.length == 2) {
         String var1 = var0[0];
         String var2 = var0[1];
         if (var1 != null && var2 != null) {
            if (var1.length() != var2.length()) {
               System.out.println("Source and Target don't have the same length");
               System.exit(2);
            } else {
               System.out.println("Verifying user is of terrestrial origin...");

               for(int var3 = 0; var3 < var1.length(); ++var3) {
                  if (!compareByte((byte)var1.charAt(var3), (short)((byte)var2.charAt(var3)))) {
                     System.out.println("=> User might be an alien!!!");
                     System.exit(3);
                     return;
                  }
               }

            }
         } else {
            System.out.println("Source and Target may not be null");
            System.exit(2);
         }
      } else {
         System.out.println("Verifying requires source and target");
         System.exit(1);
      }
   }
}

Trong lớp Verify1, thực hiện kiểm tra hai chuỗi. Nó so sánh từng ký tự của hai chuỗi và in ra một thông báo nếu chúng không giống nhau. Nếu một trong hai chuỗi là null hoặc nếu chiều dài của chúng không giống nhau, nó cũng in ra một thông báo tương ứng.

Như ta đã phân tích ở trên, hai chuỗi đó chính là passwordcheck_password_byte. Ta viết chương trình đề tìm ra nửa đầu của flag. Chú ý: bytes != Bytes và short != Short

bytes_mapping = [0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
short_mapping = [0x00, 0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xEC, 0xEB, 0xEA, 0xE9, 0xE8, 0xE7, 0xE6, 0xE5, 0xE4, 0xE3, 0xE2, 0xE1, 0xE0, 0xDF, 0xDE, 0xDD, 0xDC, 0xDB, 0xDA, 0xD9, 0xD8, 0xD7, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xD0, 0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8, 0xC7, 0xC6, 0xC5, 0xC4, 0xC3, 0xC2, 0xC1, 0xC0, 0xBF, 0xBE, 0xBD, 0xBC, 0xBB, 0xBA, 0xB9, 0xB8, 0xB7, 0xB6, 0xB5, 0xB4, 0xB3, 0xB2, 0xB1, 0xB0, 0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, 0xA8, 0xA7, 0xA6, 0xA5, 0xA4, 0xA3, 0xA2, 0xA1, 0xA0, 0x9F, 0x9E, 0x9D, 0x9C, 0x9B, 0x9A, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8F, 0x8E, 0x8D, 0x8C, 0x8B, 0x8A, 0x89, 0x88, 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
cipher = [0x7E, 0x50, 0x4C, 0x7B, 0x41, 0x3B, 0x50, 0x4C, 0x7B, 0x3F, 0x3B, 0x3A, 0x3D, 0x7C, 0x50, 0x49, 0x43, 0x7B, 0x48, 0x7A, 0x50, 0x3A, 0x41, 0x3B, 0x7E, 0x78]
stage1 = ''.join(chr(short_mapping[bytes_mapping[(value)]]) for value in cipher)
print(stage1)
# stage1 = 1_c4nt_c4ptur3_fl4g5_unt17

Sau khi lớp Verify1 được thực thi, ánh xạ của Byte và Short được trả về ánh xạ bình thường của chúng.

Hàm check2():

Ta phân tích hàm check2(), nó cũng gần tương tự như hàm check1(), nó có hơi phức tạp hơn một chút.

__int64 __fastcall SetBooleanField(JNIEnv *env)
{
  ByteClassObject = env->function->FindClass(env, "java/lang/Boolean");
  FalseMethodID = env->function->GetStaticMethodID(env,ByteClassObject,"FALSE","Ljava/lang/Boolean;");
  TrueMethodID = env->function->GetStaticMethodID(env,ByteClassObject,"TRUE","Ljava/lang/Boolean;");
  False_MethodID = env->function->GetStaticMethodID(env,ByteClassObject,TrueMethodID);
  True_MethodID = env->function->GetStaticMethodID(env,ByteClassObject,FalseMethodID);
  env->function->SetStaticObjectField(env,ByteClassObject,FalseMethodID,True_MethodID);
  env->function->SetStaticObjectField(env,ByteClassObject,TrueMethodID,False_MethodID);
}
Thực hiện đặt các byte từ mangJNI1 vào một biến trong môi trường JVM

Nó cũng hoán đổi ý nghĩa của True và False, do đó True trở thành False và False trở thành True.

image

Tại hàm loadShutdownNativeFunctions, halt0 ánh xạ tới hàm sub_190F(), thay vì thay đổi giá trị Byte và Short, nó thay đổi giá trị của Characters. Điều này có thể được thực hiện lên đến 13 lần.

__int64 __fastcall check2(JNIEnv *env, __int64 password){
    // trả về hàm sub_190F()
  loadShutdownNativeFunctions(env, sub_190F);
    // trỏ tới các mảng character sẽ truyền cho biến của JVM - dùng để ánh xạ
  array3 = return_array_for_mapping(3);
  copy_ascii_table(env,array3)
  SetBooleanField(env);    
    // tạo Java Class Object
  BufferContainClassData = get_verify_class(0, 0xCAFEBABE);
  Verify2ClassObject = env->function->DefineClass(env, "Verify2", 0LL, BufferContainClassData, 0XCAFEBABE);
    // tạo mảng cho vùng nhớ unk_3140 để lưu các mảng, nó là Java Array Object
  NewArrayObject = env->function->NewObjectArray;
  javaStringObject = env->function->NewStringUTF(env, &unk_3140);
    // tạo 1 Array Object để lưu trữ Password và Check_password_byte
  javaStringClass = env->function->FindClass(env, "java/lang/String");
  stringArrayObject = NewArrayObject(env, 1LL, javaStringClass, javaStringObject);
    // tạo Java Array Object từ Password
  NewPasswordStringObject = env->function->NewStringUTF(env, password);
  PasswordStringObjectClass = env->function->GetObjectClass(env,NewPasswordStringObject);
    // nhận ID của phương thức Substring
  SubstringMethod = env->function->GetMethodID(env,PasswordStringObjectClass,"substring","(II)Ljava/lang/String;");
    // Lấy giá trị Password từ 0x1A->0x1A*2 (vẫn là Array Object)
  SetObjectArrayElement = env->function->_SetObjectArrayElement;
  PasswordSubstring = env->function->CallObjectMethod)(env,NewPasswordStringObject,SubstringMethod,0x1A,0x1A+0x1A);
  SetObjectArrayElement(env, stringArrayObject, 0LL, PasswordSubstring);
    // nhận ID của phương thức main() và thực hiện gọi (verify1.class,main(),password)
  MethodString = env->function->GetStaticMethodID(env,Verify1ClassObject,"main","([Ljava/lang/String;)V");
  env->function->CallStaticVoidMethod(env,Verify1ClassObject,MethodString,stringArrayObject);
    // trả về ánh xạ bình thường
    SetBooleanField(env); 
    return (unsigned int)dword_87F4;
}

Hãy đọc mô tả hoạt động của hàm check2() ở trong phần mô ta code ở trên, tôi đã comment khá kĩ.

import java.io.PrintStream;
import java.util.Arrays;
import java.util.stream.Collectors;

public class Verify2 {
   private static boolean compareByte(Byte var0, Short var1) {
      PrintStream var10000 = System.out;
      byte var10001 = var0;
      var10000.println(var10001 + " == " + var1);
      return var0 == var1;
   }

   private static String complexSort(String var0, Boolean var1) {
      Object[] var2 = var0.chars().mapToObj((var0x) -> {
         return (char)var0x;
      }).toArray();
      if (var1) {
         Arrays.sort(var2);
      }

      String var3 = (String)Arrays.stream(var2).map(Object::toString).collect(Collectors.joining());
      return var3;
   }

   private static Boolean verifyPassword(String var0, String var1) {
      return var0.equals(var1);
   }

   public static void main(String[] var0) {
      if (var0 != null && var0.length == 1) {
         String var1 = var0[0];
         if (var1 == null) {
            System.out.println("Source may not be null");
            System.exit(1);
         } else if (var1.length() % 2 != 0) {
            System.out.println("Length must be even");
            System.exit(1);
         } else {
            System.out.println("Verifying user has authorization...");

            for(int var2 = 0; var2 < var1.length() / 2; ++var2) {
               String var3 = var1.substring(var2 * 2, var2 * 2 + 2);
               String var4 = complexSort(var3, true);
               String var5 = complexSort("Cr1KD5mk0_uUzQYifaGVqlN2B3wvpgPtSx6Odo{8hjJLHy9IXb4RnWZ}TAFEsMce7", false);
               if (var4.equals(var5.substring(var2 * 2, var2 * 2 + 2))) {
                  System.exit(var2 + 3);
               }
            }

            if (!verifyPassword(var1, "Tinfoil")) {
               System.out.println("Please enter the correct password");
               System.exit(2);
            }

         }
      } else {
         System.out.println("Verifying requires source");
         System.exit(1);
      }
   }
}

Có thể thấy, có một vài Boolean được hoán đổi, System.exit(i+3) sẽ hoán đổi các bảng giá trị ở mỗi lần lặp của vòng lặp, v.v. Điều này có nghĩa là cứ sau 2 lần lặp lại các ký tự sẽ cần một bảng thay thế khác được lưu trữ trong tệp. Ta viết chương trình đề tìm ra nửa sau của flag.

mapping = [
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x69,0x31,0x6C,0x64,0x5F,0x4E,0x34,0x61,0x6B,0x50,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x53,0x4F,0x65,0x71,0x41,0x76,0x46,0x32,0x52,0x43,0x4D,0x38,0x55,0x45,0x75,0x68,0x57,0x72,0x73,0x54,0x7B,0x47,0x62,0x56,0x49,0x7D,0x5B,0x5C,0x5D,0x5E,0x30,0x60,0x42,0x4B,0x67,0x63,0x6E,0x77,0x5A,0x4C,0x79,0x37,0x33,0x36,0x48,0x6A,0x6F,0x44,0x51,0x35,0x66,0x78,0x6D,0x74,0x7A,0x58,0x4A,0x70,0x59,0x7C,0x39,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x34,0x6F,0x4B,0x33,0x68,0x59,0x37,0x47,0x7A,0x4E,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x6E,0x45,0x51,0x7D,0x62,0x77,0x49,0x4A,0x38,0x57,0x79,0x67,0x35,0x74,0x78,0x58,0x56,0x66,0x71,0x65,0x54,0x73,0x6C,0x7B,0x43,0x76,0x5B,0x5C,0x5D,0x5E,0x36,0x60,0x75,0x69,0x6D,0x53,0x5F,0x63,0x6A,0x4F,0x6B,0x30,0x48,0x70,0x5A,0x52,0x4D,0x39,0x50,0x55,0x46,0x4C,0x31,0x32,0x64,0x42,0x41,0x72,0x61,0x7C,0x44,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x7D,0x46,0x6D,0x6E,0x72,0x64,0x54,0x37,0x75,0x5F,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x4A,0x41,0x70,0x66,0x30,0x68,0x50,0x43,0x57,0x39,0x69,0x65,0x4C,0x4B,0x71,0x53,0x47,0x55,0x62,0x42,0x49,0x67,0x6B,0x56,0x74,0x78,0x5B,0x5C,0x5D,0x5E,0x34,0x60,0x77,0x4F,0x38,0x7B,0x52,0x36,0x44,0x35,0x59,0x6F,0x61,0x76,0x73,0x45,0x33,0x31,0x51,0x58,0x63,0x6C,0x48,0x7A,0x4D,0x5A,0x32,0x4E,0x79,0x7C,0x6A,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x34,0x6C,0x32,0x5F,0x36,0x79,0x39,0x70,0x6F,0x74,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x50,0x4D,0x61,0x69,0x4F,0x67,0x68,0x51,0x75,0x63,0x58,0x72,0x7D,0x64,0x4C,0x57,0x5A,0x48,0x4E,0x31,0x77,0x42,0x71,0x49,0x53,0x6E,0x5B,0x5C,0x5D,0x5E,0x6D,0x60,0x30,0x54,0x59,0x37,0x35,0x6B,0x44,0x55,0x52,0x43,0x7B,0x66,0x33,0x7A,0x46,0x4B,0x4A,0x41,0x78,0x62,0x45,0x73,0x47,0x76,0x38,0x6A,0x65,0x7C,0x56,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x7B,0x79,0x70,0x6B,0x75,0x65,0x71,0x56,0x61,0x51,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x64,0x66,0x4E,0x74,0x58,0x48,0x47,0x42,0x4A,0x73,0x44,0x4C,0x36,0x7D,0x54,0x77,0x76,0x7A,0x4D,0x78,0x45,0x6D,0x59,0x62,0x67,0x50,0x5B,0x5C,0x5D,0x5E,0x38,0x60,0x39,0x5A,0x31,0x41,0x6F,0x37,0x46,0x35,0x49,0x72,0x69,0x43,0x33,0x57,0x32,0x6C,0x52,0x63,0x4B,0x55,0x68,0x34,0x53,0x30,0x6E,0x4F,0x5F,0x7C,0x6A,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x62,0x41,0x46,0x7A,0x56,0x58,0x4A,0x44,0x77,0x64,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x51,0x30,0x31,0x76,0x63,0x79,0x37,0x7D,0x72,0x59,0x61,0x45,0x32,0x4C,0x71,0x7B,0x54,0x35,0x69,0x6B,0x48,0x6C,0x75,0x5A,0x55,0x52,0x5B,0x5C,0x5D,0x5E,0x57,0x60,0x66,0x4B,0x4E,0x65,0x49,0x6E,0x74,0x67,0x38,0x5F,0x78,0x42,0x43,0x4F,0x36,0x53,0x50,0x34,0x70,0x33,0x6D,0x6F,0x39,0x6A,0x4D,0x68,0x47,0x7C,0x73,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x59,0x52,0x68,0x76,0x6E,0x7B,0x65,0x6A,0x5A,0x6D,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x45,0x31,0x79,0x7D,0x38,0x42,0x61,0x78,0x7A,0x63,0x6F,0x30,0x4D,0x57,0x41,0x50,0x39,0x67,0x64,0x4A,0x4C,0x56,0x58,0x4B,0x75,0x46,0x5B,0x5C,0x5D,0x5E,0x43,0x60,0x6B,0x6C,0x55,0x33,0x5F,0x71,0x47,0x4E,0x73,0x72,0x4F,0x32,0x44,0x49,0x74,0x54,0x70,0x34,0x77,0x66,0x35,0x69,0x51,0x53,0x62,0x36,0x37,0x7C,0x48,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x56,0x30,0x6F,0x78,0x64,0x4A,0x38,0x32,0x42,0x4D,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x75,0x62,0x7B,0x37,0x7D,0x7A,0x43,0x49,0x6E,0x53,0x50,0x5F,0x69,0x54,0x6D,0x72,0x65,0x6A,0x48,0x4F,0x58,0x41,0x6B,0x66,0x79,0x71,0x5B,0x5C,0x5D,0x5E,0x46,0x60,0x70,0x59,0x77,0x39,0x67,0x4C,0x35,0x68,0x52,0x33,0x47,0x55,0x36,0x5A,0x74,0x73,0x76,0x6C,0x51,0x4E,0x63,0x31,0x44,0x34,0x45,0x4B,0x61,0x7C,0x57,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x47,0x70,0x42,0x6C,0x30,0x71,0x4B,0x6F,0x59,0x62,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x34,0x4A,0x66,0x75,0x41,0x39,0x61,0x53,0x46,0x52,0x43,0x4D,0x79,0x73,0x49,0x38,0x54,0x50,0x55,0x65,0x57,0x7B,0x58,0x6A,0x32,0x56,0x5B,0x5C,0x5D,0x5E,0x7D,0x60,0x7A,0x36,0x68,0x69,0x76,0x31,0x4C,0x5F,0x6B,0x77,0x4F,0x37,0x78,0x6E,0x74,0x67,0x72,0x35,0x64,0x44,0x33,0x6D,0x63,0x48,0x4E,0x51,0x5A,0x7C,0x45,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x71,0x39,0x66,0x41,0x7A,0x62,0x76,0x30,0x4F,0x67,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x4A,0x55,0x49,0x38,0x59,0x51,0x61,0x69,0x45,0x6E,0x75,0x7B,0x47,0x68,0x33,0x34,0x58,0x54,0x5A,0x37,0x5F,0x44,0x74,0x50,0x4E,0x79,0x5B,0x5C,0x5D,0x5E,0x57,0x60,0x4D,0x35,0x77,0x6B,0x64,0x46,0x4C,0x36,0x42,0x56,0x31,0x52,0x6D,0x53,0x4B,0x70,0x48,0x73,0x7D,0x43,0x6C,0x65,0x32,0x6A,0x78,0x6F,0x63,0x7C,0x72,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x75,0x4E,0x72,0x42,0x74,0x44,0x45,0x63,0x4D,0x53,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x43,0x51,0x50,0x30,0x4C,0x4B,0x68,0x5F,0x67,0x33,0x32,0x66,0x70,0x52,0x7A,0x6A,0x76,0x47,0x4A,0x49,0x77,0x6E,0x64,0x7D,0x61,0x41,0x5B,0x5C,0x5D,0x5E,0x5A,0x60,0x46,0x73,0x7B,0x38,0x39,0x54,0x34,0x35,0x55,0x79,0x58,0x6C,0x62,0x71,0x69,0x48,0x36,0x4F,0x6D,0x6B,0x56,0x57,0x78,0x31,0x59,0x6F,0x65,0x7C,0x37,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x36,0x56,0x4B,0x4C,0x31,0x6F,0x47,0x7D,0x54,0x48,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x4E,0x4D,0x51,0x52,0x42,0x77,0x59,0x38,0x7B,0x32,0x41,0x74,0x57,0x6E,0x50,0x30,0x4A,0x79,0x46,0x58,0x6C,0x44,0x72,0x5F,0x43,0x6B,0x5B,0x5C,0x5D,0x5E,0x37,0x60,0x76,0x69,0x4F,0x6A,0x35,0x66,0x55,0x63,0x33,0x65,0x73,0x5A,0x67,0x7A,0x71,0x61,0x75,0x68,0x70,0x78,0x49,0x45,0x6D,0x39,0x64,0x53,0x62,0x7C,0x34,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
		[0x00,0x01,0x02,0x03,0x04,0x0c5,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x36,0x39,0x71,0x57,0x6F,0x38,0x4C,0x4A,0x51,0x56,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x7A,0x4F,0x48,0x4D,0x50,0x5A,0x68,0x75,0x58,0x73,0x55,0x49,0x4E,0x44,0x78,0x72,0x6B,0x63,0x4B,0x67,0x35,0x43,0x6E,0x62,0x70,0x74,0x5B,0x5C,0x5D,0x5E,0x66,0x60,0x64,0x30,0x77,0x46,0x34,0x41,0x32,0x45,0x6C,0x47,0x54,0x7D,0x61,0x65,0x33,0x6A,0x31,0x69,0x53,0x59,0x37,0x5F,0x52,0x42,0x76,0x7B,0x6D,0x7C,0x79,0x7E,0x7F,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
]

comparingstr = b'Cr1KD5mk0_uUzQYifaGVqlN2B3wvpgPtSx6Odo{8hjJLHy9IXb4RnWZ}TAFEsMce7'

def complexSort(s, mapping):
    mapped_chars = [mapping[c] for c in s]
    sorted_chars = sorted(mapped_chars)
    return sorted_chars

stage2 = ""

for i in range(13):
    secret = complexSort(comparingstr, mapping[i])
    stage2 +=  chr(mapping[i].index(secret[i*2])) + chr(mapping[i].index(secret[i*2+1]))
print(stage2)
# stage2 = _1v3_h4d_a1l_my_0xCAFEBABE

Tiến hành nhập flag ta vừa tìm được.

image

Flag: HTB{1_c4nt_c4ptur3_fl4g5_unt17_1v3_h4d_a1l_my_0xCAFEBABE}

Challenge 16: FFModule

After more and more recent hits of the infamous Jupiter Banking Malware we finally managed to get a sample of one module. Supposedly it steals secrets from Firefox users?

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

Mở chương trình trong IDA.

image

Khả năng cao chương trình sẽ hook module của Firefox. Vì vậy mình đã cài Firefox cho máy tính. Ta có thể quan sát hàm sub_140001000.

image

Sử dụng hàm CreateToolhelp32Snapshot để tạo ảnh chụp nhanh của các tiến trình đang chạy. Lặp qua danh sách các tiến trình và tìm tiến trình firefox.exe. Hàm CreateRemoteThread khiến một luồng thực thi mới bắt đầu trong không gian địa chỉ của quy trình đã chỉ định. Thread có quyền truy cập vào tất cả các đối tượng mà tiến trình mở ra => khả năng cao nó sẽ injected Firefox process.

Các chương trình mã độc sẽ sử dụng CreateRemoteThread API để có thể chạy mã lệnh trên một tiến trình khác. Ta so sánh giữa CreateThreadCreateRemoteThread

HANDLE CreateThread(
  [in, optional]  LPSECURITY_ATTRIBUTES   lpThreadAttributes,
  [in]            SIZE_T                  dwStackSize,
  [in]            LPTHREAD_START_ROUTINE  lpStartAddress,
  [in, optional]  __drv_aliasesMem LPVOID lpParameter,
  [in]            DWORD                   dwCreationFlags,
  [out, optional] LPDWORD                 lpThreadId
);
HANDLE CreateRemoteThread(
  [in]  HANDLE                 hProcess,
  [in]  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  [in]  SIZE_T                 dwStackSize,
  [in]  LPTHREAD_START_ROUTINE lpStartAddress,
  [in]  LPVOID                 lpParameter,
  [in]  DWORD                  dwCreationFlags,
  [out] LPDWORD                lpThreadId
);

Cả hai API đều khá giống nhau, tuy nhiên CreateRemoteThread có nhiều thuộc tính hơn.

  • hProcess: lấy handle của tiến trình mà ta sẽ thực thi lệnh
  • lpStartAddress: con trỏ tới hàm do ứng dụng xác định sẽ được luồng thực thi. Con trỏ này đại diện cho địa chỉ bắt đầu của luồng.
  • lpParameter: Một con trỏ tới một biến được truyền tới luồng.

image

Cách thức hoạt động: đầu tiên, Injector Process sẽ tạo nhớ trong không gian địa chỉ ảo và ghi DLL file path lên vùng nhớ đó. Sau đó, CreateRemoteThread sẽ gọi LoadLibrary API (hàm này sẽ cần path của các thư viện API). Khi ta tạo thread trong Target Pcocess - thread này sẽ trỏ đến LoadLibrary và load DLL mà ta đã ghi path vào vùng nhớ ở trên => injected DLL

Ta viết đoạn mã IDAPython để XOR vùng nhớ sub_140017000 và 0x72. Từ đó ta có thể quan sát hàm sub_140017005 chính xác hơn.

import ida_bytes
start = 0x140017000
for i in range(0x5A4):
    byte = ida_bytes.get_byte(start+i)
    ida_bytes.patch_byte(start+i,byte^0x72)

image

Hàm lấy con trỏ đến danh sách liên kết các module. NtCurrentTeb() trả về con trỏ đến cấu trúc Thread Environment Block, từ đó chúng ta truy cập thông tin về tiến trình thông qua ProcessEnvironmentBlock và danh sách liên kết các module bởi Ldr->InMemoryOrderModuleList. Tính mã CRC32 của module và so sánh để load module cần dùng

Một kĩ thuật hay hơn mình học được từ bạn kvn11 là mình có thể viết đoạn mã để tạo danh sách các module và tính CRC32. Ta sẽ chạy đoạn mã python để tạo danh sách các module, sau đó đưa danh sách ấy vào mảng name trong đoạn mã C

import requests
from bs4 import BeautifulSoup

URL = "https://www.geoffchappell.com/studies/windows/win32/kernel32/api/"

resp = requests.get(URL)
h = resp.text
soup = BeautifulSoup(h, 'html.parser')
fns = [tag.text for tag in soup.find_all('span', class_='function')]
print(fns)
// g++ -o api api.cpp -msse4.2

#include <immintrin.h>
#include <iostream>
#include <cstring>

unsigned int custom_crc32_u8(const char* data, size_t length, unsigned int crc) {
    for (size_t i = 0; i < length; i++) {
        crc = _mm_crc32_u8(crc, data[i]);
    }
    return crc;
}


int main() {
    const char* names[] = { 
        "functionNames",
    };
    unsigned int initial_value = 0xFFFFFFFF;

    for (const char* name : names) {
        unsigned int crc = custom_crc32_u8(name, strlen(name), initial_value);
        if ( ~crc == 0x43AAC47D) {
            std::cout << "~CRC-32 for '" << name << "': 0x" << std::hex << crc << std::dec << std::endl;
            break;
        }
    }
    return 0;
}

Ta tính được mã CRC32 là của hàm GetProcessAddress(). Chương trình lưu GetProcessAddress() vào r12 và sẽ thực hiện gọi nhiều lần.

Ta tiếp tục quan sát hàm sub_14001742D(), chương trình tiếp tục tính mã CRC32 của các module (ở đây là các *.dll).

image

Ta chạy đoạn mã python để tạo danh sách các module, sau đó đưa danh sách ấy vào mảng name trong đoạn mã C.

import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor

URL = "https://wikidll.com/{}-list?page="

def get_dll_links(char):
    dll_links = []
    url = URL.format(chr(char))
    for i in range(10):
        temp_url = url + str(i) 
        resp = requests.get(temp_url)
        html_content = resp.text
        soup = BeautifulSoup(html_content, 'html.parser')
        dll_links += [tag.text for tag in soup.find_all('a') if '.dll' in tag.text]
    return dll_links

with ThreadPoolExecutor() as executor:
    results = executor.map(get_dll_links, range(0x61, 0x7b))

dll_links = []
for result in results:
    dll_links.extend(result)

print(dll_links)
    // g++ -o api api.cpp -msse4.2

#include <immintrin.h>
#include <iostream>
#include <cstring>

unsigned int custom_crc32_u8(const char* data, size_t length, unsigned int crc) {
    for (size_t i = 0; i < length; i++) {
        crc = _mm_crc32_u8(crc, data[i]);
    }
    return crc;
}


int main() {
    const char* names[] = { 
        "NSS3.DLL","NSS3.dll","nss3.dll"

    };
    unsigned int initial_value = 0xFFFFFFFF;

    for (const char* name : names) {
        unsigned int crc = custom_crc32_u8(name, strlen(name), initial_value);
        // if ( ~crc == 0x8861D80B || ~crc == 0x3DCE28A2  || ~crc == 0x83BCBE6A) {
        if ( ~crc == 0x43AAC47D || ~crc == 0x8861D80B || ~crc == 0x3DCE28A2  || ~crc == 0x83BCBE6A) {
            std::cout << "CRC-32 for " << name << ": 0x" << std::hex << crc << std::dec << std::endl;
            std::cout << "~CRC-32 for " << name << ": 0x" << std::hex << ~crc << std::dec << std::endl;
            // break;
        }
    }
    return 0;
}

Sau khi đưa danh sách các DLL và tính toán, ta biết được kết ứng với nss3.dll và là kết quả duy nhất. Mình dự đoán chương trình sẽ chỉ gọi bản sao tên của nss3.dll nên đã thử và tìm được:

  • 0x3DCE28A2 ứng với NSS3.dll
  • 0x8861d80b ứng với nss3.dll
  • 0x83bcbe6a ứng với NSS3.DLL

Sau khi có địa chỉ bắt đầu của thư viện đó, Firefox sẽ lấy địa chỉ của hàm PR_Write trong Firefox's NSPR - được sử dụng để ghi dữ liệu vào một tệp hoặc socket. Hàm này trả về số byte đã được ghi thành công hoặc -1 nếu có lỗi xảy ra.

PRInt32 PR_Write(
  PRFileDesc *fd,
  const void *buf,
  PRInt32 amount);

Tại hàmsub_1400174B7(), chương trình thực hiện sao chép từ PR_Write sẽ được sao chép lên vùng nhớ của tiến trình.

image

Sau đó chương trình kiểm tra giá trị của RBX liệu có nhỏ hơn 4 và giá trị tại RDX có phải là STOP không. Ta có thể bỏ qua bước kiểm tra bằng cách thay RIP hiện tại.

Để bắt đầu sử dụng API Windows Sockets (ws2_32.dll), chương trình khởi tạo việc sử dụng WS2_32.DLL bằng lệnh gọi tới WSAStartup. Hàm này phải là hàm Windows Sockets đầu tiên được gọi bởi một ứng dụng hoặc DLL, cho biết phiên bản đặc tả Windows Sockets mà ứng dụng hoặc DLL mong muốn sử dụng và bắt đầu sử dụng WS2_32.DLL.

Chương trình gọi socket(2, 2, 17) để tạo một socket với các tham số cụ thể: Số đầu tiên 2 đại diện cho loại địa chỉ (AF_INET cho IPv4), số thứ hai 2 chỉ loại socket (SOCK_DGRAM cho gói tin datagram), và 17 chỉ định giao thức (IPPROTO_UDP cho giao thức UDP). Lệnh này sẽ tạo một socket UDP để giao tiếp qua IPv4.

Chương trình lấy địa chỉ của hàm sendto. Tiếp đó, chương trình tiến hành giải mã các byte và gửi dữ liệu đến một đích cụ thể.

image

Sau khi thực hiện xong, chương trình gọi closesocket để đóng socket hiện có. Từ đây, ta có thể viết đoạn mã để giải mã các byte được gửi đó.

encoded_message = [0x54, 0xD5, 0x13, 0x3A, 0x41, 0x99, 0xD4, 0xB6, 0x93, 0x74, 0x19, 0x41, 0x97, 0x61, 0x5A, 0xB6, 0x54, 0x61, 0x61, 0x38, 0x81, 0x98, 0xB7, 0xB6, 0xF4, 0xE1, 0xD8, 0xB9, 0x77, 0x19, 0xF7, 0xFA]

def rotate_left(data, shift, size=8):
    return ((data << shift) | (data >> (size - shift))) & ((1 << size) - 1)

flag = ''.join(chr(rotate_left((byte + 0xED) & 0xFF, 3) ^ 0x42) for byte in encoded_message)
Flag: HTB{3vL_FIr3f0x_H00k1ng_M4lware}

Challenge 17: SEPC

We've extracted an embedded operating system running on an intercepted deep-space satellitle launched by Arodor. If we can breach the secure enclave and extract their security mechanisms, we can crack their encrypted communications

Download Challenge Here

Solution

Chúng ta có thể sử dụng lệnh 'file' để cung cấp cái nhìn tổng quan về loại tệp.

image

Ta được cung cấp các tệp tin sau:

  • bzImage là kernel Linux image, được sử dụng để khởi động hệ điều hành.
  • initramfs.cpio.gz là hệ thống tập tin ban đầu được nén, chứa các công cụ và tập tin cần thiết để khởi động hệ thống.
  • run.sh là tập tin script bash, chứa các lệnh để tự động hóa việc khởi động hệ thống hoặc thực hiện các tác vụ khác.
qemu-system-x86_64 \
    -kernel bzImage \
    -initrd initramfs.cpio.gz \
    --append "console=ttyS0" \
    -nographic
    
`#    qemu-system-x86_64` lệnh QEMU để mô phỏng hệ thống 64-bit.
`#    `-kernel bzImage` là compressed Linux kernel, được sử dụng để khởi động hệ điều hành
`#    `-initrd initramfs.cpio.gz` là filesystem được tạo trong bộ nhớ RAM trong quá trình khởi động ban đầu mà QEMU sẽ sử dụng.
`#    `--append "console=ttyS0"` chỉ định các tham số được chuyển đến kernel khi nó được khởi động. Khi kernel được yêu cầu sử dụng console trên cổng serial ttyS0.
`#    `-nographic`: QEMU không sử dụng giao diện đồ họa. Nó sẽ xuất ra thông tin ra terminal.

Ta biết được đây là thử thách kiểu kernel exploitation. Đây là lần đầu tiên mình làm dạng bài này nên gặp nhiều khó khăn.

Ta tiến hành giải nén bằng lệnh gunzip -c initramfs.cpio.gz > initramfs.cpio.

Tệp initramfs.cpio là một tập tin nén được sử dụng trong quá trình khởi động của hệ điều hành Linux. Nó chứa một hệ thống tệp cơ bản được giải nén vào bộ nhớ RAM trong quá trình khởi động ban đầu. Tệp này bao gồm các chương trình và thư viện cần thiết để khởi động hệ điều hành và thiết lập môi trường người dùng. Ta tiếp tục giải nén tệp initramfs.cpio bằng lệnh cpio -i -F initramfs.cpio

Trong tất cả các tệp được giải nén, chỉ có tệp checkerchecker.ko là đáng chú ý. Tệp checker.ko là một phần của một mô-đun nhân Linux có trách nhiệm quản lý một thiết bị ký tự có tên là checker. Giá trị nhập vào sẽ được lưu trong biến của tệp checker và đưa cho tệp checker.ko thực hiện kiểm tra. Kết quả trả về sẽ được check in ra thông báo.

Ta dễ dàng tìm ra hàm thực hiện kiểm tra giá trị ta nhập như sau:

image

Nó chỉ là một phép xor đơn giản, ta viết chương trình để tìm ra giá trị đó.

data = [0xB4, 0xE4, 0xE9, 0xAB, 0x09, 0x36, 0x4A, 0xC2, 0xA5, 0x14, 
  0xE5, 0x35, 0x66, 0xC3, 0x99, 0x14, 0x5A, 0x34, 0xF1, 0x18, 
  0x91, 0x7D, 0x23, 0x70, 0xFA, 0xB5, 0x3D, 0xFA, 0x3D, 0xE5, 
  0x00, 0xD1, 0x69, 0x15, 0xF0, 0xA6, 0x83, 0x48, 0xC6, 0x30, 
  0x2E, 0x45, 0x29, 0x02, 0x0A, 0xA9, 0x0F, 0x38, 0x89, 0x0D, 
  0xAC, 0x1C, 0x89, 0x7C, 0xF4, 0xD3, 0xF0, 0x6B, 0x2F, 0x21, 
  0xB7, 0xD8, 0xC0, 0xFB]
xor = [0xFC, 0xB0, 0xAB, 0xD0, 0x6E, 0x44, 0x2B, 0xA0, 0xC7, 0x7D, 
  0x8B, 0x52, 0x39, 0xA7, 0xAD, 0x60, 0x6E, 0x6B, 0x97, 0x6A, 
  0xA1, 0x10, 0x7C, 0x1B, 0xC9, 0xC7, 0x53, 0xC9, 0x51, 0xD0, 
  0x70, 0xE5, 0x0A, 0x26]

flag = ''.join(chr(data[i] ^ xor[i % len(xor)]) for i in range(len(0x22)))
print(flag)

Flag: HTB{grabbing_d4t4_fr0m_k3rn3l5p4c3}

Challenge 18: Maze

I am stuck in a maze. Can you lend me a hand to find the way out?

Download Challenge Here

Solution

Ta có được ba tệp: enc_maze.zip, maze.exe, maze.png. Mở tệp maze.exe trong DIE.

image

Ta biết được tệp này có trình nén là PyInstaller. Tôi sử dụng pyinstxtractor-ng trích các tệp được nhúng bên trong. Bạn cũng có thể dùng link để thao tác trên web mà không cần tải về.

image

Ta biết EntryPoint có khả năng là maze.pycpyiboot01_bootstrap.pyc. Ta sử dụng Uncompyle6 để decompile Python bytecode.

# uncompyle6 .\maze.pyc > maze.py

import sys, obf_path
ZIPFILE = 'enc_maze.zip'
print('Look who comes to me :)')
print()
inp = input('Now There are two paths from here. Which path will u choose? => ')
if inp == 'Y0u_St1ll_1N_4_M4z3':
    obf_path.obfuscate_route()
else:
    print('Unfortunately, this path leads to a dead end.')
    sys.exit(0)
import pyzipper

def decrypt(file_path, word):
    with pyzipper.AESZipFile(file_path, 'r', compression=(pyzipper.ZIP_LZMA), encryption=(pyzipper.WZ_AES)) as (extracted_zip):
        try:
            extracted_zip.extractall(pwd=word)
        except RuntimeError as ex:
            try:
                try:
                    print(ex)
                finally:
                    ex = None
                    del ex

            finally:
                ex = None
                del ex


decrypt(ZIPFILE, 'Y0u_Ar3_W4lkiNG_t0_Y0uR_D34TH'.encode())
with open('maze', 'rb') as (file):
    content = file.read()
data = bytearray(content)
data = [x for x in data]
key = [0] * len(data)
for i in range(0, len(data), 10):
    data[i] = (data[i] + 80) % 256
else:
    for i in range(0, len(data), 10):
        data[i] = (data[i] ^ key[i % len(key)]) % 256
    else:
        with open('dec_maze', 'wb') as (f):
            for b in data:
                f.write(bytes([b]))

Ta biết được mật khẩu của enc_maze.zipY0u_Ar3_W4lkiNG_t0_Y0uR_D34TH và chương trình có import obf_path nên ta cũng hãy cùng xem đoạn mã của nó.

# uncompyle6 .\obf_path.pyc > obf_path.py
def obfuscate_route():
    from marshal import loads
    exec(loads(b'\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00@\x00\x00\x00s(\x00\x00\x00d\x00d\x01l\x00Z\x00d\x00d\x01l\x01Z\x01e\x02e\x00\xa0\x03e\x01\xa0\x03d\x02\xa1\x01\xa1\x01\x83\x01\x01\x00d\x01S\x00)\x03\xe9\x00\x00\x00\x00Ns4\x03\x00\x00\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3\x01\x02\xf6x\x9c\xedV[o\xd30\x14\xfe+^_\xd6\x02+Kz\xdf\x18\x9a\xe0\x01\x8d\x07@\x82\xa7)R\xe5\xc4\'\xa9\xb7\xd4\x8elgk#~<\xc7\x8e=\xba\xb6\x13\x9ax\xe9C#\xc5\xf9\xce\xfd\xf8\xf3q\xd5\xf9\\A\x91J\xad\xe7\xf8\x1c*\xbc\xea\x1cB\x17\xff\x84\x9d\xcbC\xe8\xe2\xc8\xe6\x91\xcd}l\xc2\n\xb2n))\xd3\xdd\xb4\x93\xac`\x90\xac\xce\xcf\xff\xf3\x1do\xca\xd7\x9b\x82\xc6\n\xd3M\x05\x0bKTZt\xbb\xab\x8b\xac.z\xd2\xc5V\x17/q\x19X\x83m7\xb26\xb0\xe0\x0e\x97!ksG\xb3\x90p\x04\xad\x86\xfa\xdeh\x14,\x13\x16\xf2L-\x1aZ\xc7\xd1\xbd\xf5R\xbf 1V7JV\xd3P\xc4\x17r\xfa\xf1\xae\xde\x01,"|\x074\xda\xb6\x9f\xdf\xb5\x19]\'\xe9\x8e&\xb3\x9a\x89]\xa6>:\x0eY\xf4o_w\xf2\xfa\xba\n\xc2\x06\xa7>8\xf6\x05a\x93\x8c\xdc\xba\xe5,1\x81;/\x8b \xe3w\xb2\xa1\xc7\x1d\xbch\xc9\xb6-X j\xa9S/\x10\n\xfb66\xb0\x96|\x7f\x84\xcd\x87K\xb2\x9a\xa5~8"\xb4\xceX;\x15{#\xe2\xd7\x92\xe7\xa6\xf0\xa7E=\x0c\xc7P\x98m\xcf\xfb\xb7^\xeb\xcc\xa8=I]\x02T\x8d\xa5zI\x1b\xe8W\xa2\xb0\xc2\xa0_\xad\x9b\xb3\x9bBH\xc5EA\xcc\x02H\xa5dZ\xc2\x92<Jqj\xc8\x92\xde\x03\xe1\x860\xaeiU\x01U\x97\xcdU&E\xae\xa406\x82\nF(c\n\xb4\xb6"zr\xed\xd2\x18Uc.j\x16\xc4H\x82fY\xd6\x86K\xd1o\xbe~\xbfG\x07jN5)\xa4d$\xad\r\xb9!E\x8d\x19\x9c\x9e\xd4D/d]2"\xe4#F\x9aZ\t\x82\xf5\x96\xbe;x\xe0\xb2\xd6.\xb5\xdf[\xacR\x8e0jyl7\xcf\xaf\xedxx\xfcc\x03\xb7\x9c\x06\xb19C,\xbe \x9f\'\'d-k\x92\xb9\xca\xa03Z\x81+(\xd3\xbcF\xc9\x00s%\x91\xb4(5\x96\x14\xb3\xc0\x9dr\xcb\xd0\x9a,\xa0\xacl\xf8\x05\xf1\x07\x11o\x1eD\xe3n\xa5\xd0\x00\xac\xdb\xbc\xed%"\x97\x8ap\xc2\x05QT\x14\xd0\x1d\xe0!^$\x82\xe0\x83\n\xc6\x85\xe9\x0e\xe2wQ<B\xd7\xe6\xfd\' \x9f\xa9\x82\xbc.O\xf0q=)Y\x1bh9Y\x80\x02K\xb9\x90\x86h\x9aC\xbf\xd7N[K\x8c\xd4\x1e\r\xf4:\xc0\xa1\xe1KP\xdb=\x06#U\xc5C\xc0\x1b\x14\x8f\x0b0\xd9#\xb3\x97%\xcaj\xa5@\x989\xe3\n2#\xd5\xfa6\x11\\0X\xcds^B\x98\xb7\n\x07\xca\x84L\xb0\xe2\x01\x8f\x11k\xf3\xd4\xcc\x9d\xe4"`Y\xc1\x13V@YH\xe5\x92\x07\x83e\x11\xcf\xd0M\xbbjG\xff\xef.v\x14>j\x92I\x86\x94)/N?,Q.\xe1c\xb8M\xe1\xd5o\x9e\x07\xdbK\xec<2\xc7\x97\xf0\xd2\xd4\x7f\x87\x9e\xc5\xe9\x96\xbe\xfdz\xefh\xbcO\xdb^p\xb27\xf0y\x01\xffk\x9b\xe7.t\x14\xac\x9d^\xef\xf8\x87\xe3\xf8\xf7\xed@a\xe7\x0f\xdc9\x01G\x00\x00(\xe3\xdf}\x13\x01@\xad\x00\x01\x8f\x06\xf7\x05\x00\x00\x85k\x89\xbe\xb1\xc4g\xfb\x02\x00\x00\x00\x00\x04YZ)\x04\xda\x04zlib\xda\x04lzma\xda\x04exec\xda\ndecompress\xa9\x00r\x06\x00\x00\x00r\x06\x00\x00\x00\xda\x07coduter\xda\x08<module>\x01\x00\x00\x00s\x02\x00\x00\x00\x10\x01'))

Ta gần như không thể đọc đoạn mã từ đây do đã bị mã hóa, bạn hãy làm theo tại đây để tìm được nội dung đoạn mã gốc.

Chương trình giải mã đầu tiên

import marshal,dis
marshal_c = marshal.loads(b'\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00@\x00\x00\x00s(\x00\x00\x00d\x00d\x01l\x00Z\x00d\x00d\x01l\x01Z\x01e\x02e\x00\xa0\x03e\x01\xa0\x03d\x02\xa1\x01\xa1\x01\x83\x01\x01\x00d\x01S\x00)\x03\xe9\x00\x00\x00\x00Ns4\x03\x00\x00\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3\x01\x02\xf6x\x9c\xedV[o\xd30\x14\xfe+^_\xd6\x02+Kz\xdf\x18\x9a\xe0\x01\x8d\x07@\x82\xa7)R\xe5\xc4\'\xa9\xb7\xd4\x8elgk#~<\xc7\x8e=\xba\xb6\x13\x9ax\xe9C#\xc5\xf9\xce\xfd\xf8\xf3q\xd5\xf9\\A\x91J\xad\xe7\xf8\x1c*\xbc\xea\x1cB\x17\xff\x84\x9d\xcbC\xe8\xe2\xc8\xe6\x91\xcd}l\xc2\n\xb2n))\xd3\xdd\xb4\x93\xac`\x90\xac\xce\xcf\xff\xf3\x1do\xca\xd7\x9b\x82\xc6\n\xd3M\x05\x0bKTZt\xbb\xab\x8b\xac.z\xd2\xc5V\x17/q\x19X\x83m7\xb26\xb0\xe0\x0e\x97!ksG\xb3\x90p\x04\xad\x86\xfa\xdeh\x14,\x13\x16\xf2L-\x1aZ\xc7\xd1\xbd\xf5R\xbf 1V7JV\xd3P\xc4\x17r\xfa\xf1\xae\xde\x01,"|\x074\xda\xb6\x9f\xdf\xb5\x19]\'\xe9\x8e&\xb3\x9a\x89]\xa6>:\x0eY\xf4o_w\xf2\xfa\xba\n\xc2\x06\xa7>8\xf6\x05a\x93\x8c\xdc\xba\xe5,1\x81;/\x8b \xe3w\xb2\xa1\xc7\x1d\xbch\xc9\xb6-X j\xa9S/\x10\n\xfb66\xb0\x96|\x7f\x84\xcd\x87K\xb2\x9a\xa5~8"\xb4\xceX;\x15{#\xe2\xd7\x92\xe7\xa6\xf0\xa7E=\x0c\xc7P\x98m\xcf\xfb\xb7^\xeb\xcc\xa8=I]\x02T\x8d\xa5zI\x1b\xe8W\xa2\xb0\xc2\xa0_\xad\x9b\xb3\x9bBH\xc5EA\xcc\x02H\xa5dZ\xc2\x92<Jqj\xc8\x92\xde\x03\xe1\x860\xaeiU\x01U\x97\xcdU&E\xae\xa406\x82\nF(c\n\xb4\xb6"zr\xed\xd2\x18Uc.j\x16\xc4H\x82fY\xd6\x86K\xd1o\xbe~\xbfG\x07jN5)\xa4d$\xad\r\xb9!E\x8d\x19\x9c\x9e\xd4D/d]2"\xe4#F\x9aZ\t\x82\xf5\x96\xbe;x\xe0\xb2\xd6.\xb5\xdf[\xacR\x8e0jyl7\xcf\xaf\xedxx\xfcc\x03\xb7\x9c\x06\xb19C,\xbe \x9f\'\'d-k\x92\xb9\xca\xa03Z\x81+(\xd3\xbcF\xc9\x00s%\x91\xb4(5\x96\x14\xb3\xc0\x9dr\xcb\xd0\x9a,\xa0\xacl\xf8\x05\xf1\x07\x11o\x1eD\xe3n\xa5\xd0\x00\xac\xdb\xbc\xed%"\x97\x8ap\xc2\x05QT\x14\xd0\x1d\xe0!^$\x82\xe0\x83\n\xc6\x85\xe9\x0e\xe2wQ<B\xd7\xe6\xfd\' \x9f\xa9\x82\xbc.O\xf0q=)Y\x1bh9Y\x80\x02K\xb9\x90\x86h\x9aC\xbf\xd7N[K\x8c\xd4\x1e\r\xf4:\xc0\xa1\xe1KP\xdb=\x06#U\xc5C\xc0\x1b\x14\x8f\x0b0\xd9#\xb3\x97%\xcaj\xa5@\x989\xe3\n2#\xd5\xfa6\x11\\0X\xcds^B\x98\xb7\n\x07\xca\x84L\xb0\xe2\x01\x8f\x11k\xf3\xd4\xcc\x9d\xe4"`Y\xc1\x13V@YH\xe5\x92\x07\x83e\x11\xcf\xd0M\xbbjG\xff\xef.v\x14>j\x92I\x86\x94)/N?,Q.\xe1c\xb8M\xe1\xd5o\x9e\x07\xdbK\xec<2\xc7\x97\xf0\xd2\xd4\x7f\x87\x9e\xc5\xe9\x96\xbe\xfdz\xefh\xbcO\xdb^p\xb27\xf0y\x01\xffk\x9b\xe7.t\x14\xac\x9d^\xef\xf8\x87\xe3\xf8\xf7\xed@a\xe7\x0f\xdc9\x01G\x00\x00(\xe3\xdf}\x13\x01@\xad\x00\x01\x8f\x06\xf7\x05\x00\x00\x85k\x89\xbe\xb1\xc4g\xfb\x02\x00\x00\x00\x00\x04YZ)\x04\xda\x04zlib\xda\x04lzma\xda\x04exec\xda\ndecompress\xa9\x00r\x06\x00\x00\x00r\x06\x00\x00\x00\xda\x07coduter\xda\x08<module>\x01\x00\x00\x00s\x02\x00\x00\x00\x10\x01')

byte_string = b'a\r\r\n\x00\x00\x00\x00\xf6\x971a\x00\x00\x00\x00'
with open('ConfusedCharacter.pyc', 'wb') as pyc:
     pyc.write(byte_string )
     marshal.dump(dis.Bytecode(marshal_c).codeobj, pyc)

Câu lệnh đầu tiên để giải mã

./pycdc ConfusedCharacter.pyc > stage1.py

Kết quả giải mã đầu tiên

import zlib
import lzma
exec(zlib.decompress(lzma.decompress(b'\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/\xe5\xa3\x01\x02\xf6x\x9c\xedV[o\xd30\x14\xfe+^_\xd6\x02+Kz\xdf\x18\x9a\xe0\x01\x8d\x07@\x82\xa7)R\xe5\xc4\'\xa9\xb7\xd4\x8elgk#~<\xc7\x8e=\xba\xb6\x13\x9ax\xe9C#\xc5\xf9\xce\xfd\xf8\xf3q\xd5\xf9\\A\x91J\xad\xe7\xf8\x1c*\xbc\xea\x1cB\x17\xff\x84\x9d\xcbC\xe8\xe2\xc8\xe6\x91\xcd}l\xc2\n\xb2n))\xd3\xdd\xb4\x93\xac`\x90\xac\xce\xcf\xff\xf3\x1do\xca\xd7\x9b\x82\xc6\n\xd3M\x05\x0bKTZt\xbb\xab\x8b\xac.z\xd2\xc5V\x17/q\x19X\x83m7\xb26\xb0\xe0\x0e\x97!ksG\xb3\x90p\x04\xad\x86\xfa\xdeh\x14,\x13\x16\xf2L-\x1aZ\xc7\xd1\xbd\xf5R\xbf 1V7JV\xd3P\xc4\x17r\xfa\xf1\xae\xde\x01,"|\x074\xda\xb6\x9f\xdf\xb5\x19]\'\xe9\x8e&\xb3\x9a\x89]\xa6>:\x0eY\xf4o_w\xf2\xfa\xba\n\xc2\x06\xa7>8\xf6\x05a\x93\x8c\xdc\xba\xe5,1\x81;/\x8b \xe3w\xb2\xa1\xc7\x1d\xbch\xc9\xb6-X j\xa9S/\x10\n\xfb66\xb0\x96|\x7f\x84\xcd\x87K\xb2\x9a\xa5~8"\xb4\xceX;\x15{#\xe2\xd7\x92\xe7\xa6\xf0\xa7E=\x0c\xc7P\x98m\xcf\xfb\xb7^\xeb\xcc\xa8=I]\x02T\x8d\xa5zI\x1b\xe8W\xa2\xb0\xc2\xa0_\xad\x9b\xb3\x9bBH\xc5EA\xcc\x02H\xa5dZ\xc2\x92<Jqj\xc8\x92\xde\x03\xe1\x860\xaeiU\x01U\x97\xcdU&E\xae\xa406\x82\nF(c\n\xb4\xb6"zr\xed\xd2\x18Uc.j\x16\xc4H\x82fY\xd6\x86K\xd1o\xbe~\xbfG\x07jN5)\xa4d$\xad\r\xb9!E\x8d\x19\x9c\x9e\xd4D/d]2"\xe4#F\x9aZ\t\x82\xf5\x96\xbe;x\xe0\xb2\xd6.\xb5\xdf[\xacR\x8e0jyl7\xcf\xaf\xedxx\xfcc\x03\xb7\x9c\x06\xb19C,\xbe \x9f\'\'d-k\x92\xb9\xca\xa03Z\x81+(\xd3\xbcF\xc9\x00s%\x91\xb4(5\x96\x14\xb3\xc0\x9dr\xcb\xd0\x9a,\xa0\xacl\xf8\x05\xf1\x07\x11o\x1eD\xe3n\xa5\xd0\x00\xac\xdb\xbc\xed%"\x97\x8ap\xc2\x05QT\x14\xd0\x1d\xe0!^$\x82\xe0\x83\n\xc6\x85\xe9\x0e\xe2wQ<B\xd7\xe6\xfd\' \x9f\xa9\x82\xbc.O\xf0q=)Y\x1bh9Y\x80\x02K\xb9\x90\x86h\x9aC\xbf\xd7N[K\x8c\xd4\x1e\r\xf4:\xc0\xa1\xe1KP\xdb=\x06#U\xc5C\xc0\x1b\x14\x8f\x0b0\xd9#\xb3\x97%\xcaj\xa5@\x989\xe3\n2#\xd5\xfa6\x11\\0X\xcds^B\x98\xb7\n\x07\xca\x84L\xb0\xe2\x01\x8f\x11k\xf3\xd4\xcc\x9d\xe4"`Y\xc1\x13V@YH\xe5\x92\x07\x83e\x11\xcf\xd0M\xbbjG\xff\xef.v\x14>j\x92I\x86\x94)/N?,Q.\xe1c\xb8M\xe1\xd5o\x9e\x07\xdbK\xec<2\xc7\x97\xf0\xd2\xd4\x7f\x87\x9e\xc5\xe9\x96\xbe\xfdz\xefh\xbcO\xdb^p\xb27\xf0y\x01\xffk\x9b\xe7.t\x14\xac\x9d^\xef\xf8\x87\xe3\xf8\xf7\xed@a\xe7\x0f\xdc9\x01G\x00\x00(\xe3\xdf}\x13\x01@\xad\x00\x01\x8f\x06\xf7\x05\x00\x00\x85k\x89\xbe\xb1\xc4g\xfb\x02\x00\x00\x00\x00\x04YZ')))

Chương trình giải mã thứ hai sau khi bỏ chuỗi "__regboss__"

import marshal,dis
marshal_c = marshal.loads(b"\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00@\x00\x00\x00s\xe8\x00\x00\x00d\x00d\x01l\x00Z\x00d\x00d\x01l\x01Z\x01d\x00d\x02l\x02m\x03Z\x03\x01\x00e\x01j\x04d\x00\x19\x00Z\x05e\x00\xa0\x06\xa1\x00Z\x07d\x03Z\x08d\x04e\x05k\x06rTe\td\x05\x83\x01\x01\x00e\td\x06\x83\x01\x01\x00e\x01\xa0\nd\x00\xa1\x01\x01\x00e\x00j\x05\xa0\x0be\x00j\x05\xa0\x0ce\x07e\x08\xa1\x02\xa1\x01s|e\td\x07\x83\x01\x01\x00e\x01\xa0\nd\x00\xa1\x01\x01\x00e\re\x08d\x08\x83\x02\xa0\x0e\xa1\x00Z\x0fe\x0fd\t\x19\x00e\x0fd\n\x19\x00\x17\x00e\x0fd\x0b\x19\x00\x17\x00e\x0fd\x0c\x19\x00\x17\x00Z\x10e\td\r\x83\x01\x01\x00e\td\x0e\x83\x01\x01\x00e\x03d\x0f\x83\x01\x01\x00e\td\x10e\x10\x9b\x00d\x11\x9d\x03\x83\x01\x01\x00e\td\x12\x83\x01\x01\x00e\x01\xa0\nd\x00\xa1\x01\x01\x00d\x01S\x00)\x13\xe9\x00\x00\x00\x00N)\x01\xda\x05sleepz\x08maze.pngz\x03.pyz-Ignoring the problem won\'t make it disappear;z=confronting and addressing it is the true path to resolution.zJOk that\'s good but I guess that u should now return from the previous path\xda\x02rbi\xd1\x12\x00\x00i@\n\x00\x00iP\n\x00\x00i\xa0\n\x00\x00z-\n\nG00d!! you could escape the obfuscated pathz\x1btake this it may help you: \xe9\x02\x00\x00\x00z\x06\nseed(z+)\nfor i in range(300):\n    randint(32,125)\nz/Be Careful!!!! the route from here is not safe.)\x11\xda\x02os\xda\x03sys\xda\x04timer\x02\x00\x00\x00\xda\x04argv\xda\x04path\xda\x06getcwdZ\x11current_directoryZ\nindex_file\xda\x05print\xda\x04exit\xda\x06exists\xda\x04join\xda\x04open\xda\x04read\xda\x05index\xda\x04seed\xa9\x00r\x13\x00\x00\x00r\x13\x00\x00\x00\xda\x07coduter\xda\x08<module>\x01\x00\x00\x00s*\x00\x00\x00\x10\x01\x0c\x02\n\x01\x08\x01\x04\x02\x08\x01\x08\x01\x08\x01\n\x01\x16\x01\x08\x01\n\x01\x0e\x01 \x01\x08\x01\x08\x01\x08\x01\x04\x01\x02\xff\n\x05\x08\x01")

byte_string = b'a\r\r\n\x00\x00\x00\x00\xf6\x971a\x00\x00\x00\x00'
with open('ConfusedCharacter.pyc', 'wb') as pyc:
     pyc.write(byte_string )
     marshal.dump(dis.Bytecode(marshal_c).codeobj, pyc)

Câu lệnh thứ hai để giải mã

./pycdc ConfusedCharacter.pyc > stage2.py

Kết quả giải mã thứ hai

import os
import sys
from time import sleep
path = sys.argv[0]
current_directory = os.getcwd()
index_file = 'maze.png'
if '.py' in path:
    print("Ignoring the problem won't make it disappear;")
    print('confronting and addressing it is the true path to resolution.')
    sys.exit(0)
if not os.path.exists(os.path.join(current_directory, index_file)):
    print("Ok that's good but I guess that u should now return from the previous path")
    sys.exit(0)
index = open(index_file, 'rb').read()
seed = index[4817] + index[2624] + index[2640] + index[2720]
print('\n\nG00d!! you could escape the obfuscated path')
print('take this it may help you: ')
sleep(2)
print(f'''\nseed({seed})\nfor i in range(300):\n    randint(32,125)\n''')
print('Be Careful!!!! the route from here is not safe.')
sys.exit(0)

Thực thi đoạn mã trên ta có gợi ý seed = 493for i in range(300): randint(32,125). Trong đoạn mã của maze.py, tôi đã thắc mắc vì sao lại dùng mảng key rỗng để giải mã tệp. Nên mình để key = RandomNumberArray.

ZIPFILE = 'enc_maze.zip'

import pyzipper
import random

def decrypt(file_path, word):
    with pyzipper.AESZipFile(file_path, 'r', compression=(pyzipper.ZIP_LZMA), encryption=(pyzipper.WZ_AES)) as (extracted_zip):
        extracted_zip.extractall(pwd=word)

decrypt(ZIPFILE, 'Y0u_Ar3_W4lkiNG_t0_Y0uR_D34TH'.encode())

with open('maze', 'rb') as (file):
    content = file.read()
data = bytearray(content)
data = [x for x in data]

seed = 493
random.seed(seed)
key = [random.randint(32, 125) for _ in range(300)]

for i in range(0, len(data), 10):
    data[i] = (data[i] + 80) % 256
else:
    for i in range(0, len(data), 10):
        data[i] = (data[i] ^ key[i % len(key)]) % 256
    else:
        with open('dec_maze', 'wb') as (f):
            for b in data:
                f.write(bytes([b]))

Ta nhận được một tệp ELF64. Mở nó trong IDA.

image

Chương trình kiểm tra dữ liệu nhập đúng hay sai bằng cách tính tổng của ba kí tự kế nhau và so sánh với mảng unk_2060. Tới đây ta viết đoạn giải mã thôi.

data = [0x111, 0x134, 0x122, 0xFE, 0xE6, 0x10F, 0xE8, 0xFE, 0x104, 0x117, 0xD2, 0xE8, 0x111, 0x145, 0x12F, 0x108, 0xD9, 0xDD, 0xCC, 0x107, 0xD7, 0x102, 0xE6, 0x11B, 0xED, 0x10C, 0x103, 0x11F, 0xE0, 0xDB, 0xC1, 0xC0, 0x87, 0x75, 0xBF]
flag = "HTB"
for i in range(len(data)):
    flag += chr(data[i] - ord(flag[-1]) - ord(flag[-2]))
print(flag)