NeoQuest 2017: get out of the dodecahedron, without running anything in qemu
"lost in the dodecahedron"
On Earth the Egyptian pyramids, and on this planet is one (but what!) a gigantic dodecahedron, levitating in the air at a height of about ten meters. Should be, in it lies the whole mystery of this planet. The figure itself seems to be inviting you to explore it – one of the faces is missing, indicating the entrance, and from there to the land of the recoil rope ladder. Of course, we have got there.
/ > "Here and gone no one knows where the space expedition..." – sadly said we are already the third hour of unsuccessfully trying to get out of the stupid dodecahedron, the door is immediately locked as soon as the last of us climbed inside. To break down the door failed, the only solution was wandering through the maze of three-dimensional figures. It's hard to tell how much time passed, but our searches were unsuccessful: in one of the corners we found quite a earth's ancient computer! Dissatisfied with the humming and otorbaeva, it still booted. All that managed to find – one file. Good thing I had a laptop and flash drive, I threw the file on the laptop and began to study it carefully.
Download the provided file. This qemu binary, but not quite normal.
Tip 2: you need to see all virtual devices that you can use, among them one will be special, it must be added when loading a new path. To interact with the device, use the IO ports.
View a list of virtual devices:
the
$ ./qemu-system-x86_64_final.qemu -device help
In the section "Misc devices" find the most "special":
the
name "a42b145c", bus PCI, desc "PCI= Hex Sudoku =-"
The hint tells us that then you need to load something in qemu to interact with the device via IO ports. But we'll go the other way: if there is a virtual device, then qemu is provided in the code, let's retraverse.
Downloadable binary in IDA and see that all the characters in place, it is for us. We look for our device. Search "Hex Sudoku" does nothing, apparently the strings are encrypted. Look in qemu added new devices, a good example is here. See for device registration is used type_register_static. Find it in IDA and see where it is invoked. Among all features, one stands out:

It seems that this is the desired device.

In kYw8zJoR2P79 find the pointer in class_init:

Here for clarity I've added the necessary structures of qemu and set variables with the correct types:

See the transcript for the string "PCI= Hex Sudoku =-", but she is not interested. Go to init

In wF5kdW6bDnmo find the function pointers of read and write:

Let's start with reading:

Looks a little weird. The device stores all data chunks with 16 * 4 bytes, scattered fLA0hXGQ.
Tip 3: read from the port 0x0 values are the initial values for Sudoku 16x16, the high byte is the index, the younger is the value.
Now, using the offset from dword_88B6C64, we can get all 92 initial values for Sudoku. Solve by any convenient method, at its discretion:
the
solution = [
[ 0xF, 0x0, 0x3, 0xB, 0xD, 0xC, 0x4, 0xE, 0x8, 0x5, 0x2, 0xA, 0x9, 0x1, 0x6, 0x7 ],
[ 0x4, 0xC, 0x8, 0xE, 0x1, 0xF, 0x5, 0x2, 0xB, 0x9, 0x7, 0x6, 0xD, 0x3, 0xA, 0x0 ],
[ 0x9, 0x1, 0x5, 0x7, 0x6, 0xA, 0x0, 0x8, 0x4, 0xE, 0x3, 0xD, 0xB, 0xF, 0x2, 0xC ],
[ 0xD, 0x6, 0x2, 0xA, 0xB, 0x7, 0x9, 0x3, 0x0, 0xF, 0x1, 0xC, 0x5, 0x4, 0x8, 0xE ],
[ 0x5, 0x8, 0x7, 0x0, 0xA, 0xD, 0x2, 0x1, 0x9, 0x3, 0x6, 0x4, 0xE, 0xB, 0xC, 0xF ],
[ 0x2, 0xA, 0x4, 0xD, 0xF, 0xB, 0x3, 0x0, 0xE, 0xC, 0x5, 0x1, 0x6, 0x9, 0x7, 0x8 ],
[ 0x3, 0xF, 0x6, 0x9, 0xE, 0x5, 0xC, 0x4, 0xD, 0x7, 0xB, 0x8, 0x2, 0xA, 0x0, 0x1 ],
[ 0x7, 0x3, 0xF, 0x5, 0x0, 0x6, 0xA, 0xB, 0x2, 0x4, 0x8, 0x9, 0xC, 0xE, 0x1, 0xD ],
[ 0xE, 0x4, 0x0, 0x6, 0xC, 0x2, 0x8, 0xF, 0x1, 0xB, 0xD, 0x7, 0x3, 0x5, 0x9, 0xA ],
[ 0xA, 0xB, 0xC, 0x2, 0x9, 0x1, 0xE, 0xD, 0x5, 0x6, 0x0, 0x3, 0x8, 0x7, 0xF, 0x4 ],
[ 0x8, 0x9, 0xD, 0x1, 0x4, 0x3, 0x7, 0x5, 0xC, 0xA, 0xF, 0xE, 0x0, 0x2, 0xB, 0x6 ],
[ 0xB, 0xD, 0x1, 0x4, 0x2, 0x0, 0xF, 0xA, 0x3, 0x8, 0xC, 0x5, 0x7, 0x6, 0xE, 0x9 ],
[ 0x0, 0x7, 0xA, 0x8, 0x5, 0xE, 0xD, 0x9, 0x6, 0x2, 0x4, 0xF, 0x1, 0xC, 0x3, 0xB ],
[ 0x6, 0x2, 0x9, 0xF, 0x3, 0x4, 0xB, 0xC, 0x7, 0x1, 0xE, 0x0, 0xA, 0x8, 0xD, 0x5 ],
[ 0xC, 0x5, 0xE, 0x3, 0x7, 0x8, 0x1, 0x6, 0xA, 0xD, 0x9, 0xB, 0xF, 0x0, 0x4, 0x2 ]
]
How can I get the answer? At address 0x4 device gives 4096 bytes — perhaps there needs to be a key, of course after we provide the correct solution to the device. View recording function:

