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.