NtOpenFile() with ConDrv device shows 0xC0000005 error - winapi

I'm mimicking the connection between conhost.exe and condrv.sys driver. So I copied the code from conhost.exe in a simple C file and compiled it. But NtOpenFile() always shows 0xc0000005 error. Here is the code snippet.
RtlInitUnicodeString(&DestinationString, L"\\Device\\ConDrv\\Server");
ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
ObjectAttributes.RootDirectory = 0;
ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE;
ObjectAttributes.ObjectName = &DestinationString;
ObjectAttributes.SecurityDescriptor = 0;
status = NtOpenFile(&Handle, GENERIC_ALL, &ObjectAttributes, &IoStatusBlock, 0, 0);
How to modify that code to work properly? Am I doing anything wrong?

Thanks #RbMm for that advice. The OBJECT_ATTRIBUTES struct is defined as:
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
The error shows because I forget to make SecurityQualityOfService zero. So NtOpenFile() grabs the SecurityQualityOfService value from whatever left over in memory. And it shows 0xC0000005 aka. Memory Access Violation. I add ObjectAttributes.SecurityQualityOfService = 0; and it works.

Related

How to write memory of a dll?

I'm trying to replace a specific string in memory belongs to a dll. Here's the code.
I can read it, and it gives me correct result, but when writing VC++ shows 'Access violation writing location'.
HMODULE HMODULE1 = LoadLibrary(L"my.dll");
std::string x1(8, '\0');
std::string x2 = "CIFCDMEY";
auto startPos = (void*)((char*)(HMODULE1)+0x1158A0 + 9);
// Correct, I can read the memory
memcpy_s((void*)x1.data(), x1.size(), startPos, x1.size());
// Access violation writing location
memcpy_s(startPos, x2.size(), x2.data(), x2.size());
auto handle = GetCurrentProcess();
SIZE_T num;
auto ret = WriteProcessMemory(handle, startPos, x2.data(), x2.size(), &num);
auto lastError1 = GetLastError();
LPVOID lpMessageBuffer1 = NULL;
size_t size1 = ::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
lastError1,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMessageBuffer1,
0,
NULL);
std::wstring errorMessage1;
if (size1 > 0) {
// errorMessage1: Invalid access to memory location.
errorMessage1 = std::wstring((LPCTSTR)lpMessageBuffer1, size1);
}
In 'Watch' window, the value of variable startPos is my.dll!0x0f2a58a9 (load symbols for additional information).
I know people use 'WriteProcessMemory' to write memory of a process, how about a dll?
If the target memory page does not have write permissions you need to take them using VirtualProtect()
I use a simple wrapper function for all my patching, it uses the PAGE_EXECUTE_READWRITE memory protection constant because if you are modifying a code page this will avoid crashes when the instruction pointer lands in the same memory page and you only used PAGE_READWRITE
void Patch(char* dst, char* src, const intptr_t size)
{
DWORD oldprotect;
VirtualProtect(dst, size, PAGE_EXECUTE_READWRITE, &oldprotect);
memcpy(dst, src, size);
VirtualProtect(dst, size, oldprotect, &oldprotect);
}

SEH Handlers using RtlAddFunctionTable

