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

Windows Internal на примере user32.dll!__ClientLoadLibrary (Часть 1.0)

Запись от _lunar_ размещена 29.10.2019 в 16:15
Обновил(-а) _lunar_ Сегодня в 01:42

Internal (или внутренние) функции операционной системы Windows как известно не входят в таблицу экспорта и используются исключительно самой библиотекой для различных вычислений.
Кроме того, системные библиотеки Windows условно можно разделить на 2 группы:
- пользовательские (библиотеки, функции которых можно использовать в UserMode (также известный как Ring3));
- ядерные (библиотеки, к функциям которых доступ ограничен из Ring3, и при попытке их исполнения можно лишь только славить EXCEPTION_ACCESS_VIOLATION или в максимально возможном случае (права администратора + привилегия отладчика + выполнение из-под SYSTEM процесс (например svchost.exe) пример) исключение после выполнения первой инструкции EXCEPTION_PRIV_INSTRUCTION).
К пользовательским библиотекам можно отнести kernel32.dll, KernelBase.dll, advapi32.dll, gdi32.dll, user32.dll (эти библиотеки образуют WinAPI), а также часть функций ntdll.dll (известных как NativeAPI).
Любая функция из WinAPI делает вызов своего прототипа в NativeAPI, а уже из ntdll.dll осуществляется переход в ядро системы (по средствам вызова инструкции sysenter и syscall или int 2e на старых операционных системах).
К ядерным библиотекам можно отнести csrsrv.dll, win32k.sys ну и конечно же само ядро ntoskrnl.exe
Ниже ядра только слой аппаратных абстракций (hal.dll), обеспечивающий взаимодействие аппаратного обеспечения с программным обеспечением.

Большинство Internal функций WinAPI не взаимодействуют с NativeAPI, тем самым, этими функциями можно управлять из-под UserMode, при этом система ничего не будет знать об этом.
Как это выглядит в действительности можно почитать на примере разбора Эксплойта нулевого дня специалистами Kaspersky Lab. Суть уязвимости заключается в перехвате функций fnDWORD, fnNCDESTROY и fnINLPCREATESTRUCT и последующего запуска серии хуков (также прикрепил pdf данной статьи, на случай если ссылка не актуальна Эксплойт нулевого дня (CVE-2018-8453) в целевых атаках.pdf)

Мы же рассмотрим пример иного характера - внутреннюю функцию __ClientLoadLibrary пользовательской библиотеки user32.dll

В библиотеке user32.dll есть диспетчер под названием apfnDispatch, который является тоже внутренним и не экспортируется.
В этом диспетчере содержатся Internal функции различного характера, вот их список (актуален для Windows 10 1903)
Кликните здесь для просмотра всего текста
apfnDispatch
dq offset __fnCOPYDATA
dq offset __fnCOPYGLOBALDATA
dq offset __fnDWORD
dq offset __fnNCDESTROY
dq offset __fnDWORDOPTINLPMSG
dq offset __fnINOUTDRAG
dq offset __fnGETTEXTLENGTHS
dq offset __fnINCNTOUTSTRING
dq offset __fnPOUTLPINT // в х32 здесь находится __fnINCNTOUTSTRINGNULL, и при этом в символах х64 имя функции также __fnINCNTOUTSTRINGNULL
dq offset __fnINLPCOMPAREITEMSTRUCT
dq offset __fnINLPCREATESTRUCT
dq offset __fnINLPDELETEITEMSTRUCT
dq offset __fnINLPDRAWITEMSTRUCT
dq offset __fnPOPTINLPUINT
dq offset __fnPOPTINLPUINT
dq offset __fnINLPMDICREATESTRUCT
dq offset __fnINOUTLPMEASUREITEMSTRUCT
dq offset __fnINLPWINDOWPOS
dq offset __fnINOUTLPPOINT5
dq offset __fnINOUTLPSCROLLINFO
dq offset __fnINOUTLPRECT
dq offset __fnINOUTNCCALCSIZE
dq offset __fnINOUTLPPOINT5
dq offset __fnINPAINTCLIPBRD
dq offset __fnINSIZECLIPBRD
dq offset __fnINDESTROYCLIPBRD
dq offset __fnINSTRINGNULL
dq offset __fnINSTRINGNULL
dq offset __fnINDEVICECHANGE
dq offset __fnPOWERBROADCAST
dq offset __fnINLPUAHDRAWMENU
dq offset __fnOPTOUTLPDWORDOPTOUTLPDWORD
dq offset __fnOPTOUTLPDWORDOPTOUTLPDWORD
dq offset __fnOUTDWORDINDWORD
dq offset __fnOUTLPRECT
dq offset __fnOUTSTRING
dq offset __fnPOPTINLPUINT
dq offset __fnPOUTLPINT
dq offset __fnSENTDDEMSG
dq offset __fnINOUTSTYLECHANGE
dq offset __fnHkINDWORD
dq offset __fnHkINLPCBTACTIVATESTRUCT
dq offset __fnHkINLPCBTCREATESTRUCT
dq offset __fnHkINLPDEBUGHOOKSTRUCT
dq offset __fnHkINLPMOUSEHOOKSTRUCTEX
dq offset __fnHkINLPKBDLLHOOKSTRUCT
dq offset __fnHkINLPMSLLHOOKSTRUCT
dq offset __fnHkINLPMSG
dq offset __fnHkINLPRECT
dq offset __fnHkOPTINLPEVENTMSG
dq offset __xxxClientCallDelegateThread
dq offset __ClientCallDummyCallback2
dq offset __fnKEYBOARDCORRECTIONCALLOUT
dq offset __fnOUTLPCOMBOBOXINFO
dq offset __fnINLPCOMPAREITEMSTRUCT
dq offset __ClientCallDummyCallback2
dq offset __xxxClientCallDitThread
dq offset __xxxClientEnableMMCSS
dq offset __xxxClientUpdateDpi
dq offset __xxxClientExpandStringW
dq offset __ClientCopyDDEIn1
dq offset __ClientCopyDDEIn2
dq offset __ClientCopyDDEOut1
dq offset __ClientCopyDDEOut2
dq offset __ClientCopyImage
dq offset __ClientEventCallback
dq offset __ClientFindMnemChar
dq offset __ClientFreeDDEHandle
dq offset __ClientFreeLibrary
dq offset __ClientGetCharsetInfo
dq offset __ClientGetDDEFlags
dq offset __ClientGetDDEHookData
dq offset __ClientGetListboxString
dq offset __ClientGetMessageMPH
dq offset __ClientLoadImage
dq offset __ClientLoadLibrary
dq offset __ClientLoadMenu
dq offset __ClientLoadLocalT1Fonts
dq offset __ClientPSMTextOut
dq offset __ClientLpkDrawTextEx
dq offset __ClientExtTextOutW
dq offset __ClientGetTextExtentPointW
dq offset __ClientCharToWchar
dq offset __ClientAddFontResourceW
dq offset __ClientThreadSetup
dq offset __ClientDeliverUserApc
dq offset __ClientNoMemoryPopup
dq offset __ClientMonitorEnumProc
dq offset __ClientCallWinEventProc
dq offset __ClientWaitMessageExMPH
dq offset __ClientWOWGetProcModule
dq offset __ClientWOWTask16SchedNotify
dq offset __ClientImmLoadLayout
dq offset __ClientImmProcessKey
dq offset __fnIMECONTROL
dq offset __fnINWPARAMDBCSCHAR
dq offset __fnGETTEXTLENGTHS
dq offset __fnINLPKDRAWSWITCHWND
dq offset __ClientLoadStringW
dq offset __ClientLoadOLE
dq offset __ClientRegisterDragDrop
dq offset __ClientRevokeDragDrop
dq offset __fnINOUTMENUGETOBJECT
dq offset __ClientPrinterThunk
dq offset __fnOUTLPCOMBOBOXINFO
dq offset __fnOUTLPSCROLLBARINFO
dq offset __fnINLPUAHDRAWMENU
dq offset __fnINLPUAHDRAWMENUITEM
dq offset __fnINLPUAHDRAWMENU
dq offset __fnINOUTLPUAHMEASUREMENUITEM
dq offset __fnINLPUAHDRAWMENU
dq offset __fnOUTLPTITLEBARINFOEX
dq offset __fnTOUCH
dq offset __fnGESTURE
dq offset __fnPOPTINLPUINT
dq offset __fnPOPTINLPUINT
dq offset __xxxClientCallDefaultInputHandler
dq offset __fnEMPTY
dq offset __ClientRimDevCallback
dq offset __xxxClientCallMinTouchHitTestingCallback
dq offset __ClientCallLocalMouseHooks
dq offset __xxxClientBroadcastThemeChange
dq offset __xxxClientCallDevCallbackSimple
dq offset __xxxClientAllocWindowClassExtraBytes
dq offset __xxxClientFreeWindowClassExtraBytes
dq offset __fnGETWINDOWDATA
dq offset __fnINOUTSTYLECHANGE
dq offset __fnHkINLPMOUSEHOOKSTRUCTEX

