Record the first shelling

Posted by compbry15 on Tue, 30 Nov 2021 04:28:55 +0100

In the course assignment of "malware analysis" a few days ago, the additional problem is a VMP file in elf format. It is said that it can be solved by writing a disassembler with a virtual shell. The goal is to enter the correct password and let it report conversions. However, the linux virtual machine that I put in doesn't run. After checking, the header file is missing, so I installed the environment and ran it.
The cracking tool is IDA. The main function calls a function. After entering, there is a variable declaration, followed by a pile of switch es in the document, that is, the way the virtual shell receives the instruction set. Through reading and variable renaming, I finally understand its principle. The real code is placed in a data segment. The function only reads it out, and then judges the instruction according to the first bit in the code. The last few bits are the corresponding parameters, which are basically binary versions of assembly instructions such as MOV, ax and BX. My initial goal is very simple, that is to translate these codes, at least into sentence by sentence text assembly instructions.
I have been using C + + most recently. Considering that I am not unfamiliar with it, I decided to practice python. Python can read binary files. At the beginning, it felt uncomfortable, but the code was very short. It was also with open. When writing disassembly, it found that there was no switch, so it struggled to write a pile of elif s. Therefore, the reverse exchange code is written on the split screen. Because there are many jump instructions, the display of line numbers is added. Among them, 4154 to 7899 are the code segment addresses starting from 59 (about?). I have done the reverse xor processing, otherwise 59 will be disordered. We can see that there are still many imperfections, but the basic instructions can be seen. Capable readers can recover the 30 bit ascii code password from some hard coded data.

1: mov ds[0], 4154
8: mov ds[1], 7899
15: mov ds[3], ds[0]
19: mov ds[5], 24432450
26: mov ds[4], [ds[3]]
29: ds[4] = ds[5] xor ds[4]
34: mov [ds[3]], ds[4]
37: ds[3] = ds[3] + 4
45: cmp ds[1], ds[3]
49: jge not jumping
54: jmp to 58 (40fa)
59: jmp to 3008 (4c80)
3009: push
3012: push
3015: push
3018: call 2669
2670: mov ds[0], 80
2677: call 63
64: io: put_char
66: ret (2681)
2682: mov ds[0], 108
2689: call 63
64: io: put_char
66: ret (2693)
2694: mov ds[0], 101
2701: call 63
64: io: put_char
66: ret (2705)
2706: mov ds[0], 97
2713: call 63
64: io: put_char
66: ret (2717)
2718: mov ds[0], 115
2725: call 63
64: io: put_char
66: ret (2729)
2730: mov ds[0], 101
2737: call 63
64: io: put_char
66: ret (2741)
2742: mov ds[0], 32
2749: call 63
64: io: put_char
66: ret (2753)
2754: mov ds[0], 101
2761: call 63
64: io: put_char
66: ret (2765)
2766: mov ds[0], 110
2773: call 63
64: io: put_char
66: ret (2777)
2778: mov ds[0], 116
2785: call 63
64: io: put_char
66: ret (2789)
2790: mov ds[0], 101
2797: call 63
64: io: put_char
66: ret (2801)
2802: mov ds[0], 114
2809: call 63
64: io: put_char
66: ret (2813)
2814: mov ds[0], 32
2821: call 63
64: io: put_char
66: ret (2825)
2826: mov ds[0], 121
2833: call 63
64: io: put_char
66: ret (2837)
2838: mov ds[0], 111
2845: call 63
64: io: put_char
66: ret (2849)
2850: mov ds[0], 117
2857: call 63
64: io: put_char
66: ret (2861)
2862: mov ds[0], 114
2869: call 63
64: io: put_char
66: ret (2873)
2874: mov ds[0], 32
2881: call 63
64: io: put_char
66: ret (2885)
2886: mov ds[0], 112
2893: call 63
64: io: put_char
66: ret (2897)
2898: mov ds[0], 97
2905: call 63
64: io: put_char
66: ret (2909)
2910: mov ds[0], 115
2917: call 63
64: io: put_char
66: ret (2921)
2922: mov ds[0], 115
2929: call 63
64: io: put_char
66: ret (2933)
2934: mov ds[0], 119
2941: call 63
64: io: put_char
66: ret (2945)
2946: mov ds[0], 111
2953: call 63
64: io: put_char
66: ret (2957)
2958: mov ds[0], 114
2965: call 63
64: io: put_char
66: ret (2969)
2970: mov ds[0], 100
2977: call 63
64: io: put_char
66: ret (2981)
2982: mov ds[0], 58
2989: call 63
64: io: put_char
66: ret (2993)
2994: mov ds[0], 32
3001: call 63
64: io: put_char
66: ret (3005)
3006: ret (3022)
3023: mov ds[1], 30
3030: mov ds[0], 4
3037: call 128
129: push
132: push
135: mov ds[30], ds[1]
ds[0] = ds[0] * ds[30] mul
144: ds[0] = ds[0] + 8
152: mov ds[29], ds[0]
156: io: return and inc
158: and ds[0], 0
162: jz to 194
167: mov ds[4], ds[29]
171: ds[4] = 3 >> ds[4] right shift
179: mov [ds[0]], ds[4]
182: ds[0] = ds[0] + 8
pop
pop
194: ret (3041)
3042: mov ds[11], ds[0]
3046: jmp to 3055 (4caf)
3056: mov ds[9], 0
3063: jmp to 3430 (4e26)
3431: mov ds[30], ds[9]
3435: mov ds[0], 30
3442: cmp ds[30], ds[0]
3446: jl 3067
3451: call 75
76: io: scan char
78: ret (3455)
3456: mov ds[1], ds[0]
3460: mov ds[30], ds[1]
3464: mov ds[0], 10
3471: cmp ds[30], ds[0]
3475: jnz 3484
3480: jmp to 3774 (4f7e)
3775: mov ds[0], ds[11]
3779: call 681
682: push
685: push
688: mov ds[10], ds[0]
692: mov ds[1], 30
699: mov ds[0], 4
706: call 128
129: push
132: push
135: mov ds[30], ds[1]
ds[0] = ds[0] * ds[30] mul
144: ds[0] = ds[0] + 8
152: mov ds[29], ds[0]
156: io: return and inc
158: and ds[0], 0
162: jz to 194
167: mov ds[4], ds[29]
171: ds[4] = 3 >> ds[4] right shift
179: mov [ds[0]], ds[4]
182: ds[0] = ds[0] + 8
pop
pop
194: ret (710)
711: mov ds[9], ds[0]
715: mov ds[1], 4
722: mov ds[0], 4
729: call 128
129: push
132: push
135: mov ds[30], ds[1]
ds[0] = ds[0] * ds[30] mul
144: ds[0] = ds[0] + 8
152: mov ds[29], ds[0]
156: io: return and inc
158: and ds[0], 0
162: jz to 194
167: mov ds[4], ds[29]
171: ds[4] = 3 >> ds[4] right shift
179: mov [ds[0]], ds[4]
182: ds[0] = ds[0] + 8
pop
pop
194: ret (733)
734: mov ds[5], ds[0]
738: mov ds[30], 253
745: mov [ds[5]], ds[30]
748: mov ds[30], 1
 mul