I've been trying to setup SEH on x64 windows using gcc by calling the RtlAddFunctionTable. Unfortunately, the API call returns success but my handler doesn't seem to ever be called. And I can't find out what's wrong. My small example is:
EXCEPTION_DISPOSITION catchDivZero( struct _EXCEPTION_RECORD* rec
, void* arg1 __attribute__((unused))
, struct _CONTEXT* ctxt __attribute__((unused))
, void* arg2 __attribute__((unused))
)
{
printf("Exception will be handled!\n");
return ExceptionContinueSearch;
}
HMODULE GetCurrentModule()
{ // NB: XP+ solution!
HMODULE hModule = NULL;
GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)GetCurrentModule,
&hModule);
return hModule;
}
typedef struct {
UINT8 Version : 3;
UINT8 Flags : 5;
UINT8 SizeOfProlog;
UINT8 CountOfUnwindCodes;
UINT8 FrameRegister : 4;
UINT8 FrameRegisterOffset : 4;
ULONG ExceptionHandler;
} UNWIND_INFO;
/* Hack, for bug in ld. Will be removed soon. */
#if defined(__GNUC__)
#define __ImageBase __MINGW_LSYMBOL(_image_base__)
#endif
/* Get the end of the text section. */
extern char etext[] asm("etext");
/* Get the base of the module. */
/* This symbol is defined by ld. */
extern IMAGE_DOS_HEADER __ImageBase;
static UNWIND_INFO info[1];
static RUNTIME_FUNCTION handlers[1];
#define base (ULONG)((HINSTANCE)&__ImageBase)
int main()
{
HANDLE hProcess = GetCurrentProcess();
HMODULE hModule = GetCurrentModule();
MODULEINFO mi;
GetModuleInformation(hProcess, hModule, &mi, sizeof(mi));
printf( "Module: 0x%.8X (0x%.8X) 0x%.8X |0x%.8X| [0x%.8X] {0x%.8X}\n\n"
, mi.lpBaseOfDll
, base
, (char*)etext
, mi.SizeOfImage
, &catchDivZero
, (ULONG)(&catchDivZero - base)
);
printf("Building UNWIND_INFO..\n");
info[0].Version = 1;
info[0].Flags = UNW_FLAG_EHANDLER;
info[0].SizeOfProlog = 0;
info[0].CountOfUnwindCodes = 0;
info[0].FrameRegister = 0;
info[0].FrameRegisterOffset = 0;
info[0].ExceptionHandler = (ULONG)(&catchDivZero - base);
printf("Created UNWIND_INFO at {0x%.8X}\n", info[0].ExceptionHandler);
printf("Building SEH handlers...\n");
handlers[0].BeginAddress = 0;
handlers[0].EndAddress = (ULONG)(etext - base);
handlers[0].UnwindData = (ULONG)((char*)info - base);
printf("Adding SEH handlers to .pdata..\n");
printf("Handler Unwind: 0x%.8X\n", &info);
printf( "Handler Info:: s: 0x%.8X, e: 0x%.8X, u: 0x%.8X\n"
, handlers[0].BeginAddress
, handlers[0].EndAddress
, handlers[0].UnwindData
);
if (RtlAddFunctionTable(handlers, 1, (DWORD64)base))
{
printf("Hook succeeded.\nTesting..\n");
printf("Things to do: %i\n", 12 / 0);
}
else
{
printf("Hook failed\n");
DWORD result = GetLastError();
printf("Error code: 0x%.8X\n", result);
}
}
However when called the output I get is:
> .\a.exe
Module: 0x00400000 (0x00400000) 0x00402FF0 |0x00022000| [0x00401530] {0x00001530}
Building UNWIND_INFO..
Created UNWIND_INFO at {0x00001530}
Building SEH handlers...
Adding SEH handlers to .pdata..
Handler Unwind: 0x00407030
Handler Info:: s: 0x00000000, e: 0x00002FF0, u: 0x00007030
Hook succeeded.
Testing..
The message in my handler is never printed.
Any help/pointers would be greatly appreciated.
RtlAddFunctionTable() adds a dynamic function table; if there already is a static function table (.pdata section) for the base address, the RtlAddFunctionTable() calls succeeds, but the static function table still takes precedence.
You need to allocate memory outside the image range, e.g. using VirtualAlloc(), and have your code and runtime table and unwind info there. The address of allocated memory is the base address for all the RVAs in the tables, and needs to be passed to RtlAddFunctionTable().
You can experiment with RtlLookupFunctionEntry() to see if the function table entry is found for a given address.
Sample code showing RtlAddFunctionTable() in action is at https://pmeerw.net/blog/programming/RtlAddFunctionTable.html.
Didn't you forget to register your handler with call to SetUnhandledExceptionFilter (if you use SEH as stated in your post) or AddVectoredExceptionHandler (if you decide to switch to VEH)? In your code you add information about the handler but do not register it.
I have tested your sample with the change of the handler itself:
LONG WINAPI catchDivZero(EXCEPTION_POINTERS * ExceptionInfo)
{
printf("Exception will be handled!\n");
return ExceptionContinueSearch;
}
and adding the code:
if (::AddVectoredExceptionHandler(TRUE, catchDivZero))
{
printf("Set exception handler.\nContinuing..\n");
}
else
{
printf("Setting exception handler failed\n");
DWORD result = GetLastError();
printf("Error code: 0x%.8X\n", result);
return 1;
}
just before the call to RtlAddFunctionTable.
Now the message from the handler is printed.
To remove the handler use:
::RemoveVectoredExceptionHandler(catchDivZero);
Hope it helps.
Note: as an alternative you may use SetUnhandledExceptionFilter(catchDivZero)). Keep in mind that it's not that useful for debugging:
After calling this function, if an exception occurs in a process that
is not being debugged, and the exception makes it to the unhandled
exception filter, that filter will call the exception filter function
specified by the lpTopLevelExceptionFilter parameter.
With VEH way we can debug the handler function right in IDE, with SEH we can not (there is probably a solution to this but I do not know about it) so I've proposed VEH as the main solution.

