• Fuentes

 #485980  por Blau
 03 May 2016, 23:40
Hola gente,
el otro día estuve buscando información sobre el PEB y dí con la [ Debe registrarse para ver este enlace ] donde proporcionaban el código necesario para poder obtener el base addres del kernel32, por lo cual, se puede usar LoadLibrary para cargar más módulos. También obtiene la dirección de las APIs de los módulos. Como lo encontré muy útil hice una clase para facilitar el uso. Con esta clase se puede hacer cualquier ejecutable sin usar APIs directamente así que resultaría en un ejecutable sin IAT. Veréis que es fácil añadir más APIs; he añadido algunas de ejemplo (si os fijais qué APIs son os podéis hacer una idea para qué quería algo así ).

DynamicLoad.cpp
#include "DynamicLoad.hpp"

/**
    DynamicLoad class by Blau (2016)
    Credits to: Topher Timzen (https://www.tophertimzen.com/blog/shellcodeTechniquesCPP/)
**/

unsigned int kernel32BaseAddr = 0;
unsigned int ntdllBaseAddr = 0;
unsigned int msvcrtBaseAddr = 0;
unsigned int psapiBaseAddr = 0;
unsigned int user32BaseAddr = 0;

void DynamicLoad::LoadLibraries() {
    //kernel32.dll
    kernel32BaseAddr = DynamicLoad::FindKernel32();

    //ntdll.dll
    char szNtdllDll[] = {0x6E, 0x74, 0x64, 0x6C, 0x6C, 0x2E, 0x64, 0x6C, 0x6C, 0x00};
    ntdllBaseAddr = getLibrary(szNtdllDll);

    //msvcrt.dll
    char szMsvcrt[] = {0x6D, 0x73, 0x76, 0x63, 0x72, 0x74, 0x2E, 0x64, 0x6C, 0x6C, 0x00};
    msvcrtBaseAddr = getLibrary(szMsvcrt);

    //Psapi.dll
    char szPsapi[] = {0x50, 0x73, 0x61, 0x70, 0x69, 0x2E, 0x64, 0x6C, 0x6C, 0x00};
    psapiBaseAddr = getLibrary(szPsapi);

    //user32.dll
    char szUser32Dll[] = {'u', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', 0};
    user32BaseAddr = getLibrary(szUser32Dll);
}

__declspec(naked)unsigned int DynamicLoad::FindKernel32() {
    __asm {
        mov eax, fs:[0x30];    // get a pointer to the PEB
        mov eax, [eax + 0x0C];  // get PEB->Ldr
        mov eax, [eax + 0x14];  // get PEB->Ldr.InMemoryOrderModuleList.Flink
        mov eax, [eax];         // get the next entry (2nd entry)
        mov eax, [eax];         // get the next entry (3rd entry)
        mov eax, [eax + 0x10];  // get the 3rd entries base address (kernel32.dll)
        ret;
    };
}

unsigned int __stdcall DynamicLoad::hashString(char* symbol) {
    __asm {
        mov esi, symbol;
        xor edi, edi;
        xor eax, eax;
        cld;
        continueHashing:
        lodsb;
        test al, al
        jz hash_done;
        ror edi, 0xd; //0xd = 13
        add edi, eax;
        jmp  continueHashing;
        hash_done:
        mov eax, edi;
    };
}

unsigned int __stdcall DynamicLoad::findSymbolByHash(unsigned int dllBase, unsigned int symHash) {
    __asm {
        pushad;
        mov edi, symHash;
        mov ebp, dllBase;
        mov eax, [ebp + 0x3c];        //PEheader
        mov edx, [ebp + eax + 0x78];  //export table
        add edx, ebp;
        mov ecx, [edx + 0x18];        //numberOfNames
        mov ebx, [edx + 0x20];        //numberOfExports
        add ebx, ebp;
        search_loop:
        jecxz noHash;
        dec ecx;                      //decrement numberOfNames
        mov esi, [ebx + ecx * 4];     //get an export name
        add esi, ebp;
        push ecx;
        push ebx;
        push edi;
        push esi;                     //setup stack frame and save clobber registers
        call hashString;
        pop edi;
        pop ebx;
        pop ecx;                      //restore clobber registers
        cmp eax, edi;                 //check if hash matched
        jnz search_loop;
        mov ebx, [edx + 0x24];        //get address of the ordinals
        add ebx, ebp;
        mov cx, [ebx + 2 * ecx];      //current ordinal number
        mov ebx, [edx + 0x1c];       //extract the address table offset
        add ebx, ebp;
        mov eax, [ebx + 4 * ecx];    //address of function
        add eax, ebp;
        jmp done;
        noHash:
        mov eax, 1;
        done:
        mov[esp + 0x1c], eax;
        popad;
    };
}

unsigned int DynamicLoad::getLibrary(char *libraryName) {
    FunPtr_LoadLibrary MyLoadLibraryA;
    MyLoadLibraryA = (FunPtr_LoadLibrary)(findSymbolByHash(kernel32BaseAddr, 0xEC0E4E8E));
    unsigned int baseAddr = MyLoadLibraryA(libraryName);
    return baseAddr;
}

LONG DynamicLoad::fNtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress) {
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef LONG ( __stdcall *NTUNMAPVIEWOFSECTION)(HANDLE ProcessHandle, PVOID BaseAddress);
    NTUNMAPVIEWOFSECTION bNtUnmapViewOfSection = (NTUNMAPVIEWOFSECTION)findSymbolByHash(ntdllBaseAddr, 0xF21037D0);

    return bNtUnmapViewOfSection(ProcessHandle, BaseAddress);
}

