Privacy Inspector is a super-mega-twitcher-clicker on your system, which, of course, is the best way to keep your privacy and destroy personal data accumulated during your work on the computer, temporary files, empties the trash and kindly performs a lot of other actions. But it does all this useless nonsense for no reason at all – you have to pay a certain amount of evergreen money for the license.
We start by downloading the distribution package. Install it and take a look. There are signs that your executable is covered with PECompact package. You may use an external utility to unpack it, but it will be more useful if you unpack it manually. Load the file into the debugger, but don’t run it.
PECompact uses an anti-debugging trick based on setting a SEH frame whose address is the jump address to the next code. The transition address is written to the EAX register, then a write to the forbidden memory location is performed, an error handler is triggered, and control is transferred to the transition address.
Place a breakpoint here and run the program. If an exception is thrown (and it will be thrown) we should forcibly continue executing the program bypassing the exception (Shift F9).
Scroll down a couple of screens until you get to the characteristic JMP EAX command followed by a bunch of null bytes. This is the jump to OEP. Put a breakpoint on JMP EAX and run the program again.
After the breakpoint triggers, do one step-by-step trace and get to OEP. That’s it, the program is ready for dumping and import recovery.
Let’s make a dump. I am using OllyDump plugin for this, but no one is stopping you from using any other tools, the point doesn’t change.
Search and load import table. The OEP address is calculated by subtracting the code base from the virtual OEP address (00428A01 00400000 = 28A01), substitute it in ImpREC, then two clicks on IAT AutoSearch and Get Imports. the import table is not damaged, you can screw it to the dump immediately.
Click on Fix Dump, select the created dump file and in a couple of seconds we get a fully unpacked and working file. Exactly the same algorithm is used to unpack other files covered by PECompact. It took much longer to describe than to decompress itself.
All overhangs are removed from the file, you can send the unpacked and restored file to the disassembler. Registration works as follows: the program accepts any serial number, but after that it requires restart. No messages about correct and incorrect entered data are displayed. You can only be guided by the inscriptions in the header, for example. I did not find anything like that in the file, but I found it in the language file English.ini in the folder Language. The inscription that is displayed in the header consists of several parts.
So, we should not search for the strings themselves but for their indexes. The first index shows the following code:
; Check the value in the memory cell .text:0041C190 cmp dword_469DA4, ebx .text:0041C196 jnz short loc_41C1A9 ; If it is not null, then proceed to add a flat caption .text:0041C198 push offset Caption ; Privacy Inspector .text:0041C19D mov ecx, esi .text:0041C19F call sub_43D788 .text:0041C1A4 jmp loc_41C33F .text:0041C1A9 ; .text:0041C1A9 loc_41C1A9: .text:0041C1A9 mov eax, dword_469DA8 .text:0041C1AE lea ecx, [esp 0Ch] .text:0041C1B2 push ecx .text:0041C1B3 push ecx .text:0041C1B4 test eax, eax .text:0041C1B6 mov ecx, esp .text:0041C1B8 jnz loc_41C2DF .text:0041C1BE mov [esp 2Ch], esp ; Load string by index .text:0041C1C2 push offset aIds_submain1 ; IDS_SUBMAIN1 .text:0041C1C7 call sub_439BD0 .text:0041C1CC push ecx .text:0041C1CD mov byte ptr [esp 3Ch], 2 .text:0041C1D2 mov ecx, esp .text:0041C1D4 mov [esp 2Ch], esp .text:0041C1D8 push offset aMain ; Main .text:0041C1DD call sub_439BD0
We check the value in some variable and if it is not zero, the program is considered trial and various extraneous messages are added into the header. The next step is to find out where and how this variable is initialized. By cross-references we get to this interesting code:
.text:0041955D push ecx .text:0041955E mov ecx, ebx ; Call test function .text:00419560 call sub_419DB0 .text:00419565 test eax, eax ; Based on its results, write to variable 0 or 1 .text:00419567 jz short loc_41957B .text:00419569 mov eax, [ebp lpszUrl] .text:0041956C mov dword_469DA4, 1 .text:00419576 cmp eax, 4 .text:00419579 jnb short loc_419585 .text:0041957B loc_41957B: .text:0041957B mov dword_469DA4, 0 .text:00419585 loc_419585: .text:00419585 lea edx, [ebp var_128] .text:0041958B mov ecx, ebx .text:0041958D push edx ; Call another check function .text:0041958E call sub_41A110 .text:00419593 test eax, eax ; If it returned 0, overwrite the variable with this zero value .text:00419595 jnz loc_419715 .text:0041959B push eax .text:0041959C lea ecx, [ebp var_11F8] .text:004195A2 mov dword_469DA4, eax .text:004195A7 call sub_41CB00 .text:004195AC lea ecx, [ebp var_11F8] .text:004195B2 mov byte ptr [ebp var_4], 0Bh
Some checks are performed twice and according to their results different values are written into the variable several times. If you look into the first check function under the debugger, you will see that it converts the registration name into something resembling a serial number, which, in its turn, is compared to the entered serial number. So as not to waste your time, I will say that this is a trick from the afftar. With any comparison result, even if you pull under the debugger valid pair for a particular name, this check does not affect the registration. So it makes sense to look at the second check below.
.text:0041A110 mov eax, 2264h .text:0041A115 call __alloca_probe .text:0041A11A mov ax, word_464AA8 .text:0041A120 push ebx .text:0041A121 push esi .text:0041A122 push edi .text:0041A123 mov word ptr [esp 2270h var_2262], ax .text:0041A128 mov ecx, 226h .text:0041A12D xor eax, eax .text:0041A12F lea edi, [esp 2270h var_1130] .text:0041A136 rep stosd .text:0041A138 mov ecx, 226h .text:0041A13D lea edi, [esp 2270h var_2260] .text:0041A141 rep stosd .text:0041A143 mov ecx, 226h .text:0041A148 lea edi, [esp 2270h var_19C8] .text:0041A14F rep stosd .text:0041A151 mov ecx, 226h .text:0041A156 lea edi, [esp 2270h var_898] .text:0041A15D rep stosd .text:0041A15F or ecx, 0FFFFFFFFh .text:0041A162 mov edi, offset aDcji77cfDf1g75 ; DCJI77CF,DF1G752F,GGD24KF7,9FGKD85H,88H .text:0041A167 repne scasb .text:0041A169 not ecx .text:0041A16B sub edi, ecx .text:0041A16D lea edx, [esp 2270h var_1130] .text:0041A174 mov eax, ecx .text:0041A176 mov esi, edi .text:0041A178 shr ecx, 2 .text:0041A17B mov edi, edx .text:0041A17D lea edx, [esp 2270h var_2260] .text:0041A181 rep movsd .text:0041A183 mov ecx, eax .text:0041A185 xor eax, eax .text:0041A187 and ecx, 3 .text:0041A18A rep movsb .text:0041A18C mov edi, offset aNbgd3eeqEb3hme ; NBGD3EEQ,EB3HMEQM,C3GH7N3F,IIE3D7HI,BHV .text:0041A191 or ecx, 0FFFFFFFFh .text:0041A194 repne scasb .text:0041A196 not ecx .text:0041A198 sub edi, ecx .text:0041A19A mov eax, ecx .text:0041A19C mov esi, edi .text:0041A19E mov edi, edx .text:0041A1A0 lea edx, [esp 2270h var_19C8] .text:0041A1A7 shr ecx, 2 .text:0041A1AA rep movsd .text:0041A1AC mov ecx, eax .text:0041A1AE xor eax, eax .text:0041A1B0 and ecx, 3 .text:0041A1B3 rep movsb .text:0041A1B5 mov edi, offset aBqjgbbej5548zg ; BQJGBBEJ,5548ZGB3,5HHF5BIM,2JJE3GZJ,GFB .text:0041A1BA or ecx, 0FFFFFFFFh .text:0041A1BD repne scasb .text:0041A1BF not ecx .text:0041A1C1 sub edi, ecx .text:0041A1C3 mov eax, ecx .text:0041A1C5 mov esi, edi .text:0041A1C7 mov edi, edx .text:0041A1C9 lea edx, [esp 2270h var_898] .text:0041A1D0 shr ecx, 2 .text:0041A1D3 rep movsd .text:0041A1D5 mov ecx, eax .text:0041A1D7 xor eax, eax .text:0041A1D9 and ecx, 3 .text:0041A1DC rep movsb .text:0041A1DE mov edi, offset aMmv7mb1eGfgj5g ; MMV7MB1E,GFGJ5GJ7,7JDEE6EB,NMHJ12A1,DAA .text:0041A1E3 or ecx, 0FFFFFFFFh .text:0041A1E6 repne scasb .text:0041A1E8 not ecx
If you come here under the debugger, you can see that the entered serial number is compared one by one with strings from quite long lists. It is believed that valid serial numbers are saved into the program. Check. Registration name is any, serial number is any from any list. Restart the program. Voila!
I still don’t understand why I had to divide the list of serial numbers into several parts. This is definitely not the compiler’s trick. This is how the source program was written. And why would he send the reverse engineer on a false trace, generating fake serial number, if few lines below this trap neutralizes itself? The hinged packer is apparently used to hide all this ugly stuff from the eyes of outsiders. The keygen on the other hand comes down to selecting a random serial from the list of valid ones. Exactly the same way the rest of the developer’s software is protected, only the set of serial keys will be different. Although it is a stretch to call it protection. But we have practiced a little in manual unpacking.
best bins for cc