UNICODE_STRING to std String Conversion

I am using pFileObject->FileName to get the name of file opened in a kernel mode filter driver.This file name returned by this is in the form of UNICODE_STRING. I want to convert it into std String. What is the method ??? Please do provide example if possible...
Below is the code
NTSTATUS FsFilterDispatchCreate(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp
)
{
PFILE_OBJECT pFileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
DbgPrint("%wZ\n", &pFileObject->FileName);
return FsFilterDispatchPassThrough(DeviceObject, Irp);
}
I agree with Hans' comment. Making std:: classes work in Windows kernel mode is extremely difficult if not impossible. The default WinDDK environment is C rather than C++. Your best bet is to convert UNICODE_STRING to ANSI null-terminated string. (You can print it with DbgPrint("%s"...) etc). See example below.
UNICODE_STRING tmp;
// ...
ANSI_STRING dest;
ULONG unicodeBufferSize = tmp.Length;
// Length of unicode string in bytes must be enough to keep ANSI string
dest.Buffer = (PCHAR)ExAllocatePool(NonPagedPool, unicodeBufferSize+1);
// check for allocation failure...
dest.Length = 0;
dest.MaximumLength = unicodeBufferSize+1;
RtlUnicodeStringToAnsiString(&dest, &tmp, FALSE);
// check for failure...
dest.Buffer[dest.Length] = 0; // now we get it in dest.Buffer

SIGSEGV handler and mprotect and looping effect when injecting instructions at runtime. Handler can't get info->si_addr

