Runtime Code Generation or Just Some Hax

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Runtime Code Generation or Just Some Hax

Post by 1000101 »

I was playing around trying to create executable code on the fly. This is a very simple, very bad example of how you can create some code at runtime and execute it.

Requires fbc 0.21

Code: Select all

namespace       opcodes
        
        
        Const   As uByte _
                FLAG_NONE               = 0, _
                FLAG_IMMEDIATE          = 1, _
                FLAG_MEM_DST            = 2, _
                FLAG_MEM_SRC            = 4
        
        
        sub     ret             naked   ()
                asm
                        .byte   FLAG_NONE
                        .byte   __FUNCTION_NQ__##FINISH - __FUNCTION_NQ__##BEGIN
                        __FUNCTION_NQ__##BEGIN:
                        ret
                        __FUNCTION_NQ__##FINISH:
                end asm
        end sub
        
        
        namespace       add
                
                
                sub     ab      naked   ()
                        asm
                                .byte   FLAG_NONE
                                .byte   __FUNCTION_NQ__##FINISH - __FUNCTION_NQ__##BEGIN
                                __FUNCTION_NQ__##BEGIN:
                                add     eax, ebx
                                __FUNCTION_NQ__##FINISH:
                        end asm
                end sub
                
                
                sub     ba      naked   ()
                        asm
                                .byte   FLAG_NONE
                                .byte   __FUNCTION_NQ__##FINISH - __FUNCTION_NQ__##BEGIN
                                __FUNCTION_NQ__##BEGIN:
                                add     ebx, eax
                                __FUNCTION_NQ__##FINISH:
                        end asm
                end sub
                
                
        end namespace
        
        
        namespace       mov
                
                
                sub     ai      naked   ()
                        asm
                                .byte   FLAG_IMMEDIATE
                                .byte   __FUNCTION_NQ__##FINISH - __FUNCTION_NQ__##BEGIN
                                __FUNCTION_NQ__##BEGIN:
                                mov     eax, 0
                                __FUNCTION_NQ__##FINISH:
                        end asm
                end sub
                
                
                sub     bi      naked   ()
                        asm
                                .byte   FLAG_IMMEDIATE
                                .byte   __FUNCTION_NQ__##FINISH - __FUNCTION_NQ__##BEGIN
                                __FUNCTION_NQ__##BEGIN:
                                mov     ebx, 0
                                __FUNCTION_NQ__##FINISH:
                        end asm
                end sub
                
                
                sub     ma      naked   ()
                        asm
                                .byte   FLAG_MEM_DST
                                .byte   __FUNCTION_NQ__##FINISH - __FUNCTION_NQ__##BEGIN
                                __FUNCTION_NQ__##BEGIN:
                                mov     [0], eax
                                __FUNCTION_NQ__##FINISH:
                        end asm
                end sub
                
                
                sub     am      naked   ()
                        asm
                                .byte   FLAG_MEM_SRC
                                .byte   __FUNCTION_NQ__##FINISH - __FUNCTION_NQ__##BEGIN
                                __FUNCTION_NQ__##BEGIN:
                                mov     eax, [0]
                                __FUNCTION_NQ__##FINISH:
                        end asm
                end sub
                
                
        end namespace
        
        
end namespace


type    runtimecode
        
        
        Declare                         Constructor     ( Byval As Const uInteger )
        Declare                         Destructor      ()
        
        Declare Sub                     AddOp           ( Byval As Const Sub (), Byval As Const uInteger = 0 )
        
        Declare Sub                     sExecute        ()
        Declare Function                fExecute        () As uInteger
        
        Declare Sub                     Dump            ()
        
        Private:
        Union
                As uByte Ptr                    rData
                As Sub()                        sCode
                As Function() As uInteger       fCode
        End Union
        
        As uInteger                     Offset
        As uInteger                     Bytes
        
end type


Constructor     runtimecode             ( Byval Size As Const uInteger )
        
        Bytes           = 0
        rData           = Callocate( Size )
        If( rData       = 0 )Then Exit Constructor
        
        Offset          = 0
        Bytes           = Size
        
End Constructor


Destructor      runtimecode             ()
        
        
        If( rData )Then Deallocate( rData )
        Offset          = 0
        Bytes           = 0
        
        
End Destructor


