Форум программистов, компьютерный форум, киберфорум
_lunar_
Войти
Регистрация
Восстановить пароль

Правильный прототип LdrLoadDll

Запись от _lunar_ размещена 22.07.2019 в 15:14
Показов 12262 Комментарии 0
Метки c, c++, winapi

Почему-то везде в интернете ходит один и тот же неправильный прототип nt-функции LdrLoadDll
C++
1
2
3
4
5
6
7
8
9
NTSYSAPI
NTSTATUS
NTAPI
LdrLoadDll(
    _In_opt_ PWSTR DllPath,
    _In_opt_ PULONG DllCharacteristics,
    _In_ PUNICODE_STRING DllName,
    _Out_ PVOID *DllHandle
    );
ведать один написал (ещё со времен какой-нить висты) и все с него бездумно копируют.

Начнём разбирать.
Количество параметров функции. Хотя бы здесь не ошиблись (тут собственно и не ошибёшься, такие функции тянутся ещё с XP и редко меняются) - всего 4 параметра.
Теперь берём IDA и запихиваем в неё KernelBase.dll (именно её, а не kernel32.dll - с Windows 7 эта либа стала заглушкой, которая просто перенаправляет на KernelBase).
Смотрим на LoadLibraryA - банальный механизм через twain ссылается на LoadLibraryExA
Assembler
1
2
3
4
xor     r8d, r8d        ; dwFlags
xor     edx, edx        ; hFile
mov     rcx, rdi        ; lpLibFileName
call    LoadLibraryExA
переходим к LoadLibraryExA и видим что она вызывает LoadLibraryExW (в ядре нет ansi, только юникод)
Assembler
1
2
3
4
mov     rcx, [rsp+38h+UnicodeString.Buffer] ; lpLibFileName
mov     r8d, ebx        ; dwFlags
mov     rdx, rdi        ; hFile
call    LoadLibraryExW
аналогично и для LoadLibraryW (там ещё проще, никакого twain)
Assembler
1
2
3
xor     r8d, r8d
xor     edx, edx
jmp     LoadLibraryExW
Итак, конечную функцию перед переходом в NT мы нашли, теперь посмотрим на её прототип
Кликните здесь для просмотра всего текста
C++
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
HMODULE __stdcall LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
{
  DWORD v3; // ebx
  unsigned int v4; // eax
  USHORT v5; // cx
  signed int v6; // edx
  unsigned int v7; // eax
  unsigned int v8; // esi
  bool v10; // zf
  __int64 v11; // [rsp+30h] [rbp-20h]
  __int64 v12; // [rsp+38h] [rbp-18h]
  UNICODE_STRING Source; // [rsp+40h] [rbp-10h]
  int v14; // [rsp+70h] [rbp+20h]
  __int64 v15; // [rsp+88h] [rbp+38h]
 
  v3 = dwFlags;
  if ( !lpLibFileName || hFile || dwFlags & 0xFFFF0000 || (dwFlags & 0x42) == 66 )
    goto LABEL_31;
  v4 = RtlInitUnicodeStringEx(&Source, lpLibFileName);
  if ( (v4 & 0x80000000) != 0 )
  {
    BaseSetLastNTError(v4);
    return 0i64;
  }
  v5 = Source.Length;
  if ( !Source.Length )
    goto LABEL_31;
  do
  {
    if ( Source.Buffer[((unsigned __int64)v5 >> 1) - 1] != 32 )
      break;
    v10 = v5 == 2;
    v5 -= 2;
    Source.Length = v5;
  }
  while ( !v10 );
  if ( !v5 )
  {
LABEL_31:
    BaseSetLastNTError(3221225485i64);
    return 0i64;
  }
  v6 = 0;
  v15 = 0i64;
  if ( v3 & 0x62 )
  {
    JUMPOUT(LdrGetDllPath(Source.Buffer, v3 & 0x7F08, &v11, &v12), 0, sub_18009AE5E);
    v7 = BasepLoadLibraryAsDataFileInternal(&Source, (__int64)&v15);
    v8 = v7;
    if ( (signed int)(v7 + 2147483648) >= 0 && v7 != -1073741809 && v3 & 0x20 && v3 & 0x42 )
      v8 = BasepLoadLibraryAsDataFileInternal(&Source, (__int64)&v15);
    RtlReleasePath(v11);
  }
  else
  {
    v14 = 0;
    if ( v3 & 1 )
    {
      v14 = 2;
      v6 = 2;
    }
    if ( (v3 & 0x80u) != 0 )
      v14 = v6 | 0x800000;
    JUMPOUT(v3 & 4, 0, sub_18009AE65);
    JUMPOUT(_bittest((const signed int *)&v3, 0xFu), sub_18009AE70);
    v8 = LdrLoadDll(v3 & 0x7F08 | 1i64, &v14, &Source, &v15);
  }
  if ( (v8 & 0x80000000) == 0 )
    return (HMODULE)v15;
  BaseSetLastNTError(v8);
  return 0i64;
}

