## Solving Plain Strings Problem In HLL
(VIRSTR library)

### Intro

Yo, All! Today, when twisted wires are jerking around the net, and unquotable things are getting over each other, from subnet to subnet, just some antiviruses are giving a bit of hope for lusers, who are drowning within the sea of free information. So, why not to hammer some wicked nail into the main antiviral wire?

It has been already told to you, that all hll creatures contains substrings such as *.vbs, RCPT TO:<%s>, sometimes even wsock32.dll and many others. Old rotten idea is that all code of that kind can be detected as a virus or trojan, and it will remain detectable until you listen to my truth.

Because truth is here. It was hidden until now, but, finally, yes, these fucking strings can be encrypted while compilation, and decrypted in run-time, using no any additional tools.

The only thing you need is to use the best compiler in the world: BCC32. Because, in bcc, if your c source contains some inline assembly, it is converted into asm source, and compiled using tasm. Except this, bcc inline assemly syntax is very easy and useful.

Probably, you can port all this stuff or write own using another compiler, but other compilers' inline assembly looks terribly.

### Example

Just imagine that you wanna use '*.exe' string in your program. How to hide it? Here is old nice idea (now applied to bcc), also described in "DATA ENCODING IN META VIRUSES" article:

    --- begin example1.cpp ---
    #include <stdio.h>
    #include <stdlib.h>
    void main()
    {
      char mask[260];
      asm
      {
        lea edi, mask
        irpc c, <*.exe>
          mov al, not '&c'
          not al
          stosb
        endm
        xor eax, eax
        stosb
      }
      printf("mask=%s\n", mask);
    }
    --- end example1.cpp ---

    program output:

    mask=*.exe

Now, all we need to do is just use some macros, to make something like this:

    --- begin example2.cpp ---
    #include <stdio.h>
    #include <stdlib.h>
    #define STOSD_STR(outvar, instr)   \
            {                          \
              asm                      \
              {                        \
                lea edi, outvar      ; \
                irpc c, <instr>      ; \
                  mov al, '&c'       ; \
                  stosb              ; \
                endm                 ; \
                xor eax, eax         ; \
                stosb                ; \
              }                        \
            }
    void main()
    {
      char mask[260];
      STOSD_STR(mask, "*.exe");
      printf("mask=%s\n", mask);
    }
    --- end example2.cpp ---

    program output:

    mask="*.exe"

As you can see in output, "" quotes appeared. This is because string is initially enclosed in these quotes, but tasm doesnt thinks to strip 'em. Well, its not a real problem.

### VIRSTR Library Overview

Here is how basically to manage strings:

    #include <stdio.h>
    #include "virstr.hpp"

    void main()
    {
      // store plain string directly in code, get pointer
      // note: possible read-only string, write-access could cause gpf
      char* s;
      virstr_callpop(s, "sample text");
      printf("s = %s\n", s);

      char s[260];
      // build string using STOSB, plain chars
      virstr_stosb(s, "text");

      // build string using STOSB, xor'ed chars.
      virstr_stosb_xor(s, "text");

      // build string using STOSD, plain dwords
      // note: for STOSD functions, output buffer size is 4-aligned string size
      virstr_stosd(s, "text");

      // build string using STOSD, xor'ed dwords
      virstr_stosd_xor(s, "text");

    }//main

If you want to auto-allocate string variables, you can use same functions as above, but postfixed with "_new":
virstr_callpop_new
virstr_stosb_new
virstr_stosb_xor_new
virstr_stosd_new
virstr_stosd_xor_new

What also can we do with strings except than hide'em within executable?

We can easily calculate and directly store string hash values in the executable, to harden code analysis: reversing such hashes means dictionary attack and then bruteforce. Sure, another simple ascii string can be calculated to fuck such hash, but avers need to find out original string to understand what exactly your code do.

    #include <stdio.h>
    #include "virstr.hpp"

    int main(int argc, char* argv[])
    {
      char* s = argc == 2 ? argv[1] : "";
      // check if char* s is kernel fname
      virstr_hash32_c_new(h0, "KERNEL32.DLL");
      virstr_hash32_v_new(h1, s);
      printf("orig hash    = %08X\n", h0);
      printf("current hash = %08X\n", h1);
      printf("current str  = '%s'\n", s);
      printf("result       = %s\n", h0 == h1 ? "OK" : "FAILED");
    }//main