763: mov ds[0], ds[5]
767: ds[30] = ds[0] + ds[30]
772: mov ds[1], ds[30]
776: mov ds[30], 14
783: mov [ds[1]], ds[30]
786: mov ds[30], 1
 mul
801: mov ds[0], ds[5]
805: ds[30] = ds[0] + ds[30]
810: mov ds[1], ds[30]
814: mov ds[30], 99
821: mov [ds[1]], ds[30]
824: mov ds[30], 1
 mul
839: mov ds[0], ds[5]
843: ds[30] = ds[0] + ds[30]
848: mov ds[1], ds[30]
852: mov ds[30], 79
859: mov [ds[1]], ds[30]
862: mov ds[30], 141
869: mov [ds[9]], ds[30]
872: mov ds[30], 1
 mul
887: mov ds[0], ds[9]
891: ds[30] = ds[0] + ds[30]
896: mov ds[1], ds[30]
900: mov ds[30], 111
907: mov [ds[1]], ds[30]
910: mov ds[30], 1
 mul
925: mov ds[0], ds[9]
929: ds[30] = ds[0] + ds[30]
934: mov ds[1], ds[30]
938: mov ds[30], 0
945: mov [ds[1]], ds[30]
948: mov ds[30], 1
 mul
963: mov ds[0], ds[9]
967: ds[30] = ds[0] + ds[30]
972: mov ds[1], ds[30]
976: mov ds[30], 36
983: mov [ds[1]], ds[30]
986: mov ds[30], 1
 mul
1001: mov ds[0], ds[9]
1005: ds[30] = ds[0] + ds[30]
1010: mov ds[1], ds[30]
1014: mov ds[30], 152
1021: mov [ds[1]], ds[30]
1024: mov ds[30], 1
 mul
1039: mov ds[0], ds[9]
1043: ds[30] = ds[0] + ds[30]
1048: mov ds[1], ds[30]
1052: mov ds[30], 124
1059: mov [ds[1]], ds[30]
1062: mov ds[30], 1
 mul
1077: mov ds[0], ds[9]
1081: ds[30] = ds[0] + ds[30]
1086: mov ds[1], ds[30]
1090: mov ds[30], 16
1097: mov [ds[1]], ds[30]
1100: mov ds[30], 1
 mul
