No mremap for windows? - linux

As I understand it, to reserve a chunk of virtual memory in linux, you call mmap with MAP_ANONYMOUS and MAP_PRIVATE, and the equivalent system call on windows is VirtualAlloc.
However, linux provides mremap to resize a memory mapping, which the man page says
changes the mapping between virtual addresses and memory pages
I cannot find an equivalent system call for windows. It seems that to reallocate memory, it is necessary to use HeapAlloc instead of VirtualAlloc, and then use HeapReAlloc. Regarding HeapReAlloc, msdn says
The process of preserving the memory content involves a memory copy operation that is potentially very time-consuming.
So is there no way of remapping pieces of virtual memory in Windows? If not, why not?

Fine-grained control of virtual memory on Windows may be achieved through the AWE-family of functions in the Win32 API.
Initial allocation is done with AllocateUserPhysicalPages, which, as the name alludes to, allocates actual physical pages for you. You may then proceed to map these physical pages to virtual pages using MapUserPhysicalPages into a virtual address space range that you have previously reserved using VirtualAlloc. Note that you may remap an already mapped physical page to a different virtual page.
This does come with a different set of semantics as you are dealing with both physical and virtual memory at the same time. Among a few of the drawbacks that may be worth mentioning are that you need to ensure that there is no aliasing present; and that you are effectively restricted to using the native page size, i.e. you will not be able to use large pages.

