flat assembler
Message board for the users of flat assembler.

Index > Main > Self-modifying COFF

Author
Thread Post new topic Reply to topic
donn



Joined: 05 Mar 2010
Posts: 321
donn 10 Mar 2017, 19:26
Can I self-modify a
Code:
section '.text' code readable writeable executable    
section in a COFF during execution?

For example, can I copy some instructions over into a function at a particular label? This seems possible during runtime, as long as I reserve enough space in the function.

Any limitations anyone is aware of?


Thanks!
Post 10 Mar 2017, 19:26
View user's profile Send private message Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2565
Furs 10 Mar 2017, 23:14
As long as the section is writeable, yes you can use self-modifying code.

I'm not aware of any "limitations" except that doing so often is slow (cache / pipeline flushing etc). But of course, if you do a rare change such as from a setting or input, the result could actually be faster if it's ran many times (no conditionals for that setting if you "hardcode" it into the code by modifying it). Just don't modify code within an inner loop or something Smile

I assume COFF is the PE executable right? (cause I've used self-modifying code on Windows binaries just fine...)
Post 10 Mar 2017, 23:14
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 11 Mar 2017, 02:37
Many AVs will panic when they see SMC. So there is that "problem" that you might encounter.

But otherwise the x86 CPU will do-the-right-thing and correctly handle SMC without a problem. Even the caches and pipelines are properly snooped and flushed when required.
Post 11 Mar 2017, 02:37
View user's profile Send private message Visit poster's website Reply with quote
donn



Joined: 05 Mar 2010
Posts: 321
donn 11 Mar 2017, 16:14
Awesome! That's certainly a valid concern regarding the inner loops. Copying the instructions is a lot different from conditions and addressing.

MS COFF is Windows, Common Object Format I think, linkable also. Yes. I was a bit worried the x86 might perform some modifications of its own or cache incorrectly and get confused.

Will try this soon...
Post 11 Mar 2017, 16:14
View user's profile Send private message Reply with quote
Xorpd!



Joined: 21 Dec 2006
Posts: 161
Xorpd! 12 Mar 2017, 16:05
I am myself curious as to your results, although unfortunately too lazy to check just now. I thought that if you linked a bunch of *.OBJ files together that all segments with the same name got concatenated into a single segment.

But does that mean that your segment becomes no longer writeable because it's linked with other non-writeable segments or that that other segments become writeable thus creating a security hole?

In Windows you can map pages as writeable at run-time with VirtualAlloc and VirtualProtect. In 32-bit Windows you can link the FASM.DLL into your application and assemble code at run-time as well. No such luck in 64-bit Windows.
Post 12 Mar 2017, 16:05
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 12 Mar 2017, 16:21
All linkers I've used will not merge sections that are not the same is all respects. So if you have differing write-permission flags then you get two sections.
Post 12 Mar 2017, 16:21
View user's profile Send private message Visit poster's website Reply with quote
Xorpd!



Joined: 21 Dec 2006
Posts: 161
Xorpd! 13 Mar 2017, 05:09
I didn't know that. I tried an example *.OBJ file:
Code:
format MS64 COFF

section '.text' code readable writeable executable
public test1
test1:
   mov RAX, test2
   ret

section '.text' code readable executable
public test2
test2:
   mov RAX, test1
   ret

section 'stuff' code readable executable
public test3
test3:
   mov RAX, 100
   ret

section 'more' code readable executable
public test4
test4:
   mov RAX, test3
   ret
    

So when you call test4 it gives you a pointer to the code of test3 and when you call test1 it gives you a pointer to the code of test2. Using these pointers to copy the test3 code into test2, the program crashes. However, if we instead call test2 first to get a pointer to the code of test1 and then copy the code of test3 into test1, the program runs and test1 now returns 100. So this worked with LINK.exe, although it whines with a LNK4078. Nice to know Smile
Post 13 Mar 2017, 05:09
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20451
Location: In your JS exploiting you and your system
revolution 13 Mar 2017, 05:17
There might be some command line switches that allow forcing the merge? But would it use the most restrictive or the most permissive setting for the flag?
Post 13 Mar 2017, 05:17
View user's profile Send private message Visit poster's website Reply with quote
donn



Joined: 05 Mar 2010
Posts: 321
donn 27 Apr 2017, 19:50
Just an update: Put some time into this but getting some errors when it runs. I think I'm able to copy the instructions into a function, but when I run the function, the executable stalls.

It's probably just a problem with the addresses of the functions and offsets I'm using, so should be fixable. Haven't been able to spend too much time on it either.
Post 27 Apr 2017, 19:50
View user's profile Send private message Reply with quote
donn



Joined: 05 Mar 2010
Posts: 321
donn 30 Apr 2017, 18:22
Wow, it actually works. I was able to copy a couple mov instructions to another function (func2 below) and verified that the movs executed when the function (func2) ran. My setup:

Code:
func1:
.modificationLabel:
mov rcx, 58 ;random instructions
mov rax, rcx ;random instructions
...;random instructions for later verification
.endModificationLabel:
;optionally subtract modificationLabel from endModificationLabel to determine instruction byte size
;then, movsb to func2's destinationLabel 

func2:
.destinationLabel:
rb 32 ;size determined once from subtraction. Re-run the subtraction if any changes are made there, not able to determine this dynamically?
;then, writeFile the contents of rax, etc (set by random instructions defined in func1)
    


There's a bit more to the setup, but it's behaving as expected so far. Before getting started with this, I had to spend time converting the entire COFF from 32 to 64 bits, which was a bit of a learning curve. The rsp alignment manipulations were a huge pain (still are).

I'm not able to copy calls yet, however. They cause runtime stalls when func2 executes. For example,

Code:
        
.modificationLabel:
mov rcx, 81
sub rsp, 8*4
call numAsLetters
add rsp, 8*4
mov rcx, rax
sub rsp, 8*4
call debugMsg2
add rsp, 8*4
.endModificationLabel:
    



which my subtraction says is 36 bytes, will copy to func2, but the moment I run func2, the executable stalls and the calls do not execute (numAsLetters, debugMsg2 are custom functions). Maybe it's an rsp problem, not sure yet.
Post 30 Apr 2017, 18:22
View user's profile Send private message Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2565
Furs 30 Apr 2017, 19:52
Calls are encoded as relative to the instruction pointer, are you sure you use the same base address? You need to find the base of the function you want to modify (i.e. the address of func2) and use 'org' directive before your modification label. This tells FASM to assume the address of the function is there, so it encodes calls properly. Of course you will have to make sure your code is relocated relative to the exe/library always the exact same.

If the executable (or library, even worse) is dynamically relocated (ASLR? idk if you can turn it off in Windows x64 with some PE/COFF property) you'll have to absolutely make sure your numAsLetters and other functions are always relocated in the exact same way relative to it. So if it gets placed at +1000, your code must be at +1000 also.

Otherwise, you'll have to generate the call instruction's offset when you "copy" it, accordingly. You can't just copy it and expect relative-addressing to work. BTW this includes any rip-relative offsets you use in the replacement that accesses your variables (globals).

Also I don't know if this works with COFF, but sounds to me like you need to fiddle with low level stuff. You should learn some basic instruction encoding first. Wink
Post 30 Apr 2017, 19:52
View user's profile Send private message Reply with quote
donn



Joined: 05 Mar 2010
Posts: 321
donn 02 Jun 2017, 15:33
Cool, working on a few things in parallel, but almost got it now. The conversion to 64-bit has required a lot of changes.

Think I more or less get the RIP requirements and yes, assembling by hand really helps. I've encoded (with db) some 32 bit instructions with mod/rm etc, getting up to speed with the 64-bit.

A big problem I just realized was that enough stack space needs to be reserved for any function that is called or that the called function calls. So if function A requires only 4 parameters but A calls B, which requires 6, rsp needs to be decremented enough for function B.

My debug function called the WIN createfile which required 7 parameters. It was stalling in 64-bit mode when calling the debug func within another func with
Code:
sub rsp, 8*4    
. Trying not to use a debugger yet, so gets difficult when my "debugger" breaks.

Should be good now, will reach out if I have any questions down the road, but think it'll work out.
Post 02 Jun 2017, 15:33
View user's profile Send private message Reply with quote
donn



Joined: 05 Mar 2010
Posts: 321
donn 05 Jul 2017, 19:42
Got it to work with this syntax, FYI:

Code:
        .modification:
        mov rcx, 89                             ;Test value to retrieve once moved
        sub rsp, 8*4
        mov rdx, numAsLetters
        call rdx
        add rsp, 8*4
        mov rcx, rax
        sub rsp, 8*7
        mov rdx, debugMsg2
        call rdx
        add rsp, 8*7
        .endModification:    


Copied this block to another function at runtime. Wrote 89 to a file once the destination function was executed.
Post 05 Jul 2017, 19:42
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.