Расписывать каждую функцию я не буду, может быть какие-то интересные в следующих блогах
А сейчас рассмотрим __ClientLoadLibrary.
Как ни странно, но использование __ClientLoadLibrary может стать защитой от внедрения dll средствами SetWindowsHookEx.
Почти все эти функции возвращают адрес обратного вызова из ядерного сервиса (NtCallbackReturn). При вызове теневых сервисов часто до возврата из сервиса управление возвращается в UserMode, другими словами адрес обратного вызова получает именно __ClientLoadLibrary, а уже потом, после возврата из сервиса, его получает SetWindowsHookEx.

Интересно то, что поле PEB.KernelCallbackTable указывает как раз на user32.apfnDispatch.
Теоретически можно было бы просто отсчитать от него по 8 байт до функции __ClientLoadLibrary, но нет никакой гарантии, что в будущем Microsoft не внесёт изменения в эти структуры (изменит номер функции и её относительный адрес).
Поэтому лучшим способом будет поиск по сигнатуре.

Итак, для начала нужно посмотреть на библиотеку user32.dll под микроскопом (коим является конечно же дизассемблер IDA).
Загрузив символы user32.pdb, нажимаем Alt+T и ищем по тексту __ClientLoadLibrary, вот начало искомой функции
Нажмите на изображение для увеличения
Название: 1.png
Просмотров: 343
Размер:	58.4 Кб
ID:	5676

Чтобы определить сигнатуру, необходим воспользоваться отладчиком (может быть конечно и для IDA есть какие-то плагины, но лично я предпочитаю работать с динамической памятью).
Для этого нужно сложить базовый адрес, загруженной в память user32.dll, со смещением до __ClientLoadLibrary (на картинке видно, что смещение относительно базового адреса в статике (0x180000000) равно 0х5390).
Открываем x64dbg, перемещаемся в модуль user32.dll (базовый адрес в динамике на момент загрузки модуля - 0х00007FFFD17F0000) и добавляем смещение 0х5390, в итоге попадаем туда куда нужно
Нажмите на изображение для увеличения
Название: 2.png
Просмотров: 437
Размер:	81.9 Кб
ID:	5677

С помощью плагина SwissArmyKnife делаем сигнатуру первых 7-10 инструкций (обычно этого достаточно для уникальности сигнатуры)
Нажмите на изображение для увеличения
Название: 3.png
Просмотров: 322
Размер:	57.8 Кб
ID:	5678
Получаем саму сигнатуру и маску.

__ClientLoadLibrary принимает только 1 аргумент - указатель на недокументированную структуру, выделенную в стеке процесса
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typedef struct _CAPTUREBUF {
    SIZE_T BufferSize;          // [0] содержит длину всего буфера, включая данные переменной длины
    SIZE_T AdditionalDataSize;  // [1] содержит длину данных переменной длины
    ULONG FixupsCount;          // [2] количество исправлений
    PVOID pFree;                // [3] указатель на конец данных переменной длины
    ULONG offCbkPtrs;           // [4] смещение от начала структуры
    BOOL bFixed;                // [5] если FALSE, каждый указатель содержит не адрес, а смещение относительно начала структуры
    UNICODE_STRING lpDLLPath;   // [6] имя модуля, загружаемого через LoadLibraryExW
    union {
        ULONG lpfnNotify;                   // [7] для x32: поле lpfnNotify является смещением относительно загруженного модуля вызываемой функции
        UNICODE_STRING lpInitFunctionName;  // [8] для x64: поле lpInitFunctionName является именем вызываемой функции; эта функция должна быть экспортируемой, потому что она извлекается с помощью GetProcAddress
    };
    ULONG offCbk[2];            // [9,10] чтобы пропустить вызов функции инициализации, просто укажите значение 0 для lpfnNotify в x32, или не указывайте смещение для имени функции (FixupsCount = 1 и offCbk[1] = 0) для x64
    ULONG undefined[4];         // [11,12,13,14]
} CAPTUREBUF, *PCAPTUREBUF;
Эта структура является специализацией более общего и сложного механизма, который существует в драйвере win32k.sys для обратных вызовов пользовательского режима.
Она состоит из фиксированного заголовка (от BufferSize до bFixed) и данных переменной длины (начиная с lpDLLPath).

Немного слов о внутренней структуре __ClientLoadLibrary. Реализация этой функции и функций, которые она вызывает для 32-х битного и 64-х битного кодов разная. Поэтому в дальнейшем я буду использовать директиву препроцессора _WIN64 для разделения соответствующего кода.
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
typedef LONG(CALLBACK *gpfnInitUserApi)(ULONG, PVOID);
 
