I seek for any lib or function to convert a string of assembly code to machine code,
like the following:
char asmString[] = {"mov eax,13H"};
byte[] output; // array of byte
output = asm2mach(asmString); // {0xB8, 0x13, 0x00, 0x00, 0x00}
The motivation is to inject machine code to call asm function in the program. This injection mainly has 3 steps: VirtualAllocEx, WriteProcessMemory and CreateRemoteThread. Here are the code:
bool injectAsm(const char* exeName,const byte* code, int size)
{
LPVOID allocAddr = NULL;
HANDLE ThreadProcess = NULL;
HANDLE hProcess = OpenProcessEasy(exeName);
allocAddr = VirtualAllocEx(hProcess, NULL, size, MEM_COMMIT, PAGE_READWRITE);
if(allocAddr){
if(WriteProcessMemory(hProcess, allocAddr, code, size, NULL)) {
ThreadProcess = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)allocAddr, NULL, 0, NULL);
WaitForSingleObject(ThreadProcess, INFINITE);
VirtualFreeEx(hProcess,allocAddr, 0, MEM_RELEASE);
CloseHandle(ThreadProcess);
return true;
}
}
if(allocAddr){
VirtualFreeEx(hProcess, allocAddr, 0, MEM_RELEASE);
}
return false;
}
int main()
{
byte code[] = {0xB8, 0x10, 0xED, 0x4A, 0x00, 0xFF, 0xD0, 0xC3, 0x90};
injectAsm("game.exe",code,sizeof(code));
system("pause");
return 0;
}
I would recommend using both AsmJit and AsmTK. AsmTK is a new project that uses AsmJit as a toolkit and adds additional functionality on top of it. NOTE that at the moment AsmTK requies asmjit:next branch to work, as this is a new functionality.
This is a minimal example that uses AsmTK to parse some asm:
#include <stdio.h>
#include <stdlib.h>
#include <asmtk/asmtk.h>
using namespace asmjit;
using namespace asmtk;
static const char someAsm[] =
"test eax, eax\n"
"jz L1\n"
"mov eax, ebx\n"
"mov eax, 0xFFFFFFFF\n"
"pand mm0, mm1\n"
"paddw xmm0, xmm1\n"
"vpaddw ymm0, ymm1, ymm7\n"
"vaddpd zmm0 {k1}{z}, zmm1, [rax] {1tox}\n"
"L1:\n";
int main(int argc, char* argv[]) {
CodeHolder code;
// Here select the target architecture - either X86 or X64.
code.init(CodeInfo(Arch::kTypeX64));
X86Assembler a(&code);
AsmParser p(&a);
Error err = p.parse(someAsm);
if (err) {
printf("ERROR: %0.8x (%s)\n", err, DebugUtils::errorAsString(err));
return 1;
}
// The machine-code is now stored in CodeHolder's first section:
code.sync();
CodeBuffer& buffer = code.getSection(0)->buffer;
// You can do whatever you need with the buffer:
uint8_t* data = buffer.data;
size_t length = buffer.length;
return 0;
}
AsmJit uses JitRuntime to allocate executable memory and to relocate the resulting machine code into it. However, AsmJit's virtual memory allocator can be created with hProcess, which could be your remote process handle, so it can also allocate memory of that process. Here is a small example of how it could be done:
bool addToRemote(HPROCESS hRemoteProcess, CodeHolder& code) {
// VMemMgr is AsmJit's low-level VM manager.
VMemMgr vm(hRemoteProcess);
// This will tell `vm` to not destroy allocated blocks when it
// gets destroyed.
vm.setKeepVirtualMemory(true);
// Okay, suppose we have the CodeHolder from previous example.
size_t codeSize = code.getCodeSize();
// Allocate a permanent memory of `hRemoteProcess`.
uint64_t remoteAddr = (uint64_t)
vm.alloc(codeSize, VMemMgr::kAllocPermanent);
// Temporary buffer for relocation.
uint8_t* tmp = ::malloc(code.getCodeSize());
if (!tmp) return false;
// First argument is where to relocate the code (it must be
// current's process memory), second argument is the base
// address of the relocated code - it's the remote process's
// memory. We need `tmp` as it will temporarily hold code
// that we want to write to the remote process.
code.relocate(tmp, remoteAddr);
// Now write to the remote process.
SIZE_T bytesWritten;
BOOL ok = WriteProcessMemory(
hRemoteProcess, (LPVOID)remoteMem, tmp, codeSize, &bytesWritten);
// Release temporary resources.
::free(tmp);
// Now the only thing needed is the CreateRemoteThread thingy...
return ok;
}
I would recommend wrapping such functionality into a new RemoteRuntime to make it a matter of a single function call, I can help with that if needed.
You should define what you really want:
Do you want to generate machine code at runtime? Then use some JIT compilation library like libgccjit, libjit, LLVM, GNU lightning, or asmjit. asmjit is a library emitting x86 machine code, probably what you need. There is no absolute need to use a string containing assembler code.
Or do you want to translate some assembler syntax (and there are several assembler syntaxes even for x86) to object code or machine code? Then you'll better run a real assembler as an external program. The produced object code will contain relocation directives, and you'll need something to handle these (e.g. a linker).
Alternative, you should consider generating some (e.g.) C code at runtime, then forking a compilation, and dynamically loading and using the resulting function at runtime (e.g. with dlopen(3) and dlsym). See this
Details are obviously operating system, ABI, and processor specific.
Here is a project that can convert a string of assembly code (Intel or ARM) into its corresponding bytes.
https://github.com/bsmt/Assembler
It's written in Objective-C, but the source is there. I hope this helps.
Related
This is an experiment to exploit the availability of a 32-bit "compatibility" mode selector in GDT in Windows x64 which has the value of 0x23.
I 've successfully loaded a x86 DLL into the address space of a x64 application. This is done by first taking all imports of the x86 dll and saving it into a XML, then using a modified MemoryModule to load the DLL from memory and patch the Import Address Table with those pointers.
Then, in the x64 host I jump to a compatibility code segment:
push 0x23
xor rcx,rcx
mov ecx,Start32
push rcx
retf
Start32 is a 32-bit entry point that would call a configured function:
USE32
push eax
push dword [WhatToPass]
mov eax, [WhatToCall]
call eax
pop eax
Then go back to 64-bit
USE64
db 0eah
ret_64:
dd 0
dw 0x33
nop
This works, as long as the configured exp1 function does practically nothing. The concept is fully discussed in my CodeProject article and the source is on GitHub.
It doesn't work when run in Visual Studio, but it does work when run in WinDbg; WinDbg shows a 'x86' running mode when switching.
Now the ambitious project is to call the API from the x86 module. This fails even with a simple MessageBeep(0);. I don't of course expect it at this point to go fully to the function but it doesn't even enter; I get an invalid execution instruction on the call. The address is valid.
What could be wrong? Yes this is too much perhaps but I'm still curious.
Patching the IAT works correctly. Sample code:
void PatchIAT(HINSTANCE h,std::vector<FANDP>* CustomLoading = 0)
{
PCHAR codeBase = (PCHAR)h;
XML3::XML x(xResult);
PIMAGE_NT_HEADERS32 ntheaders = (PIMAGE_NT_HEADERS32)(PCHAR(h) + PIMAGE_DOS_HEADER(h)->e_lfanew);
PIMAGE_SECTION_HEADER pSech = IMAGE_FIRST_SECTION(ntheaders);//Pointer to first section header
DWORD ulsize = 0;
PIMAGE_IMPORT_DESCRIPTOR importDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(h, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulsize);
if (!importDesc)
return;
for (; importDesc && importDesc->Name; importDesc++) {
PSTR pszModName = (PSTR)((PBYTE)h + importDesc->Name);
if (!pszModName)
break;
XML3::XMLElement* module = ... ; // find the XML entry
if (!module)
continue;
DWORD* thunkRef;
DWORD* funcRef = 0;
if (importDesc->OriginalFirstThunk) {
thunkRef = (DWORD*)(codeBase + importDesc->OriginalFirstThunk);
funcRef = (DWORD*)(codeBase + importDesc->FirstThunk);
}
else {
// no hint table
thunkRef = (DWORD*)(codeBase + importDesc->FirstThunk);
funcRef = (DWORD *)(codeBase + importDesc->FirstThunk);
}
DWORD V = 0;
for (; *thunkRef; thunkRef++, funcRef++) {
DWORD* wr = (DWORD*)funcRef;
if (IMAGE_SNAP_BY_ORDINAL(*thunkRef)) {
// *funcRef = module->getProcAddress(handle, (LPCSTR)IMAGE_ORDINAL(*thunkRef), module->userdata);
const char* fe = (LPCSTR)IMAGE_ORDINAL(*thunkRef);
// find V from xml
...
}
else {
PIMAGE_IMPORT_BY_NAME thunkData = (PIMAGE_IMPORT_BY_NAME)(codeBase + (*thunkRef));
// *wr = module->getProcAddress(handle, (LPCSTR)&thunkData->Name, module->userdata);
... // Find V from XML
}
// Patch it now...
DWORD dwOldProtect = 0;
if (VirtualProtect((LPVOID)wr, 4, PAGE_READWRITE, &dwOldProtect))
{
memcpy((void*)wr, &V, 4);
VirtualProtect((LPVOID)wr, 4, dwOldProtect, &dwOldProtect);
}
VirtualProtect((LPVOID)V, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect);
}
}
}
I'm trying to create a mod loader for an 18 year old game to help me get better at c++. Right now I'm just trying to inject a dll into the same process of the mod loader. The sample dll just prints some text to the command window but doesn't. I think that the code that I have loading the entry point of the dll is not working because everything works up until I call the entry point function of my sample dll within my ModLoader.exe, and Visual Studio just throws an Access Violation. I poked through the memory viewer in debug mode within visual studio to try and see where my ModLoader program thinks the dll entry point is located within the dll but the address just points to a bunch of zeros. I recently learned the PE file format and tried to understand all the code that I wrote when I was following a tutorial on Youtube on how to do this, so forgive me for my inexperience I'm just trying to learn. The other code that I do not show is me locating and finding the target process, reading the dll binary, getting the headers from the dll, me allocating space on the target process for the dll, and finally me writing all of the section header data into the target process. I can provide any other code that y'all would like to see!
Injector.h
using ModLoader_LoadLibrary = HINSTANCE(WINAPI*)(const char* filename);
using ModLoader_GetProcAddress = UINT_PTR(WINAPI*)(HINSTANCE module, const char* procName);
using ModLoader_DllEntry = BOOL(WINAPI*)(HINSTANCE dll, DWORD reason, LPVOID reserved);
struct ModLoader_ManualMapping_Data
{
ModLoader_LoadLibrary ML_LoadLibrary; //Function pointer to the windows load library function
ModLoader_GetProcAddress ML_ProcAddress; //Function pointer to a function to be called
HINSTANCE ML_Module; //dll instance
};
Injector.cpp : Shellcode function that'll run alongside the target executable
void __stdcall Shellcode(ModLoader_ManualMapping_Data* data)
{
if (!data)
return;
BYTE* pData = reinterpret_cast<BYTE*>(data);
IMAGE_OPTIONAL_HEADER& optHeader = reinterpret_cast<IMAGE_NT_HEADERS*>(pData + reinterpret_cast<IMAGE_DOS_HEADER*>(pData)->e_lfanew)->OptionalHeader;
auto loadLibrary = data->ML_LoadLibrary;
auto procAddress = data->ML_ProcAddress;
auto dllLoad = reinterpret_cast<ModLoader_DllEntry>(pData + optHeader.AddressOfEntryPoint); //Loads entry point func from dll
BYTE* locationDelta = pData - optHeader.ImageBase; //pData = the new address | ImageBase = preferred address -> Get the difference between the two to add to every address in the relocation table
if (locationDelta) //THIS DOES NOT GET RAN
{
//Adds the delta value to all addresses within the base relocation table
}
//Import table
if (optHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
{
IMAGE_IMPORT_DESCRIPTOR* imgImport = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR*>(pData
+ optHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (imgImport->Name) //THIS DOES NOT GET RAN B\C imgImport is all zeros.
{
//Loops through import table
}
}
if (optHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size) //THIS DOES NOT GET RAN
{
//Calls the callback functions within dll
}
dllLoad(reinterpret_cast<HINSTANCE>(pData), DLL_PROCESS_ATTACH, nullptr); //PROBLEM: ACCESS VIOLATION
}
Injector.cpp : bool ManualMapping(HANDLE process, const char* dllFilepath)
-- This function is called in main.cpp.
The srcData variable is just the binary contents of the dll
ModLoader_ManualMapping_Data loadData = { 0 };
loadData.ML_LoadLibrary = LoadLibraryA;
loadData.ML_ProcAddress = reinterpret_cast<ModLoader_GetProcAddress>(GetProcAddress);
memcpy(srcData, &loadData, sizeof(loadData));
WriteProcessMemory(process, locOfDll, srcData, 0x1000, nullptr);
void* shellCodeBase = VirtualAllocEx(process, nullptr, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); //Allocates 0x1000 bytes in the process memory for the shellcode
WriteProcessMemory(process, shellCodeBase, Shellcode, 0x1000, nullptr); //Injects the Shellcode function into the process
HANDLE thread = nullptr;
thread = CreateRemoteThread(process, nullptr, 0, reinterpret_cast<PTHREAD_START_ROUTINE>(shellCodeBase), locOfDll, 0, nullptr); //Runs
Finally the sample dll code
#include <Windows.h>
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD reason_for_call, LPVOID lpReserved)
{
switch (reason_for_call)
{
case DLL_PROCESS_ATTACH:
OutputDebugStringA("Injected!");
break;
}
return TRUE;
}
EDIT
After rewriting all the code and looking at it all day I finally figured it out. I just had to make sure that the parameters were right when I called dllLoad!
I'm trying to hook a function with a lock xcmpchg16b. I have tried about 20 different things.
Expected result:
In real func
In hook func
Result in Debug build:
Exception thrown at 0x..: 0xC0000005 Access violation reading 0xFFFFFFFFFFFFFFFF
I'm not sure why it is trying to read from 0xFFFFFFFFFFFFFFFF, none of the pointers go there.
In a Release build, it doesn't crash! But it doesn't hook the function either.
Source:
#include <stdio.h>
#include <Windows.h>
int RealFunc()
{
printf("In real func\n");
return 2;
}
int HookFunc()
{
printf("In hook func\n");
return 1;
}
int main()
{
DWORD dwOld;
if (!VirtualProtect(&RealFunc, 0x1000, PAGE_EXECUTE_READWRITE, &dwOld))
{
printf("Unable to make mem RWX.\n");
return 0;
}
RealFunc();
__declspec(align(16)) PVOID ProcAddress = &RealFunc;
__declspec(align(16)) LONG64 Restore[2];
Restore[0] = 0x0000000025ff9090; // nop, nop, jmp [rip + 0]
Restore[1] = (LONG64)&HookFunc;
_InterlockedCompareExchange128((LONG64*)ProcAddress, Restore[0], Restore[1], Restore);
RealFunc();
system("PAUSE");
return 0;
}
Here is the function documentation: https://msdn.microsoft.com/en-us/library/windows/desktop/hh972640(v=vs.85).aspx
_InterlockedCompareExchange128((LONG64*)ProcAddress,
Restore[0], Restore[1], Restore);
this is of course wrong. if look for function signature
unsigned char __cdecl InterlockedCompareExchange128(
_Inout_ LONGLONG volatile *Destination,
_In_ LONGLONG ExchangeHigh,
_In_ LONGLONG ExchangeLow,
_Inout_ LONGLONG *ComparandResult
);
second operand is ExchangeHigh and third is ExchangeLow - so must be Restore[1], Restore[0] but not Restore[0], Restore[1]. also ComparandResult must hold original function data. so it can not be Restore.
also note next, from MSDN:
The parameters for this function must be aligned on a 16-byte
boundary; otherwise, the function will behave unpredictably on x64
systems.
but which parameters ? all ? obvious that no. for example ExchangeHigh and ExchangeLow is passed by value. we can use direct values here which at all have no any address. so speak about align is senseless for second and third params. really InterlockedCompareExchange128 is converted to lock cmpxchg16b instruction. from intel manual
Note that CMPXCHG16B requires that the destination (memory) operand be
16-byte aligned.
so only Destination must be 16-byte aligned. ComparandResult - not (it will be moved to RCX:RBX register pairs)
so __declspec(align(16)) LONG64 Restore[2]; you not need at all - you can pass direct values to InterlockedCompareExchange128. then
__declspec(align(16)) PVOID ProcAddress = &RealFunc;
with _InterlockedCompareExchange128((LONG64*)ProcAddress..
wrong and senseless. what is different which align of ProcAddress ?? the memory to which point ProcAddress must be 16 byte aligned. but not ProcAddress itself. and again we not need any temporary variable here. we can direct use
_InterlockedCompareExchange128((LONG64*)RealFunc, ...)
of course RealFunc must be be 16-byte aligned. otherwise we got exactly 0xC0000005 Access violation reading 0xFFFFFFFFFFFFFFFF exception.
so i guess that in debug mode RealFunc not 16 byte aligned.
In a Release build, it doesn't crash! But it doesn't hook the function
either.
not hook because you use Restore in place ComparandResult and no exception because RealFunc was randomly 16byte align.
because in general function can have any address and must not be aligned on 16 bytes - _InterlockedCompareExchange128 not useful at all here. also this is only for x64, not for x86
code (which anyway not hook function, if RealFunc not aligned on 16 bytes)can look like
int RealFunc()
{
printf("In real func\n");
return 2;
}
int HookFunc()
{
printf("In hook func\n");
return 1;
}
int xxx()
{
DWORD dwOld;
if (VirtualProtect(RealFunc, 2*sizeof(PVOID), PAGE_EXECUTE_READWRITE, &dwOld))
{
RealFunc();
#if defined(_M_X64)
if (!((LONG_PTR)RealFunc & 15))
{
LONG64 Comparand[2] = { ((LONG64*)RealFunc)[0], ((LONG64*)RealFunc)[1] };
InterlockedCompareExchange128((LONG64*)RealFunc, (LONG64)HookFunc, 0x0000000025ff9090, Comparand);
}
else
{
printf("bad function address %p\n", RealFunc);
}
#elif defined(_M_IX86)
static PVOID pvHookFunc = HookFunc;
LARGE_INTEGER Exchange = { 0x25ff9090, (LONG)&pvHookFunc };
LONG64 Comparand;
memcpy(&Comparand, RealFunc, sizeof(Comparand));
InterlockedCompareExchange64((LONG64*)RealFunc, Exchange.QuadPart, Comparand);
#else
#error not implemented
#endif
FlushInstructionCache(NtCurrentProcess(), RealFunc, 2*sizeof(PVOID));
if (dwOld != PAGE_EXECUTE_READWRITE)
{
VirtualProtect(RealFunc, 2*sizeof(PVOID), dwOld, &dwOld);
}
RealFunc();
}
return 0;
}
I am trying to compile an application to x64 platform architecture in Windows. A couple of threads, handling the parsing of a scripting language, uses this code recommended by Microsoft to trap stack overflows and avoid access violation exceptions:
__try
{
DoSomethingThatMightUseALotOfStackMemory();
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
LPBYTE lpPage;
static SYSTEM_INFO si;
static MEMORY_BASIC_INFORMATION mi;
static DWORD dwOldProtect;
// Get page size of system
GetSystemInfo(&si);
// Find SP address
_asm mov lpPage, esp;
// Get allocation base of stack
VirtualQuery(lpPage, &mi, sizeof(mi));
// Go to page beyond current page
lpPage = (LPBYTE)(mi.BaseAddress)-si.dwPageSize;
// Free portion of stack just abandoned
if (!VirtualFree(mi.AllocationBase,
(LPBYTE)lpPage - (LPBYTE)mi.AllocationBase,
MEM_DECOMMIT))
{
exit(1);
}
// Reintroduce the guard page
if (!VirtualProtect(lpPage, si.dwPageSize,
PAGE_GUARD | PAGE_READWRITE,
&dwOldProtect))
{
exit(1);
}
Sleep(2000);
}
Unfortunately it uses one line of inline assembler to get the stack pointer. Visual Studio does not support inline assembly for x64 mode and I can't find a compiler intrinsic for getting the stack pointer neither.
Is it possible to do this in a x64 friendly manner?
As pointed out in a comment to the question, the whole "hack" above can be replaced by the _resetstkoflw function. This works fine in both x86 and x64 mode.
The code snippet above then becomes:
// Filter for the stack overflow exception. This function traps
// the stack overflow exception, but passes all other exceptions through.
int stack_overflow_exception_filter(int exception_code)
{
if (exception_code == EXCEPTION_STACK_OVERFLOW)
{
// Do not call _resetstkoflw here, because at this point
// the stack is not yet unwound. Instead, signal that the
// handler (the __except block) is to be executed.
return EXCEPTION_EXECUTE_HANDLER;
}
else
return EXCEPTION_CONTINUE_SEARCH;
}
void example()
{
int result = 0;
__try
{
DoSomethingThatMightUseALotOfStackMemory();
}
__except(stack_overflow_exception_filter(GetExceptionCode()))
{
// Here, it is safe to reset the stack.
result = _resetstkoflw();
}
// Terminate if _resetstkoflw failed (returned 0)
if (!result)
return 3;
return 0;
}
I have a driver code which works good on 32 bit. On 64 bit i compiled it and also digitally signed it. The driver loads but fails to work properly. The main functionality of the driver to to register process creation and termination to my program in call back. So i have two IOCTL working. The code is as follows..
NTSTATUS DispatchIoctl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PPROCESS_CALLBACK_INFO pProcCallbackInfo;
//
// These IOCTL handlers are the set and get interfaces between
// the driver and the user mode app
//
switch(irpStack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_PROCOBSRV_ACTIVATE_MONITORING:
{
ntStatus = ActivateMonitoringHanlder( Irp );
break;
}
case IOCTL_PROCOBSRV_GET_PROCINFO:
{
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PROCESS_CALLBACK_INFO))
{
pProcCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
pProcCallbackInfo->hParentId = extension->hParentId;
pProcCallbackInfo->hProcessId = extension->hProcessId;
pProcCallbackInfo->bCreate = extension->bCreate;
ntStatus = STATUS_SUCCESS;
}
break;
}
default:
break;
}
Irp->IoStatus.Status = ntStatus;
//
// Set number of bytes to copy back to user-mode
//
if(ntStatus == STATUS_SUCCESS)
Irp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
else
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}
when i call
bReturnCode = ::DeviceIoControl(
hDriverFile,
IOCTL_PROCOBSRV_ACTIVATE_MONITORING,
&activateInfo,
sizeof(activateInfo),
NULL,
0,
&dwBytesReturned,
NULL
);
The code succeeds but when i call
bReturnCode = ::DeviceIoControl(
m_hDriverFile,
IOCTL_PROCOBSRV_GET_PROCINFO,
0,
0,
&callbackInfo, sizeof(callbackInfo),
&dwBytesReturned,
&ov
);
getLastError returns 31. Can anyone help me with this. Is it a problem of IOCTL structure with 64 bit? Please help me find a solution to this. Thanks..
If you don't have driver debugging experience, try to diagnose this problem using trace. Add KdPrint lines to your code in all places where it is necessary, for example:
case IOCTL_PROCOBSRV_GET_PROCINFO:
{
KdPrint(("IOCTL_PROCOBSRV_GET_PROCINFO. OutputBufferLength = %d\n", irpStack->Parameters.DeviceIoControl.OutputBufferLength));
KdPrint(("sizeof(PROCESS_CALLBACK_INFO) = %d\n", sizeof(PROCESS_CALLBACK_INFO)));
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PROCESS_CALLBACK_INFO))
{
pProcCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
pProcCallbackInfo->hParentId = extension->hParentId;
pProcCallbackInfo->hProcessId = extension->hProcessId;
pProcCallbackInfo->bCreate = extension->bCreate;
KdPrint(("IOCTL_PROCOBSRV_GET_PROCINFO. STATUS_SUCCESS\n"));
ntStatus = STATUS_SUCCESS;
}
break;
}
This is just a sample, add KdPrint lines to all places to understand what happens. Build the driver in checked configuration, install it and run your program. See KdPrint output in DbgView program, with Caprure Kernel option enabled.
You can use DbgPrint instead of KdPrint, in this case it will work also in free driver configuration.
Edit:
How is PROCESS_CALLBACK_INFO defined? What is client code that calls the driver? Is client compiled as 32 or 64 bit? Passing a structure between client and driver, ensure that it doesn't contain bitness-dependent fields (has the same size when compiled both in 32 and 64 bit), and structure padding is the same.
Not too much information here, but you could always check that the size of your own defined structures are the same in the compiled user-mode client and the driver when running 64-bit. There might be packing/alignment issues that can be fixed by using #pragma pack (or whatever your compiler supports) for your structs.
As a general rule also try to set the status code to a more specific value on detected problems, such as e.g. STATUS_BUFFER_TOO_SMALL if you detect that a passed buffer is too small. I suspect that this isn't the actual issue here when using the IOCTL_PROCOBSRV_GET_PROCINFO IOCTL as you are getting back Win32 error 31, but it helps clients to troubleshoot their problems in general.
Update: As the differences actually seem to mismatch judging from your comments, try to surround the struct definitions with packing and then make sure to recompile both the client and driver. Example if you are using the Visual C++ compiler:
#pragma pack(push, 8) // Save current packing and set to 8-byte
typedef struct _PROCESS_CALLBACK_INFO
{
// Whatever ...
} PROCESS_CALLBACK_INFO;
#pragma pack(pop) // Restore previous packing
I found the answer. Thanks to the debugging. As mention earlier the outputBufferLength was less than the structure length due to which the driver was failing.
The outputBufferLength depands on the size of the struct you pass while calling the following function..
bReturnCode = ::DeviceIoControl(
m_hDriverFile,
IOCTL_PROCOBSRV_GET_PROCINFO,
0,
0,
&callbackInfo, sizeof(callbackInfo),
&dwBytesReturned,
&ov
);
So callbackInfo size was 12 so the outputBufferLength = 12. The structure callbackInfo has DWORD datamember which for 64 bit had to be DWORD64. When i changed the datatype of the member in the structure and then called the DeviceIOControl function , the driver worked great and the outputBufferLength was = 24 as expected. Thanks for all your help.