Hi.
Is it possible to make self modifiying code in Win32?
If so, where can we find examples?
Basically what I want is to modify a function at runtime depending on the procesor. (Pentium, AMD, etcetera).
Why don't you just add the code for all the processors and then add a IF/ELSE/ENDIF to jump to the right code, according to the type of processor?
Thomas
Yes it is very possible, because usually selectord in GDT or LDT are defined in such a way that there is a data read/write slelctor exactly at the same address as the code selector ;)
this makes windows so UNSURE and UNPROTECTED ;) besides windows also has some undocumented selectors that can gain access to the HOLE memory.....(this a great system design flaw)
i usually think a lot about that....for my own OS ... but FORTH requires that data and code will be mixed together ... (and i like FORTH too much to discard it ;)
also COM likes that (objects) and ultimately all von Neuman architecture is based on this data and code mixture....
IMHO this gives great opportunities...but also great problems ;(
Can you give more details please ? How can you avoid protection fault when you use a segment selector that points to an execute-read code segment ? I've used the VirtualProtect function to change the access rights of the pages where the code is executed, but when I write in the code segment there is a protection fault. Do you have more info ?
BogdanOntanu,
are u talking about win2k too?i dont think so..
Do you want to change your own program's code or code of another process? If you just want to change your own code you can set the 'write' flag in the code section with the /SECTION option of link. Sorry if I misunderstood what you want but this seems a lot easier to me.
Thomas
I only want to self modify my own code. I want to make math functions optimized for different processors (so I can take advantage of SMID and Athlon optimizations when available), but without using Virtual tables or a different dll. (I wish them to go as fast as possible).
Hey, I would like to self modify the code to improve math calculations too!
BogdanOntanu, I know this is contradictory, but that is exactly what I thought until I tried to modify my own code, and it didn't work. Unless you do specify the /SECTION:.text,w switch in linking or call VirtualProtect to adjust the page attributes you are going to cause a page fault.
I still havn't figured out why, I dont actuly know enought about the actual paging ins and outs to say if its attributes to do with the page table.
I think using a simple lookup table will be much easier, like:
mov eax, ProcessorType
lea eax,
jmp dword ptr
Then in the lookuptable, put the offsets of the different procedures, indexed by the ProcessorType. It takes some extra clocks but does that really matter?
If you want to use self modifying code: I haven't used this but to get you started:
.code
Function1 proc
xor eax, eax
inc eax
ret
Function1 endp
Function1len equ $-Function1
Function2 proc
mov eax, 123
ret
Function2 endp
Function2len equ $-Function2
Function3 proc
mov eax, 6
shl eax, 5
add eax, 600
ret
Function3 endp
Function3len equ $-Function3
Now there are three functions, and you should have some space in the code where each of these functions fits. You have to choose this yourself, either allocate some extra bytes:
FunctionWillBeWrittenHere db 100 dup (?)
Or you can use the longest function, and then overwrite it with one of the other functions if necessary.
To change a function, just use MemCopy from the masm32lib:
invoke MemCopy, offset ProcedureYouWantToUse,\
offset OffsetInCodeToWrite,\
FunctionXXXlen
offset OffsetInCodeToWrite is the offset of the function that has to be changed. This is either the allocated blank space or the longest function (this way you don't have to add useless bytes).
After the memcopy, call the OffsetInCodeToWrite to execute the routine.
The code isn't tested or something, so it might have some problems, but maybe it helps you.
Thomaswhat about VirtualProtect():
DWORD OldProt;
invoke VirtualProtect, o AdressWhereToChange, Size_Where_To_Change, PAGE_EXECUTE_READWRITE, o OldProt
; now change everything
;and then again put the old one
invoke VirtualProtect, o AdressWhereToChange, Size_Where_To_Change, OldProt, o OldProt
just PAGE_EXECUTE is better (performance) than PAGE_EXECUTE_READWRITE so put the original state back.
oh sorry, i see someone already said that. i should better read before i write :)
This message was edited by vineon, on 5/7/2001 1:15:41 PM
There is also the WriteProcessMemory function. I write this small program but it doesn't work. Here is the source :
.data
handle HANDLE ?
str1 byte "Function1", 0
str2 byte "Function2", 0
.code
; F1 displays "function1"
F1 proc
invoke MessageBox, NULL, addr str1, addr str1, MB_OK
ret
F1 endp
; F1 length
LF1 = $ - F1
; F2 displays "function2"
F2 proc
invoke MessageBox, NULL, addr str2, addr str2, MB_OK
ret
F2 endp
; F2 length
LF2 = $ - F2
; compute max length for F
if LF2 gt LF1
MAX = LF2
else
MAX = LF1
endif
; F will be overwritten by F1 and F2
F proc
dword MAX/4+1 dup (090909090h) ; 090 is NOP opcode
F endp
start:
invoke GetCurrentProcessId
; get a handle with right access
invoke OpenProcess, PROCESS_VM_READ or PROCESS_VM_WRITE,
TRUE, eax
mov handle, eax
; overwrite F with F1
invoke WriteProcessMemory, handle, F, F1, LF1, NULL
call F
; overwrite F with F2
invoke WriteProcessMemory, handle, F, F2, LF2, NULL
call F
invoke ExitProcess, 0
end
When debugging the program with VC++, F is at offset 00401038h in memory. The problem is that the F argument in the WriteProcessMemory function call is passed with a "push 0400000h" instead of a "push 00401038h" . When the function is executed, the F function is overwritten with the data at 0400000h. There is no protection fault. The only problem is the offset. Do you have any ideas ?I've never done a self-modifying code, but I have a idea wich could help (I hope). I was reading the Win32API and discovered the following...
"The GlobalAlloc function allocates the specified number of bytes from the heap...
All memory is created with execute access; no special function is required to execute dynamically generated code.
"
I think you could allocate some Mem for your functions, modify them and then execute them directly from that memory. In this way you can load and execute the best function for that specific processor.
Easiest is definitely to use the /SECTION switch when linking,
and give your code (.text) section write access.
As for you BogdanOgtanu, are you saying that flat mode is bad
and we should go back to segmented? Sure, with 32bit pmode we
can have big segments and all, but (imho) flatmode is the best.
It's very easy, and you can do protection on a page basis, which
is also a hell of a lot more secure. The reason win9x is "unprotected"
and "unsure" is that it doesn't do the page protections very
well -- ie, you have read/write access to the IDT and other
memory areas that a ring3 app definitely shouldn't have access
to.
As for the original topic, self modifying code, I think it's a
great thing -- but know when to use it and when not! If you have
to modify the code often to make your stuff work, then it's
probably not worth it (iirc, there's pretty big time penalties
when executing code that has just been modified. Pipelines and
stuff). But if you only have to set up the SMC once at app start,
it can very well be worth it.
Also, keep in mind that SM code isn't re-entrant. You can run
into some pretty interesting problems if you don't keep this in
mind ;).
Oh, and a final thing...if you do a lot of SMC, you should set
the write permission with the linker switch. If you only do a
single "init" at program start, and don't change code after that,
I would go for VirtualProtect, so the code is protected the rest
of the time, which makes it easier to catch bugs.
I've found a solution to my problem. Here is an example of self modifing code :
.486
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
.data
handle HANDLE ?
g_hFunc DWORD ?
str1 byte "Function1", 0
str2 byte "Function2", 0
.code
F1:
push MB_OK
push offset str1
push offset str1
push NULL
call g_hFunc
ret
LF1 = $ - F1
F2:
push MB_OK
push offset str2
push offset str2
push NULL
call g_hFunc
ret
LF2 = $ - F2
if LF2 gt LF1
MAX = LF2
else
MAX = LF1
endif
F:
DWORD MAX/4+1 dup (090909090h) ; NOP opcode
ret
start:
; save MessageBox absolute address
mov eax, near32 ptr MessageBox
mov g_hFunc, eax
; change access rights for the process memory
invoke GetCurrentProcessId
invoke OpenProcess, PROCESS_VM_READ or PROCESS_VM_WRITE, TRUE, eax
mov handle, eax
; F <- F1
invoke WriteProcessMemory, handle, F, F1, LF1, NULL
call F
; F <- F2
invoke WriteProcessMemory, handle, F, F2, LF2, NULL
call F
invoke ExitProcess, 0
end start
First I have compiled with the /coff option. Then, the problem was that the call to MessageBox in F1 is actually a relative jump to another instruction which jumps to the real address of the function. So when you copy F1 into F, all the offsets are translated and you jump to the wrong instruction.
To correct the problem, I use the absolute offset of the MessageBox function.
This message was edited by karim, on 5/11/2001 2:48:59 AMFirst of all i have to say that we are coding in ASM, not in Basic!
Dont mess around with WriteProcessMemory or VirtualProtect or
etc shit..
Very Simple way: Stuff your code into the .DATA section which is
already read/write able ==> so no exception occurs!
Another way is
to manually set the Flags in the Section-header of the compiled and linked file!
you can use a tool like PEWRSEC from Jacky Qwerty
Happy coding!
Nope i did not want to say that flat pmode is better or worst then segmented pmode....(this is still undecided)
i just wanted to point out the BIG mistakes (same as you) that make Win95 so unprotected...
like selectors 30 and 31 ...whole memory accesc :)
BogdanOnatu, how do you use a specific selector? I'm pretty new to OS coding, I've only found some good sites. Could you give me some links?
Here's what I have:
http://www.v2os.cx/
http://www.winix.org/osdev/index.html
http://www.execpc.com/~geezer/osd/index.htm
Qweerdy, here's a few site on pmode and os related that i once-
found.
PMODE
Operating System
by the way, if you have spare time, spend it with the OPERATING
SYSTEM link. It has alot of useful info!!! keep on reading and-
soon or later you'll be able to code your very own small OS.
dos programming is cool. happy coding.