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).
Posted on 2001-05-05 14:03:00 by dxantos
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
Posted on 2001-05-05 15:20:00 by 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 ;(
Posted on 2001-05-06 03:43:00 by BogdanOntanu
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 ?
Posted on 2001-05-06 04:56:00 by karim
BogdanOntanu, are u talking about win2k too?i dont think so..
Posted on 2001-05-06 06:12:00 by Shaolinwu
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
Posted on 2001-05-06 07:55:00 by 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).
Posted on 2001-05-06 17:02:00 by dxantos
Hey, I would like to self modify the code to improve math calculations too!
Posted on 2001-05-06 17:31:00 by wolfao
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.
Posted on 2001-05-07 01:03:00 by George
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. Thomas
Posted on 2001-05-07 01:46:00 by Thomas
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
Posted on 2001-05-07 13:12:00 by vineon
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 ?
Posted on 2001-05-07 19:58:00 by karim
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.
Posted on 2001-05-07 20:43:00 by eeprom
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.
Posted on 2001-05-09 06:22:00 by f0dder
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 AM
Posted on 2001-05-10 18:20:00 by karim
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!
Posted on 2001-05-11 05:25:00 by MikeW
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 :)
Posted on 2001-05-11 07:19:00 by BogdanOntanu
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
Posted on 2001-05-11 13:02:00 by Qweerdy

 Qweerdy, here's a few site on pmode and os related that i once-
 found.
PMODE Operating System
Posted on 2001-05-11 13:23:00 by disease_2000

 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.
Posted on 2001-05-11 13:28:00 by disease_2000