Our lab has recently got its hands on a new sample of TDL4, also known as TDSS.

outlkupd.exe

The sample is likely distributed as a dropper file named; its file size 1,224Kb. Some of the components that it drops were compiled in July 2012, and some were compiled in September 2012 - so it's relatively a 'fresh' one.

push offset aPhoenixAzU_s_2 ; "Phoenix AZ (U.S.) : %2d:%02d

%d" sub word ptr [ebp-0Ch], 8A51h call printf ... push offset aBeijingMa2d02d ; "Beijing (MA) : %2d:%02d

" cmp dword ptr [ebp-20h], 0F001E96Fh jz loc_4027D9 ... push offset aCurrentTimeAro ; "Current time around the World:" call printf

The dropper is packed with an interesting packer that disguises the protected executable underneath as a normal code, with the normal flow and innocent API calls. The 'normal' code produced by the protector is designed to fool AV engines: its entropy is fine, so it does not 'ring any bells' within AV heuristics, the APIs it imports are from kernel32.dll and C++ run-time library only, and the algorithm itself displays current time around the world, so no alarms from the AV emulators either:The resources of the dropper indicate it's a 'shell extension library', having a dialog window in its GUI:

The only discrepancy is that while the sample has resources, their size is just 5Kb, while the data section is around 1.2Mb - so what does it carry in its protected luggage?

When run, the dropper allocates a heap memory where it unpacks the code and then jump in it:

From there, it will reconstruct the code in its data section and then pass control back to it:

The code reconstructed in the data section now has an interesting characteristic - instead of a traditional flow, it now assembles the pointers of its functions into a vector. Then, it enumerates the vector and calls each of the function by its pointer. If the function returns FALSE, the code quits. Some functions that it calls contain nested code that also assembles the pointers of other functions into a vector and then calls functions from that vector. Thus, the code flow now reminds a tree where all the nodes located on one level are called subsequently, and all of them have to return TRUE.

.data:0040A830 mov dword ptr [esi], offset run_query_ANTI_VM ... .data:0040A841 mov [esp+20h+var_14], offset _check_usernames .data:0040A849 cmp eax, esi .data:0040A84B jnb short next_function_pointer ... .data:0040A860 lea eax, [esp+20h+Memory] .data:0040A864 call add_to_function_vector ... .data:0040AB80 call_next: .data:0040AB80 call dword ptr [ebx] ; CALL function .data:0040AB82 test eax, eax .data:0040AB84 jz short exit_loop .data:0040AB86 add ebx, 4 ; advance index .data:0040AB89 cmp ebx, esi ; check against the limit .data:0040AB8B jnz short call_next ; CALL function

For example:The dropper then starts extracting resources from the encrypted stubs of its data section.

"affid"

"FILE"

"540"

"subid"

"FILE"

"direc47"

"540-direc47"

First, it extracts resourceof the type of, and decodes it in a string. Next, it extractsresource oftype, and decodes it into. Then it concatenates both strings into

"outlkupd.exe"

"name"

"PAIR"

The stringis then extracted from the resourceof type

"ba1039e8cdae53e44ac3e6185b0871f3d031a476"

"1010"

"1011"

creates mutex: Global\ba1039e8cdae53e44ac3e6185b0871f3d031a4761010



creates event: Global\ba1039e8cdae53e44ac3e6185b0871f3d031a4761011



%TEMP%\outlkupd.exe



%TEMP%\[rnd].tmp



%TEMP%

To make sure there is only instance of the dropper running, the code takes a hard-coded stringand appendsto it to create a mutex, then appendsto create an event:Following that, the dropper creates a copy of itself under the following names:whereis a temporary directory.

outlkupd.exe

The dropper then checks the version of the operating system, and acts accordingly. If the OS is Windows 2000, Windows XP, Windows Server 2003, or Windows Server 2003 R2, it will run

appverif.exe

vrfcore.dll

appverif.exe

