суббота, 21 сентября 2013 г.

Загрузка библиотеки средствами ntdll.LdrLoadDll

Собственно маленький пример загрузки dll через недокументированную LdrLoadDll из Ntdll.dll. Код полностью независим от Kernel32.dll, что даёт возможность использования его в shellcode. Для получения адреса ntdll.dll используется трюк с PEB, а для поиска адреса LdrLoadDll используется самописанный парсер заголовка PE, аналог GetProcAddress. Всё предельно просто, но мало ли кому пригодится.

* код работает только под x86, чуть позже добавлю и для x64

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// --------------------------------------------------------------
// This is example, how to load libraries using Ntdll.LdrLoadDll, 
// without Kernel32.dll
// by JKornev <c> http://k0rnev.blogspot.com
// --------------------------------------------------------------
#include <Windows.h>
#include <stdio.h>

typedef struct _LSA_UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _PEB_LDR_DATA {
    ULONG Length;
    BOOLEAN Initialized;
    PVOID SsHandle;
    LIST_ENTRY InLoadOrderModuleList;
    LIST_ENTRY InMemoryOrderModuleList;
    LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _LDR_DATA_TABLE_ENTRY {
    LIST_ENTRY InLoadOrderLinks;
    LIST_ENTRY InMemoryOrderLinks;
    LIST_ENTRY InInitializationOrderLinks;
    PVOID DllBase;
    PVOID EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT TlsIndex;
    union {
        LIST_ENTRY HashLinks;
        struct {
            PVOID SectionPointer;
            ULONG CheckSum;
        };
    };
    ULONG   TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

typedef NTSTATUS (NTAPI *LdrLoadDllProc)(PWCHAR PathToFile, ULONG Flags, PUNICODE_STRING ModuleFileName, HMODULE *ModuleHandle);

// Unicode string compare
BOOL StrCmpW(LPWSTR str1, LPWSTR str2)
{
    int i = 0;
    for (i = 0; ; i++) {
        if (str1[i] != str2[i]) {
            break;
        }
        if (!str1[i]) {
            return TRUE;
        }
    }
    return FALSE;
}

// String compare
BOOL StrCmp(LPSTR str1, LPSTR str2)
{
    int i = 0;
    for (i = 0; ; i++) {
        if (str1[i] != str2[i]) {
            break;
        }
        if (!str1[i]) {
            return TRUE;
        }
    }
    return FALSE;
}

// Searching module base address from LDR_MODULE list
LPVOID GetModuleBaseAddr(LPWSTR mod_name)
{
    DWORD peb = __readfsdword(0x30);
    LPVOID baseaddr = NULL;
    PPEB_LDR_DATA pldr_data = *(PPEB_LDR_DATA *)(peb + 0x0C);
    PLDR_DATA_TABLE_ENTRY pldr_mod = (PLDR_DATA_TABLE_ENTRY)((UINT)pldr_data->InMemoryOrderModuleList.Blink - 8), pldr_first;
    
    pldr_first = pldr_mod;
    do {
        if (pldr_mod->DllBase && StrCmpW(pldr_mod->BaseDllName.Buffer, mod_name)) {
            return pldr_mod->DllBase;
        }
        pldr_mod = (PLDR_DATA_TABLE_ENTRY)((UINT)pldr_mod->InMemoryOrderLinks.Blink - 8);
    } while (pldr_first != pldr_mod);

    return NULL;
}

// Searching export procedure address from PE module(dll)
FARPROC GetExportProcAddr(LPVOID mod_base, LPSTR proc_name)
{
    PIMAGE_DOS_HEADER pdos;
    PIMAGE_OPTIONAL_HEADER32 popt32;
    PIMAGE_EXPORT_DIRECTORY pexp;
    PDWORD pnames, pfuncs;
    PWORD pords;
    int i;
    LPSTR proc;

    //getting export directory
    pdos = (PIMAGE_DOS_HEADER)mod_base;
    if (pdos->e_magic != IMAGE_DOS_SIGNATURE) {
        return NULL;
    }
    popt32 = (PIMAGE_OPTIONAL_HEADER32)(pdos->e_lfanew + (UINT)mod_base + 4 + sizeof(IMAGE_FILE_HEADER));
    pexp = (PIMAGE_EXPORT_DIRECTORY)(popt32->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (UINT)mod_base);
    if (!pexp) {//export not found
        return NULL;
    }

    //searching function name
    pnames = (PDWORD)(pexp->AddressOfNames + (UINT)mod_base);
    pords = (PWORD)(pexp->AddressOfNameOrdinals + (UINT)mod_base);
    pfuncs = (PDWORD)(pexp->AddressOfFunctions + (UINT)mod_base);

    for (i = 0; i < pexp->NumberOfNames; i++) {
        proc = (LPSTR)(pnames[i] + (UINT)mod_base);
        if (StrCmp(proc, proc_name)) {
            break;
        }
    }
    if (i == pexp->NumberOfNames) {//not found
        return NULL;
    }

    return (FARPROC)(pfuncs[pords[i]] + (UINT)mod_base);
}

// Loading .dll example, without Kernel32.dll
HMODULE LoadLibraryFromNtDll(LPWSTR lib_path)
{
    HMODULE hmod, hlib = 0;
    LdrLoadDllProc LdrLoadDll;
    NTSTATUS res;
    UNICODE_STRING uni;

    hmod = (HMODULE)GetModuleBaseAddr(L"ntdll.dll");
    if (!hmod) {
        return NULL;
    }

    LdrLoadDll = (LdrLoadDllProc)GetExportProcAddr(hmod, "LdrLoadDll");
    uni.Buffer = lib_path;
    uni.Length = wcslen(lib_path) * 2;
    uni.MaximumLength = uni.Length + 2;

    res = LdrLoadDll(NULL, 0, &uni, &hlib);
    if (res) {
        return NULL;
    }
    return hlib;
}

int main(int argc, char *argv[])
{
    if (!LoadLibraryFromNtDll(L"testlib.dll")) {
        printf("Loading DLL failed!\n");
    } else {
        printf("Loading DLL ok!\n");
    }
    getchar();
    return 0;
}

Комментариев нет:

Отправить комментарий