This is a working solution using Address Windowing Extensions (AWE).
The idea is to temporarily map the starting physical pages to the end of the virtual memory. In order to do this, you have to virtually allocate twice the size of the cyclic array.
It is not as convenient as Linux mremap, but it works.
Regarding the MSDN documentation (https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc2), you could also use "placeholders" with VirtualAlloc2, but it is only available on Windows 10 and later.
This solution is based on the MSDN example (https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx). Please remember to get the "lock page in memory" privilege for your account in Windows before running it.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define MEMORY_REQUESTED 1024*1024 // request a megabyte
BOOL
LoggedSetLockPagesPrivilege ( HANDLE hProcess,
BOOL bEnable);
BOOL
CyclicMapUserPhysicalPages( void* VirtualAddress,
void* VirtualHeadAddress,
ULONG_PTR NumberOfPages,
ULONG_PTR* PageArray,
DWORD dwPageSize);
void _cdecl main()
{
BOOL bResult; // generic Boolean value
ULONG_PTR NumberOfPages; // number of pages to request
ULONG_PTR NumberOfPagesInitial; // initial number of pages requested
ULONG_PTR *aPFNs; // page info; holds opaque data
PVOID lpMemReserved; // AWE window
SYSTEM_INFO sSysInfo; // useful system information
int PFNArraySize; // memory to request for PFN array
GetSystemInfo(&sSysInfo); // fill the system information structure
_tprintf(_T("This computer has page size %d.\n"), sSysInfo.dwPageSize);
// Calculate the number of pages of memory to request.
NumberOfPages = MEMORY_REQUESTED/sSysInfo.dwPageSize;
_tprintf (_T("Requesting %d pages of memory.\n"), NumberOfPages);
// Calculate the size of the user PFN array.
PFNArraySize = NumberOfPages * sizeof (ULONG_PTR);
_tprintf (_T("Requesting a PFN array of %d bytes.\n"), PFNArraySize);
aPFNs = (ULONG_PTR *) HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
if (aPFNs == NULL)
{
_tprintf (_T("Failed to allocate on heap.\n"));
return;
}
// Enable the privilege.
if( ! LoggedSetLockPagesPrivilege( GetCurrentProcess(), TRUE ) )
{
return;
}
// Allocate the physical memory.
NumberOfPagesInitial = NumberOfPages;
bResult = AllocateUserPhysicalPages( GetCurrentProcess(),
&NumberOfPages,
aPFNs );
if( bResult != TRUE )
{
_tprintf(_T("Cannot allocate physical pages (%u)\n"), GetLastError() );
return;
}
if( NumberOfPagesInitial != NumberOfPages )
{
_tprintf(_T("Allocated only %p pages.\n"), NumberOfPages );
return;
}
// Reserve the virtual memory.
lpMemReserved = VirtualAlloc( NULL,
MEMORY_REQUESTED*2, // NB: Twice the size
MEM_RESERVE | MEM_PHYSICAL,
PAGE_READWRITE );
if( lpMemReserved == NULL )
{
_tprintf(_T("Cannot reserve memory.\n"));
return;
}
// Cyclic Map the physical memory into the window.
void* Head = ((char*)lpMemReserved) + MEMORY_REQUESTED - 6; // Arbitrary Head Address (must be between >= lpMemReserved and <lpMemReserved+MEMORY_REQUESTED)
bResult = CyclicMapUserPhysicalPages( lpMemReserved,
Head,
NumberOfPages,
aPFNs,
sSysInfo.dwPageSize );
if( bResult != TRUE )
{
_tprintf(_T("CyclicMapUserPhysicalPages failed (%u)\n"), GetLastError() );
return;
}
sprintf((char*)Head, "Hello World");
/// unmap Cyclic
bResult = CyclicMapUserPhysicalPages( lpMemReserved,
Head,
NumberOfPages,
NULL,
sSysInfo.dwPageSize );
if( bResult != TRUE )
{
_tprintf(_T("CyclicMapUserPhysicalPages failed (%u)\n"), GetLastError() );
return;
}
// Map the physical memory into the window.
bResult = MapUserPhysicalPages( lpMemReserved,
NumberOfPages,
aPFNs );
if( bResult != TRUE )
{
_tprintf(_T("MapUserPhysicalPages failed (%u)\n"), GetLastError() );
return;
}
if (strcmp((char const*)lpMemReserved, "World"))
{
_tprintf(_T("Mem Content Check failed\n") );
return;
}
// unmap
bResult = MapUserPhysicalPages( lpMemReserved,
NumberOfPages,
NULL );
if( bResult != TRUE )
{
_tprintf(_T("MapUserPhysicalPages failed (%u)\n"), GetLastError() );
return;
}
// Free the physical pages.
bResult = FreeUserPhysicalPages( GetCurrentProcess(),
&NumberOfPages,
aPFNs );
if( bResult != TRUE )
{
_tprintf(_T("Cannot free physical pages, error %u.\n"), GetLastError());
return;
}
// Free virtual memory.
bResult = VirtualFree( lpMemReserved,
0,
MEM_RELEASE );
// Release the aPFNs array.
bResult = HeapFree(GetProcessHeap(), 0, aPFNs);
if( bResult != TRUE )
{
_tprintf(_T("Call to HeapFree has failed (%u)\n"), GetLastError() );
}
}
/*****************************************************************
LoggedSetLockPagesPrivilege: a function to obtain or
release the privilege of locking physical pages.
Inputs:
HANDLE hProcess: Handle for the process for which the
privilege is needed
BOOL bEnable: Enable (TRUE) or disable?
Return value: TRUE indicates success, FALSE failure.
*****************************************************************/
BOOL
LoggedSetLockPagesPrivilege ( HANDLE hProcess,
BOOL bEnable)
{
struct {
DWORD Count;
LUID_AND_ATTRIBUTES Privilege [1];
} Info;
HANDLE Token;
BOOL Result;
// Open the token.
Result = OpenProcessToken ( hProcess,
TOKEN_ADJUST_PRIVILEGES,
& Token);
if( Result != TRUE )
{
_tprintf( _T("Cannot open process token.\n") );
return FALSE;
}
// Enable or disable?
Info.Count = 1;
if( bEnable )
{
Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else
{
Info.Privilege[0].Attributes = 0;
}
// Get the LUID.
Result = LookupPrivilegeValue ( NULL,
SE_LOCK_MEMORY_NAME,
&(Info.Privilege[0].Luid));
if( Result != TRUE )
{
_tprintf( _T("Cannot get privilege for %s.\n"), SE_LOCK_MEMORY_NAME );
return FALSE;
}
// Adjust the privilege.
Result = AdjustTokenPrivileges ( Token, FALSE,
(PTOKEN_PRIVILEGES) &Info,
0, NULL, NULL);
// Check the result.
if( Result != TRUE )
{
_tprintf (_T("Cannot adjust token privileges (%u)\n"), GetLastError() );
return FALSE;
}
else
{
if( GetLastError() != ERROR_SUCCESS )
{
_tprintf (_T("Cannot enable the SE_LOCK_MEMORY_NAME privilege; "));
_tprintf (_T("please check the local policy.\n"));
return FALSE;
}
}
CloseHandle( Token );
return TRUE;
}
/*
--->(tail) (head) ----- ~~~~>
v v
+-------------------------------|-------------------------------+
| virtual memory |
+-------------------------------|-------------------------------+
<--- Memory Requested Size ---->
*/
BOOL CyclicMapUserPhysicalPages(void* VirtualAddress, void* VirtualHeadAddress, ULONG_PTR NumberOfPages, ULONG_PTR* PageArray, DWORD dwPageSize){
ULONG_PTR iStartPage = (ULONG_PTR(VirtualHeadAddress)-ULONG_PTR(VirtualAddress))/dwPageSize;
void* pEnd = ((BYTE*)VirtualAddress)+dwPageSize*iStartPage;
void* pStart = ((BYTE*)VirtualAddress)+dwPageSize*NumberOfPages;
BOOL bResult = MapUserPhysicalPages( pEnd, NumberOfPages-iStartPage, PageArray ? (PageArray+iStartPage) : NULL );
if( !bResult )
return FALSE;
if (iStartPage)
{
bResult = MapUserPhysicalPages( pStart, iStartPage, PageArray );
if( !bResult ){
if (PageArray)
MapUserPhysicalPages( pEnd, NumberOfPages-iStartPage, NULL );
return FALSE;
}
}
return TRUE;
}

You can do it with Address Windowing Extensions (AWE). For example, you can reserve two regions of virtual memory and then map them to the same physical region one after another. Or you can reserve single virtual region but map different segments of it.
It is not as convenient as Linux mremap, but it works.
Check out Address Windowing Extensions (AWE) please:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366531(v=vs.85).aspx
My working code for your reference based on the MSDN example. Please remember to get the "lock page in memory" privilege for your account in Windows before running it.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define MEMORY_REQUESTED 1024*1024 // request a megabyte
BOOL
LoggedSetLockPagesPrivilege(HANDLE hProcess,
BOOL bEnable);
void _cdecl main()
{
BOOL bResult; // generic Boolean value
ULONG_PTR NumberOfPages; // number of pages to request
ULONG_PTR NumberOfPagesInitial; // initial number of pages requested
ULONG_PTR *aPFNs; // page info; holds opaque data
PVOID lpMemReserved; // AWE window
PVOID lpMemReserved2; // AWE window
SYSTEM_INFO sSysInfo; // useful system information
int PFNArraySize; // memory to request for PFN array
GetSystemInfo(&sSysInfo); // fill the system information structure
_tprintf(_T("This computer has page size %d.\n"), sSysInfo.dwPageSize);
// Calculate the number of pages of memory to request.
NumberOfPages = MEMORY_REQUESTED / sSysInfo.dwPageSize;
_tprintf(_T("Requesting %d pages of memory.\n"), NumberOfPages);
// Calculate the size of the user PFN array.
PFNArraySize = NumberOfPages * sizeof(ULONG_PTR);
_tprintf(_T("Requesting a PFN array of %d bytes.\n"), PFNArraySize);
aPFNs = (ULONG_PTR *)HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
if (aPFNs == NULL)
{
_tprintf(_T("Failed to allocate on heap.\n"));
return;
}
// Enable the privilege.
if (!LoggedSetLockPagesPrivilege(GetCurrentProcess(), TRUE))
{
return;
}
// Allocate the physical memory.
NumberOfPagesInitial = NumberOfPages;
bResult = AllocateUserPhysicalPages(GetCurrentProcess(),
&NumberOfPages,
aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("Cannot allocate physical pages (%u)\n"), GetLastError());
return;
}
if (NumberOfPagesInitial != NumberOfPages)
{
_tprintf(_T("Allocated only %p pages.\n"), (void*)NumberOfPages);
return;
}
// Reserve the virtual memory.
lpMemReserved = VirtualAlloc(NULL,
MEMORY_REQUESTED,
MEM_RESERVE | MEM_PHYSICAL,
PAGE_READWRITE);
if (lpMemReserved == NULL)
{
_tprintf(_T("Cannot reserve memory.\n"));
return;
}
lpMemReserved2 = VirtualAlloc(NULL,
MEMORY_REQUESTED,
MEM_RESERVE | MEM_PHYSICAL,
PAGE_READWRITE);
if (lpMemReserved2 == NULL)
{
_tprintf(_T("Cannot reserve memory.\n"));
return;
}
// Map the physical memory into the window.
bResult = MapUserPhysicalPages(lpMemReserved,
NumberOfPages,
aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("MapUserPhysicalPages failed (%u)\n"), GetLastError());
return;
}
else {
int* pa = (int*)lpMemReserved;
pa[1] = pa[100] = 0xF0F0;
_tprintf(_T("MapUserPhysicalPages successfully at %p\n"), lpMemReserved);
}
// unmap
bResult = MapUserPhysicalPages(lpMemReserved,
NumberOfPages,
NULL);
if (bResult != TRUE)
{
_tprintf(_T("MapUserPhysicalPages failed (%u)\n"), GetLastError());
return;
}
//remap
bResult = MapUserPhysicalPages(lpMemReserved2,
NumberOfPages,
aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("Re-MapUserPhysicalPages failed (%u)\n"), GetLastError());
return;
}
else {
int* pa = (int*)lpMemReserved2;
if(pa[1] != pa[100] || pa[100] != 0xF0F0)
_tprintf(_T("Re-MapUserPhysicalPages failed (%u)\n"), GetLastError());
_tprintf(_T("Re-MapUserPhysicalPages successfully at %p\n"), lpMemReserved2);
}
// Free the physical pages.
bResult = FreeUserPhysicalPages(GetCurrentProcess(),
&NumberOfPages,
aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("Cannot free physical pages, error %u.\n"), GetLastError());
return;
}
// Free virtual memory.
bResult = VirtualFree(lpMemReserved,
0,
MEM_RELEASE);
// Release the aPFNs array.
bResult = HeapFree(GetProcessHeap(), 0, aPFNs);
if (bResult != TRUE)
{
_tprintf(_T("Call to HeapFree has failed (%u)\n"), GetLastError());
}
_tprintf(_T("Successfully finished\n"));
}
/*****************************************************************
LoggedSetLockPagesPrivilege: a function to obtain or
release the privilege of locking physical pages.
Inputs:
HANDLE hProcess: Handle for the process for which the
privilege is needed
BOOL bEnable: Enable (TRUE) or disable?
Return value: TRUE indicates success, FALSE failure.
*****************************************************************/
BOOL
LoggedSetLockPagesPrivilege(HANDLE hProcess,
BOOL bEnable)
{
struct {
DWORD Count;
LUID_AND_ATTRIBUTES Privilege[1];
} Info;
HANDLE Token;
BOOL Result;
// Open the token.
Result = OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES,
&Token);
if (Result != TRUE)
{
_tprintf(_T("Cannot open process token.\n"));
return FALSE;
}
// Enable or disable?
Info.Count = 1;
if (bEnable)
{
Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else
{
Info.Privilege[0].Attributes = 0;
}
// Get the LUID.
Result = LookupPrivilegeValue(NULL,
SE_LOCK_MEMORY_NAME,
&(Info.Privilege[0].Luid));
if (Result != TRUE)
{
_tprintf(_T("Cannot get privilege for %s.\n"), SE_LOCK_MEMORY_NAME);
return FALSE;
}
// Adjust the privilege.
Result = AdjustTokenPrivileges(Token, FALSE,
(PTOKEN_PRIVILEGES)&Info,
0, NULL, NULL);
// Check the result.
if (Result != TRUE)
{
_tprintf(_T("Cannot adjust token privileges (%u)\n"), GetLastError());
return FALSE;
}
else
{
if (GetLastError() != ERROR_SUCCESS)
{
_tprintf(_T("Cannot enable the SE_LOCK_MEMORY_NAME privilege; "));
_tprintf(_T("please check the local policy.\n"));
return FALSE;
}
}
CloseHandle(Token);
return TRUE;
}

