Dynamic code execution in Writeable+Executable memory alloc

Share your advanced PureBasic knowledge/code with the community.
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Dynamic code execution in Writeable+Executable memory alloc

Post by Keya »

hello, today ive been learning all about dynamic code execution, or a feature Intel calls self-modifying code, but of course it doesn't have to be self-modifying, it can simply be code copied over to a new memory region and ran from there. Of course that's then not self-modifying code, just copied or copied+modified code, but it needs the same environment - memory that is Writeable+Executable, and with a cpu instruction cache flush when the code is modified.

Some uses include compression - packers like UPX decompress your executable code into writeable+executable memory section then call it, encryption - protecting code from disassembly, and optimization - for example detecting a CPU feature and modifying some code to take advantage accordingly, just to name a few! Endless possibilities, lol. Hopefully Fred will add support for protection + alignment flags to AllocateMemory() and an option for the main .code section :)

The method is very simple, whew!
1) Get the system page size so we can allocate memory of appropriate size, and it must be page-aligned too so we need to call api such as valloc/VirtualAlloc instead of AllocateMemory.
2) Change its protection to Readable+Writeable+Executable. This is the key - all our other program code is just Readable+Executable, not Writeable
3) Copy the code over, and if we want to make any modifications we can also do them now
4) Flush the instruction cache to ensure the cpu will be executing our new code
5) Call/jmp to the code

Anyway I have managed to put together code to demonstrate this for Windows + Linux + OSX, 32+64, maybe somebody will find them useful too, i couldnt find any similar postings. If not I still had fun learning anyway heehee

For this demo my dynamic code is simply "mov eax 0, ret" (bytes: B8 00000000 C3) ... pretend it was compressed and ive just decompressed it and have copied it into memory at a new Writeable+Executable section. I also patch the code so it becomes "mov eax,123" to prove the dynamic ability.

Linux & OSX:

Code: Select all

#PROT_NONE  = 0
#PROT_READ  = 1
#PROT_WRITE = 2
#PROT_EXEC  = 4
#PROT_ALL   = #PROT_READ + #PROT_WRITE + #PROT_EXEC

ImportC ""
  mprotect (*pmem, pagesize.i, protect.i)
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    clear_cache (*pmem, bytes.i) As "__clear_cache"
  CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
    sys_icache_invalidate(*pmem, bytes.i)
  CompilerEndIf
EndImport


;1) Get system memory page size so we can allocate in multiples of the correct size
pagesize.i = getpagesize_()
If pagesize <= 0: pagesize = 4096: EndIf

;2) Allocate memory. In this case a single page is big enough
*pmem = valloc_(pagesize)
If *pmem = 0
  MessageRequester("Error","valloc failed"): End
EndIf

;3) Change memory section protection to Read+Write+Exec
If mprotect(*pmem, pagesize, #PROT_ALL) = -1
  MessageRequester("Error","mprotect failed"): End
EndIf

;4) Copy the code over to the new memory region at *pmem
CopyMemory(?StartDynCode, *pmem, ?EndDynCode-?StartDynCode)

;5) Its dynamic code so here i overwrite the 0 in "mov eax,0" with 123
PokeA(*pmem+1, 123)   ;Note that we're writing to the new *pmem, not the original at DataSection's StartDynCode

;6) Flush instruction cache to ensure new code is ready to be executed
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  clear_cache (*pmem, pagesize)
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
  sys_icache_invalidate(*pmem, pagesize)
CompilerEndIf

;7) Call the code
Define lret.l
EnableASM 
call *pmem
mov lret, eax
DisableASM
MessageRequester("Result", Str(lret) + " (should be 123)")
End


DataSection
  StartDynCode:   ;Doesnt get executed from here, we copy it to our new memory and execute it there
  ! mov eax, 0    ;We will patch this 0 to 123
  ! ret
  EndDynCode:
EndDataSection
Windows:

Code: Select all

;1) Get system memory page size so we can allocate in multiples of the correct size
Define lpSystemInfo.SYSTEM_INFO
GetSystemInfo_(lpSystemInfo)
pagesize.i = lpSystemInfo\dwPageSize
If pagesize <= 0: pagesize = 4096: EndIf