1115: mov ds[0], ds[9]
1119: ds[30] = ds[0] + ds[30]
1124: mov ds[1], ds[30]
1128: mov ds[30], 16
1135: mov [ds[1]], ds[30]
1138: mov ds[30], 1
 mul
1153: mov ds[0], ds[9]
1157: ds[30] = ds[0] + ds[30]
1162: mov ds[1], ds[30]
1166: mov ds[30], 156
1173: mov [ds[1]], ds[30]
1176: mov ds[30], 1
 mul
1191: mov ds[0], ds[9]
1195: ds[30] = ds[0] + ds[30]
1200: mov ds[1], ds[30]
1204: mov ds[30], 96
1211: mov [ds[1]], ds[30]
1214: mov ds[30], 1
 mul
1229: mov ds[0], ds[9]
1233: ds[30] = ds[0] + ds[30]
1238: mov ds[1], ds[30]
1242: mov ds[30], 7
1249: mov [ds[1]], ds[30]
1252: mov ds[30], 1
 mul
1267: mov ds[0], ds[9]
1271: ds[30] = ds[0] + ds[30]
1276: mov ds[1], ds[30]
1280: mov ds[30], 16
1287: mov [ds[1]], ds[30]
1290: mov ds[30], 1
 mul
1305: mov ds[0], ds[9]
1309: ds[30] = ds[0] + ds[30]
1314: mov ds[1], ds[30]
1318: mov ds[30], 139
1325: mov [ds[1]], ds[30]
1328: mov ds[30], 1
 mul
1343: mov ds[0], ds[9]
1347: ds[30] = ds[0] + ds[30]
1352: mov ds[1], ds[30]
1356: mov ds[30], 99
1363: mov [ds[1]], ds[30]
1366: mov ds[30], 1
 mul
1381: mov ds[0], ds[9]
1385: ds[30] = ds[0] + ds[30]
1390: mov ds[1], ds[30]
1394: mov ds[30], 16
1401: mov [ds[1]], ds[30]
1404: mov ds[30], 1
 mul
1419: mov ds[0], ds[9]
1423: ds[30] = ds[0] + ds[30]
1428: mov ds[1], ds[30]
1432: mov ds[30], 16
1439: mov [ds[1]], ds[30]
1442: mov ds[30], 1
 mul
1457: mov ds[0], ds[9]
1461: ds[30] = ds[0] + ds[30]
1466: mov ds[1], ds[30]
1470: mov ds[30], 156
1477: mov [ds[1]], ds[30]
1480: mov ds[30], 1
 mul
1495: mov ds[0], ds[9]
1499: ds[30] = ds[0] + ds[30]
1504: mov ds[1], ds[30]
1508: mov ds[30], 96
1515: mov [ds[1]], ds[30]
1518: mov ds[30], 1
 mul
1533: mov ds[0], ds[9]
1537: ds[30] = ds[0] + ds[30]
1542: mov ds[1], ds[30]
1546: mov ds[30], 7
1553: mov [ds[1]], ds[30]
1556: mov ds[30], 1
 mul
1571: mov ds[0], ds[9]
1575: ds[30] = ds[0] + ds[30]
1580: mov ds[1], ds[30]
1584: mov ds[30], 16
1591: mov [ds[1]], ds[30]
1594: mov ds[30], 1
 mul
1609: mov ds[0], ds[9]
1613: ds[30] = ds[0] + ds[30]
1618: mov ds[1], ds[30]
1622: mov ds[30], 133
1629: mov [ds[1]], ds[30]
1632: mov ds[30], 1
 mul
1647: mov ds[0], ds[9]
1651: ds[30] = ds[0] + ds[30]
1656: mov ds[1], ds[30]
1660: mov ds[30], 97
1667: mov [ds[1]], ds[30]
1670: mov ds[30], 1
 mul
1685: mov ds[0], ds[9]
1689: ds[30] = ds[0] + ds[30]
1694: mov ds[1], ds[30]
1698: mov ds[30], 17
1705: mov [ds[1]], ds[30]
1708: mov ds[30], 1
 mul
1723: mov ds[0], ds[9]
1727: ds[30] = ds[0] + ds[30]
1732: mov ds[1], ds[30]
1736: mov ds[30], 60
1743: mov [ds[1]], ds[30]
1746: mov ds[30], 1
 mul
1761: mov ds[0], ds[9]
1765: ds[30] = ds[0] + ds[30]
1770: mov ds[1], ds[30]
1774: mov ds[30], 162
1781: mov [ds[1]], ds[30]
1784: mov ds[30], 1
 mul
1799: mov ds[0], ds[9]
1803: ds[30] = ds[0] + ds[30]
1808: mov ds[1], ds[30]
1812: mov ds[30], 97
1819: mov [ds[1]], ds[30]
1822: mov ds[30], 1
 mul