If the OS is Windows Vista or Windows Server 2008, it will extract resourcesand, then runand wait for 10 seconds before continuing (the user is supposed to accept UAC message during that time).

"stclient.dll"

PROXY32

%TEMP%\stclient.dll

IsWow64Process()

sqmapi.dll

PROXY64

%TEMP%\sqmapi.dll

If the OS is Windows 7, Windows 8, Windows Server 2012 or Windows Server 2008 R2, it will extract resourceof typeas, if the OS is 32-bit. If the OS is 64-bit (via callingon its own process), it will instead extract the resourceof typeas. Next, it constructs a long string that consists of the following lines:

"%SYSTEM%\cmd.exe"

"C:\%TEMP%\sqmapi.dll"

"C:\WINDOWS\ehome"

"C:\WINDOWS\ehome\Mcx2Prov.exe"

"%TEMP%\outlkupd.exe"

%SYSTEM%

"C:\WINDOWS\System32"

"C:\WINDOWS\SysWOW64"

wheremay look likeon a 32-bit Windows oron a 64-bit OS.

CreateProcess()

The dropper will then attempt to run a process with the name composed from the lines above, with theAPI.

CreateRemoteThread()

LoadLibrary()

kernel32.dll

GetProcAddress()

.data:0040FAB0 call VirtualAllocEx .data:0040FAB6 mov edi, eax .data:0040FAB8 test edi, edi .data:0040FABA jz short loc_40FA5D .data:0040FABC push 0 ; lpNumberOfBytesWritten .data:0040FABE push ebx ; nSize .data:0040FABF lea ecx, [esp+14h+FileName] .data:0040FAC3 push ecx ; lpBuffer .data:0040FAC4 push edi ; lpBaseAddress .data:0040FAC5 push esi ; hProcess .data:0040FAC6 call WriteProcessMemory .data:0040FACC test eax, eax .data:0040FACE jz short loc_40FA5D .data:0040FAD0 mov al, 65h .data:0040FAD2 push offset dword_4261B4 ; lpModuleName .data:0040FAD7 mov dword_4261B4, 'nrek' .data:0040FAE1 mov byte_4261B8, al .data:0040FAE6 mov dword_4261B9, '.23l' .data:0040FAF0 mov dword_4261BD, 'lld' .data:0040FAFA call GetModuleHandleA ; get handle of kernel32.dll .data:0040FB00 push offset dword_4261C4 ; lpProcName .data:0040FB05 push eax ; hModule .data:0040FB06 mov dword_4261C4, 'daoL' .data:0040FB10 mov dword_4261C8, 'rbiL' .data:0040FB1A mov dword_4261CC, 'Wyra' .data:0040FB24 mov byte_4261D0, 0 .data:0040FB2B call GetProcAddress ; get ptr to LoadLibrary .data:0040FB31 mov ecx, eax ; lpStartAddress .data:0040FB33 mov eax, edi .data:0040FB35 mov edx, esi ; hProcess .data:0040FB37 call _CreateRemoteThread ; run LoadLibrary(path to DLL)

The dropper then attempts to inject the dropped DLL into the launched process and run it there. The injection is implemented by callingand passing it as a parameter the address ofAPI in, obtained with, and a path of the dropped DLL.Following the steps above, the dropper starts checking if it is running under a virtual machine. To achieve that, it uses Windows Management Instrumentation (WMI) to query a number of key system parameters via WMI query interface.

SELECT * FROM Win32_Processor WHERE Name LIKE "%QEMU%"



SELECT * FROM Win32_BIOS WHERE Manufacturer LIKE "%QEMU%"



SELECT * FROM Win32_DiskDrive WHERE Model LIKE "%QEMU%"



SELECT * FROM Win32_Processor WHERE Name LIKE "%Bochs%"



SELECT * FROM Win32_DiskDrive WHERE Model LIKE "%Red Hat%"