BOOL DynamicLoad::fCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef BOOL ( __stdcall * CREATEPROCESSA)(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);
    CREATEPROCESSA bCreateProcessA = (CREATEPROCESSA)(findSymbolByHash(kernel32BaseAddr, 0x16B3FE72));

    return bCreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
}

BOOL DynamicLoad::fCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef BOOL ( __stdcall * CREATEPROCESSW)(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);
    CREATEPROCESSW bCreateProcessW = (CREATEPROCESSW)(findSymbolByHash(kernel32BaseAddr, 0x16B3FE88));

    return bCreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
}


LPVOID DynamicLoad::fVirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef LPVOID ( __stdcall * VIRTUALALLOCEX)(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
    VIRTUALALLOCEX bVirtualAllocEx = (VIRTUALALLOCEX)(findSymbolByHash(kernel32BaseAddr, 0x6E1A959C));

    return bVirtualAllocEx(hProcess, lpAddress, dwSize, flAllocationType, flProtect);
}

LPVOID DynamicLoad::fVirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef LPVOID ( __stdcall * VIRTUALALLOC)( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
    VIRTUALALLOC bVirtualAlloc = (VIRTUALALLOC)(findSymbolByHash(kernel32BaseAddr, 0x91AFCA54));

    return bVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
}

BOOL DynamicLoad::fGetThreadContext(HANDLE hThread, LPCONTEXT lpContext){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef BOOL ( __stdcall * GETTHREADCONTEXT)(HANDLE hThread, LPCONTEXT lpContext);
    GETTHREADCONTEXT bGetThreadContext = (GETTHREADCONTEXT)(findSymbolByHash(kernel32BaseAddr, 0x68A7C7D2));

    return bGetThreadContext(hThread, lpContext);
}

BOOL DynamicLoad::fReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef BOOL ( __stdcall * READPROCESSMEMORY)(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead);
    READPROCESSMEMORY bReadProcessMemory = (READPROCESSMEMORY)(findSymbolByHash(kernel32BaseAddr, 0x579D1BE9));

    return bReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead);
}

BOOL DynamicLoad::fWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef BOOL ( __stdcall * WRITEPROCESSMEMORY)(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten);
    WRITEPROCESSMEMORY bWriteProcessMemory = (WRITEPROCESSMEMORY)(findSymbolByHash(kernel32BaseAddr, 0xD83D6AA1));

    return bWriteProcessMemory(hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten);
}

