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:
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:
mov eax, ProcessorType lea eax, jmp dword ptr
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:
.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
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. Thomas
invoke MemCopy, offset ProcedureYouWantToUse,\ offset OffsetInCodeToWrite,\ FunctionXXXlen
what 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 :
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 ?
.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
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 :
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 AM
.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 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
PMODE Operating System
Qweerdy, here's a few site on pmode and os related that i once- found.
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.