SELECT * FROM Win32_SCSIController WHERE Manufacturer LIKE "%Xen%"



SELECT * FROM Win32_ComputerSystem WHERE Manufacturer LIKE "%Parallels%"



SELECT * FROM Win32_DiskDrive WHERE Model LIKE "%Virtual HDD%"



SELECT * FROM Win32_DiskDrive WHERE Model LIKE "%VMware%"



SELECT * FROM Win32_ComputerSystem WHERE Manufacturer LIKE "%Microsoft%"



SELECT * FROM Win32_BIOS WHERE Manufacturer LIKE "%innotek%"



SELECT * FROM Win32_DiskDrive WHERE Model LIKE "%VBOX%"



For example, to see if it is running under Qemu emulator, it runs the following WMI queries:Other performed queries are:

Win32_ProcessName



Win32_UserAccountName



Win32_SystemDriverName



Win32_OperatingSystem (SerialNumber, InstallDate)



Apart from the queries above, the dropper also checks the existence of several pre-defined hashes of the user names, system drivers, OS serial numbers and install dates to see if it is running under a known controlled environment or not, by using the WMI objects:If the dropper detects it is running under a sandbox, it quits.

Finally, the dropper extracts a malicious Master Boot Record and Volume Boot Record, and installs them along other components in the system.

In order to extract all the resources from the dropper, the first task is to find out what resource names and types the dropper has. These names can be seen in the memory dump below:

Next, the dropper can be debugged and forcefully directed into the flow where the resource extraction takes place:

Then, the parameters of the function that extracts the resources are patched accordingly:

ECX

After the extraction, thewill point into the extracted data, as shown below in case of the MBR resource:

By following the trick above, all the other resources can now be extracted from the dropper for further analysis:

"BIN"

MBR (440 bytes)

(440 bytes)



VBR (512 bytes)

(512 bytes)

"FILE"



BOOT (1,515 bytes)

(1,515 bytes)



DBG32 (6,656 bytes)

(6,656 bytes)



DBG64 (9,088 bytes)

(9,088 bytes)



DRV32 (37,888 bytes)

(37,888 bytes)



DRV64 (42,496 bytes)

(42,496 bytes)



CMD32 (25,088 bytes)

(25,088 bytes)



CMD64 (43,520 bytes)

(43,520 bytes)



LDR32 (6,144 bytes)

(6,144 bytes)



LDR64 (5,632 bytes)

(5,632 bytes)



MAIN (3,809 bytes)

(3,809 bytes)



AFFID - "540"

-



SUBID - "direc47"

-



TDI32 (12,800 bytes)

(12,800 bytes)



TDI64 (16,384 bytes)

(16,384 bytes)

"PAIR"



NAME - "outlkupd.exe"

-



BUILD (37 bytes)

(37 bytes)

"PROXY32"



APPVERIF.EXE (173,504 bytes)

(173,504 bytes)



VRFCORE.DLL (43,520 bytes)

(43,520 bytes)



STCLIENT.DLL (241,664 bytes)

(241,664 bytes)



SQMAPI.DLL (43,520 bytes)

(43,520 bytes)

"PROXY64"



SQMAPI.DLL (49,664 bytes)



Once all the checks were made, and all the resources were installed, along with the infected MBR and VBR, the dropper reboots the system.

PROXY32

PROXY64

Apart from several malicious components, the dropper contains some legitimate resources as well (theandones). These 'proxy' resources are likely dropped and run in order to trick behavioural analysis systems into believing that the sample in question does not only look nice statically (as explained above), but the files that it drops dynamically are also legitimate, some with the valid digital signatures.

This stealthiness makes the extremely vicious TDL4 also very crafty as it manages to bypass many AV solutions on spot.

MAIN

Theresource of TDL4 is a text configuration file. Among other sections, it contains a list of the command and control (C&C) servers that are used for communications:

[servers_begin]

7qV2SXF7gv9aKUlN8xMNwdd+nRXbjQ==

