Updated VAC3 Modules

Posted on Aug 21, 2016

As mentioned in the previous post Valve has changed the way they do import hiding. Previously there would be a bunch of string objects usually for each module that is being imported so “kernel32.dll” -> “GetProcAddress”,”ReadProcessMemory”, “OutputDebugStringA” etc and these would all be passed through a function which has an initial xor key of 0x55.

        public unsafe string DecryptString(byte[] strData)
            byte[] out_str = new byte[strData.Length];
            byte key = 0x55;

            byte* v3; // edx@1
            byte v4; // bl@1
            byte result; // al@1
            int v6; // edi@1
            int v7; // esi@2

            fixed (byte* str = strData)
                fixed (byte* str_out = out_str)
                    v3 = str_out;
                    v4 = key;
                    result = key;
                    v6 = (char)key ^ *(byte*)str;
                    if ((char)key != *(byte*)str)
                        v7 = (int)(str + 1 - (byte*)str_out);
                            result = (byte)(v4 ^ v3[v7]);
                            v4 = v3[v7];
                            *v3++ = result;
                        while (v6 != 0);

                    *v3 = 0;

            return Encoding.ASCII.GetString(out_str).TrimEnd('\0');

Now however they changed the operation and they are using IceKey encryption to decode the strings which get decoded in one big block.

Runfunc is what is called to run a vac module for a specific scan.

signed int __stdcall runfunc(int func_to_scan, void *inputPacket, int inputPacketSize, void *outputPacket, int outputPacketSize)

The inputPacket now contains a key they use to decode the strings. The decryption routine now looks like this:

Once the input packet is decrypted a 4byte key is then used to decrypt the string block with size of 0xA80.

if ( dword_115E944C )
    decryptImportStrings((int)&unk_115E9440, (int)&unk_115E9440, 0xA80, (int)v1);
  v2 = GetModuleHandleA(ModuleName);
  dword_119EA4D4 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD))GetProcAddress(v2, ProcName);
  dword_119EA4DC = (int (__stdcall *)(_DWORD, _DWORD))GetProcAddress(v2, aP);

There you have it nothing so difficult but I guess they don’t want people who have no idea what they are doing to be able to analyze the modules effectively. That being said though you can just hook GetProcAddress and everything is revealed anyway 😛