typedef LRESULT(WINAPI *_ClientLoadLibrary)(
    _In_ PCAPTUREBUF pCapBuffer
    );
 
LRESULT ClientLoadLibrary(PCAPTUREBUF pCapBuffer)
{
    HMODULE hMod, newhMod;
    CHAR Dst;
    PCWCH pWideCharStr;
 
    memset(&Dst, 0, MAX_PATH);
 
    if (pCapBuffer->FixupsCount && !pCapBuffer->bFixed)
        FixupCallbackPointers(pCapBuffer);
 
    AppModelPolicy_PolicyValue ModelPolicy_Value = DllSearchOrder_Traditional;
 
    PS_PKG_CLAIM PsPkgClaim = { 0 };
    ULONG_PTR AttributesPresent = 0;
 
    gpfnInitUserApi gfInitUserApi = 0;
 
#ifdef _WIN64
    LONG_PTR dwhMod;
    LONG newWideCharStr;
 
    AppModelPolicy_GetPolicy_Internal(GetCurrentThreadEffectiveToken(), DllSearchOrder, &ModelPolicy_Value, &PsPkgClaim, &AttributesPresent);
    hMod = LoadLibraryExW(pCapBuffer->lpDLLPath.Buffer, nullptr, ModelPolicy_Value != DllSearchOrder_PackageGraphBased ? 8 : 0);
    dwhMod = (LONG_PTR)hMod;
    if (hMod) {
        pWideCharStr = pCapBuffer->lpInitFunctionName.Buffer;
        if (pWideCharStr) {
            newhMod = hMod;
            newWideCharStr = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pWideCharStr, -1, &Dst, MAX_PATH, nullptr, nullptr);
            dwhMod = newWideCharStr;
            if (!newWideCharStr) goto LABEL_16;
            gfInitUserApi = (gpfnInitUserApi)GetProcAddress(newhMod, &Dst);
            if (!gfInitUserApi || !(ULONG)InitUserApiHook(newhMod, gfInitUserApi)) dwhMod = 0;
            if (dwhMod) dwhMod = (LONG_PTR)newhMod;
            else
                LABEL_16:
            FreeLibrary(newhMod);
        }
    }
    LONG_PTR Result = dwhMod;
#else
    AppModelPolicy_GetPolicy_Internal(GetCurrentThreadEffectiveToken(), &ModelPolicy_Value, &PsPkgClaim, &AttributesPresent);
    hMod = LoadLibraryExW(*(PCWCH*)pCapBuffer->lpfnNotify, nullptr, ModelPolicy_Value != DllSearchOrder_PackageGraphBased ? 8 : 0);
    if (hMod) {
        pWideCharStr = *(PCWCH*)(pCapBuffer->offCbk[0]);
        if (pWideCharStr) {
            newhMod = hMod;
            hMod = (HMODULE)WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pWideCharStr, -1, &Dst, MAX_PATH, nullptr, nullptr);
            if (!hMod) goto LABEL_16;
            if (!GetProcAddress(newhMod, &Dst) || !InitUserApiHook((HMODULE)pCapBuffer, gfInitUserApi)) hMod = nullptr;
            if (hMod) hMod = newhMod;
            else
                LABEL_16:
            FreeLibrary(newhMod);
        }
    }
    HMODULE Result = hMod;
#endif // _WIN64
 
    return NtCallbackReturn(&Result, 0x18u, 0);
}
В начале функции проверяются значения FixupsCount и bFixed и затем вызывается FixupCallbackPointers.
FixupCallbackPointers исправляет указатели довольно интересным способом. Сначала ищется адрес указателей обратного вызова, затем она просматривает список указателей и исправляет его, разрешая смещение по фактическому (реальному) адресу
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
typedef VOID(WINAPI *_FixupCallbackPointers)(
    _In_ PCAPTUREBUF pCapBuffer
    );
 