7qV2SXF7guxdMlZG+wYX39t80gLBzprn9w==

7qV2SXF7gvRLLlBc+QsQyZx53Bs=

[servers_end]

The server names are in base-64 form, but the unpacked strings are encrypted. How to decrypt them? Let's analyse the following resource first.

CMD32

CMD64

MAIN

CMD32

svchost.exe

The 32-bitcomponent, as well as its 64-bit counterpart, is a DLL that is injected the memory of the system process, according to the configuration of TDL4. For example, if theconfiguration file specifies the section below, thencan be found within the system process

[injects_begin]

cmd32|svchost.exe,

[injects_end]

svchost.exe

CMD32

The infected system indeed haswith a memory area whereruns from, along with the mapped configuration file itself.

CMD32

services.exe

svchost.exe

explorer.exe

explorer.exe

WhenDll is run, it checks to make sure it is loaded either intoor. Next, it makes sure thatprocess is also running. Ifis not running, the code falls asleep for 3 minutes, then checks again.

Init()

Uninit()

The Dll then retrieves the image base of its host process and start looking for the APIs calledand. If found, the pointers of these functions are retrieved and remembered.

Init()

Uninit()

MAIN

MAIN

Through the static code analisys, it is assumed that theandfunctions are implemented within one of the missing modules that the DLL can download from the command and control servers. The functions are responsible for extracting configuration file (similar to) from the JPEG images hosted on the blog sites specified in theconfiguration file. The JPEG images contain concealed configuration data by using steganography.

The DLL deletes the registry key:

HKLM\SYSTEM\CurrentControlSet\Services\IpFilterDriver

Next, it deletes a file (presumably a legitimate driver file used by MalwareBytes):

%SYSTEM%\drivers\mbam.sys

XOR

Following that, it applies81 operation to four 256-bit hard-coded seed values. These seeds are then used to initialise four RC4 keys. These keys are then used for encryption/decryption purposes.

MAIN

[servers_begin]

[servers_end]

The code locates thesection mapped in the process memory and extracts the server list enclosed withinandtags. These names are then unpacked from base-64 and decrypted with RC4 algorithm. Key #3 is used to decrypt the server names below:

http://dfsvegasmed.com



http://wahinotisifatu.com



http://owtotmyne.com



193.169.86.56

93.174.88.224

At the time of writing, the first domain does not resolve to an IP, the 2nd one resolves to an IPlocated in Ukraine, the 3rd domain resolves to IPlocated in Netherlands.

CMD32

then requests a new configuration file from the C&C servers above, by constructing a line with several parameters, as shown below:

affid=540&subid=direc47&bbid=1f5af5611542886af50307110b155b02ea41bc35&v=12&fb=1&mode=cfg

affid/subid

mode

Theparameters are used to identify the client of TDL4 network, theparameter clearly specifies that a new configuration is needed.

The parameters above are mixed with the random value parameters in order to avoid cached server responses.

The URL parameters line is encrypted with RC4, by using the key #2, then packed into base-64 format.

[SCRIPT_SIGNATURE_CHECK]

[SCRIPT_SIGNATURE_CHECK_END]

Once the configuration file is returned by the server, it is decrypted with the RC4 key #1, then scanned for the presence of the tagsand, then mapped back into the host process memory.

CMD32/CMD64