;2) Allocate memory. In this case a single page is big enough
*pmem = VirtualAlloc_(0, pagesize, #MEM_COMMIT, #PAGE_EXECUTE_READWRITE)
If *pmem = 0
  MessageRequester("Error","VirtualAlloc failed"): End
EndIf

;3) Change memory section protection to Read+Write+Exec
;Not needed though because we already set the protection when calling VirtualAlloc()
;If VirtualProtect_(*pmem, pagesize, #PAGE_EXECUTE_READWRITE, @oldprot) = 0
;  MessageRequester("Error","VirtualProtect failed"): End
;EndIf

;4) Copy the code over to the new memory region at *pmem
CopyMemory(?StartDynCode, *pmem, ?EndDynCode-?StartDynCode)

;5) Its dynamic code so here i overwrite the 0 in "mov eax,0" with 123
PokeA(*pmem+1, 123)   ;Note that we're writing to the new *pmem, not the original at DataSection's StartDynCode

;6) Flush instruction cache to ensure new code is ready to be executed
If FlushInstructionCache_(GetCurrentProcess_(), *pmem, pagesize) = 0
  MessageRequester("Warning", "Cache flush failed")
EndIf

;7) Call the code
Define lret.l
EnableASM 
call *pmem
mov lret, eax
DisableASM
MessageRequester("Result", Str(lret) + " (should be 123)")
End


DataSection
  StartDynCode:   ;Doesnt get executed from here, we copy it to our new memory and execute it there
  ! mov eax, 0    ;We will patch this 0 to 123
  ! ret
  EndDynCode:
EndDataSection
User avatar
idle
Always Here
Always Here
Posts: 5075
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Dynamic code execution in Writeable+Executable memory al

Post by idle »

8) “Joo Janta 200 Super-Chromatic Peril Sensitive Sunglasses have been specially designed to help people develop a relaxed attitude to danger. At the first hint of trouble, they turn totally black and thus prevent you from seeing anything that might alarm you.”

Ok I'm both afraid and impressed! Nice example. :mrgreen:
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Re: Dynamic code execution in Writeable+Executable memory al

Post by Keya »

thankyou :) i dont see anything to be afraid of though
Thorium
Addict
Addict
Posts: 1271
Joined: Sat Aug 15, 2009 6:59 pm

Re: Dynamic code execution in Writeable+Executable memory al

Post by Thorium »

While there are still situations modifying code is usefull. Like the cases you allready told and it's essential for hooks.

Self modifying code in the classical sense is a outdated concept and should not be used on modern CPU's at least not on the x86/64 family of CPU's.
Back in the days self modifiying code was been used to save memory and speed up execution. For example you would have a loop which modified itself instead of branching out.
Today this realy hurts performance. If the CPU detects self modifying code it disables all loop optimizations. This will lead to stalls and makes branch prediction impossible. Performance will drop heavily if you use self modifying code.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Dynamic code execution in Writeable+Executable memory al

Post by djes »

I hadn't seen this nice code at first ! Thank you :)
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: Dynamic code execution in Writeable+Executable memory al

Post by walbus »

On the C64, self-modifying code was regarded as the highest art of programming
For today's machines I self see no need and no sensible application
But it was always a mixture of dirty and ingenious :twisted:

The above mentioned deceleration we get now anyway
Google for the vulnerabilities "Meltdown" and "Spectre"
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Dynamic code execution in Writeable+Executable memory al

Post by djes »

walbus wrote:On the C64, self-modifying code was regarded as the highest art of programming
For today's machines I self see no need and no sensible application
But it was always a mixture of dirty and ingenious :twisted:

The above mentioned deceleration we get now anyway
Google for the vulnerabilities "Meltdown" and "Spectre"
:)
Marc56 remembered us that a long time ago, before personal computer, patches were applied directly in memory on running processus. Engineers then were afraid of a computer reboot because they didn't always know all of them ;)
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: Dynamic code execution in Writeable+Executable memory al

Post by walbus »

Yes, at that time, assembler programming was absolutely necessary
if you needed something that should be fast, or simply better, or available