Теперь разберёмся что и к чему здесь.
Сначала происходит инициализация юникод-строки RtlInitUnicodeStringEx.
Далее рассмотрим вот этот участок кода
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
else
{
    v14 = 0;
    if (v3 & 1)
    {
        v14 = 2;
        v6 = 2;
    }
    if ((v3 & 0x80u) != 0)
        v14 = v6 | 0x800000;
    JUMPOUT(v3 & 4, 0, sub_18009AE65);
    JUMPOUT(_bittest((const signed int *)&v3, 0xFu), sub_18009AE70);
    v8 = LdrLoadDll(v3 & 0x7F08 | 1i64, &v14, &Source, &v15);
}
if ((v8 & 0x80000000) == 0)
    return (HMODULE)v15;
BaseSetLastNTError(v8);
return 0i64;
Итак:
v8 это просто NTSTATUS
v3 (если смотреть на прототип LoadLibraryExW) это dwFlags (v3 = dwFlags)
v14 это целочисленное значение, которое зависит от передаваемого в функцию флага
Source - всё просто, это UNICODE_STRING
v15 это HMODULE, указатель на загружаемую библиотеку.

Флаг, который обрабатывается в LdrLoadDll, является флагом критерия поиска библиотеки (про каждый из них можно прочитать на MSDN)
C++
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
#define DONT_RESOLVE_DLL_REFERENCES         0x00000001
#define LOAD_LIBRARY_AS_DATAFILE            0x00000002
// reserved for internal LOAD_PACKAGED_LIBRARY: 0x00000004
#define LOAD_WITH_ALTERED_SEARCH_PATH       0x00000008
#define LOAD_IGNORE_CODE_AUTHZ_LEVEL        0x00000010
#define LOAD_LIBRARY_AS_IMAGE_RESOURCE      0x00000020
#define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE  0x00000040
#define LOAD_LIBRARY_REQUIRE_SIGNED_TARGET  0x00000080
#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR    0x00000100
#define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x00000200
#define LOAD_LIBRARY_SEARCH_USER_DIRS       0x00000400
#define LOAD_LIBRARY_SEARCH_SYSTEM32        0x00000800
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS    0x00001000
 
#if (NTDDI_VERSION >= NTDDI_WIN10_RS1)
 
#define LOAD_LIBRARY_SAFE_CURRENT_DIRS      0x00002000
 
#define LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER   0x00004000
 
#else
 
//
// For anything building for downlevel, set the flag to be the same as LOAD_LIBRARY_SEARCH_SYSTEM32
// such that they're treated the same when running on older version of OS.
//
 
#if (NTDDI_VERSION >= NTDDI_WIN10_RS2)
 
#define LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY   0x00008000
 
#endif
Именно поэтому в неправильном прототипе указан тип первого параметра - PWSTR DllPath. Кто-то не до конца понял, что это не путь к Dll, а флаг поиска, который система реализует сама.

И вот теперь, учитывая разбор через IDA, мы можем написать правильный прототип:
C++
1
2
3
4
5
6
7
typedef NTSTATUS(__fastcall* _LdrLoadDll)(
    _In_opt_ UINT32 Flags,
    _In_opt_ PUINT32 Reserved,
    _In_ PUNICODE_STRING ModuleFileName,
    _Out_ HMODULE* ModuleHandle
    );