VOID FixupCallbackPointers(PCAPTUREBUF pCapBuffer)
{
    ULONG fixCount;
    PULONG_PTR pOffset;
    LONG_PTR newOffset;
 
    fixCount = 0;
    pOffset = (PULONG_PTR)((PCH)pCapBuffer + pCapBuffer->offCbkPtrs);
    if (pCapBuffer->FixupsCount)
        do {
            newOffset = *pOffset;
            *(PULONG_PTR)((PCH)pCapBuffer + newOffset) += *(PULONG_PTR)pCapBuffer;
            ++pOffset;
            ++fixCount;
        } while (fixCount < pCapBuffer->FixupsCount);
}
Далее отрабатывает AppModelPolicy_GetPolicy_Internal
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
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
typedef enum _AppModelPolicy_Type {
    LifecycleManager = 0x1,
    AppDataAccess = 0x2,
    WindowingModel = 0x3,
    DllSearchOrder = 0x4,
    Fusion = 0x5,
    NonWindowsCodeLoading = 0x6,
    ProcessEnd = 0x7,
    BeginThreadInit = 0x8,
    DeveloperInformation = 0x9,
    CreateFileAccess = 0xA,
    ImplicitPackageBreakaway_Internal = 0xB,
    ProcessActivationShim = 0xC,
    AppKnownToStateRepository = 0xD,
    AudioManagement = 0xE,
    PackageMayContainPublicComRegistrations = 0xF,
    PackageMayContainPrivateComRegistrations = 0x10,
    LaunchCreateProcessExtensions = 0x11,
    ClrCompat = 0x12,
    LoaderIgnoreAlteredSearchForRelativePath = 0x13,
    ImplicitlyActivateClassicAAAServersAsIU = 0x14,
    ComClassicCatalog = 0x15,
    ComUnmarshaling = 0x16,
    ComAppLaunchPerfEnhancements = 0x17,
    ComSecurityInitialization = 0x18,
    RoInitializeSingleThreadedBehavior = 0x19,
    ComDefaultExceptionHandling = 0x1A,
    ComOopProxyAgility = 0x1B,
    AppServiceLifetime = 0x1C,
    WebPlatform = 0x1D,
    WinInetStoragePartitioning = 0x1E,
    IndexerProtocolHandlerHost = 0x1F,
    LoaderIncludeUserDirectories = 0x20,
    ConvertAppContainerToRestrictedAppContainer = 0x21,
    PackageMayContainPrivateMapiProvider = 0x22,
    AdminProcessPackageClaims = 0x23,
    RegistryRedirectionBehavior = 0x24,
    BypassCreateProcessAppxExtension = 0x25,
    KnownFolderRedirection = 0x26,
    PrivateActivateAsPackageWinrtClasses = 0x27,
    AppPrivateFolderRedirection = 0x28,
    GlobalSystemAppDataAccess = 0x29,
    ConsoleHandleInheritance = 0x2A,
    ConsoleBufferAccess = 0x2B,
    ConvertCallerTokenToUserTokenForDeployment = 0x2C
} AppModelPolicy_Type;
 
 
typedef enum _AppModelPolicy_PolicyValue {
    None = 0,
    LifecycleManager_Unmanaged = 0x10000,
    LifecycleManager_ManagedByPLM = 0x10001,
    LifecycleManager_ManagedByEM = 0x10002,
    AppDataAccess_Allowed = 0x20000,
    AppDataAccess_Denied = 0x20001,
    WindowingModel_Hwnd = 0x30000,
    WindowingModel_CoreWindow = 0x30001,
    WindowingModel_LegacyPhone = 0x30002,
    WindowingModel_None = 0x30003,
    DllSearchOrder_Traditional = 0x40000,
    DllSearchOrder_PackageGraphBased = 0x40001,
    Fusion_Full = 0x50000,
    Fusion_Limited = 0x50001,
    NonWindowsCodeLoading_Allowed = 0x60000,
    NonWindowsCodeLoading_Denied = 0x60001,
    ProcessEnd_TerminateProcess = 0x70000,
    ProcessEnd_ExitProcess = 0x70001,
    BeginThreadInit_RoInitialize = 0x80000,
    BeginThreadInit_None = 0x80001,
    DeveloperInformation_UI = 0x90000,
    DeveloperInformation_None = 0x90001,
    CreateFileAccess_Full = 0xA0000,
    CreateFileAccess_Limited = 0xA0001,
    ImplicitPackageBreakaway_Allowed = 0xB0000,
    ImplicitPackageBreakaway_Denied = 0xB0001,
    ImplicitPackageBreakaway_DeniedByApp = 0xB0002,
    ProcessActivationShim_None = 0xC0000,
    ProcessActivationShim_PackagedCWALauncher = 0xC0001,
    AppKnownToStateRepository_Known = 0xD0000,
    AppKnownToStateRepository_Unknown = 0xD0001,
    AudioManagement_Unmanaged = 0xE0000,
    AudioManagement_ManagedByPBM = 0xE0001,
    PackageMayContainPublicComRegistrations_Yes = 0xF0000,
    PackageMayContainPublicComRegistrations_No = 0xF0001,
    PackageMayContainPrivateComRegistrations_None = 0x100000,
    PackageMayContainPrivateComRegistrations_PrivateHive = 0x100001,
    LaunchCreateProcessExtensions_None = 0x110000,
    LaunchCreateProcessExtensions_RegisterWithPsm = 0x110001,
    LaunchCreateProcessExtensions_RegisterWithDesktopAppX = 0x110002,
    ClrCompat_Others = 0x120000,
    ClrCompat_ClassicDesktop = 0x120001,
    ClrCompat_Universal = 0x120002,
    ClrCompat_PackagedDesktop = 0x120003,
    LoaderIgnoreAlteredSearchForRelativePath_False = 0x130000,
    LoaderIgnoreAlteredSearchForRelativePath_True = 0x130001,
    ImplicitlyActivateClassicAAAServersAsIU_Yes = 0x140000,
    ImplicitlyActivateClassicAAAServersAsIU_No = 0x140001,
    ComClassicCatalog_MachineHiveAndUserHive = 0x150000,
    ComClassicCatalog_MachineHiveOnly = 0x150001,
    ComUnmarshaling_ForceStrongUnmarshaling = 0x160000,
    ComUnmarshaling_ApplicationManaged = 0x160001,
    ComAppLaunchPerfEnhancements_Enabled = 0x170000,
    ComAppLaunchPerfEnhancements_Disabled = 0x170001,
    ComSecurityInitialization_ApplicationManaged = 0x180000,
    ComSecurityInitialization_SystemManaged = 0x180001,
    RoInitializeSingleThreadedBehavior_ASTA = 0x190000,
    RoInitializeSingleThreadedBehavior_STA = 0x190001,
    ComDefaultExceptionHandling_HandleAll = 0x1A0000,
    ComDefaultExceptionHandling_HandleNone = 0x1A0001,
    ComOopProxyAgility_Agile = 0x1B0000,
    ComOopProxyAgility_NonAgile = 0x1B0001,
    AppServiceLifetime_StandardTimeout = 0x1C0000,
    AppServiceLifetime_ExtendedForSamePackage = 0x1C0001,
    WebPlatform_Edge = 0x1D0000,
    WebPlatform_Legacy = 0x1D0001,
    WinInetStoragePartitioning_Isolated = 0x1E0000,
    WinInetStoragePartitioning_SharedWithAppContainer = 0x1E0001,
    IndexerProtocolHandlerHost_PerUser = 0x1F0000,
    IndexerProtocolHandlerHost_PerApp = 0x1F0001,
    LoaderIncludeUserDirectories_False = 0x200000,
    LoaderIncludeUserDirectories_True = 0x200001,
    ConvertAppContainerToRestrictedAppContainer_False = 0x210000,
    ConvertAppContainerToRestrictedAppContainer_True = 0x210001,
    PackageMayContainPrivateMapiProvider_None = 0x220000,
    PackageMayContainPrivateMapiProvider_PrivateHive = 0x220001,
    AdminProcessPackageClaims_None = 0x230000,
    AdminProcessPackageClaims_Caller = 0x230001,
    RegistryRedirectionBehavior_None = 0x240000,
    RegistryRedirectionBehavior_CopyOnWrite = 0x240001,
    BypassCreateProcessAppxExtension_False = 0x250000,
    BypassCreateProcessAppxExtension_True = 0x250001,
    KnownFolderRedirection_Isolated = 0x260000,
    KnownFolderRedirection_RedirectToPackage = 0x260001,
    PrivateActivateAsPackageWinrtClasses_AllowNone = 0x270000,
    PrivateActivateAsPackageWinrtClasses_AllowFullTrust = 0x270001,
    PrivateActivateAsPackageWinrtClasses_AllowNonFullTrust = 0x270002,
    AppPrivateFolderRedirection_None = 0x280000,
    AppPrivateFolderRedirection_AppPrivate = 0x280001,
    GlobalSystemAppDataAccess_Normal = 0x290000,
    GlobalSystemAppDataAccess_Virtualized = 0x290001,
    ConsoleHandleInheritance_ConsoleOnly = 0x2A0000,
    ConsoleHandleInheritance_All = 0x2A0001,
    ConsoleBufferAccess_RestrictedUnidirectional = 0x2B0000,
    ConsoleBufferAccess_Unrestricted = 0x2B0001,
    ConvertCallerTokenToUserTokenForDeployment_UserCallerToken = 0x2C0000,
    ConvertCallerTokenToUserTokenForDeployment_ConvertTokenToUserToken = 0x2C0001,
} AppModelPolicy_PolicyValue, *pAppModelPolicy_PolicyValue;
 
typedef struct _PS_PKG_CLAIM {
    ULONG_PTR Flags;
    ULONG_PTR Origin;
} PS_PKG_CLAIM, *PPS_PKG_CLAIM;
 
