If I'm not wrong, A handle is an index inside a table maintained on per process basis.
For 64bit Windows, Each entry in this table is made up of 8 byte address to the kernel object + 4 byte of access mask making the entry 12 byte long. However as I understood, for alignment purpose each entry made 16 byte long.
But when you you look at handle opened by a process using process explorer, Value of handle are in multiple of 4. Shouldn't this be in multiple of 16 instead?
A Windows handle is just an index per se, it could be a multiple of 1 in principle. It has been probably more efficient to implent a word (16 bit value) alignment than the byte alignment you're implying.
The lowest two bits of a kernel handle are called "tag bits" and are available for application use. This has nothing to do with the size of an entry in the handle table.
The comment in ntdef.h (in Include\10.0.x.x\shared) says:
//
// Low order two bits of a handle are ignored by the system and available
// for use by application code as tag bits. The remaining bits are opaque
// and used to store a serial number and table index.
//
#define OBJ_HANDLE_TAGBITS 0x00000003L
My guess is that it's a similar misuse like using the most significant bit of 32 bit pointers as a boolean flag, which is why we have LAA (large address aware) and non-LAA applications.
You could (but should not) add 1, 2 or 3 to a HANDLE and it should not affect other Windows API methods. E.g. WaitForSingleObject():
#include <iostream>
#include <windows.h>
int main()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
auto created = CreateProcess(L"C:\\Windows\\System32\\cmd.exe",
nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi
);
if (created)
{
pi.hProcess = static_cast<byte*>(pi.hProcess) + 3;
const auto result = WaitForSingleObject(pi.hProcess, INFINITE);
if (result == 0)
std::cout << "Completed!\n";
else
std::cout << "Failed!\n" << result << "\n";
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else
std::cout << "Not created";
}
Related
I have a problem. As far as I know, processes in Windows share dynamic-linked libraries among each other, allowing only one instance of every library to exist at once in the memory. Knowing that, I wrote a small program in C, which can change some data in this shared section. In my example, I chose to change the beginning of MessageBoxW function. This is the code:
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#define SIZE 12 // size of JMP byte array defined below
int WINAPI CustomMessageBoxW(HWND, LPCWSTR, LPCWSTR, UINT);
void BeginRedirect(LPVOID);
// JMP bytes translated to assembly (x64):
// mov rax, 0x1234567890ABCDEF - this value will be changed to newFunction address, in BeginRedirect procedure
// jmp rax - jump to newFunction
BYTE JMP[SIZE] = { 0x48, 0xB8, 0xEF, 0xCD, 0xAB, 0x90, 0x78, 0x56, 0x34, 0x12, 0xFF, 0xE0 };
DWORD oldProtect, myProtect = PAGE_EXECUTE_READWRITE;
int main()
{
printf("MessageBoxW address: %p\n", MessageBoxW);
printf("redirect? ");
char res[4];
scanf_s("%4s", res, _countof(res));
if (strcmp(res, "yes") == 0) // redirect
{
printf("redirecting...\n");
BeginRedirect(MessageBoxW, CustomMessageBoxW);
}
while (1)
{
MessageBoxW(NULL, L"This is original MessageBoxW", L"Caption", MB_OKCANCEL);
printf("MessageBoxW address: %p\nBytes:\n", MessageBoxW);
for (int i = 0; i < 20; i++)
{
printf("0x%hhX ", *((char*)MessageBoxW + i));
}
puts("\n");
SleepEx(1000, FALSE);
}
}
void BeginRedirect(LPVOID oldFunction, LPVOID newFunction)
{
BYTE tempJMP[SIZE];
memcpy(tempJMP, JMP, SIZE);
BOOL result = VirtualProtect(oldFunction, SIZE, PAGE_EXECUTE_READWRITE, &oldProtect);
printf("\tVirtualProtect result: %u\n", result);
memcpy(tempJMP + 2, &newFunction, 8); // change the basic 0x1234... address to the actual function address
memcpy(oldFunction, tempJMP, SIZE);
result = VirtualProtect(oldFunction, SIZE, oldProtect, &myProtect);
printf("\tVirtualProtect result: %u\n", result);
}
int WINAPI CustomMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uiType)
{
printf("MyMessageBoxW: Custom message\n");
}
The program allows to choose if I want to redirect the function in the current instance of the program. Here comes the interesting part.
I run a first instance. When asked if to redirect, I type "yes", so the program does. It changes the beginning code of MessageBoxW, so that it points to my CustomMessageBoxW. Then, in the while loop, the program executes MessageBoxW every second and outputs some debugging information (first 20 bytes of the function). In this instance, the redirection works properly and instead of popup, the program outputs "MyMessageBoxW: Custom message" every second (as expected in CustomMessageBoxW)
Then, I run the second instance of the program (the first instance still executes!). Now, I decide not to redirect the function (type anything apart from "yes"). From the information printed by both instances about their MessageBoxW addresses, I can see that they're clearly identical. At that point, I thought that if the addresses are the same (both instances share one instance of user32.dll which contains MessageBoxW), then the second instance which didn't modify the MessageBoxW function itself will still attempt to execute the CustomMessageBoxW, which will probably result in memory access violation. But no. It turns out that the second instance works just fine and pops up a standard Windows message box, while the first instance (which still runs) still executes the redirected function (remember that in both program instances, the addresses of MessageBoxW are the same). Apart from that, the bytes outputed by
printf("MessageBoxW address: %p\nBytes:\n", MessageBoxW);
for (int i = 0; i < 20; i++)
{
printf("0x%hhX ", *((char*)MessageBoxW + i));
}
are completely different in both instances, while the function address is still the same.
I even decided to debug both instances at the same time using WinDbg, and it also showed that both instances stored different values under the same address. I'd really appreciate it if someone figured out what is actually going round here. Thanks!
I wanted to try seeing the limits on how "far" i can point to in 64 bit C program by trying to map very far addresses, as close to 64 bit as possible into valid memory by using VirtualAlloc.
I managed to get to 0x6ffffffffff which is a 42 bit address, but any number above that results in failure to allocate, with error code 0x57(The parameter is incorrect).
This is my code:
#include <Windows.h>
#include <stdio.h>
int main(int argc, char **argv)
{
LPVOID mem;
WCHAR message[] = L"Hello, World!";
mem = VirtualAlloc (
(LPVOID)0x00006ffffffffff,
4096,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE
);
if (mem == 0) {
wprintf(L"%x.\n", GetLastError());
system("pause");
exit(-1);
}
memcpy(mem, message, sizeof(message));
wprintf(L"[%llx] -> %ls\n", mem, mem);
system("pause");
return 0;
}
Why can't I VirtualAlloc above 0x6ffffffffff?
The explanation is that the address you request is outside of the available range. Although there is a theoretical 64 bit range of available addresses, in practise not all of that range is available to a user mode application. You can find the allowable range by calling GetSystemInfo and inspecting the values of lpMinimumApplicationAddress and lpMaximumApplicationAddress. If you attempt to reserve an address outside of this range, the call to VirtualAlloc will fail and the error code is set to ERROR_INVALID_PARAMETER.
Note that these minimum and maximum values are not precise. You will start observing ERROR_INVALID_PARAMETER when you get close to the limits.
I retrieve the serial number of the physical hard-drive using the function DeviceIoControl following the suggestions from Blacktempel in this post. Getting the number works fine in principle, but I (still) have trouble with the format of the serial number as it keeps changing from computer to computer and with time. Also I experienced a format change on some computers between running the program as normal user or as admin.
For example, I retrieved a number with the following format:
WD-WCAZAF632086
when I tested the program first and after a few weeks it looks like:
2020202057202d4443575a414641333630323638
This is still the same number, only the characters have been replaced by their hex codes and swapped pair-wise. I've encountered different formats like a normal string with the characters exchanged pair-wise. Among other values, I need to check this number to verify if a software license is valid for a certain computer. Having an instable and unknown format is annoying and if the format changes to something I'm not yet aware of, I risk that the software license check fails although the license is still valid.
Does anyone know how to get the serial number in a stable format, or how to predict the format so it can be adapted for comparison?
Here is minimal C++ example of code that I used to retrieve the serial number of the first physical disc. I build it using Visual Studio 2015:
#include "stdafx.h"
#include "Windows.h"
#include <string>
#include <vector>
#include <iostream>
bool GetDeviceString(std::string &serialnumber)
{
HANDLE deviceHandle = CreateFileW(L"//./PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); // Get Handle to device
if (deviceHandle == INVALID_HANDLE_VALUE) // Check if Handle is valid
return false;
STORAGE_PROPERTY_QUERY query{};
query.PropertyId = StorageDeviceProperty;
query.QueryType = PropertyStandardQuery;
STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader = { 0 };
DWORD dwBytesReturned;
if (!DeviceIoControl(deviceHandle, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(STORAGE_PROPERTY_QUERY),
&storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER), &dwBytesReturned, NULL))
{
}
// Alloc the output buffer
const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
std::vector<BYTE> pOutBuffer(dwOutBufferSize,0);
if (!DeviceIoControl(deviceHandle, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(STORAGE_PROPERTY_QUERY),
pOutBuffer.data(), dwOutBufferSize,
&dwBytesReturned, NULL))
{
// handle error, do cleanup and return
}
STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = (STORAGE_DEVICE_DESCRIPTOR*)pOutBuffer.data();
const DWORD dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset;
if (dwSerialNumberOffset != 0)
{
// Finally, get the serial number
serialnumber = (char*)(pOutBuffer.data() + dwSerialNumberOffset);
}
}
int main()
{
std::string serialnumber;
if (GetDeviceString(serialnumber))
{
std::cout << "serial number of first disc: " << serialnumber << std::endl;
}
else
{
std::cout << "Failed!" << std::endl;
}
std::cin.ignore();
return 0;
}
I want to turn on a LED using C, meaning that I want to write on parallel port.
but the code doesn't work.
I use char ledStatus instead of BYTE ledStatus. is there any difference??
what is the problem in this code?
#include <windows.h>
#include <conio.h>
#include <staio.h>
#define LED_ON 1
int main()
{
HANDLE h;
unsigned long dwSize=1;
int success;
h = CreateFile(
L"LPT1",
GENERIC_WRITE, // access (read-write) mode
0, // share mode
NULL, // pointer to security attributes
OPEN_EXISTING, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL // handle to file with attributes to copy
);
if (INVALID_HANDLE_VALUE == h)
{
//Handle Error
printf("CreateFile failed with error %d\n", GetLastError());
exit(1);
}
else
{
printf("CreateFile1 Successful\n");
}
char ledStatus;
// turn on LED
ledStatus = LED_ON;
success = WriteFile(h, &ledStatus, 1, &dwSize, NULL);
if (success)
{
printf("File Write Successful - %i bytes\n", dwSize);
}
else
{
printf("File Write Failed\n");
}
// close port
CloseHandle(h);
return 0;
}
Your question is very poorly documented, you didn't describe what signal you used or how you wired the LED. Lots of ways to get that wrong. But you have no hope of making it work with the standard Windows parallel driver. It was written to interface parallel devices like printers. Which requires handshaking to clock a byte to the device. The driver turns on the STROBE signal, the device must turn on the ACK signal to acknowledge it copied the byte. That of course doesn't happen, the WriteFile() calls only fill a buffer in the driver.
You'll need another driver to directly control the output lines, Inpout32 is a common choice. Find essential advice in Jan Axelson's book, also includes a link to Inpout32.
How does one use VirtualAllocEx do make room for a code cave? I am currently in possession of a piece of software with very little "free space" and I read that VirtualAllocEx is used for making this space..
After the question about "code cave" is cleared, you can find interesting following code which enumerate blocks allocated by VirtualAllocEx in the current process and find all PE (DLLs and the EXE itself).
SYSTEM_INFO si;
MEMORY_BASIC_INFORMATION mbi;
DWORD nOffset = 0, cbReturned, dwMem;
GetSystemInfo(&si);
for (dwMem = 0; dwMem<(DWORD)si.lpMaximumApplicationAddress;
dwMem+=mbi.RegionSize) {
cbReturned = VirtualQueryEx (GetCurrentProcess(), (LPCVOID)dwMem, &mbi,
sizeof(mbi));
if (cbReturned) {
if ((mbi.AllocationProtect & PAGE_EXECUTE_WRITECOPY) &&
(mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY))) {
if (*(LPWORD)mbi.AllocationBase == IMAGE_DOS_SIGNATURE) {
IMAGE_DOS_HEADER *pDosHeader =
(IMAGE_DOS_HEADER *)mbi.AllocationBase;
if (pDosHeader->e_lfanew) {
IMAGE_NT_HEADERS32 *pNtHeader = (IMAGE_NT_HEADERS32 *)
((PBYTE)pDosHeader + pDosHeader->e_lfanew);
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
continue;
// now you can examine of module loaded in current process
}
}
}
}
}
The code could looks like a large loop. In reality it is a typical application it makes about 200 loops, so it is very quickly to goes through all blocks allocated with respect of VirtualAllocEx during loading of EXE all all depended DLLs.
#include <stdio.h>
#include <windows.h>
#include <commctrl.h>
unsigned long pid;
HANDLE process;
GetWindowThreadProcessId(listview, &pid);
process = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ | PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid);
int *vptr = (int *)VirtualAllocEx(process, NULL, sizeof(int), MEM_COMMIT, PAGE_READWRITE);
References
- MSDN VirtualAllocEx Function
- CodeProject Stealing Program's Memory
- StackOver What is a code cave... ?
HTH,