Related

Fail to unmount a block device within kernel sources

I'm trying to check if a file on a jffs2 fs exist from a kernel space. I have a Barrier Breaker OpenWrt with a 3.10.14 Linux kernel. (There's an MTD subsystem in use, so I have pseudo block devices for partitions on a NAND flash (/dev/mtdblock1, ...12).)
(I'm implementing some upgrading logic which requires keeping some state between reboots, to store this state, I use the file.)
To check a file existence I just try to open the file (without an O_CREAT flag) and make a decision based on a result of opening. I use the next article about opening a file from within kernel: Read/write files within a Linux kernel module.
I'm able to check a file existence using this approach, but this file is placed not on a rootfs partition, so I have to mount that partition before I can open the file on it.
I'm able to mount the partition, open file (to check it existence) and close it, if it was opened, but failed to un-mount it: I got an error -16: EBUSY which, as I guess, means that someone else keep using this block device/mount point. So a question who can keep a reference on it?
I think it's a bad idea, but just to test, I tried to un-mount forcibly with an MNT_FORCE, but, as this article https://linux.die.net/man/2/umount states that this option only for NFS fs, nothing changed.
Here's a code:
/* lool at https://stackoverflow.com/questions/1184274/read-write-files-within-a-linux-kernel-module */
static struct file *file_open( const char *path, int flags, int rights )
{
struct file *filp = NULL;
mm_segment_t oldfs;
int err = 0;
oldfs = get_fs();
set_fs( get_ds() );
filp = filp_open( path, flags, rights );
set_fs( oldfs );
if( IS_ERR( filp ) )
{
err = PTR_ERR( filp );
return NULL;
}
return filp;
}
bool need_to_switch_to_me_upgrade_mode( void )
{
struct file* me_upgrade_finished_file;
dev_t me_upgrade_dev;
char full_name[256] = { 0 };
bool result;
int err;
const char* me_upgrade_dir = "/me_upgrade";
const char* me_upgrade_dev_name = "/dev/me_upgrade";
const char* me_upgrade_finished_flag = "/etc/me_upgrade_finished";
// /dev/mtdblock6
const char* me_upgrade_finished_flag_partition = "/dev/mtdblock" str( RECOVERY_ROOTFS_DATA_MTD_PART_NUM );
err = sys_mkdir( (const char __user __force *) me_upgrade_dir, 0700 );
if( err < 0 )
panic( "fail to mkdir %s\n", me_upgrade_dir );
me_upgrade_dev = name_to_dev_t( me_upgrade_finished_flag_partition );
err = create_dev( me_upgrade_dev_name, me_upgrade_dev );
if( err < 0 )
panic( "fail to create_dev %s\n", me_upgrade_dev_name );
err = sys_mount( me_upgrade_dev_name, me_upgrade_dir, "jffs2", MS_SILENT, NULL );
if( err < 0 )
panic( "fail to mount %s on to %s, err: %d\n", me_upgrade_dev_name, me_upgrade_dir, err );
strlcat( full_name, me_upgrade_dir, sizeof( full_name ) );
strlcat( full_name, me_upgrade_finished_flag, sizeof( full_name ) );
me_upgrade_finished_file = file_open( full_name, O_RDONLY, 0 );
if( !me_upgrade_finished_file )
{
printk( "fail to open a %s file\n", full_name );
result = true;
}
else
{
printk( "success to open a file\n" );
result = false;
}
if( me_upgrade_finished_file )
{
err = filp_close( me_upgrade_finished_file, NULL );
printk( "filp_close returned: %d\n", err );
}
err = sys_umount( me_upgrade_dir, MNT_DETACH );
printk( "sys_umount returned: %d\n", err );
sys_unlink( me_upgrade_dev_name ); // destroy_dev( me_upgrade_dev_name );
sys_rmdir( me_upgrade_dir );
return result;
}
This code is called from a kernel_init_freeable function (init/main.c) after we have MTD subsystem initialized (after do_basic_setup() and before a rootfs gets mounted).
So the questions are:
who can keep using a block device/mount point after I closed a file?
is any other ways to check if file exist from within kernel?
I have a second option, just to place my state in a partition without any fs, and check it by performing a raw access to the flash memory, but this approach will require significant changes to user code I have now, so I'm trying to avoid it...
P.S. I tried to change a call to file_open/filp_close by sys_open/sys_close (with the same arguments), but nothing changed...

Cant pass different strings to multiple threads

I have a function that will generate multiple threads and i pass to them a different string every time, but it seems that the threads have the same string. The strings are coming from a socket. Here is the code:
pthread_t *MirrorManager;
MirrorManager = malloc(sizeof(pthread_t)*th_size);
if( MirrorManager == NULL ) { perror("malloc"); exit(1); }
/* -------------------------------------- */
int th_num = 0;
while( true )
{
received = 0;
/* Read the desired readable size */
if( read(newsock, &size, sizeof(size)) < 0 )
{ perror("Read"); exit(1); }
/* Read all data */
while( received < size )
{
if( (nread = read(newsock, buffer + received, size - received)) < 0 )
{ perror("Read"); exit(1); }
received += nread;
}
if( strcmp(buffer, "end") == 0 ) { break; }
printf("Received string: %s\n",buffer);
/* Create thread */
strcpy(th_str, buffer);
if( (err = pthread_create(&MirrorManager[th_num], NULL, thread_start, (void*) th_str)) == true )
{ show_error("pthread_create", err); }
/* Take next thread */
th_num++;
}
Here i generate two threads. The two threads have the same string, actually this string is the last string that will come out of the socket. Why this is happening and how can i prevent this? Please help i have stuck here for a few days now.
You should post the complete code.
Given what you have posted, it looks like your issue is that all of your threads share the same parameter th_str:
pthread_create(&MirrorManager[th_num], NULL, thread_start, (void*) th_str))
Instead you should be allocating a separate th_str for each thread, as you're passing a pointer to it for each thread, rather than the string itself.
th_str = malloc(strlen(buffer));
strcpy(th_str, buffer);
And then be sure to have each thread free the pointer that was passed into it.
PS: I'd strongly recommend using strncmp and strncpy on all data from your socket.