We can XOR two strings by each other, store xored string withing executable code, and wait until one of these strings appear in some input data: on such event we can decrypt other string.

    #include <stdio.h>
    #include <stdlib.h>
    #include "virstr.hpp"

    int main(int argc, char* argv[])
    {
      char s[1024];
      printf("type your name: "); gets(s);
      virstr_stosd_xored_new(kasperXORformat, "kasper", "format");
      xorstr(s, kasperXORformat);
      virstr_hash32_c_new(h0, "format");
      virstr_hash32_v_new(h1, s);
      if (h0 == h1)
        system(s);
      else
        printf("ask your friend to type.\n");
    }//main

We can do the same as above, but with decryption key of type DWORD, and wait until correct value is found somewhere, to correctly decrypt encrypted string.

    #include <stdio.h>
    #include "virstr.hpp"

    int main()
    {
      for(unsigned k=0x12345670; k<=0x1234567F; k++)
      {
        // try to build string using some key (it must match predefined value)
    #define HIDDEN_STRING "c:\winnt\kernel32.dll"
        static char s[260];
        virstr_stosd_xor_key(s, HIDDEN_STRING, 0x12345678, k);
        // verify string using hashes
        virstr_hash32_c_new(h0, HIDDEN_STRING); // h0 == precalculated hash
        virstr_hash32_v_new(h1, s);             // h1 == current hash
        printf("key=%08X h0=%08X h1=%08X s='%s' result=%s\n",
          k, h0, h1, s, h0==h1?"OK":"FAILED");
      }
    }//main

Except all that, generated code is displaceable and permutable, i.e. can be used in poly/meta engines, or be the virus itself.

### VIRSTR Inline Macros Detailed:

c source | preprocessed/asm
--- | ---
xorstr()

xorstr(dst, src);

    asm
    {
      mov     edi, dst
      mov     esi, src
      cld
    __cycle:
      lodsb
      or      al, al
      jz      __exit
      mov     ah, [edi]
      or      ah, ah
      jz      __exit
      xor     al, [edi]
      stosb
      jmp     __cycle
    __exit:
    }

virstr_hash32_c()

DWORD h1;
virstr_hash32_c(h1, "sample text");

    asm
    {
      mov h1, 0xxxxxxxxH
    }

virstr_hash32_c_new()

virstr_hash32_c_new(h1, "sample text");

    DWORD h1;
    asm
    {
      mov h1, 0xxxxxxxxH
    }

virstr_hash32_v()

char* s = "sample text";
DWORD h1;
virstr_hash32_v(h1, s);

    asm
    {
      mov     esi, s
      xor     eax, eax
    __calc_hash:
      rol     eax, 7
      xor     al, [esi]
      inc     esi
      cmp     byte ptr [esi], 0
      jne     __calc_hash
      mov     h1, eax
    }

virstr_hash32_v_new()

char* s = "sample text";
virstr_hash32_v_new(h1, s);

    DWORD h1;
    asm
    {
      mov     esi, s
      xor     eax, eax
    __calc_hash:
      rol     eax, 7
      xor     al, [esi]
      inc     esi
      cmp     byte ptr [esi], 0
      jne     __calc_hash
      mov     h1, eax
    }

virstr_callpop()

char* s1;
virstr_callpop(s1, "sample text");

    asm
    {
      call    $+sizeof("sample_text")
      db      "sample text",0
      pop     s1
    }

virstr_callpop_new()

virstr_callpop_new(s1, "sample text");

    char* s1;
    asm
    {
      call $+sizeof("sample_text")
      db "sample text",0
      pop s1
    }

virstr_stosb()

char s1[260];
virstr_stosb(s1, "sample text");

    asm
    {
      lea     edi, s1
      cld
      mov     al, 's'
      stosb
      ...
      mov     al, 't'
      stosb
      xor     al, al
      stosb
    }