Much was not available
It wasn't even possible to draw a circle, let alone a filled circle
An 8 bit processor has its drawbacks, overflows occur quickly
But this also had a big advantage, one was forced to master and understand the basics
Programming was also thought to become easier in the future
Unfortunately, the opposite has happened
Actually, things can't go on as they are now
It's all become a big mess
Bitblazer
Enthusiast
Enthusiast
Posts: 735
Joined: Mon Apr 10, 2017 6:17 pm
Location: Germany
Contact:

Re: Dynamic code execution in Writeable+Executable memory al

Post by Bitblazer »

walbus wrote:Programming was also thought to become easier in the future
Unfortunately, the opposite has happened
Actually, things can't go on as they are now
It's all become a big mess
Actually its the same as usual for decades

The QA process for a few experts will now include enhanced mathmatical verification models (or they will get introduced finally ;) - but for millions of developers this doesn't change anything at all. It's really nothing new and this is one of the historical chances where you enter a market while the uninformed masses panic.
User avatar
djes
Addict
Addict
Posts: 1806
Joined: Sat Feb 19, 2005 2:46 pm
Location: Pas-de-Calais, France

Re: Dynamic code execution in Writeable+Executable memory al

Post by djes »

About Meltdown and Spectre, it's crazy how we can get panicked about a program being able to read whole memory, when in the past, full memory was readable by any processus. Computers were and are still untrustworthy machines, but they're now containing much more delicate data...

BTW, Spectre has showed that it's possible to access protected memory content with javascript. I think it's not only the hardware maker who is responsible, but the OS and navigator developer.

Anyway, you're right, it's giving us opportunities because a lot of people will now feel more concerned than ever about privacy, and lack of real security.
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: Dynamic code execution in Writeable+Executable memory al

Post by walbus »

Yes djes, where there are people, mistakes are made
And unfortunately, it's always a banging and stabbing, the big ones eat the little ones.

I think the AI will come up with a solution someday.

As soon as you succeed in constructing an intelligent machine that can replicate itself in an improved way, there will be no stopping LOL

@Bitblazer
I myself am always looking for simple solutions, because I am more of a practical thinker
I self think, you don't have to be stupid to look for the easy way or solutions
The Americans have developed a ballpoint pen for one million dollars that works in weightlessness, the Russians use a pencil :wink:
User avatar
blueb
Addict
Addict
Posts: 1043
Joined: Sat Apr 26, 2003 2:15 pm
Location: Cuernavaca, Mexico

Re: Dynamic code execution in Writeable+Executable memory al

Post by blueb »

walbus wrote:... The Americans have developed a ballpoint pen for one million dollars that works in weightlessness, the Russians use a pencil :wink:
Very true and I applaud that type of thinking. :)

But NASA and it's 'expensive' ideas have also benefited society.. https://spinoff.nasa.gov/Spinoff2008/pd ... ff2008.pdf
- It was too lonely at the top.

System : PB 6.10 LTS (x64) and Win Pro 11 (x64)
Hardware: AMD Ryzen 9 5900X w/64 gigs Ram, AMD RX 6950 XT Graphics w/16gigs Mem
walbus
Addict
Addict
Posts: 929
Joined: Sat Mar 02, 2013 9:17 am

Re: Dynamic code execution in Writeable+Executable memory al

Post by walbus »

Yep blueb, you are right, of course there are not simple solutions for everything, our future lies in high technology

But, also the search for simple solutions is very important.
Costs are saved, errors are reduced and more people have access to them.

I also find it outrageous and arrogant to want to leave or attribute efficient programming to an elite.

Nobody should underestimate the "swarm intelligence", together a lot can be achieved.
User avatar
Psychophanta
Addict
Addict
Posts: 4990
Joined: Wed Jun 11, 2003 9:33 pm
Location: Lípetsk, Russian Federation
Contact:

Re: Dynamic code execution in Writeable+Executable memory al

Post by Psychophanta »

Nice. Specially the Linux & OSX code.
It remembered to me to this history:
http://www.purebasic.fr/english/viewtop ... f=3&t=8502
http://www.zeitgeistmovie.com

While world=business:world+mafia:Wend
Will never leave this forum until the absolute bugfree PB :mrgreen:
Post Reply