Remote Code injection in Win 7 SP 1 using NtCreateThreadEx API

I am trying to learn how to inject code into a running process using NtCreateThreadEx. I found few tutorials online and tried the code shown below which basically tries to inject a piece of code to a a running notepad.exe. Code injection to notepad.exe was successful; however, this program crashes just after injection (i.e., after calling funNtCreateThreadEx) throwing following error:
Run-Time Check Failure #2 - Stack around the variable 'temp2' was corrupted.
Could someone help me explaining why I am getting this error? I tried to Google about this error and figured out its something related to memory overflow. However, I don't see any memory overflow in this following code. Please let me know what could be the reason for the above error. Thank you so much for your time.
HANDLE NtCreateThreadEx(HANDLE process, LPTHREAD_START_ROUTINE Start, LPVOID lpParameter);
typedef NTSTATUS(WINAPI *LPFUN_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
);
struct NtCreateThreadExBuffer
{
ULONG Size;
ULONG Unknown1;
ULONG Unknown2;
PULONG Unknown3;
ULONG Unknown4;
ULONG Unknown5;
ULONG Unknown6;
PULONG Unknown7;
ULONG Unknown8;
};
HANDLE NtCreateThreadEx(HANDLE process, LPTHREAD_START_ROUTINE Start, LPVOID lpParameter) {
HMODULE modNtDll = LoadLibrary(L"ntdll.dll");
if (!modNtDll) {
std::cout << "Error loading ntdll.dll" << std::endl;
return 0;
}
LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx)GetProcAddress(modNtDll, "NtCreateThreadEx");
if (!funNtCreateThreadEx) {
std::cout << "Error loading NtCreateThreadEx()" << std::endl;
return 0;
}
NtCreateThreadExBuffer ntbuffer;
memset(&ntbuffer, 0, sizeof(NtCreateThreadExBuffer));
DWORD temp1 = 0;
DWORD temp2 = 0;
ntbuffer.Size = sizeof(NtCreateThreadExBuffer);
ntbuffer.Unknown1 = 0x10003;
ntbuffer.Unknown2 = 0x8;
ntbuffer.Unknown3 = &temp2;
ntbuffer.Unknown4 = 0;
ntbuffer.Unknown5 = 0x10004;
ntbuffer.Unknown6 = 4;
ntbuffer.Unknown7 = &temp1;
// ntbuffer.Unknown8 = 0;
HANDLE hThread;
NTSTATUS status = funNtCreateThreadEx(
&hThread,
0x1FFFFF,
NULL,
process,
(LPTHREAD_START_ROUTINE)Start,
lpParameter,
FALSE, //start instantly
0, //null
0, //null
0, //null
&ntbuffer
);
return hThread;
}
int main()
{
int res = -1;
res = privileges(); //get all required privileges
DWORD pid = getPid(L"notepad.exe");
if (pid == 0)
return PROCESS_NOT_FOUND; //error
HANDLE p;
p = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
if (p == NULL) return OPEN_PROCESS_FAILED; //error
char * mytext = "Hello by CodeCave!";
char * mycaption = "Injection result";
PARAMETERS data; //let's fill in a PARAMETERS struct
HMODULE user32 = LoadLibrary(L"User32.dll");
data.MessageBoxInj = (DWORD)GetProcAddress(user32, "MessageBoxA");
strcpy_s(data.text, mytext);
strcpy_s(data.caption, mycaption);
data.buttons = MB_OKCANCEL | MB_ICONQUESTION;
//Writing funtion to notepad memory
DWORD size_myFunc = 0x8000; //Creating more memory than required
LPVOID MyFuncAddress = VirtualAllocEx(p, NULL, size_myFunc, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(p, MyFuncAddress, (void*)myFunc, 0x1000, NULL);
//Parameters to the function to notepad's memory
LPVOID DataAddress = VirtualAllocEx(p, NULL, sizeof(PARAMETERS), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(p, DataAddress, &data, sizeof(PARAMETERS), NULL);
//invokes injected function
HANDLE thread = NtCreateThreadEx(p, (LPTHREAD_START_ROUTINE)MyFuncAddress, DataAddress);
if (thread != 0) {
//injection completed, not we can wait it to end and free the memory
}
return 0;
}
static DWORD myFunc(PARAMETERS * myparam) {
MsgBoxParam MsgBox = (MsgBoxParam)myparam->MessageBoxInj;
int result = MsgBox(0, myparam->text, myparam->caption, myparam->buttons);
switch (result) {
case IDOK:
//your code
break;
case IDCANCEL:
//your code
break;
}
return 0;
}
int privileges() {
HANDLE Token;
TOKEN_PRIVILEGES tp;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token))
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL) == 0) {
return 1; //FAIL
}
else {
return 0; //SUCCESS
}
}
return 1;
}
typedef int (WINAPI* MsgBoxParam)(HWND, LPCSTR, LPCSTR, UINT);
struct PARAMETERS {
DWORD MessageBoxInj;
char text[50];
char caption[25];
int buttons;
};
DWORD myFunc(PARAMETERS * myparam);