Sub             runtimecode.AddOp       ( Byval Op As Const Sub (), Byval something As Const uInteger )
        
        If( Bytes               = 0     )Then Exit Sub
        If( rData               = 0     )Then Exit Sub
        
        Dim As uByte            Flag    = cPtr( uByte Ptr, Op )[ 0 ]
        Dim As uByte            Size    = cPtr( uByte Ptr, Op )[ 1 ]
        Dim As uByte            cSize   = Size
        
        
        /'
                FLAG_IMMEDIATE          = 1, _
                FLAG_MEM_DST            = 2, _
                FLAG_MEM_SRC            = 4
        '/
        If      ( Flag And opcodes.FLAG_IMMEDIATE       )_
        OrElse  ( Flag And opcodes.FLAG_MEM_SRC         )_
        OrElse  ( Flag And opcodes.FLAG_MEM_DST         )Then cSize -= 4
        
        
        '?Size, cSize, bin( flag, 4 )
        
        
        If( Offset + Size       > Bytes )Then Exit Sub
        
        
        For Index As uInteger = 0 To cSize - 1
                
                rData[ Offset + Index ] = cPtr( uByte Ptr, Op )[ 2 + Index ]
                
        Next
        
        Offset          += cSize
        
        
        If      ( Flag And opcodes.FLAG_IMMEDIATE       )_
        OrElse  ( Flag And opcodes.FLAG_MEM_SRC         )_
        OrElse  ( Flag And opcodes.FLAG_MEM_DST         )Then
                
                Dim As uByte Ptr        pI      = cPtr( uByte Ptr, @something )
                
                For Index As uInteger = 0 To 3
                        rData[ Offset + Index ] = pI[ Index ]
                next
                
                Offset  += 4
                
        End If
        
        
End Sub


Sub             runtimecode.sExecute    ()
        
        If( Bytes               = 0     )Then Exit Sub
        If( rData               = 0     )Then Exit Sub
        
        
        sCode()
        
        
End Sub


Function        runtimecode.fExecute    () As uInteger
        
        If( Bytes               = 0     )Then Return &HDEADBEEF
        If( rData               = 0     )Then Return &HDEADBEEF
        
        
        Function        = fCode()
        
        
End Function


Sub             runtimecode.Dump        ()
        
        If( Bytes               = 0     )Then Exit Sub
        If( rData               = 0     )Then Exit Sub
        
        
        For Index As Integer = 0 To Offset - 1
                Print Hex( Index, 4 ) & ": " & Hex( rData[ Index ], 2 )
        Next
        
        
End Sub




Dim As runtimecode Ptr          exeObj
Dim As uInteger                 foo     = 1234
Dim As uInteger                 bar     = Any


exeObj = New runtimecode( 32 )  '' <---- MAKE SURE THIS IS LARGE ENOUGH FOR YOUR PROGRAMZORZ!



exeObj->AddOp( @opcodes.mov.am, Cast( uInteger, @foo ) )        '' No cast = stupid warnings
exeObj->AddOp( @opcodes.mov.bi, 7890 )
exeObj->AddOp( @opcodes.add.ba )
exeObj->AddOp( @opcodes.mov.ai, 6543 )
exeObj->AddOp( @opcodes.add.ab )
exeObj->AddOp( @opcodes.mov.ma, Cast( uInteger, @bar ) )        '' No cast = stupid warnings
exeObj->AddOp( @opcodes.ret )


'exeObj->Dump()


Print "foo: " & foo
Print "bar: " & bar
Print
Print "fExecute()"
Print
Print "Output: " & exeObj->fExecute()
Print "foo: " & foo
Print "bar: " & bar


Sleep
Delete exeObj
End
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Post by D.J.Peters »

nice idea
may be you can overload AddOpcode so you don't need to cast any thing.

Joshy
1000101
Posts: 2556
Joined: Jun 13, 2005 23:14
Location: SK, Canada

Post by 1000101 »

I looked at that, but it was a wasted effort for a proof of concept.
KaraK
Posts: 72
Joined: Sep 13, 2006 19:01
Location: Argentina

Post by KaraK »

interesting piece of code, really neat for implementing antidebugger/anti-RE techniques more effectively.
JaDogg
Posts: 345
Joined: Apr 13, 2008 12:11
Location: Sri Lanka - Negombo
Contact:

Post by JaDogg »

man this is what i've been waiting for
Post Reply