#ifdef _WIN64
typedef LRESULT(WINAPI *_AppModelPolicy_GetPolicy_Internal)(
    _In_ HANDLE TokenHandle,
    _In_opt_ AppModelPolicy_Type ModelPolicy_Type,
    _In_ pAppModelPolicy_PolicyValue ModelPolicy_Value,
    _Out_opt_ PPS_PKG_CLAIM PkgClaim,
    _Out_opt_ PULONG_PTR AttributesPresent
    );
#else
typedef LRESULT(WINAPI *_AppModelPolicy_GetPolicy_Internal)(
    _In_ HANDLE TokenHandle,
    _In_ pAppModelPolicy_PolicyValue ModelPolicy_Value,
    _Out_opt_ PPS_PKG_CLAIM PkgClaim,
    _Out_opt_ PULONG_PTR AttributesPresent
    );
#endif // _WIN64
 
#define STATUS_NOT_FOUND 0xC0000225
#ifdef _WIN64
LRESULT AppModelPolicy_GetPolicy_Internal(HANDLE TokenHandle, AppModelPolicy_Type ModelPolicy_Type, pAppModelPolicy_PolicyValue ModelPolicy_Value, PPS_PKG_CLAIM PsPkgClaim, PULONG_PTR AttributesPresent)
{
    AppModelPolicy_PolicyValue newModelPolicy_Value;
    ULONG_PTR newPsPkgClaim;
 
    NTSTATUS Result = RtlQueryPackageClaims(TokenHandle, nullptr, nullptr, nullptr, nullptr, nullptr, PsPkgClaim, AttributesPresent);
 
    if (Result == STATUS_NOT_FOUND) {
        *AttributesPresent = 0;
        Result = 0;
        *(PULONG_PTR)PsPkgClaim = 0;
    }
 
    *ModelPolicy_Value = None;
 
    if ((Result & 0x80000000) == 0) {
        if (*(PBYTE)AttributesPresent & 1 && *(PBYTE)AttributesPresent & 2 && !(*(PBYTE)AttributesPresent & 4)) {
            newPsPkgClaim = *(PULONG_PTR)PsPkgClaim;
            if (_bittest64((const PLONG_PTR)&newPsPkgClaim, 0xAu) || _bittest64((const PLONG_PTR)&newPsPkgClaim, 0xBu) || newPsPkgClaim & 4) {
                newModelPolicy_Value = DllSearchOrder_PackageGraphBased;
                goto LABEL_6;
            }
            if (!(newPsPkgClaim & 8)) {
                newModelPolicy_Value = DllSearchOrder_Traditional;
                if (!(newPsPkgClaim & 0x40))
                    newModelPolicy_Value = (AppModelPolicy_PolicyValue)(~(UCHAR)(newPsPkgClaim >> 12) & 1 | DllSearchOrder_Traditional);
                goto LABEL_6;
            }
        }
        newModelPolicy_Value = DllSearchOrder_PackageGraphBased;
    LABEL_6:
        *ModelPolicy_Value = newModelPolicy_Value;
    }
    return Result;
}
#else
LRESULT AppModelPolicy_GetPolicy_Internal(HANDLE TokenHandle, pAppModelPolicy_PolicyValue ModelPolicy_Value, PPS_PKG_CLAIM PsPkgClaim, PULONG_PTR AttributesPresent)
{
    AppModelPolicy_PolicyValue newModelPolicy_Value;
    LONG newPsPkgClaim;
    LONG newAttributesPresent;
 
    NTSTATUS Result = RtlQueryPackageClaims(TokenHandle, nullptr, nullptr, nullptr, nullptr, nullptr, PsPkgClaim, AttributesPresent);
 
    if (Result == STATUS_NOT_FOUND) {
        *AttributesPresent = 0;
        Result = 0;
        *(PULONG_PTR)PsPkgClaim = 0;
    }
 
    *ModelPolicy_Value = None;
 
    if (Result >= 0) {
        newAttributesPresent = *AttributesPresent;
        if (!(*AttributesPresent & 1) || !(newAttributesPresent & 2) || newAttributesPresent & 4) goto LABEL_12;
        newPsPkgClaim = *(PLONG)PsPkgClaim;
        if (!(*(PLONG)PsPkgClaim & 0x400) && !(newPsPkgClaim & 0x800) && !(newPsPkgClaim & 4)) {
            if (newPsPkgClaim & 8 || newPsPkgClaim & 0x40) {
            LABEL_12:
                newModelPolicy_Value = DllSearchOrder_Traditional;
            LABEL_15:
                *ModelPolicy_Value = newModelPolicy_Value;
                return Result;
            }
            newModelPolicy_Value = DllSearchOrder_Traditional;
            if (newPsPkgClaim & 0x1000) goto LABEL_15;
        }
        newModelPolicy_Value = DllSearchOrder_PackageGraphBased;
        goto LABEL_15;
    }
    return Result;
}
#endif // _WIN64
После исправления всех указателей мы возвращаемся к __ClientLoadLibrary, и затем вызывается InitUserApiHook
C++
1
2
3
4
typedef LRESULT(WINAPI *_InitUserApiHook)(
    _In_ HMODULE ghmodUserApiHook,
    _Inout_ gpfnInitUserApi gfInitUserApi
    );
Она вызывает функцию ResetUserApiHook, которая заполняет массив адресом функции, указанным в аргументе 1. После этого она вызывает функцию уведомления, на которую указывает (hModule + lpfnNotify), передавая массив адреса в качестве аргумента 2.
C++
1
2
3
typedef VOID(WINAPI *_ResetUserApiHook)(
    _In_ PUSERAPIHOOK pUserApiHook
    );
ResetUserApiHook Заполняет массив, указателем PUSERAPIHOOK (эти данные содержаться в uxtheme.dll)
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
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
typedef struct _MSGMASK {
    ULONG_PTR rgb;
    ULONG cb;
    UCHAR undefined[4];
} MSGMASK, *PMSGMASK;
 
typedef struct _USEROWPINFO {
    PVOID pfnBeforeOWP;
    PVOID pfnAfterOWP;
    MSGMASK mm;
} USEROWPINFO, *PUSEROWPINFO;
 