GetProcAddress returnning null for remote process for windowds xp

I have injected one of my dll in many process.What I want to do is call the function in that dll from my application in all the process in which it is loaded. I used following codes.It works fine in windows vista+ OS but it get failed at line GetProcAddress() in windows xp...why this is happening please help me out. Thanks in advance.
const TCHAR * pszDllName = _T("MyDll.dll");
void CallProcessFunc( DWORD processID,LPCSTR funcName)
{
// Get a handle to the process.
HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_WRITE |
PROCESS_VM_READ | PROCESS_VM_OPERATION | PROCESS_CREATE_THREAD,
FALSE, processID );
if(hProcess == NULL)
return;
HMODULE hMods[1024];
DWORD cbNeeded;
if ( EnumProcessModules( hProcess, hMods, sizeof(hMods), &cbNeeded) )
{
for (int i = 0; i < (int)(cbNeeded / sizeof(HMODULE)); i++ )
{
TCHAR szModName[MAX_PATH];
// Get the full path to the module's file.
if ( GetModuleFileNameEx( hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)) == FALSE)
continue;
if(_tcsstr(szModName, pszDllName) == NULL)
continue;
LPTHREAD_START_ROUTINE lpRoutine = (LPTHREAD_START_ROUTINE) ::GetProcAddress(hMods[i], funcName);// here it get failed in windows xp
if(lpRoutine == NULL)
continue;
HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, lpRoutine, NULL, NULL, NULL);
if(hRemoteThread == NULL)
continue;
WaitForSingleObject(hRemoteThread, INFINITE);
DWORD ret = 0;
GetExitCodeThread(hRemoteThread, &ret);
CloseHandle(hRemoteThread);
break;
}
}
CloseHandle( hProcess );
}
void fnCallRemoteFuntion()
{
LPCSTR fuctName = "NotifyDll";
DWORD aProcesses[1024], cbNeeded = 0;
EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded );
int cProcesses = (int)(cbNeeded / sizeof(DWORD));
for (int i = 0; i < cProcesses; i++ )
{
if( aProcesses[i] == 0 )
continue;
CallProcessFunc(aProcesses[i], fuctName);
}
}
I got my solution from an article for which link is given.
http://www.codeproject.com/Tips/139349/Getting-the-address-of-a-function-in-a-DLL-loaded
i was using GetProcAddress function which was incorrect Bcoz it is giving proc address in current process not in remote process and my need was getting proc address in remote thread,which is explain in above link.