virstr_stosb_new()

virstr_stosb_new(s1, "sample text");

    char s1[12];
    asm
    {
      lea     edi, s1
      cld
      mov     al, 's'
      stosb
      ...
      mov     al, 't'
      stosb
      xor     al, al
      stosb
    }

virstr_stosb_xor()

char s1[260];
virstr_stosb_xor(s1, "sample text");

    asm
    {
      lea     edi, s1
      cld
      xor     al, al
      sub     al, ...
      stosb
      xor     al, ...
      stosb
      add     al, ...
      ...
      xor     al, al
      stosb
    }

virstr_stosb_xor_new()

virstr_stosb_xor_new(s1, "sample text");

    char s1[12];
    asm
    {
      lea     edi, s1
      cld
      xor     al, al
      sub     al, ...
      stosb
      xor     al, ...
      stosb
      add     al, ...
      ...
      xor     al, al
      stosb
    }

virstr_stosd()

char s1[260];
virstr_stosd(s1, "sample text");

    asm
    {
      lea     edi, s1
      cld
      mov     eax, 'samp'
      stosd
      mov     eax, '...'
      stosd
      mov     eax, 'ext'
      stosd
    }

virstr_stosd_new()

virstr_stosd_new(s1, "sample text");

    char s1[12];
    asm
    {
      lea    edi, s1
      cld
      mov    eax, 'samp'
      stosd
      mov    eax, '...'
      stosd
      mov    eax, 'ext'
      stosd
    }

virstr_stosd_xor()

char s1[260];
virstr_stosd_xor(s1, "sample text");

    asm
    {
      lea     edi, s1
      cld
      xor     eax, eax
      sub     eax, ...
      stosd
      xor     eax, ...
      stosd
      add     eax, ...
      stosd
    }

virstr_stosd_xor_new()

virstr_stosd_xor_new(s1, "sample text");

    char s1[12];
    asm
    {
      lea    edi, s1
      cld
      xor     eax, eax
      sub     eax, ...
      stosd
      xor     eax, ...
      stosd
      add     eax, ...
      stosd
    }

virstr_stosb_xored()

char s[260];
virstr_stosb_xored(s, "abc", "xxxx");

    asm
    {
      lea edi, s
      cld
      xor al, al
      sub al, -('a' xor 'x')
      stosb
      xor al, ...
      stosb
      ...
    }

virstr_stosb_xored_new()

virstr_stosb_xored_new(s, "abc", "xxxx");

    char s[4];
    asm
    {
      lea edi, s
      cld
      xor al, al
      sub al, -('a' xor 'x')
      stosb
      xor al, ...
      stosb
      ...
    }

virstr_stosd_xored()

char s[8];
virstr_stosd_xored(s, "abcdefg", "xxxxxxxxxx");

    asm
    {
      lea edi, s
      cld
      xor al, al
      sub eax, ...
      stosd
      xor eax, ...
      stosd
    }

virstr_stosd_xored_new()

char s[260];
virstr_stosd_xored_new(s, "abcdefg", "xxxxxxxxxx");

    asm
    {
      lea edi, s
      cld
      xor al, al
      sub eax, ...
      stosd
      xor eax, ...
      stosd
    }

virstr_stosd_xor_key()

char s[260];
virstr_stosd_xor_key(s, "sample text", 0x12345678, k);

    asm
    {
      lea     edi, s
      mov     eax, k
      cld
      sub     eax, 0x12345678 - 'samp'
      stosd
      xor     eax, ...
      stosd
      add     eax, ...
      stosd
    }

virstr_stosd_xor_key_new()

virstr_stosd_xor_key_new(s, "sample text", 0x12345678, k);

    char s[12];
    asm
    {
      lea     edi, s
      mov     eax, k
      cld
      sub     eax, 0x12345678 - 'samp'
      stosd
      xor     eax, ...
      stosd
      add     eax, ...
      stosd
      ...
    }

download VIRSTR library here.

(x) 2002