typedef enum _WINDOWPARTS {
    WP_CAPTION = 0x1,
    WP_SMALLCAPTION = 0x2,
    WP_MINCAPTION = 0x3,
    WP_SMALLMINCAPTION = 0x4,
    WP_MAXCAPTION = 0x5,
    WP_SMALLMAXCAPTION = 0x6,
    WP_FRAMELEFT = 0x7,
    WP_FRAMERIGHT = 0x8,
    WP_FRAMEBOTTOM = 0x9,
    WP_SMALLFRAMELEFT = 0x0A,
    WP_SMALLFRAMERIGHT = 0x0B,
    WP_SMALLFRAMEBOTTOM = 0x0C,
    WP_SYSBUTTON = 0x0D,
    WP_MDISYSBUTTON = 0x0E,
    WP_MINBUTTON = 0x0F,
    WP_MDIMINBUTTON = 0x10,
    WP_MAXBUTTON = 0x11,
    WP_CLOSEBUTTON = 0x12,
    WP_SMALLCLOSEBUTTON = 0x13,
    WP_MDICLOSEBUTTON = 0x14,
    WP_RESTOREBUTTON = 0x15,
    WP_MDIRESTOREBUTTON = 0x16,
    WP_HELPBUTTON = 0x17,
    WP_MDIHELPBUTTON = 0x18,
    WP_HORZSCROLL = 0x19,
    WP_HORZTHUMB = 0x1A,
    WP_VERTSCROLL = 0x1B,
    WP_VERTTHUMB = 0x1C,
    WP_DIALOG = 0x1D,
    WP_CAPTIONSIZINGTEMPLATE = 0x1E,
    WP_SMALLCAPTIONSIZINGTEMPLATE = 0x1F,
    WP_FRAMELEFTSIZINGTEMPLATE = 0x20,
    WP_SMALLFRAMELEFTSIZINGTEMPLATE = 0x21,
    WP_FRAMERIGHTSIZINGTEMPLATE = 0x22,
    WP_SMALLFRAMERIGHTSIZINGTEMPLATE = 0x23,
    WP_FRAMEBOTTOMSIZINGTEMPLATE = 0x24,
    WP_SMALLFRAMEBOTTOMSIZINGTEMPLATE = 0x25,
    WP_FRAME = 0x26
} WINDOWPARTS;
 
typedef enum _FRAMESTATES {
    FS_ACTIVE = 0x1,
    FS_INACTIVE = 0x2
} FRAMESTATES;
 
typedef interface ICustomDrawing ICustomDrawing;
typedef ICustomDrawing *LPCUSTOMDRAWING;
typedef VOID(WINAPI *_ClassicNcPaint)(LPCUSTOMDRAWING picd, HWND *hwnd, WPARAM wParam, PWCH pszCaption);
typedef HRESULT(WINAPI *ClassicWndProc)(PVOID pvThis, HWND *hwnd, ULONG nMsg, WPARAM wParam, LPARAM lParam, PULONG_PTR plRet);
 
class CImageFile {
public:
    CImageFile ();
    ~CImageFile ();
private:
};
CImageFile ::CImageFile (){}
CImageFile ::~CImageFile (){}
 
typedef struct _MARGINS {
    //00000000 cxLeftWidth     dd ? ; XREF: CThemeWnd::NcPaint(HDC *, ulong, HRGN *, _NCPAINTOVERIDE *) + 20C / r;
    //00000004 cxRightWidth    dd ? ; XREF: CImageFile::GetPartSize(CRenderObj const *, HDC *, RECT const *, THEMESIZE, SIZE *) + BC / r;
    //00000008 cyTopHeight     dd ? ; XREF: CImageFile::GetPartSize(CRenderObj const *, HDC *, RECT const *, THEMESIZE, SIZE *) + 5B / r;
    //0000000C cyBottomHeight  dd ? ; XREF: CImageFile::GetPartSize(CRenderObj const *, HDC *, RECT const *, THEMESIZE, SIZE *) + C6 / r;
} MARGINS, *PMARGINS;
 
typedef enum _CLOSEBUTTONSTATES {
    CBS_NORMAL = 0x1,
    CBS_HOT = 0x2,
    CBS_PUSHED = 0x3,
    CBS_DISABLED = 0x4
} CLOSEBUTTONSTATES;
 
typedef struct _NCWNDMET {
    //00000000 fValid          dd ? ;
    //00000004 fFrame          dd ? ;
    //00000008 fSmallFrame     dd ? ;
    //0000000 fMin            dd ? ;
    //00000010 fMaxed          dd ? ;
    //00000014 fFullMaxed      dd ? ;
    //00000018 fDirtyRects     dd ? ;
    //0000001 fCustomFrame    dd ? ;
    //00000020 fCustom         dd ? ;
    ULONG dwStyle;
    ClassicWndProc dwExStyle;
    ULONG dwWindowStatus;
    ULONG dwStyleClass;
    WINDOWPARTS rgframeparts;
    WINDOWPARTS rgsizehitparts;
    FRAMESTATES framestate;
    _ClassicNcPaint hfCaption;
    SIZE sizeCaptionText;
    MARGINS CaptionMargins;
    ULONG iMinButtonPart;
    ULONG iMaxButtonPart;
    CLOSEBUTTONSTATES rawCloseBtnState;
    CLOSEBUTTONSTATES rawMinBtnState;
    CLOSEBUTTONSTATES rawMaxBtnState;
    CLOSEBUTTONSTATES rawHelpBtnState;
    ULONG cyMenu;
    ULONG cnMenuOffsetLeft;
    ULONG cnMenuOffsetRight;
    ULONG cnMenuOffsetTop;
    ULONG cnBorders;
    ClassicWndProc rcS0;
    ClassicWndProc rcW0;
    ULONG _rgbCaption;
    UCHAR _fIsCaptionColorValid;
    UCHAR undefined[7];
} NCWNDMET, *PNCWNDMET;
 
typedef enum _MSGTYPE {
    MSGTYPE_PRE_WNDPROC = 0,
    MSGTYPE_POST_WNDPROC = 1,
    MSGTYPE_PRE_DEFDLGPROC = 2,
    MSGTYPE_POST_DEFDLGPROC = 3,
    MSGTYPE_DEFWNDPROC = 4
} MSGTYPE;
 
typedef HRESULT(WINAPI *ThemePostDefDlgProc)(HWND *hwnd, ULONG uMsg, WPARAM wParam, LPARAM lParam, PLONG_PTR plRes, PVOID *ppvData);
 
typedef struct _THEME_MSG {
    HWND hwnd;
    ULONG uMsg;
    UCHAR undefined1[4];
    WPARAM wParam;
    LPARAM lParam;
    MSGTYPE type;
    ULONG uCodePage;
    PVOID pfnDefProc;
    ULONG_PTR lRet;
    ThemePostDefDlgProc fHandled;
    UCHAR undefined2[4];
} THEME_MSG, *PTHEME_MSG;
 
class CThemeWnd {
public:
    CThemeWnd();
    ~CThemeWnd();
private:
};
inline CThemeWnd::CThemeWnd(){}
CThemeWnd::~CThemeWnd(){}
 
typedef LRESULT(WINAPI *OnOwpPostThemeChanged)(CThemeWnd *pwnd, PTHEME_MSG ptm);
typedef HBRUSH(WINAPI *GetDialogColor)(HWND *hwnd);
 
typedef struct _NCTRANSPARENCY {
    ULONG _bf0;
} NCTRANSPARENCY, *PNCTRANSPARENCY;
 