In the beginning, is written to the passed value. Then checked the correctness of the decision, and if it is true, then calculate the answer.
Stampin fLA0hXGQ contents to a file and will rewrite code in Python:
the
xor1_offset = [
0x11b0, 0x180, 0xcd0, 0x1e10, 0x1d50, 0x13d0, 0x560, 0xf60,
0x1a40, 0xe10, 0x1d00, 0x1100, 0xed0, 0xf10, 0xa20, 0x630,
0xd90, 0x2070, 0x1530, 0x1cc0, 0xf0, 0x1110, 0x1030, 0x1390,
0x710, 0x6e0, 0x1d10, 0x3a0, 0x1290, 0x1150, 0x9d0, 0xcb0,
0x1ad0, 0x17b0, 0x6b0, 0x1510, 0xf30, 0xad0, 0x1350, 0x450,
0x1160, 0x810, 0x8a0, 0x1550, 0x1ed0, 0x1f60, 0x1120, 0x1660,
0x2030, 0xfc0, 0x17e0, 0x1640, 0xde0, 0x900, 0xff0, 0x17f0,
0xf40, 0x10f0, 0x8f0, 0x880, 0x160, 0x1400, 0x19d0, 0x7f0,
0x1490, 0x30, 0x1e80, 0x15b0, 0x1f20, 0xbf0, 0x11c0, 0x1a70,
0x1380, 0x960, 0x1c50, 0x1fb0, 0x570, 0x1c30, 0xd60, 0x290,
0x1260, 0x240, 0x1060, 0x1b90, 0x1230, 0x280, 0xdf0, 0x1190,
0x1240, 0xeb0, 0xb40, 0xdb0, 0x820, 0x1f70, 0x1330, 0xd70,
0xe90, 0xf00, 0xc60, 0xe60, 0x390, 0x1c00, 0x1bb0, 0x1690,
0x600, 0x12a0, 0xef0, 0x17d0, 0x970, 0x670, 0x1990, 0xac0,
0x3f0, 0x1b70, 0x1790, 0xf70, 0x1b60, 0x1070, 0x1200, 0x1680,
0x1b50, 0xf90, 0x4c0, 0x1840, 0x1800, 0x2e0, 0xbc0, 0x1780,
0x14d0, 0x80, 0x1dd0, 0x16a0, 0x8b0, 0x1e90, 0x7e0, 0x1450,
0x20f0, 0x20e0, 0x2040, 0x9f0, 0x2150, 0x1250, 0xa70, 0xcc0,
0xa00, 0x5d0, 0x20, 0xfa0, 0x500, 0x1c70, 0x1ae0, 0x16d0,
0x1470, 0x18b0, 0x270, 0xc80, 0x1850, 0x1a50, 0x1a90, 0xe30,
0x1440, 0x2110, 0x340, 0x1af0, 0x1010, 0x510, 0x310, 0x830,
0x3c0, 0x860, 0x3e0, 0x13e0, 0x19f0, 0x1ac0, 0x1e60, 0xbe0,
0x950, 0x1b80, 0x680, 0x1220, 0xd40, 0x14a0, 0xb10, 0xe70,
0x19e0, 0x1b20, 0x10a0, 0x1730, 0x4d0, 0x120, 0x12c0, 0x16e0,
0x14c0, 0x1de0, 0x1d0, 0x420, 0x910, 0x1b0, 0x2080, 0x1920,
0x1460, 0x40, 0x11a0, 0x15e0, 0xb00, 0x1ba0, 0x1650, 0x440,
0x650, 0x350, 0x300, 0x330, 0x1e0, 0x13c0, 0xd50, 0x1fd0,
0xae0, 0x12f0, 0xa80, 0x50, 0xbb0, 0x1e70, 0x1b30, 0xc0,
0x1340, 0xd20, 0x2c0, 0xaf0, 0x6d0, 0x1570, 0xc00, 0x1580,
0x5e0, 0x1700, 0x1ea0, 0x1890, 0x1d20, 0x1aa0, 0x840, 0x1f40,
0x1590, 0x700, 0x150, 0x890, 0x4e0, 0x1720, 0xd30, 0x990,
0x16f0, 0x3b0, 0x1970, 0x1c0, 0x0, 0x1320, 0x1ff0, 0x760
]
xor2_offset = 0x170
row_offset = [
0xfb0, 0x2a0, 0xec0, 0x140, 0x1090, 0xdc0, 0x15f0, 0x610,
0x7c0, 0x1a10, 0x780, 0x13b0, 0xc20, 0x1750, 0x1860, 0x6a0, 0x12B0
]
answer_offset = [
0x12b0, 0xfd0, 0x1ca0, 0x2020, 0xaa0, 0x5a0, 0x470, 0x4f0,
0x1a00, 0xa40, 0x1870, 0x1810, 0x690, 0x1410, 0x15d0, 0x20b0,
0x870, 0x1c60, 0x1da0, 0xa90, 0x980, 0x1000, 0x930, 0x2000,
0x2160, 0x5c0, 0x1370, 0x15a0, 0xca0, 0x790, 0x200, 0x2060,
0xb30, 0x1fe0, 0x90, 0x18a0, 0x5b0, 0x1e40, 0x1d70, 0x1d30,
0x530, 0x1d90, 0x2130, 0x1600, 0x9e0, 0x1940, 0x1910, 0x1670,
0x60, 0x10e0, 0x1950, 0xfe0, 0x430, 0x20c0, 0x380, 0x230,
0xf80, 0x1270, 0x2b0, 0x1130, 0xe20, 0x20d0, 0x2010, 0x720,
0x1c40, 0x1df0, 0x16c0, 0x13a0, 0xc90, 0x320, 0x1ce0, 0x18d0,
0x1dc0, 0x520, 0x250, 0x1fc0, 0x11f0, 0xe50, 0x800, 0x4b0,
0xc70, 0x1c90, 0xba0, 0x1ec0, 0x10c0, 0x8c0, 0xea0, 0x1db0,
0x6c0, 0x1740, 0x1820, 0x590, 0x360, 0x1f80, 0xb20, 0x1770,
0x1e50, 0x940, 0x1710, 0x1bf0, 0x7a0, 0x1c20, 0x1310, 0x220,
0xab0, 0xe00, 0x17a0, 0xf20, 0x730, 0x1cd0, 0x9a0, 0x640,
0x18c0, 0x19c0, 0x5f0, 0xdd0, 0x1560, 0x1bc0, 0x1360, 0x1c80,
0x10, 0x1f0, 0xc10, 0xd80, 0x1500, 0x1620, 0x660, 0x2090,
0x1d40, 0xe80, 0x15c0, 0x850, 0xa60, 0x1e30, 0x14f0, 0x12d0,
0xc30, 0x920, 0x10d0, 0x1210, 0x3d0, 0x1760, 0x740, 0x6f0,
0xe0, 0x1610, 0x1520, 0x19a0, 0xe40, 0x130, 0x1a30, 0x190,
0xa50, 0xf50, 0xb0, 0xc40, 0x14b0, 0x1a0, 0x400, 0xb50,
0x480 the dialled, 0xc50, 0x1d60, 0x1480, 0x9c0, 0x1d80, 0x1f90, 0x12e0,
0x17c0, 0x1050, 0xa10, 0x1830, 0x620, 0x1e00, 0x1f00, 0x1430,
0x1170, 0xcf0, 0xb70, 0x2120, 0x1cb0, 0x1420, 0xce0, 0x1f10,
0x210, 0x1980, 0x9b0, 0x100, 0x110, 0xd10, 0x550, 0x1eb0,
0x1960, 0x1930, 0xb80, 0x7b0, 0xd00, 0x1be0, 0x1900, 0x8d0,
0x1fa0, 0x4a0, 0x1ab0, 0x580, 0x2100, 0x490, 0x8e0, 0x750,
0x1ef0, 0x2140, 0x1ee0, 0x11e0, 0x1b00, 0x16b0, 0x1a20, 0x1630,
0x410, 0x540, 0xd0, 0x1b40, 0x260, 0x1b10, 0x11d0, 0xee0,
0x18f0, 0x2f0, 0x1300, 0x2050, 0x1880, 0x1a80, 0x1080, 0x1c10,
0x1280, 0x18e0, 0x7d0, 0xb60, 0x2d0, 0x1e20, 0x13f0, 0x1bd0,
0xbd0, 0x1f50, 0x70, 0x1020, 0x1540, 0x10b0, 0x14e0, 0xda0,
0x1f30, 0x19b0, 0x460, 0xa30, 0x1180, 0x20a0, 0x1140, 0x1040
]
solution = [
[ 0xF, 0x0, 0x3, 0xB, 0xD, 0xC, 0x4, 0xE, 0x8, 0x5, 0x2, 0xA, 0x9, 0x1, 0x6, 0x7 ],
[ 0x4, 0xC, 0x8, 0xE, 0x1, 0xF, 0x5, 0x2, 0xB, 0x9, 0x7, 0x6, 0xD, 0x3, 0xA, 0x0 ],
[ 0x9, 0x1, 0x5, 0x7, 0x6, 0xA, 0x0, 0x8, 0x4, 0xE, 0x3, 0xD, 0xB, 0xF, 0x2, 0xC ],
[ 0xD, 0x6, 0x2, 0xA, 0xB, 0x7, 0x9, 0x3, 0x0, 0xF, 0x1, 0xC, 0x5, 0x4, 0x8, 0xE ],
[ 0x5, 0x8, 0x7, 0x0, 0xA, 0xD, 0x2, 0x1, 0x9, 0x3, 0x6, 0x4, 0xE, 0xB, 0xC, 0xF ],
[ 0x1, 0xE, 0xB, 0xC, 0x8, 0x9, 0x6, 0x7, 0xF, 0x0, 0xA, 0x2, 0x4, 0xD, 0x5, 0x3 ],
[ 0x2, 0xA, 0x4, 0xD, 0xF, 0xB, 0x3, 0x0, 0xE, 0xC, 0x5, 0x1, 0x6, 0x9, 0x7, 0x8 ],
[ 0x3, 0xF, 0x6, 0x9, 0xE, 0x5, 0xC, 0x4, 0xD, 0x7, 0xB, 0x8, 0x2, 0xA, 0x0, 0x1 ],
[ 0x7, 0x3, 0xF, 0x5, 0x0, 0x6, 0xA, 0xB, 0x2, 0x4, 0x8, 0x9, 0xC, 0xE, 0x1, 0xD ],
[ 0xE, 0x4, 0x0, 0x6, 0xC, 0x2, 0x8, 0xF, 0x1, 0xB, 0xD, 0x7, 0x3, 0x5, 0x9, 0xA ],
[ 0x8, 0x9, 0xD, 0x1, 0x4, 0x3, 0x7, 0x5, 0xC, 0xA, 0xF, 0xE, 0x0, 0x2, 0xB, 0x6 ],
[ 0xB, 0xD, 0x1, 0x4, 0x2, 0x0, 0xF, 0xA, 0x3, 0x8, 0xC, 0x5, 0x7, 0x6, 0xE, 0x9 ],
[ 0x0, 0x7, 0xA, 0x8, 0x5, 0xE, 0xD, 0x9, 0x6, 0x2, 0x4, 0xF, 0x1, 0xC, 0x3, 0xB ],
[ 0x6, 0x2, 0x9, 0xF, 0x3, 0x4, 0xB, 0xC, 0x7, 0x1, 0xE, 0x0, 0xA, 0x8, 0xD, 0x5 ],
[ 0xC, 0x5, 0xE, 0x3, 0x7, 0x8, 0x1, 0x6, 0xA, 0xD, 0x9, 0xB, 0xF, 0x0, 0x4, 0x2 ]
]
memory = bytearray(open("memory", "rb").read())
def mem_read(addr):
return memory[addr * 4] | (memory[addr * 4 + 1] << 8) | (memory[addr * 4 + 2] << 16) | (memory[addr * 4 + 3] << 24)
def mem_write(addr, value):
memory[addr * 4] = value &0xff;
memory[addr * 4 + 1] = (value >> 8) & 0xff;
memory[addr * 4 + 2] = (value >> 16) & 0xff;
memory[addr * 4 + 3] = (value >> 24) & 0xff;
def set_cell(row, col, value):
mem_write(row_offset[row] + col, value)
def get_cell(row, col):
return mem_read(row_offset[row] + col)
for row in range(16):
for col in range(16):
set_cell(row, col, solution[row][col])
for i in range(16):
for cell in range(256):
c1 = get_cell(cell >> 4, cell & 0xf)
c2 = get_cell((cell + 1) >> 4, (cell + 1) & 0xf)
xor1 = mem_read(i + xor1_offset[cell]) & 0xff
xor2 = mem_read(i + xor2_offset)
mem_write(i + answer_offset[cell], ((c2 &0xff) | (c1 << 4)) ^ xor1 ^ xor2)
for i in range(16):
for j in range(256):
print(chr(mem_read(answer_offset[j] + i)), end=")
Run and get strange key in the form of ASCII art:

Комментарии
Отправить комментарий