BOOL DynamicLoad::fSetThreadContext(HANDLE hThread, CONTEXT *lpContext){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef BOOL ( __stdcall * SETTHREADCONTEXT)(HANDLE hThread, CONTEXT *lpContext);
    SETTHREADCONTEXT bSetThreadContext = (SETTHREADCONTEXT)(findSymbolByHash(kernel32BaseAddr, 0xE8A7C7D3));

    return bSetThreadContext(hThread, lpContext);
}

DWORD DynamicLoad::fResumeThread(HANDLE hThread){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef DWORD ( __stdcall * RESUMETHREAD)(HANDLE hThread);
    RESUMETHREAD bResumeThread = (RESUMETHREAD)(findSymbolByHash(kernel32BaseAddr, 0x9E4A3F88));

    return bResumeThread(hThread);
}

BOOL DynamicLoad::fVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef BOOL ( __stdcall * VIRTUALFREE)(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
    VIRTUALFREE bVirtualFree = (VIRTUALFREE)(findSymbolByHash(kernel32BaseAddr, 0x30633AC));

    return bVirtualFree(lpAddress, dwSize, dwFreeType);
}

DWORD DynamicLoad::fGetModuleFileNameA(HMODULE hModule, LPTSTR lpFilename, DWORD nSize){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef DWORD (__stdcall *GETMODULEFILENAMEA)(HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
    GETMODULEFILENAMEA bGetModuleFileNameA = (GETMODULEFILENAMEA)(findSymbolByHash(kernel32BaseAddr, 0x45B06D76));

    return bGetModuleFileNameA(hModule, lpFilename, nSize);
}

DWORD DynamicLoad::fRtlZeroMemory(VOID* Dst, SIZE_T nSize){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef DWORD ( __stdcall * RTLZEROMEMORY)(VOID* Dst, int Value, SIZE_T nSize);
    RTLZEROMEMORY bRtlZeroMemory = (RTLZEROMEMORY)(findSymbolByHash(msvcrtBaseAddr, 0x5D2E6D6B));

    return bRtlZeroMemory(Dst, 0, nSize);
}

VOID DynamicLoad::fExitProcess(UINT uExitCode){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef VOID ( __stdcall * EXITPROCESS)(UINT uExitCode);
    EXITPROCESS bExitProcess = (EXITPROCESS)(findSymbolByHash(kernel32BaseAddr, 0x73E2D87E));

    return bExitProcess(uExitCode);
}

BOOL DynamicLoad::fIsDebuggerPresent(VOID){
    if(kernel32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef BOOL ( __stdcall * ISDEBUGGERPRESENT)(VOID);
    ISDEBUGGERPRESENT bIsDebuggerPresent = (ISDEBUGGERPRESENT)(findSymbolByHash(kernel32BaseAddr, 0xA36DC676));

    return bIsDebuggerPresent();
}

PVOID DynamicLoad::fMalloc(SIZE_T nSize) {
    if(msvcrtBaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef PVOID  ( __stdcall * MALLOC)(SIZE_T nSize);
    MALLOC bMalloc = (MALLOC)(findSymbolByHash(msvcrtBaseAddr, 0x5B7E2B9A));

    return bMalloc(nSize);
}

void DynamicLoad::fFree(void* MemBlock){
    if(msvcrtBaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef void ( __stdcall * FREE)(void* MemBlock);
    FREE bFree = (FREE)(findSymbolByHash(msvcrtBaseAddr, 0xCF281CE5));

    return bFree(MemBlock);
}

int DynamicLoad::fMessageBoxA(HWND h1, LPCSTR lp1, LPCSTR lp2, UINT u1) {
    if(user32BaseAddr == 0) DynamicLoad::LoadLibraries();
    typedef int(__stdcall *MESSAGEBOXA)(HWND, LPCSTR, LPCSTR, UINT);
    MESSAGEBOXA bMessageBoxA = (MESSAGEBOXA)(findSymbolByHash(user32BaseAddr, 0xBC4DA2A8));

    return bMessageBoxA(h1, lp1, lp2, u1);
}
DynamicLoad.hpp
#ifndef __DYANMIC_LOAD_H__
#define __DYANMIC_LOAD_H__

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

typedef unsigned int(__stdcall *FunPtr_LoadLibrary)(LPCSTR);
class DynamicLoad {
private:
    static void LoadLibraries();
    static unsigned int FindKernel32();
    static unsigned int __stdcall hashString(char* symbol);
    static unsigned int __stdcall findSymbolByHash(unsigned int dllBase, unsigned int symHash);
    static unsigned int getLibrary(char *libraryName);
public:
    static LONG fNtUnmapViewOfSection(HANDLE, PVOID);
    static BOOL fCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);
    static BOOL fCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation);
    static LPVOID fVirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
    static LPVOID fVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
    static BOOL fGetThreadContext(HANDLE hThread, LPCONTEXT lpContext);
    static BOOL fReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead);
    static BOOL fWriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten);
    static BOOL fSetThreadContext(HANDLE hThread, CONTEXT *lpContext);
    static DWORD fResumeThread(HANDLE hThread);
    static BOOL fVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
    static DWORD fGetModuleFileNameA(HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
    static DWORD fRtlZeroMemory(VOID* Dst, SIZE_T nSize);
    static VOID fExitProcess(UINT uExitCode);
    static BOOL fIsDebuggerPresent(VOID);
    static PVOID  fMalloc(SIZE_T nSize);
    static void fFree(void* MemBlock);
    static int DynamicLoad::fMessageBoxA(HWND h1, LPCSTR lp1, LPCSTR lp2, UINT u1);
};
#endif // __DYANMIC_LOAD_H__
Ejemplo de uso:
#include "DynamicLoad.hpp"

int main()
{
    DynamicLoad::fMessageBoxA(0, "Message", "Title", 0);
    return 0;
}

He subido la clase a Github por si añado más APIs o mejoro el código (se podría mejorar bastante...).
[ Debe registrarse para ver este enlace ]
 #486001  por crack81
 05 May 2016, 06:24
Super linda haber si hago la implementacion en delphi o lazarus y hago mis pruebas
Saludos..
 #486014  por Blau
 06 May 2016, 00:41
crack81 escribió:Super linda haber si hago la implementacion en delphi o lazarus y hago mis pruebas
Saludos..
La próxima mejora que haré será pasar todo el ASM a C (menos un par de líneas) para que se pueda portar mejor a otros lenguajes.
 #486019  por crack81
 06 May 2016, 04:19
Hola @Blue bueno lenguajes como delphi o lazarus al igual C++ tienen soporte total para ASM asi que no hay problema he hecho algunas pruebas y muy va bien, pero para motivos educativos si seria mas adecuado trabajar en su mayoria con C++ ya que no todos trabajan con ASM ha por ultimo estas usando el compilador de visual studio? ya que ese ensamblador nunca lo he visto en gcc ni en mingw ya que por defecto en estos dos viene el ASM de at&t por defecto y no el de intel.


Saludos...
 #486020  por Blau
 06 May 2016, 05:08
crack81 escribió:Hola @Blue bueno lenguajes como delphi o lazarus al igual C++ tienen soporte total para ASM asi que no hay problema he hecho algunas pruebas y muy va bien, pero para motivos educativos si seria mas adecuado trabajar en su mayoria con C++ ya que no todos trabajan con ASM ha por ultimo estas usando el compilador de visual studio? ya que ese ensamblador nunca lo he visto en gcc ni en mingw ya que por defecto en estos dos viene el ASM de at&t por defecto y no el de intel.


Saludos...
Yo tampoco trabajo con ASM, el código lo copié del blog que enlacé. Como IDE uso Code::Blocks pero de compilador uso el Visual Studio 2005/2008, que haciendo comparativas es el que mejor me va en relación dependencias y tamaño.