typedef struct _NCTHEMEMET {
    OnOwpPostThemeChanged hTheme;
    //00000008 hThemeTab       dq ? ; offset;
    //00000010 dpi             dd ? ; XREF: CThemeWnd::GetNcWindowMetrics(tagRECT const *, NCWNDMET * *, _NCTHEMEMET *, ULONG) + 1A4 / r;
    ULONG _bf14;
    MARGINS marCaptionText;
    MARGINS marMinCaptionText;
    //00000028; CThemeWnd::GetNcWindowMetrics(tagRECT const *, NCWNDMET * *, NCTHEMEMET *, ULONG) + 82A / r;
    MARGINS marMaxCaptionText;
    MARGINS marSmCaptionText;
    ULONG dyMenuBar;
    ULONG cnSmallMaximizedWidth;
    ULONG cnSmallMaximizedHeight;
    SIZE sizeBtn;
    SIZE sizeSmBtn;
    UCHAR undefined[4];
    GetDialogColor hbrTabDialog;
    //00000080 hbmTabDialog    dq ? ; XREF: CThemeWnd::NcPaint(HDC *, ulong, HRGN *, _NCPAINTOVERIDE *) + 2CD / w;
    GetDialogColor hbrAeroTabDialog;
    //00000090 hbmAeroTabDialog dq ? ; XREF: CThemeWnd::NcPaint(HDC *, ulong, HRGN *, _NCPAINTOVERIDE *) + 22 / w;
    NCTRANSPARENCY nct;
    ULONG nGlowSize;
} NCTHEMEMET, *PNCTHEMEMET;
 
typedef LRESULT(WINAPI *_ThemeDefWindowProc)(HWND *hwnd, ULONG uMsg, WPARAM wParam, LPARAM lParam, BOOL bUnicode);
typedef HRESULT(WINAPI *ThemeGetScrollInfoProc)(HWND *hwnd, LONG nBar, LPSCROLLINFO psi);
typedef HRESULT(WINAPI *ThemeSetScrollInfoProc)(HWND *hwnd, LONG nBar, LPSCROLLINFO psi, LONG fRedraw);
typedef HRESULT(WINAPI *ThemeEnableScrollInfoProc)(HWND *hwnd, ULONG nSBFlags, ULONG nArrows);
typedef HRESULT(WINAPI *ClassicAdjustWindowRectEx)(RECT *prcWnd, ULONG dwStyle, LONG fMenu, ULONG dwExStyle);
typedef HRESULT(WINAPI *ThemeSetWindowRgn)(HWND *hwnd, HRGN *hrgn, LONG fRedraw);
typedef HRESULT(WINAPI *_GetNcBtnMetrics)(PNCWNDMET pncwm, PNCTHEMEMET pnctm, HICON *hAppIcon, LONG fCanClose);
typedef HRESULT(WINAPI *ClassicSystemParametersInfoA)(ULONG uiAction, ULONG uiParam, PVOID pvParam, ULONG fWinIni);
typedef HRESULT(WINAPI *ClassicSystemParametersInfoW)(ULONG uiAction, ULONG uiParam, PVOID pvParam, ULONG fWinIni);
typedef HRESULT(WINAPI *ThemeHookShutdown)(VOID);
typedef HRESULT(WINAPI *ThemeDrawFrameControl)(HDC *hdc, PRECT prc, ULONG uType, ULONG uState);
typedef HRESULT(WINAPI *ThemeDrawCaption)(HWND *hwnd, HDC *hdc, PRECT prc, ULONG uType);
typedef VOID(WINAPI *ThemeMDIRedrawFrame)(HWND *hwndChild, LONG fAdd);
typedef HRESULT(WINAPI *ClassicGetSystemMetricsForDpi)(LONG iMetric, ULONG dpi);
typedef HRESULT(WINAPI *ClassicSystemParametersInfoForDpi)(ULONG uiAction, ULONG uiParam, PVOID pvParam, ULONG fWinIni, ULONG dpi);
typedef HRESULT(WINAPI *_FreshenThemeMetricsCB)(HWND *hwnd, LPARAM lParam);
 
typedef struct _USERAPIHOOK {
    ULONG cbSize;
    UCHAR undefined[4];
    _ThemeDefWindowProc pfnDefWindowProcA;
    _ThemeDefWindowProc pfnDefWindowProcW;
    MSGMASK mmDWP;
    ThemeGetScrollInfoProc pfnGetScrollInfo;
    ThemeSetScrollInfoProc pfnSetScrollInfo;
    ThemeEnableScrollInfoProc pfnEnableScrollBar;
    ClassicAdjustWindowRectEx pfnAdjustWindowRectEx;
    ThemeSetWindowRgn pfnSetWindowRgn;
    USEROWPINFO uoiWnd;
    USEROWPINFO uoiDlg;
    _GetNcBtnMetrics pfnGetSystemMetrics;
    ClassicSystemParametersInfoA pfnSystemParametersInfoA;
    ClassicSystemParametersInfoW pfnSystemParametersInfoW;
    ThemeHookShutdown pfnForceResetUserApiHook;
    ThemeDrawFrameControl pfnDrawFrameControl;
    ThemeDrawCaption pfnDrawCaption;
    ThemeMDIRedrawFrame pfnMDIRedrawFrame;
    PVOID pfnBroadcastThemeChange; // import from USER32.dll!BroadcastThemeChangeEvent -> ntdll.dll!NtUserBroadcastThemeChangeEvent
    ClassicGetSystemMetricsForDpi pfnGetSystemMetricsForDpi;
    ClassicSystemParametersInfoForDpi pfnSystemParametersInfoForDpi;
    _FreshenThemeMetricsCB pfnGetWindowProcess;
} USERAPIHOOK, *PUSERAPIHOOK;
 
typedef struct _UXTHEMEHOOKS {
    HINSTANCE hInst;
    USERAPIHOOK guah;
} UXTHEMEHOOKS, *PUXTHEMEHOOKS;
Теперь переходим к коду и пишем свой сканер сигнатур
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
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
#include "apfnDispatch.h"
#include <Psapi.h>
#include <iostream>
 
#pragma comment (lib, "ntdll")
 
 
typedef struct _apfnDispatch {
    _ClientFreeLibrary ClientFreeLibrary;
    _ClientLoadLibrary ClientLoadLibrary;
} apfnDispatch;
 