The DLL then requests from the servers an updated modulewith the parameter line: (also mixed with the random value parameters:

mode=core&filename=cmd32

The line above is then paranoidly mixed with 5 more random value parameters to avoid server response caching.

COM32/COM64

In order to be able to decrypt configurations from the back-up servers (rogue blog posts), the DLL downloads themodule with the URL parameter:

mode=mod&filename=com32

[modules_begin]

[modules_end]

The same parameter is used to request additional modules specified in the configuration section enclosed with the tagsand

DRV32/DRV64

To request an updatedmodule, the DLL constructs the line:

mode=core&filename=drv32

CMD32

If the host processes is terminated, it is immediately restarted with theand configuration data immediately re-injected in it.

By replicating TDL4 encryptor (and also decryptor as RC4 is a symmetric algorithm), it is possible to build a tool that allows quick reading of its configuration data - mainly, encrypted C&C servers.

Apart from that, in case there are NXDomains (non-registered domains) specified in TDL4 configuration, it is possible to build a sinkhole that will 'talk nerdy' to the connected victims (do you happen to know what 'GeckaSeka' means?). That is, it will understand their language and talk to them in their own protocol.

COM32

Knowing how to encrypt the URL parameters will also allow requesting additional components from C&C (such asmodule, required for decrypting configuration data concealed within the blog posts' JPEG images).

Let's build one.

Our decryptor will decrypt the C&C server name specified in the configuration, then we'll encrypt it back to see if the same original string is produced (results 1-2).

COM32

Next, we'll decrypt the URL parameter found in the TDL4 traffic below, and try encrypting our own URL parameter that requests themodule from C&C (results 3-4).

The decryptor will first 'prepare' the seeds, then make the following calls:

prepare_seed(seed2); // for config data prepare_seed(seed3); // for URL parameter char szResult1[MAX_PATH]; decrypt("7qV2SXF7gv9aKUlN8xMNwdd+nRXbjQ==", szResult1, seed3); char szResult2[MAX_PATH]; encrypt("http://dfsvegasmed.com", szResult2, seed3); char szResult3[MAX_PATH]; decrypt("JsVoFkw7PZy+4vo3+ou9d1kWdiq24NpkflIKQDuOUT9+EkJJ2iGaADle3jviKC4VYu/y6B7FyXXOk2EKT...", szResult3, seed2); char szResult4[MAX_PATH]; encrypt("mode=mod&filename=com32", szResult4, seed2);

prepare_seed()

XOR

wherewillthe seeds with 81:

void prepare_seed(LPBYTE seed) { for (int i = 0; i < 256; i++) { seed[i] ^= (BYTE)i + 81; } }

CMD32

The seeds themselves are hard-coded within thebinary; they can be copy-pasted from it as:

BYTE seed2[256] = { 0x65,0x4F,0xF7,0xEC,0x02,0xE1,0xA5,0x5C,0xF0,0xC0,0x78,0x58,0x12,0x20,0xD8,0x17, 0xA9,0xF5,0x51,0x62,0x98,0xEC,0xD5,0x0C,0xEE,0x4F,0xDC,0x3E,0x87,0xC6,0x77,0xFF, 0x66,0x14,0x0B,0x3A,0x02,0xE4,0x01,0xBD,0xAE,0x6F,0xAD,0x34,0x3A,0x5B,0xD1,0xF4, 0x9D,0xDF,0xEE,0xDE,0xE5,0x3D,0x29,0x32,0x04,0x57,0xDE,0x92,0x3B,0x94,0x53,0x41, 0x25,0xEF,0xCB,0xED,0x1E,0xB9,0xAB,0x3E,0x5B,0x6E,0x07,0xA6,0x1B,0xB6,0xBA,0xF4, 0x5A,0x3B,0xFC,0xDA,0x78,0xD4,0xFC,0x50,0xB3,0x13,0xB0,0xF5,0xD1,0xF6,0xD6,0xA9, 0xCB,0x0A,0x68,0x03,0x70,0xCE,0x6E,0x8B,0x9F,0x62,0x9E,0x69,0x5B,0x68,0x3A,0xF8, 0x45,0xD4,0x85,0xF2,0x21,0x51,0xA0,0xD2,0x9E,0xAC,0xEC,0xA9,0xCE,0xAA,0xDB,0x15, 0x4A,0xEB,0xB1,0x17,0xFF,0xF3,0x2D,0x40,0x18,0x5F,0x31,0x3F,0x4B,0x29,0x4A,0xA4, 0xFC,0xA1,0x16,0xA6,0x38,0x45,0xEF,0x4A,0x26,0xEE,0xD6,0x62,0xD8,0x04,0x67,0x93, 0x76,0x1F,0x1B,0xBE,0x12,0x34,0x58,0xBF,0xE8,0xF3,0xEB,0x5B,0xB8,0x58,0x8F,0xDC, 0x6E,0x05,0xA7,0x02,0xCA,0x55,0xC9,0xF9,0x39,0xAB,0x24,0xBE,0xE2,0x5F,0x80,0x11, 0x9F,0x00,0x5C,0xA4,0xFB,0x76,0x5A,0x44,0x3A,0xB3,0xB6,0xA3,0x12,0xA5,0x37,0x8B, 0x2C,0x3D,0x4D,0x3F,0xDC,0x2D,0x4B,0xA5,0x15,0xF3,0xB1,0xF4,0xD6,0xF9,0xD5,0x09, 0xAB,0x9E,0x68,0x03,0x6F,0xAE,0xCE,0x34,0x83,0xC2,0x82,0xCB,0x23,0x55,0x25,0x8C, 0x6F,0x89,0x3E,0x8E,0x3C,0x6A,0x43,0x63,0x95,0x3D,0x2F,0x04,0x64,0x10,0x88,0x86, }; BYTE seed3[256] = { 0x49,0x8D,0xD1,0x42,0xE9,0x03,0xD5,0x82,0x49,0x42,0xF0,0x8D,0x88,0x74,0xBD,0x6F, 0x78,0x38,0x29,0xD3,0x90,0x47,0xB9,0x51,0xA8,0xD9,0xED,0x49,0x3F,0x93,0x27,0xA1, 0xD0,0xD7,0x85,0x75,0xD2,0x19,0xE0,0x98,0x71,0xBF,0x68,0xD4,0x18,0xA2,0x57,0xDF, 0x44,0xA5,0xBE,0xD7,0xF7,0x60,0xA2,0x0E,0x86,0xCD,0x0E,0xCA,0x09,0x24,0x0C,0x36, 0x4B,0x21,0x73,0x9E,0xC2,0x90,0x4A,0x5A,0xEC,0xF3,0x9F,0x6C,0x4D,0xDA,0xDC,0x68, 0xC2,0xF2,0x62,0x10,0x05,0x15,0x64,0x07,0x68,0xBE,0x88,0x74,0x7E,0x4B,0x7D,0xE6, 0x85,0x52,0xB4,0x7E,0x87,0x03,0xD0,0xF8,0xDF,0x8A,0xE8,0xA9,0x7B,0xDA,0xEE,0x4F, 0x73,0xB6,0xE5,0x07,0x75,0x28,0xD5,0x76,0xD8,0x85,0x76,0x6E,0x91,0xC1,0xBF,0x26, 0xCC,0xDF,0x68,0xBA,0x1A,0xBB,0x46,0xB4,0xC2,0x6C,0x07,0x10,0x50,0x42,0xAD,0xF0, 0x0C,0x78,0x4A,0x1F,0x34,0x89,0xC6,0x11,0x4C,0xB1,0x13,0x22,0x6D,0x55,0x6D,0xDF, 0xA9,0xDC,0x2C,0x8E,0x2B,0x78,0xDB,0x80,0xC6,0x23,0x8E,0x24,0x76,0xC4,0xEC,0x39, 0xD5,0x3A,0xE9,0x9D,0x8C,0x9E,0x18,0x9F,0x17,0x8E,0x9D,0xFB,0x73,0x58,0x49,0xCD, 0x6A,0x1B,0xB5,0xA1,0xB0,0x2B,0xCD,0x24,0x1F,0x0F,0x4B,0x34,0x7B,0xF7,0x7A,0xC8, 0x07,0xA5,0xE6,0x6D,0xE1,0x17,0xA2,0xCE,0x0C,0x82,0xCE,0xBE,0x74,0xD8,0xCC,0xC0, 0x74,0xC3,0x25,0xD5,0x76,0x64,0x93,0x69,0x9A,0x7B,0x3E,0x8D,0xEA,0x4D,0x4E,0x64, 0x06,0x80,0x72,0x2B,0x95,0x8D,0xD6,0xBD,0xD9,0x84,0xBF,0xD3,0xBD,0x61,0xDF,0xF2, };

The RC4 algorithm itself can shamelessly be 'borrowed' from the ZeuS source code:

typedef struct { BYTE state[256]; BYTE x; BYTE y; } RC4KEY; #define swap_byte(a, b) {swapByte = a; a = b; b = swapByte;} void rc4_init(const void *binKey, WORD binKeySize, RC4KEY *key) { register BYTE swapByte; register BYTE index1 = 0, index2 = 0; LPBYTE state = &key->state[0]; register WORD i; key->x = 0; key->y = 0; for (i = 0; i < 256; i++) { state[i] = i; } for (i = 0; i < 256; i++) { index2 = (((LPBYTE)binKey)[index1] + state[i] + index2) & 0xFF; swap_byte(state[i], state[index2]); if (++index1 == binKeySize) { index1 = 0; } } } void rc4_crypt(void *buffer, DWORD size, RC4KEY *key) { register BYTE swapByte; register BYTE x = key->x; register BYTE y = key->y; LPBYTE state = &key->state[0]; for (register DWORD i = 0; i < size; i++) { x = (x + 1) & 0xFF; y = (state[x] + y) & 0xFF; swap_byte(state[x], state[y]); ((LPBYTE)buffer)[i] ^= state[(state[x] + state[y]) & 0xFF]; } key->x = x; key->y = y; }

The base-64 packer/unpacker along with the decrypt/encrypt functions can then be declared as:

#pragma comment (lib, "Crypt32.lib") int ToBase64Crypto(const BYTE* pSrc, int nLenSrc, char* pDst, int nLenDst) { DWORD nLenOut= nLenDst; BOOL fRet= CryptBinaryToString((const BYTE*)pSrc, nLenSrc, 0x40000001, pDst, &nLenOut); if (!fRet) { nLenOut=0; } return nLenOut; } int FromBase64Crypto(const BYTE* pSrc, int nLenSrc, char* pDst, int nLenDst) { DWORD nLenOut= nLenDst; BOOL fRet= CryptStringToBinary((LPCSTR)pSrc, nLenSrc, 0x00000001, (BYTE*)pDst, &nLenOut, NULL, NULL); if (!fRet) { nLenOut=0; } return nLenOut; } void decrypt(char *szBase64, char *szResult, LPBYTE seed) { memset(szResult, 0, MAX_PATH); int iResultLength = FromBase64Crypto((LPBYTE)szBase64, (int)strlen(szBase64), szResult, MAX_PATH); RC4KEY rc4_key; rc4_init(seed, 256, &rc4_key); rc4_crypt((LPBYTE)szResult, iResultLength, &rc4_key); } void encrypt(char *szStringToEncrypt, char *szResult, LPBYTE seed) { char szTemp[MAX_PATH]; strcpy_s(szTemp, MAX_PATH, szStringToEncrypt); RC4KEY rc4_key; rc4_init(seed, 256, &rc4_key); rc4_crypt((LPBYTE)szTemp, strlen(szTemp), &rc4_key); memset(szResult, 0, MAX_PATH); int iResultLength = ToBase64Crypto((LPBYTE)szTemp, (int)strlen(szTemp), szResult, MAX_PATH); }

Running the tool produces the expected results:

ba1039e8cdae53e44ac3e6185b0871f3d031a476

0x16/7ton

: the stringis not hard-coded, it's a SHA-1 hash derived from the system footprint (Windows OS, product ID); thanks to the userfor correction!