1837: mov ds[0], ds[9]
1841: ds[30] = ds[0] + ds[30]
1846: mov ds[1], ds[30]
1850: mov ds[30], 11
1857: mov [ds[1]], ds[30]
1860: mov ds[30], 1
 mul
1875: mov ds[0], ds[9]
1879: ds[30] = ds[0] + ds[30]
1884: mov ds[1], ds[30]
1888: mov ds[30], 16
1895: mov [ds[1]], ds[30]
1898: mov ds[30], 1
 mul
1913: mov ds[0], ds[9]
1917: ds[30] = ds[0] + ds[30]
1922: mov ds[1], ds[30]
1926: mov ds[30], 144
1933: mov [ds[1]], ds[30]
1936: mov ds[30], 1
 mul
1951: mov ds[0], ds[9]
1955: ds[30] = ds[0] + ds[30]
1960: mov ds[1], ds[30]
1964: mov ds[30], 119
1971: mov [ds[1]], ds[30]
1974: mov ds[3], 0
1981: jmp to 1990 (4886)
1991: mov ds[1], 0
1998: mov ds[2], 0
2005: jmp to 2144 (4920)
2145: mov ds[3], ds[1]
2149: mov ds[30], ds[2]
2153: mov ds[0], 30
2160: cmp ds[30], ds[0]
2164: jl 2009
2010: mov ds[30], ds[2]
 mul
2022: mov ds[0], ds[10]
2026: ds[30] = ds[0] + ds[30]
2031: mov ds[3], ds[30]
2035: mov ds[4], [ds[3]]
reg64 / reg32, hi: 4, lo: 2
2047: mov ds[30], ds[3]
 mul
2059: mov ds[0], ds[5]
2063: ds[30] = ds[0] + ds[30]
2068: mov ds[3], ds[30]
2072: mov ds[3], [ds[3]]
2075: ds[4] = ds[3] xor ds[4]
2080: mov ds[30], ds[2]
 mul
2092: mov ds[0], ds[9]
2096: ds[30] = ds[0] + ds[30]
2101: mov ds[3], ds[30]
2105: mov ds[3], [ds[3]]
2108: mov ds[30], ds[4]
2112: mov ds[0], ds[3]
2116: cmp ds[30], ds[0]
2120:

Then go to disassembly and find that the total length is very short (automatically exits after reading 0 or 29). The complex judgment output string logic must not be so short. So I read the previous logic again and read it between the lines for most of the day: xor. It was a long time before I realized that this was the second encryption of the code. At this time, the disassembler needs to modify the original code, but it is found that the a + mode of Python reading the file is forced to be added at the end, which can not be modified. The w mode can only be overwritten, so it has to copy the new file word by word with the W mode and then change it. As a result, when writing xor program, python can't do xor directly for byte data types read out by binary, so it first turns into int and then turns back.
I hurried to remove the shell, and the subsequent instructions couldn't be read. There were a lot of jumps. My program scanned the instructions in order. I wanted to follow its program execution, so I added dynamic processing, and the pointer scanned the instructions with the operation of the program. However, there are many branches, so on the other side, IDA is opened to remotely connect the virtual machine to actually run VMP.
There were many detours, because the code was not dry (I felt lucky if it was A small project), and then I felt A lot of problems when I was busy. In short, after analyzing the key print and read strings, we finally found that the password is 30 digits... After 30 digits are lost, we use IDA to track. Because we don't intend to write IDA script, we want to break down in A code block instead of turning in the loop of B code block. It depends on which instruction is in A but not in B, and then make A breakpoint there. It's stupid, But when people fall in, they just don't want to sharpen their knives.
The core logic is that I almost guess with Meng in the end. When outputting the previous string, I was shocked to see that the program hard coded a pile of numbers, and then took out the characters from the offset represented by those numbers. The numbers are discontinuous, so there is no comparison table, and there is no way to see the characters as in the hard coded content of the program. I'm a little worried that the password is made up like this, and the result is even more outrageous. I read down the program, read out a pile of hard code, and I (fortunately) wrote it all down. They are stored in three locations, and the afterwards numbers are 4, 1 and 29 respectively. In fact, the latter two groups are passwords. I also determined what was compared in the key comparison statements, so I found that the plaintext I entered was xor compared with the first of 30. So there is no plaintext even in the program. I did xor on the calculator manually, and then found that the first four numbers are circular keys. No. 1 acts on 1, 5 and 9 characters, No. 2 acts on 2, 6 and 10, and so on. It is not easy to find the corresponding password in the ascii table.
I won't post other contents, mainly because I didn't leave screenshots and intermediate results in the cracking process. Now I want to have some regrets.

Topics: Python