typedef struct _apfnSignature {
#ifdef _WIN64
    BYTE pattren_ClientFreeLibrary[28] = {
        0x48,0x8B,0xC4,0x48,0x89,0x58,0x08,0x48,0x89,0x68,0x10,0x48,0x89,0x70,0x18,0x48,
        0x89,0x78,0x20,0x41,0x56,0x48,0x83,0xEC,0x40,0x48,0x8B,0x39
    };
    PCCH mask_ClientFreeLibrary = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
 
    BYTE pattren_ClientLoadLibrary[10] = {
        0x48,0x89,0x5C,0x24,0x10,0x48,0x89,0x7C,0x24,0x18
    };
    PCCH mask_ClientLoadLibrary = "xxxxxxxxxx";
#else
    BYTE pattren_ClientFreeLibrary[18] = {
        0x8B,0xFF,0x55,0x8B,0xEC,0x83,0xEC,0x18,0x53,0x56,0x57,0x8B,0x7D,0x08,0x33,0xDB,
        0x8B,0xF3
    };
    PCCH mask_ClientFreeLibrary = "xxxxxxxxxxxxxxxxxx";
 
    BYTE pattren_ClientLoadLibrary[34] = {
        0x8B,0xFF,0x55,0x8B,0xEC,0x81,0xEC,0x00,0x00,0x00,0x00,0xA1,0x00,0x00,0x00,0x00,
        0x33,0xC5,0x89,0x45,0xFC,0x53,0x56,0x57,0x8B,0x7D,0x08,0x8D,0x00,0x00,0x00,0x00,
        0x00,0x68
    };
    PCCH mask_ClientLoadLibrary = "xxxxxxx????x????xxxxxxxxxxxx?????x";
#endif // _WIN64
} apfnSignature;
 
 
apfnDispatch Dispatch = { 0 };
apfnSignature Signature;
 
 
bool DataCompare(PBYTE pData, PBYTE pattern, PCCH mask) {
    for (; *mask; mask++, pattern++, pData++)
        if (*mask == 'x' && *pData != *pattern)
            return false;
    return true;
}
 
 
ULONG_PTR FindPattern(ULONG_PTR addr, ULONG length, PBYTE pattern, PCCH mask) {
    MEMORY_BASIC_INFORMATION mbi = { 0 };
    SIZE_T offset = 0;
    while (offset < length) {
        VirtualQuery((LPCVOID)(addr + offset), &mbi, sizeof(MEMORY_BASIC_INFORMATION));
        if (mbi.State != MEM_FREE) {
            PBYTE buffer = new BYTE[mbi.RegionSize];
            ReadProcessMemory(GetCurrentProcess(), mbi.BaseAddress, buffer, mbi.RegionSize, nullptr);
            for (unsigned i = 0; i < mbi.RegionSize; i++)
                if (DataCompare(buffer + i, pattern, mask)) {
                    delete[] buffer;
                    return (ULONG_PTR)mbi.BaseAddress + i;
                }
            delete[] buffer;
        }
        offset += mbi.RegionSize;
    }
    return 0;
}
 
 
int main() {
    MessageBox(nullptr, TEXT("For initialize user32.dll"), TEXT("Message"), NULL);
#ifdef _WIN64
    auto pPeb = (PPEB)__readgsqword(0x60);
#else
    auto pPeb = (PPEB)__readfsdword(0x30);
#endif // _WIN64
    auto pList = pPeb->Ldr->InMemoryOrderModuleList.Flink;
    HMODULE hMod = nullptr;
    MODULEINFO hModInfo = { 0 };
    WCHAR buffer[MAX_PATH] = { 0 }, PathTo[MAX_PATH] = { 0 };
    GetWindowsDirectoryW(buffer, MAX_PATH);
    swprintf_s(PathTo, L"%s\\System32\\USER32.dll", buffer);
    for (int i = 0; i < 100; i++) {
        auto pDataTable = (PLDR_DATA_TABLE_ENTRY)(pList - 1);
        if (wcscmp(pDataTable->FullDllName.Buffer, PathTo) == 0) {
            GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (PCCH)pDataTable->DllBase, &hMod);
            GetModuleInformation(GetCurrentProcess(), hMod, &hModInfo, sizeof(MODULEINFO));
            break;
        }
        else pList = pList->Flink;
    }
 
    std::cout << "user32.dll!apfnDispatch (PEB.KernelCallbackTable): 0x" << pPeb->Reserved7 << std::endl;
 
    Dispatch.ClientFreeLibrary = (_ClientFreeLibrary)FindPattern((ULONG_PTR)hModInfo.lpBaseOfDll, hModInfo.SizeOfImage, Signature.pattren_ClientFreeLibrary, Signature.mask_ClientFreeLibrary);
    Dispatch.ClientLoadLibrary = (_ClientLoadLibrary)FindPattern((ULONG_PTR)hModInfo.lpBaseOfDll, hModInfo.SizeOfImage, Signature.pattren_ClientLoadLibrary, Signature.mask_ClientLoadLibrary);
 
    std::cout << "apfnDispatch.ClientFreeLibrary: 0x" << Dispatch.ClientFreeLibrary << "\napfnDispatch.ClientLoadLibrary: 0x" << Dispatch.ClientLoadLibrary << std::endl;
 
    UNICODE_STRING uStr_DLL = { 0 }, uStr_Func = { 0 };
    RtlInitUnicodeString(&uStr_DLL, L"\\??\\D:\\Games\\Red Dead Redemption 2\\vulkan-1.dll");
    RtlInitUnicodeString(&uStr_Func, L"vkCreateDevice");
 
    CAPTUREBUF CaptureBuf = { 0 };
    CaptureBuf.FixupsCount = 2;
    CaptureBuf.lpDLLPath = uStr_DLL;
    CaptureBuf.lpInitFunctionName = uStr_Func;
    CaptureBuf.bFixed = TRUE;
    CaptureBuf.BufferSize = sizeof(CAPTUREBUF);
    CaptureBuf.AdditionalDataSize = sizeof(CAPTUREBUF) - sizeof(PVOID) - 2 * sizeof(SIZE_T) - 3 * sizeof(ULONG);
    CaptureBuf.offCbkPtrs = 0x28;
    CaptureBuf.offCbk[1] = 0x8;
    CaptureBuf.lpfnNotify = 0x94C0;
 
    LRESULT Result = Dispatch.ClientLoadLibrary(&CaptureBuf);
 
    CHAR Message[MAX_PATH] = { 0 };
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, 0, 0, Message, MAX_PATH, nullptr);
 
    setlocale(LC_ALL, "Russian");
    std::cout << Message << std::endl;
 
    std::cin.get();
    return 0;
}
Делаем точку останова на __ClientLoadLibrary и видим с помощью символов user32.pdb, что всё получилось как нельзя лучше (адрес найден, функция инициализирована и захвачена нами)
Нажмите на изображение для увеличения
Название: 4.png
Просмотров: 318
Размер:	78.9 Кб
ID:	5679

По мере дальнейшего углубления в дебри __ClientLoadLibrary постараюсь реализовать до конца метод перехвата SetWindowsHookEx.
Размещено в Без категории
Просмотров 375 Комментарии 1
Всего комментариев 1
Комментарии
  1. Старый комментарий
    Аватар для _lunar_
    Поправил структуру _CAPTUREBUF и ещё кое-что по мелочам. Функция отрабатывает без каких-либо ошибок.
    Запись от _lunar_ размещена 30.10.2019 в 10:01 _lunar_ вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.