I have looked at the various topics relating to this, but couldn't find this specific issue I am having.
Things I looked at:
Injecting code into executable at runtime
C SIGSEGV Handler & Mprotect
Can I write-protect every page in the address space of a Linux process?
How to write a signal handler to catch SIGSEGV?
I am able to handle SIGSEGV gracefully when the protection needs to be set to either PROT_READ or PROT_WRITE in the handler. However, when I try to inject instructions with mmap, and then use mprotect to set it to PROT_READ only, and then I execute the instructions via inline assembly, it causes a SIGSEGV as intended, but the handler is unable to get the originating address causing the signal, so I am unable to mprotect it to PROT_READ | PROT_EXEC.
Example:
void sigHandler(int signum, siginfo_t *info, void *ptr) {
printf("Received signal number: %d\n", signum);
printf("Signal originates from process %lu\n",
(unsigned long)info->si_pid);
printf("SIGSEGV caused by this address: ? %p\n", info->si_addr);
char * alignedbaseAddr = (((unsigned int)(info->si_addr)) >> 12) * getPageSize();
printf("Aligning to %p\n", alignedbaseAddr);
//flip this page to be r+x
mprotect(alignedbaseAddr, getPageSize(), PROT_READ | PROT_EXEC);
}
void setupSignalHandler() {
action.sa_sigaction = sigHandler;
action.sa_flags = SA_SIGINFO;
sigemptyset(&action.sa_mask);
sigaction(SIGSEGV, &action, NULL);
}
int main(int argc, char *argv[]) {
char * baseAddr = (char*)mmap(NULL, getDiskSize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(baseAddr == MAP_FAILED) {
perror("Unable to mmap.");
}
printf("Process address space is %d\n", getDiskSize());
//no-op filler
for(int i = 0; i < (getDiskSize()) - 1; i++) {
baseAddr[i] = 0x90;
}
//ret instruction
baseAddr[i] = 0xc3;
if( mprotect(baseAddr, getDiskSize(), PROT_READ) == -1) {
perror("mprotect");
exit(1);
}
printf("Protecting addresses: %p to %p for READ_ONLY\n", baseAddr, baseAddr + getDiskSize() - 1);
setupSignalHandler();
__asm__
(
"call %%eax;"
: "=a" (output)
: "a" (baseAddr)
);
printf("Will this ever print?");
//close fd, and unmap memory
cleanUp();
return EXIT_SUCCESS;
}
Here is the resulting output:
Received signal number: 11
Signal originates from process 0
SIGSEGV caused by this address: ? (nil)
//the above output repeatedly loops, since it fails to "re mprotect" that page.
Architecture:
x86 32 bit
OS:
Ubuntu 11.04 - Linux version 2.6.38-12-generic (buildd#vernadsky) (gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) )
Any ideas? The above logic works fine for simply read and writing into memory. Is there
a better way to execute instructions at runtime as opposed to inline assembly?
Thanks in advance!
In that case, the faulting address is the instruction pointer. Cast your third argument ptr (of your signal handler installed with SA_SIGINFO) to a ucontext_t, and retrieve the appropriate register, perhaps as (untested code!)
ucontext_t *uc = ptr;
void* faultyip = uc->uc_mcontext.gregs[REG_IP];
Read carefully /usr/include/sys/ucontext.h for more.
I'm interested to know why you are asking!!

SetFilePointerEx fails to read physical disk beyond size of LONG

It's taken a few years, but I am finally taking the plunge into VC++. I need to be able to read x number of sectors of a physical device (namely a hard drive). I am using the CreateFile() and SetFilePointerEx() and ReadFile() APIs.
I have done a LOT of reading online in all the major forums about this topic. I have exhausted my research and now I feel it's time to ask the experts to weigh in on this dilemma. As this is my very first post ever on this topic, please go easy on my :)
I should also point out that this is a .DLL that I consume with a simple C# app. The plumbing all works fine. It's the SetFilePointer(Ex)() APIs that are causing me grief.
I can get the code to work up until about the size of a LONG (4,xxx,xxx) - I can't remember the exact value. It suffices to say that I can read everything up to and including sector # 4,000,000 but not 5,000,000 or above. The problem lies in the "size" of the parameters for the SetFilePointer() and SetFilePointerEx() APIs. I've tried both and so far, SetFilePointerEx() seems to be what I should use to work on 64-bit systems.
The 2nd and 3rd parameters of the SetFilePointer are defined as follows:
BOOL WINAPI SetFilePointerEx(
__in HANDLE hFile,
__in LARGE_INTEGER liDistanceToMove,
__out_opt PLARGE_INTEGER lpNewFilePointer,
__in DWORD dwMoveMethod
);
Please note that I have tried passing the LowPart and the HighPart as the 2nd and 3 parameters without any success as I get a CANNOT CONVERT LARGE_INTEGER TO PLARGE_INTEGER (for parameter 3).
HERE IS MY CODE. I USE A CODE-BREAK TO VIEW buff[0], etc. I would like to read past the 4,xxx,xxx limitation. Obviously I am doing something wrong. Each read past this limit resets my file pointer to sector 0.
#include "stdafx.h"
#include <windows.h>
#include <conio.h>
extern "C"
__declspec(dllexport) int ReadSectors(long startSector, long numSectors)
{
HANDLE hFile;
const int SECTOR_SIZE = 512;
const int BUFFER_SIZE = 512;
LARGE_INTEGER liDistanceToMove;
PLARGE_INTEGER newFilePtr = NULL; // not used in this context.
// just reading from START to END
liDistanceToMove.QuadPart = startSector * SECTOR_SIZE;
DWORD dwBytesRead, dwPos;
LPCWSTR fname = L"\\\\.\\PHYSICALDRIVE0";
char buff[BUFFER_SIZE];
// Open the PHYSICALDEVICE as a file.
hFile = CreateFile(fname,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
// Here's the API definition
/*BOOL WINAPI SetFilePointerEx(
__in HANDLE hFile,
__in LARGE_INTEGER liDistanceToMove,
__out_opt PLARGE_INTEGER lpNewFilePointer,
__in DWORD dwMoveMethod
);*/
dwPos = SetFilePointerEx(hFile, liDistanceToMove, NULL, FILE_BEGIN);
if(ReadFile(hFile, buff, BUFFER_SIZE, &dwBytesRead, NULL))
{
if(dwBytesRead > 5)
{
BYTE x1 = buff[0];
BYTE x2 = buff[1];
BYTE x3 = buff[2];
BYTE x4 = buff[3];
BYTE x5 = buff[4];
}
}
// Close both files.
CloseHandle(hFile);
return 0;
}
startSector * SECTOR_SIZE;
startSector is a long (32bits), SECTOR_SIZE is a int (also 32bits), multiply these two guys and the intermediate result is going to be a long, which will overflow and you then stuff it into the __int64 of the LARGE_INTEGER, which is too late. You want to operate on __int64s, something like
liDistanceToMove.QuadPart = startSector;
liDistanceToMove.QuadPart *= SECTOR_SIZE;
for example.

Resources