I had, what I thought, would be a great idea to play around with while writing my memory manager:  Since I plan to return a 'handle' for each type of mass memory allocation that i required, why not set up the memory behind this handle to self free itself at the program's end.  The idea came to me when i noted that virtual memory allows for it to have executable permisions.

My plan was to keep it simple, at the very first byte of the allocated memory (which i treat as a master handle for this group of memory objects), I would dynamically provide the op-codes to essentially move into EAX the base address of the memory allocated (as determined at run time). Then to finish this little piece of dynamic code, I would call a standard free function (which will be compiled into my the library):

; compiled with the library
Private_FreeVirtual proc
  invoke VirtualFree, eax, NULL, MEM_RELEASE
  ret
Private_FreeVirtual endp



; Virtual memory base address: 12345678h
BYTE 0:  mov eax, 12345678h  ; Address will be determined at runtime and stored in memory as a constant
BYTE 5:  jmp Private_FreeVirtual


Then in pratice, Its practically idiot proof.  All one needs to do is "call h32byteMemoryObjects" to free it.

I hit the wall when debugging the idea to see why it was GPF'n.  I know it has something to do with the segment registers, but to be honest, I'm totally out of my league here.  What happens is the proper offest is loaded and dynamically placed in to the virtual memory for execution, but when executed, the interperted value of the offset is no longer correct.  That is the raw op-codes are correct but as interpreted by the paging system the value borrowed from one segment reflects a totally different address in the virtuall memory pages.

Im curious if anyone knows what the deal here is, and you have a suggestion on how to do it correctly.

I realize this is overly crazy and it would not be nearly as complicated to simply pack into my library "FreeMemoryObject PROC hBaseVirtualAddress:DWORD" but I thought it would be fun to do as a challange, now I'm determined to find out what I dont understand ;)

Thanks for your help.
PS:  I don't want to see any virus or similar responses.  I know this borders such practices and I would rather not hear from you if thats all you have to offer.  The idea has honest uses, and I'm hoping to get similar feedback.

Regadrs,
:NaN: 
Posted on 2006-08-17 19:53:53 by NaN
Hi NaN
The basics are the same as those used for the thunking method. I attached a demo developed by Jayaz that shows how it works and what APIs are required to implement it.

Regards,

Biterider
Attachments:
Posted on 2006-08-18 01:23:47 by Biterider
Since the memory being allocated is mapped into the process which allocates it, this is highly unlikely to be a segment related issue.
In fact, since I have experience with this stuff, I know that for a fact.

Which JMP encoding is being generated? If its a relative or near JMP thats being generated, there is your problem: you need to generate a far and absolute jump.

If I was you, I'd go even further, and get rid of the proc totally..
ie obtain the pointer to the VirtualFree api function - note thats not the same thing as the address of the function's stub in the IAT !!

Inject the following opcodes in the remote memory block:

push MEM_RELEASE
push NULL
push (soft address of memory block)
call  (hard address of VirtualFree api function)


Note that VirtualFree lives in Kernel32.dll, whose image has a fixed address on all 32 bit versions of Windows, but for safety and for compatibility with 64bit os I'd still obtain it via GetProcAddress, or by 'fishing' its value from the IAT.

Hopefully, some of that helps :)
Posted on 2006-08-18 01:26:55 by Homer
Pretty bad idea, NaN... if you CALL the memory free routine, you will crash on return, since it's then trying to execute from unmapped memory. You'd need to JMP to the free routine, which then *has* to be STDCALL, which will in effect return to after the "call memoryblock".

But even that is... weird. It's going to be pretty confusing to most people.
Posted on 2006-08-18 03:43:25 by f0dder
Thanks alot for your replies.?  I see now what I was doing wrong.?  I will continue to play a bit, but as f0dder has suggested its more weird than useful.?  ? I have simply defaulted at this point to implementing a standard destroy function.

I have a working memory manager now similar to Ultrano's but probably not as fast.?  I'm not after speed as much as robust uses for it.?  I added an 'lparam' extra feature for every memory allocation granted (if its required as dictated by the Creation parameter).?  Internally, its a dual direction linked list and i make use of the IsBadReadPtr API for safety checks.?  I also have made each memory item allocated to be 'smart' in that it can seek out its memory page/chunk without the need of the main handle for the allocation pool.?  This is so i can store the main handle and forget about it until clean up time.?  A new handle is generated for each new allocation pool which is provides flexibility to the owner of the pool (for OOP uses), the size of the items allocated, and if i need to embed any 'extra' data or Object pointers with each data item.

I wrote it to make as efficient use of the memory as I could.?  If you don't need extra data parameter, it will use this space for data storage.?  Like Ultrano's version, I keep keep a list of each memory item capable of allocation.?  This is for look up speed and tracking if its allocated.?  I chose to follow BiteRider's suggestion to use Bit 0 in this case.

Anyhow,?  I just finished writing it and gave it a modest debugging test, but it was in no way complete.?  I have not tested all the features and combinations at this point, but the basic uses are running correctly.?  I commented the hell out of it as well.?  To my surprise I found only one bug so far (I credit it to the extensive comments and planning).

Anywho.?  Check it out if your interested.?  Likes / Dislikes are always welcome.
Regards,
:NaN:



Attachments:
Posted on 2006-08-19 03:10:05 by NaN
BTW, you should be aware that I traced it with OlyDbg so there is Int 3's in the "Test.exe".  Also, I only store one handle in my create test routine.  If you hammer the Create button you will essentially cause a memory leak because you won't be able to destroy all but one handle.

What I checked was the memory mapping, header setup, linking, data setting, freeing memory, destroying all memory and the GetMaxBytes routine.  I haven't tested the extra parameters yet, but im 99.9% sure it will work correctly.

Regards
:NaN:
Posted on 2006-08-19 03:22:00 by NaN