Tại tcp.stream eq 1
sẽ thấy được client cho tải xuống file induct
vào /mages_tower
từ địa chỉ http/[wizardcult.flare-on.com](http://wizardcult.flare-on.com/)/induct
tcp.stream eq 2
nôm na là binary của file induct.
tcp.stream eq 3
sẽ thực hiện lệnh chmod cho file induct
đã tải xuống
tcp.stream eq 4
thực thi file đó
tcp.stream eq 5
giống như là cuộc hội thoại của một game RPG.
tcp.stream eq 6
i don't known it.
File sẽ được phần tích gồm 2 giai đoạn, giai đoạn 1 là từ đầu đến khi giết xong Goblin
Đoạn 2 thì còn lại.
Tại hàm main_main
sử dụng chuỗi wizardcult.flare-on.com
làm domain để kết nối, và những hàm github_com_lrstanley_girc cho biết rằng sẽ kết nối đến server IRC
Sau khi thực thi hàm main_main
sẽ đến hàm main_main_func1
, tại đây thấy được chương trình sau khi kết nối vào IRC sẽ join vào channel dungeon
Sau khi thực hiện kết nối, chương trình sẽ thực thi hàm mapassign
cùng với các tham số được gán trước đó
(xem thêm về mapassign
ở https://x0r19x91.gitlab.io/reversing-golang/part-3/ )
Tạo một struct làm type cho các biến tương tự như v25
để có thể rõ ràng hơn
và sẽ thấy được có 2 hàm sử dụng: ReadFile_Potion và Command_Potion
Từ đây tôi có thể tóm gọn được rằng, sau khi client tải xuống, cấp quyền và thực thi file induct
thì chương trình sẽ thực hiện việc kết nối IRC đến server có domain là wizardcult.flare-on.com
sau đó sẽ join vào channel #dungeon
, để có thể thực hiện được việc debug (tôi sử dụng remote linux debugger
của IDA) thì cần phải cài đặt môi trường cho nó:
- Sử dụng UnrealIRCd
- Đặt
induct
vào đúng đường dẫn/mages_tower
- Gắn địa chỉ của domain vào ip của server trong file
/etc/hosts
- DEBUG.
Từ hàm main_main_func2
sẽ có kiểm tra user có tên dung3onm4st3r13
có trong server không.
nếu có thì sẽ trải qua 1 loạt instruction và để ý tại hàm wizardcult_comms_ProcessDMMessage
, hàm này sẽ xử lý các tin nhắn mà dung3onm4st3r13
gửi lên server.
ở trong hàm wizardcult_comms_ProcessDMMessage
có hàm strings_index
dùng để lấy vị trí xuất hiện của chuỗi được gán trong tin nhắn gửi đến, nếu <0 thì có nghĩa là chuỗi được gán không có trong tin nhắn gửi đến. Sau khi điều kiện đúng sẽ thực hiện một loạt instruction nào đó và cuối cùng là send tin nhắn đến server IRC.
Và ở dưới cũng tương tự như thế.
Tại đoạn so sánh với chuỗi you have learned how to create the
thì sẽ thấy sử dụng các chuỗi từ bảng wizardcult_tables_Ingredients
để làm điều gì đó. Ngoài ra thì tại lúc này bên wireshark sẽ thầy IRC gửi rất nhiều như : "To brew it you must combine magnifying glass,.....".
Kết hợp với debug sẽ hiểu được rằng mỗi 2 từ được gửi đi kể từ sau "combine " chính là mỗi byte của binary data struct được sử dụng làm tham số truyền vào cho hàm wizardcult_vm_LoadProgram
Độ dài của bảng này là 0x100
Nên sử dụng python script để dump table ra file json
import json
start_offset = 0x94B580
# end_offset = 0x94B8F0
size = 0x1000
shellcode = idaapi.get_bytes(start_offset, size)
hexList = list(shellcode)
arrList = []
for i in range(0, len(hexList), 8):
temp = (hexList[i+7])&0xff
temp = ((temp << 8) + hexList[i+6])&0xffff
temp = ((temp << 8) + hexList[i+5])&0xffffff
temp = ((temp << 8) + hexList[i+4])&0xffffffff
temp = ((temp << 8) + hexList[i+3])&0xffffffffff
temp = ((temp << 8) + hexList[i+2])&0xffffffffffff
temp = ((temp << 8) + hexList[i+1])&0xffffffffffffff
temp = ((temp << 8) + hexList[i])&0xffffffffffffffff
arrList.append(temp)
result = []
id = 0
for i in range(0, len(arrList), 2):
offset = arrList[i]
length = arrList[i+1]
text = idaapi.get_bytes(offset, length)
result.append({
'id': id,
'offset': offset,
'length': length,
'text': text.decode("utf-8")
})
id = id+1
json_object = json.dumps(result, indent = 3)
with open("dump1.json", "w") as outfile:
outfile.write(json_object)
Được file dump.json:
Hàm runtime_mapaccess2_faststr
sẽ trả về con trỏ đến hàm tương ứng với khóa là v87 trong map
(map đã được khởi tạo ở hàm main_main_func1
bởi các hàm runtime_mapassign_faststr
, xem thêm chi tiết ở https://x0r19x91.gitlab.io/reversing-golang/part-3/)
Debug thì tôi thấy được key là "Potion of Acid Resistance."
Thì tương đương nó sẽ lấy con trỏ đến hàm Command_Potion
.
Đặt breakpoint tại hàm Command_Potion
Quay lại hàm wizardcult_comms_ProcessDMMessage
, hàm runtime_mapaccess1_faststr
tương tự như hàm runtime_mapaccess2_faststr
.
Hàm wizardcult_vm_LoadProgram
sẽ bắt đầu load vm với binary data struct đã encode bởi GOB (v23)
(xem thêm https://www.youtube.com/watch?v=SE13kcjJ_X0 ) được dung3onm4st3r13
gửi đến.
Debug và dump sẽ được binay truyền vào (hoặc có thể sử dụng file json đã dump ở trên và nội dung mà dung3onm4st3r13
gửi đến để tạo ra được binary đó).
Trong hàm wizardcult_vm_LoadProgram
decrypt đoạn binary trên và tạo vm.
Sử dụng degob (https://github.com/drosseau/degob) để decrypt đoạn binary trên thì được :
// type ID: 67
type OutputDevice struct {
Name string
}
// type ID: 68
type Cpu struct {
Acc int64
Dat int64
Pc int64
Cond int64
Instructions []vm.Instruction
}
// type ID: 69
type Instruction struct {
Opcode int64
A0 int64
A1 int64
A2 int64
Bm int64
Cond int64
}
// type ID: 73
type []int []int64
// type ID: 76
type []vm.RAM []RAM
// type ID: 75
type RAM struct {
A0 int64
A1 int64
Data []int
}
// type ID: 66
type InputDevice struct {
Name string
}
// type ID: 72
type ROM struct {
A0 int64
A1 int64
Data []int
}
// type ID: 77
type Link struct {
LHDevice int64
LHReg int64
RHDevice int64
RHReg int64
}
// type ID: 65
type Program struct {
Magic int64
Input InputDevice
Output OutputDevice
Cpus []vm.Cpu
ROMs []vm.ROM
RAMs []vm.RAM
Links []vm.Link
}
// type ID: 71
type []vm.Cpu []Cpu
// type ID: 70
type []vm.Instruction []Instruction
// type ID: 74
type []vm.ROM []ROM
// type ID: 78
type []vm.Link []Link
Program
{
Magic: 4919,
Input: InputDevice{Name: ""},
Output: OutputDevice{Name: ""},
Cpus: []Cpu{
Cpu{Acc: 0, Dat: 0, Pc: 0, Cond: 0,
Instructions: []Instruction{
Instruction{Opcode: 1, A0: 0, A1: 4, A2: 0, Bm: 3, Cond: 0},
Instruction{Opcode: 5, A0: 4, A1: -1, A2: 0, Bm: 1, Cond: 0},
Instruction{Opcode: 1, A0: -1, A1: 1, A2: 0, Bm: 2, Cond: 1},
Instruction{Opcode: 1, A0: 0, A1: 4, A2: 0, Bm: 3, Cond: 1},
Instruction{Opcode: 1, A0: 4, A1: 2, A2: 0, Bm: 3, Cond: 0},
Instruction{Opcode: 1, A0: 2, A1: 4, A2: 0, Bm: 3, Cond: 0},
Instruction{Opcode: 1, A0: 4, A1: 1, A2: 0, Bm: 3, Cond: 0}}},
Cpu{Acc: 0, Dat: 0, Pc: 0, Cond: 0,
Instructions: []Instruction{
Instruction{Opcode: 1, A0: 0, A1: 4, A2: 0, Bm: 3, Cond: 0},
Instruction{Opcode: 18, A0: 162, A1: 0, A2: 0, Bm: 0, Cond: 0},
Instruction{Opcode: 1, A0: 4, A1: 0, A2: 0, Bm: 3, Cond: 0}}}},
ROMs: []ROM{},
RAMs: []RAM{},
Links: []Link{
Link{LHDevice: 0, LHReg: 0, RHDevice: 2, RHReg: 0},
Link{LHDevice: 2, LHReg: 1, RHDevice: 1, RHReg: 0},
Link{LHDevice: 2, LHReg: 2, RHDevice: 3, RHReg: 0}}}
Sau khi load VM xong chương trình sẽ chạy một loạt instruction sau đó gửi tin nhắn lên server.
Từ đây có thể hiểu được dung3onm4st3r13
là đối tượng điều khiển luồng chạy của chương trình bằng tin nhắn gửi đến. Vì thế có con bot mang danh dung3onm4st3r13
(made by @Hoàng Nguyễn Minh) như sau :
Theo luồng tin nhắn trong wireshark thì tiếp theo là đến if với "you enter the dungeon" (có thể debug để chắc chắn điều này). Tại đoạn này sẽ load table như ở phía trên kia để làm điều gì đó
Dump table đó ra thì được:
Sau đoạn đó sẽ đến đoạn if với "It stares at you imposingly."
Tại đoạn này sẽ cần để ý đến hàm wizardcult_comms_CastSpells
Trong hàm đó sẽ có một table string nữa wizardcult_tables_Spells
Dump ra được:
Lúc này debug cho luồng chương trình chạy đến wizardcult_potion_CommandPotion
và chạy đến dòng 42, sẽ thấy ở stack sẽ đưa tất cả tên file trong folder /mages_tower
vào stack
theo dõi chương trình thì sẽ thầy hàm wizardcult_vm__ptr_Cpu_Execute
, hàm này sẽ load vm và excute instruction bằng hàm wizardcult_vm__ptr_Cpu_ExecuteInstruction
Kết hợp đống instruction từ file decrypt bằng degob và hàm wizardcult_vm__ptr_Cpu_ExecuteInstruction
thì tôi thấy được các opcode sẽ qua switch để dùng instruction tương ứng. Như trong đoạn instruction đã decrypt thì lúc này chương trình chỉ có XOR với 162 và instruction Teq.
Tiếp tục debug cho chạy đến khi return hàm wizardcult_potion_CommandPotion
và đến wizardcult_comms_CastSpells
, nhưng chú ý tại biến prog_size_16e
và prog_size_16f
là địa chỉ trỏ tới các byte đã được XOR với 162 vừa rồi
debug vào bên trong hàm wizardcult_comms_CastSpells
thì thấy tại dòng 47 nó sẽ dùng byte thứ 2*index của các byte được XOR trên để lấy chuỗi trong bảng wizardcult_tables_Spells
Lúc này kết hợp với đoạn chat này. Thì ta biết được mỗi byte thứ 2*index sẽ được chuyển thành chuỗi và chuỗi này được lấy từ trong bảng được dump ra file dump3.json, sau đó sẽ tạo thành 1 dòng tin nhắn và gửi lên server.
Tôi chuyển đoạn tin nhắn đó sang các byte cần thiết và tính toán ra được 2 tên file là cool_wizard_meme.png
và induct
. Lúc này tôi biết được trong folder /mages_tower
có 2 file là induct
và cool_wizard_meme.png
Từ giai đoạn 1 thì tôi biết được hướng đi là đúng.
Tiếp tục, tương tự những gì xảy ra ở giai đoạn 1 thì tại đoạn load vm, tôi lấy được binary data struct
Dùng degob để decrypt thì nhận được
Sau nhiều lần debug trâu bò thì biết được lúc này chương trình sẽ chạy hàm wizardcult_potion_ReadFilePotion
,
hàm này sẽ đọc toàn bộ byte của file cool_wizard_meme.png
, sau đó toàn bộ byte đi qua thuật toán mã hóa của vm từ đó tạo ra các dòng tin nhắn từ các byte đã mã hóa và gửi lên IRC server.
Kết hợp với dump3.json lấy được file cool_wizard_meme.png
đã bị mã hóa
cool_wizard_meme.png.encrypted
Lúc này tôi sẽ tạo một binary fake của file để debug và đặt các breakpoint ở các instruction để lấy log
Chi tiết về đặt log thì đặt log tại mỗi call instruction, ví dụ như ở hàm wizardcult_vm__ptr_Cpu_ExecuteMov
thì đặt bp tại call và thêm code như trong hình.
Đi vào hàm thì đặt log ở những chỗ quan trọng. Tiếp tục ví dụ thì tôi đặt ở 2 nơi quan trọng.
Cứ làm tương tự như ở các instruction còn lại tôi được 1 list breakpoint dùng để log
File cool_wizard_meme.png
thì cho nhị phân như trong hình (phần đầu là 8 byte signatures của file PNG sau đó toàn 'a'):
Sau khi debug thì tôi thu được đống log, từ lúc này kết hợp với vm2.txt thì bắt đầu chiêm nghiệm thuật toán
Tiến hành phần tích log, ở đoạn đầu thì thấy là AND 0x01
và so sánh bằng 0x01.
Thử tìm kiếm "& EAX:00000001h" thì thấy được sẽ con số sẽ tăng dần lên 1 đơn vị và AND với 0x01, thì có thể hiểu nôm na là index bắt đầu từ 0 và tăng dần mỗi 1 đơn vị, mỗi lần lặp như thế sẽ AND với 0x01 để kiểm tra tính chẵn lẽ.
Ở lần index = 0 thì sẽ lấy byte 0x89 tương ứng với byte đầu tiên trong binary, sau đó so sánh lớn với 0x63 và trừ cho 0x64
Bằng 1 phép màu nào đó 0x25 đã trở thành 0xB2 và XOR với 0x61
Sau một lúc suy nghĩ thì lấy 0xB2 chuyển sang dạng thập phân là 178 sau đó tìm kiếm trong các data nằm trong vm2.txt đã decrypt được, thì thấy tại bảng thứ 2 tại vị trí 0x25 (37) có số 178. Mà để ý là tất cả phần tử của mảng 3 data đầu tiên là 255 và trước khi trừ đều có so sánh lớn với 99 (0x63) nên tôi nghi vấn rằng byte từ 0 → 99 sẽ sử dụng data đầu tiên, 100→199 sử dụng data thứ 2, 200→ 255 sẽ sử dụng data thứ 3, đó chỉ mới là giả thuyết nên chưa chắc chắn.
Sau khi có giá trị là 0xB2 thì tiếp tục XOR với 0x61 (97), và còn số này được lấy từ bảng data thứ 4 nên bảng thứ 4 là key (cũng là giả thuyết).
Sau khi XOR xong được kết quả là 0xD3 và index cũng tăng lên 1. Tôi thấy 0xD3 được so sánh lớn 2 lần với 0x63 và 0xC7 sau đó trừ 0xC8, kết quả của phép trừ là 0xB
Từ 0xB trở thành 0xED
Kiểm tra trong bảng data thứ 3 thì tại vị trí 0xB có được số 237 (0xED) ⇒ Giả thuyết đầu tiên khá chắc chắn
0x80 được AND với 0xED sau đó so sánh kết quả với 0x80 sau đó XOR với 0x42.
Tại khúc này tôi không hiểu vì sao 0xAF lại trở thành 0xFFFFFF50 có lẽ tôi đã đặt log thiếu ở đâu đó
Quay lại IDA và thấy được nơi tôi chưa đặt log. Vì thế thử lấy 0xAF ^ 0xFFFFFFFF thì thu được kết quả 0xFFFFFF50.
0xFFFFFF50 & 0xFFFFFFFF thì thu được 0x50, vậy là đã có byte được mã hóa đầu tiên, kiểm tra với file png bị mã hóa thì nhận ra có vẻ con đường đang đi là đúng đắng.
Sau khi decrypt xong byte đầu tiên thì chương trình sẽ lấy byte tiếp theo để encrypt
Lúc này tôi sử dụng giả thuyết đầu tiên để tính byte 0x50 này thành byte bao nhiêu để xác nhận giả thuyết của tôi là đúng
Tính toán bằng giả thuyết tôi nhận được kết quả là 138 (0x8A)
Đọc bên log thì lấy 0x50 so sánh lớn với 0x63 nhưng không thỏa điều kiện nên giữ nguyên và được biến đổi thành 0x8A. Như vậy giả thuyết đầu tiên của tôi hoàn toàn đúng.
Lúc này sẽ lấy 0x31 (49) sau đó bằng 1 cách biến đổi nào đó trở thành 0xFFFFFFCE
Thì tôi thử dùng phép tính mà không log khi nãy tính 0x31 ^ 0xFFFFFFFF = 0xFFFFFFCE sau đó AND 0xFF thu được kết quả 0xCE. Sau đó XOR với 0x8A được kết quả 0x44
Tiếp theo là index tăng lên 1 và AND với 0x1 sau đó so sánh kết quả với 0x01.
0x44 được biến đổi thành 0xC9 (201)
0xC9 AND 0x80, lấy kết quả đi so sánh bằng với 0x80. Sau đó 0xC9 ^ 0x42 = 0x8B, 0x8B ^ 0xFFFFFFFF = 0xFFFFFF74, AND với 0xFF ta được 0x74, byte encrypt thứ 2.
Tiếp tục phân tích tương tự như trên cho byte thứ 3, đến khi AND 0x80 và có kết quả khác 0x80, thì ta thấy thay vì 0x62 XOR 0x42 sau đó XOR với 0xFFFFFFFF thì lần này sẽ lấy 0x62 XOR thẳng với 0xFFFFFFFF và được byte encrypt là 0x9D.
Ngoài ra thì tại lần encrypt byte thứ 3 thì cũng có XOR với 0x31.
Để ý ở mỗi lần XOR, lần đầu tiên là 0x61 (97) lần thứ 2 thì là 0x31 (49) nhưng bị XOR với 0xFF, và lần thứ 3 là 0x31 (49). So sánh với bảng data thứ 4 thì có thể chắc chắn hơn rằng data thứ 4 là key để XOR nhưng mỗi lần lẻ thì key sẽ XOR với 0xFF.
Tôi search "RCX:00000061h ^" thì thấy nó lặp lại 16 lần
tương đương với size của file cho là 0x170 chia cho độ dài của key là 24 thì được kết quả như trong hình. Lúc này tôi khá chắc kèo là xor với key sẽ lặp lại mỗi 24 lần.
Sau những chiêm nghiệm và phân tích trên, tôi viết thuật toán encrypt và encrypt 8 byte đầu của file PNG:
table1=[90, 132, 6, 69, 174, 203, 232, 243, 87, 254, 166, 61, 94, 65, 8, 208, 51, 34,
33, 129, 32, 221, 0, 160, 35, 175, 113, 4, 139, 245, 24, 29, 225, 15, 101, 9,
206, 66, 120, 62, 195, 55, 202, 143, 100, 50, 224, 172, 222, 145, 124, 42, 192,
7, 244, 149, 159, 64, 83, 229, 103, 182, 122, 82, 78, 63, 131, 75, 201, 130, 114,
46, 118, 28, 241, 30, 204, 183, 215, 199, 138, 16, 121, 26, 77, 25, 53, 22, 125,
67, 43, 205, 134, 171, 68, 146, 212, 14, 152, 20]
table2=[185, 155, 167, 36, 27, 60, 226, 58, 211, 240, 253, 79, 119,
209, 163, 12, 72, 128, 106, 218, 189, 216, 71, 91, 250, 150, 11, 236, 207, 73,
217, 17, 127, 177, 39, 231, 197, 178, 99, 230, 40, 54, 179, 93, 251, 220, 168,
112, 37, 246, 176, 156, 165, 95, 184, 57, 228, 133, 169, 252, 19, 2, 81, 48, 242,
105, 255, 116, 191, 89, 181, 70, 23, 194, 88, 97, 153, 235, 164, 158, 137, 238,
108, 239, 162, 144, 115, 140, 84, 188, 109, 219, 44, 214, 227, 161, 141, 80, 247, 52]
table3=[213, 249, 1, 123, 142, 190, 104, 107, 85, 157, 45, 237, 47,
147, 21, 31, 196, 136, 170, 248, 13, 92, 234, 86, 3, 193, 154, 56, 5, 111, 98, 74,
18, 223, 96, 148, 41, 117, 126, 173, 233, 10, 49, 180, 187, 186, 135, 59, 38, 210,
110, 102, 200, 76, 151, 198]
key = [97, 49, 49, 95, 109, 89, 95, 104, 111, 109, 49, 101, 115, 95, 104, 52, 116, 51, 95, 98, 52, 114, 100, 115]
def getValFromTable(byte):
if(byte < 100):
return table1[byte]
elif(byte < 200 and byte >= 100):
return table2[byte-100]
else:
return table3[byte-200]
hexlist = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A ]
i=0
j=0
tmp2 = 0
tmp3 = 0
tmp4 = 0
tmp5 = 0
while True:
if i >= len(hexlist):
break
byte = hexlist[j]
if i & 1 == 0 :
tmp2 = key[i%24] ^ getValFromTable(byte)
else:
tmpKey = key[i%24] ^ 0xFF
tmp2 = tmpKey ^ getValFromTable(byte)
tmp3 = getValFromTable(tmp2)
if ((tmp3 & 0x80) == 0x80):
tmp4 = tmp3 ^ 0x42
result = tmp4 ^ 0xff
print(hex(result), end= " ")
else:
result = tmp3 ^ 0xff
print(hex(result), end= " ")
j += 1
i += 1
Khi chạy thì thu được
Vậy là thuật toán ecrypt của tôi đúng. Thông qua thuật toán encrypt này, tôi sử dụng thuật toán kinh điển để decrypt, BRUTE FORCE:
table1=[90, 132, 6, 69, 174, 203, 232, 243, 87, 254, 166, 61, 94, 65, 8, 208, 51, 34,
33, 129, 32, 221, 0, 160, 35, 175, 113, 4, 139, 245, 24, 29, 225, 15, 101, 9,
206, 66, 120, 62, 195, 55, 202, 143, 100, 50, 224, 172, 222, 145, 124, 42, 192,
7, 244, 149, 159, 64, 83, 229, 103, 182, 122, 82, 78, 63, 131, 75, 201, 130, 114,
46, 118, 28, 241, 30, 204, 183, 215, 199, 138, 16, 121, 26, 77, 25, 53, 22, 125,
67, 43, 205, 134, 171, 68, 146, 212, 14, 152, 20]
table2=[185, 155, 167, 36, 27, 60, 226, 58, 211, 240, 253, 79, 119,
209, 163, 12, 72, 128, 106, 218, 189, 216, 71, 91, 250, 150, 11, 236, 207, 73,
217, 17, 127, 177, 39, 231, 197, 178, 99, 230, 40, 54, 179, 93, 251, 220, 168,
112, 37, 246, 176, 156, 165, 95, 184, 57, 228, 133, 169, 252, 19, 2, 81, 48, 242,
105, 255, 116, 191, 89, 181, 70, 23, 194, 88, 97, 153, 235, 164, 158, 137, 238,
108, 239, 162, 144, 115, 140, 84, 188, 109, 219, 44, 214, 227, 161, 141, 80, 247, 52]
table3=[213, 249, 1, 123, 142, 190, 104, 107, 85, 157, 45, 237, 47,
147, 21, 31, 196, 136, 170, 248, 13, 92, 234, 86, 3, 193, 154, 56, 5, 111, 98, 74,
18, 223, 96, 148, 41, 117, 126, 173, 233, 10, 49, 180, 187, 186, 135, 59, 38, 210,
110, 102, 200, 76, 151, 198]
key = [0x61, 0xCE, 0x31, 0xA0, 0x6D, 0xA6, 0x5F, 0x97, 0x6F, 0x92, 0x31, 0x9A, 0x73, 0xA0, 0x68, 0xCB, 0x74, 0xCC, 0x5F, 0x9D, 0x34, 0x8D, 0x64, 0x8C]
#key = [97, 49, 49, 95, 109, 89, 95, 104, 111, 109, 49, 101, 115, 95, 104, 52, 116, 51, 95, 98, 52, 114, 100, 115]
def getValFromTable(byte):
if(byte < 100):
return table1[byte]
elif(byte < 200 and byte >= 100):
return table2[byte-100]
else:
return table3[byte-200]
def BruteToDie(byte, i):
tmp2 = key[i%24] ^ getValFromTable(byte)
tmp3 = getValFromTable(tmp2)
if ((tmp3 & 0x80) == 0x80):
tmp4 = tmp3 ^ 0x42
result = tmp4 ^ 0xff
return result
else:
result = tmp3 ^ 0xff
return result
filein = open("cool_wizard_meme.png.encrypted","rb")
hexlist = list(filein.read())
filein.close()
j=0
fileout = open("_cool_wizard_meme.png","wb+")
for i in hexlist:
tmp = 0
while True:
if BruteToDie(tmp, j) == i:
tmp = tmp & 0xff
fileout.write(tmp.to_bytes(1, 'little'))
break
else:
tmp += 1
j += 1
fileout.close()
print("DONE!")
Chạy file tôi thu được hình có flag:
Done bài 10