MMAP fails above 4k size

This is my first post so please let me know if there is any mistake from .
My aim is to get approx 150MBytes of data transfer from KERNEL to user space.
[This is because i am building an driver for DMA device on OMAP l138 to transfer and receive data between DMA DEVICE and FPGA]
Now in LINUX KERNEL i am allocating BUFFER of VARIABLE size using dma_alloc_coherent
Then the PHYSICAL address of this buffer i am passing to user space to be user as
OFFSET parameter to be used for mmap call from user space .
Then from data is copied and read back to and from from user space to kernel
This logic work fine till size of buffer is 4096. Above 4k the mmap fails and return "MAP_FAILED"
static int driver_mmap(struct file *f, struct vm_area_struct *vma)
{
u32bit ret;
u32bit size = (vma->vm_end)-(vma->vm_start);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
if (size > (NUM_PAGE*PAGE_SIZE)){
return(-1);
}
if ((ret = remap_pfn_range(vma,vma->vm_start,
(virt_to_phys((void *)krnl_area) >> PAGE_SHIFT),
size,vma->vm_page_prot)) < 0)
{
return ret;
}
printk("\nDVR:The MMAP returned %x to USER SAPCE \n",ret);
return 0;
}
//MMAP STEP 1
dmasrc_ptr = dma_alloc_coherent( NULL ,GLOBAL_BUFFER_SIZE , &dmasrc ,0);
if( !dmasrc_ptr ) {
printk(KERN_INFO "DMA_ALLOC_FAILED for the source buffer ...\n");
return -ENOMEM;
}else{
printk( "\n--->The address of SRC is %x..\n",dmasrc_ptr);
}
temp_source=dmasrc_ptr;
//MMAP STEP 2
// Round the allocated KERNEL MEMORY to the page bondary
krnl_area=(int *)((((unsigned long)dmasrc_ptr) + PAGE_SIZE - 1)&PAGE_MASK);
printk(KERN_CRIT "DVR:The KERNEL VIRTUAL ADDRS is %x..\n",krnl_area);
//MMAP STEP 3
// Marking the PAGES as RESERVED
for (i = 0; i < (NUM_PAGE * PAGE_SIZE); i+= PAGE_SIZE) {
SetPageReserved(virt_to_page(((unsigned long)krnl_area) + i));
//Application code part
while(1){
fflush(stdin);
fflush(stdout);
printf("\n\n\n----------------------------------------------------\n");
printf("USR:Please enter your requirement ");
printf("\n----------------------------------------------------\n");
printf("\t1----->GET_UPP_OFFSET\n");
printf("\t2----->UPP_MMAP_CALL\n");
printf("\t3----->IOCTL_UPP_WRITE\n");
printf("\t4----->IOCTL_UPP_READ\n");
printf("\n");
scanf("%d",&option);
printf("\nThe OPTION is %d..\n",option);
printf("\n");
switch(option){
case 1 :
{
offset=0;
ret = ioctl(dev_FD ,IOCTL_UPP_START, &info);
if (ret < 0) {
printf("dma buffer info ioctl failed\n");
}
offset = info.var;
printf("THE ADDRESS WE GOT IS %X..\n",offset);
}
break;
case 2 :
{
printf("THE OFFSET is %X..\n",offset);
mmap_Ptr= mmap(0,BUFFER_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, dev_FD, 0);
if (mmap_Ptr == MAP_FAILED){
printf("USR[UPP] :MMAP FAiled \n\n");
close(dev_FD);
exit(-1);
}
printf("THE MMAP address is %X..\n",mmap_Ptr);
}
break;
case 3:
{
struct upp_struct user_local_struct;
printf("\n***************************************************\n");
for (i = 0; i <(1024);i++) {
*(mmap_Ptr+i)=test_var;
printf("WR:%X ",*(mmap_Ptr+i));
//test_var++;
}
ioctl(dev_FD , IOCTL_UPP_WRITE ,&user_local_struct);
printf("\n***************************************************\n\n\n");
for(i=0;i<20402;i++){
//NOP
}
//test_var=0x00;
}
break;
case 4:
{
struct upp_struct user_local_struct;
ioctl(dev_FD , IOCTL_UPP_READ,&user_local_struct);
for(i=0;i<20402;i++){
//NOP
}
printf("\n***************************************************\n");
for (i = 0; i <(1024);i++) {
printf("RD:%X",*(mmap_Ptr+i));
}
printf("\n***************************************************\n\n\n");
}
break;
default:
{
printf("USR:You have entered an wrong option \n");
printf("\nUSR:CLosing the FILE ENTERIES ...\n");
munmap(mmap_Ptr,BUFFER_SIZE);
free(source_ptr);
free(dest_ptr);
close(dev_FD);
exit(0);
}
break;
} //END OF SWITCH LOOP
} //END OF WHILE LOOP
use get_free_pages to allocate multiple pages, or use vmalloc but you need call remap_pfn_range at every page basis as vmalloc-ed physical memory could be not physically continuous.

Resources