_LdrLoadDll LdrLoadDll;
Причём реализовывать его нужно следующим образом
Кликните здесь для просмотра всего текста
C++
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
std::cout <<
    "0 - NULL (without flag)\n"
    "1 - DONT_RESOLVE_DLL_REFERENCES\n"
    "2 - LOAD_LIBRARY_AS_DATAFILE\n"
    "3 - LOAD_PACKAGED_LIBRARY (for internal)\n"
    "4 - LOAD_WITH_ALTERED_SEARCH_PATH\n"
    "5 - LOAD_IGNORE_CODE_AUTHZ_LEVEL\n"
    "6 - LOAD_LIBRARY_AS_IMAGE_RESOURCE\n"
    "7 - LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE\n"
    "8 - LOAD_LIBRARY_REQUIRE_SIGNED_TARGET\n"
    "9 - LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR\n"
    "10 - LOAD_LIBRARY_SEARCH_APPLICATION_DIR\n"
    "11 - LOAD_LIBRARY_SEARCH_USER_DIRS\n"
    "12 - LOAD_LIBRARY_SEARCH_SYSTEM32 (for anything building for downlevel)\n"
    "13 - LOAD_LIBRARY_SEARCH_DEFAULT_DIRS\n"
    "14 - LOAD_LIBRARY_SAFE_CURRENT_DIRS (WIN10_RS1)\n"
    "15 - LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER (WIN10_RS1)\n"
    "16 - LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY (WIN10_RS2)\n"
    "Choose: ";
 
UINT32 temp = 0, flag = 0, temp1 = 0;
INT32 temp2 = 0;
HMODULE hModule = nullptr;
PVOID fnAddress = nullptr;
UNICODE_STRING LibraryName = { 0 };
ANSI_STRING FunctionName = { 0 };
 
std::cin >> temp;
std::cin.get();
 
switch (temp) {
case 0:
    flag = NULL;
    break;
case 1:
    flag = DONT_RESOLVE_DLL_REFERENCES;
    break;
case 2:
    flag = LOAD_LIBRARY_AS_DATAFILE;
    break;
case 3:
    flag = 0x00000004;
    break;
case 4:
    flag = LOAD_WITH_ALTERED_SEARCH_PATH;
    break;
case 5:
    flag = LOAD_IGNORE_CODE_AUTHZ_LEVEL;
    break;
case 6:
    flag = LOAD_LIBRARY_AS_IMAGE_RESOURCE;
    break;
case 7:
    flag = LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE;
    break;
case 8:
    flag = LOAD_LIBRARY_REQUIRE_SIGNED_TARGET;
    break;
case 9:
    flag = LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
    break;
case 10:
    flag = LOAD_LIBRARY_SEARCH_APPLICATION_DIR;
    break;
case 11:
    flag = LOAD_LIBRARY_SEARCH_USER_DIRS;
    break;
case 12:
    flag = LOAD_LIBRARY_SEARCH_SYSTEM32;
    break;
case 13:
    flag = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS;
    break;
case 14:
    flag = LOAD_LIBRARY_SAFE_CURRENT_DIRS;
    break;
case 15:
    flag = LOAD_LIBRARY_SEARCH_SYSTEM32_NO_FORWARDER;
    break;
case 16:
flag = LOAD_LIBRARY_OS_INTEGRITY_CONTINUITY;
    break;
default:
    break;
}
 
if (flag & 1) {
    temp1 = 2;
    temp2 = 2;
}
 
if ((flag & 0x80u) != 0)
    temp1 = temp2 | 0x800000;
    
RtlInitUnicodeStringEx(&LibraryName, L"ntoskrnl.exe");
LdrLoadDll(flag & 0x7F08 | 1, &temp1, &LibraryName, &hModule);
std::cout << "ntoskrnl.exe = 0x" << hModule << std::endl;
    
RtlInitAnsiStringEx(&FunctionName, "IoCreateFile");
LdrGetProcedureAddressForCaller(hModule, &FunctionName, NULL, &fnAddress, FALSE, nullptr);
std::cout << "IoCreateFile = 0x" << fnAddress << std::endl;
 
std::cin.get();
Метки c, c++, winapi
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии
 
Новые блоги и статьи
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru