HelpConvert asm instruction to corresponding bytes

Posts 1–15 of 36 · Page 1 of 3
Convert asm instruction to corresponding bytes
Just as the title says, I want to 'convert' (poor word choice) from asm instruction to cpu code.

mov eax, ebx
mov ebx, eax
mov [eax], ebx
etc, etc.

It's basically just a look-up table since asm is just a text representation of the code, but I was wondering if anyone had comments/suggestions?

-My basic idea (since I know a little about asm, but not much:and will only work for my cpu type obviously) was to use CheatEngine because it allows you to type in asm and it'll compile for you. So basically I'm going to manually type in instructions into CE and see what the resulting bytes are, and go from there.


The goal is, for creating code-caves and what-not, since vb doesn't have __asm like C++ does.
Future code demo might look something like...
Code:
Dim asmStrings As List(Of String)
  
  += "push eax"
  += "mov eax, 1234"
  += "mov [eax], esp"
  += "add eax, 1" // inc eax?
  += "mov [eax], ebp
  += "pop eax"
  += "rtn"
Dim someBytes() as Byte = MyLittleCompilerClass.Compile(asmStrings)
..
-I don't want a full blown compiler! Only supporting a very small subset of the instructions. It doesn't have to make multiple passes over the asm code! No loops etc. And I know the jmps will be slightly tricky. I basically know what I have to do: I'm not looking for a "how to", just any suggestions/comments.

Comments are appreciated.
All i can say is good luck to you.

At one point i thought about doing this aswell but i wasn't up for all the coding that would be involved.
I still use bytes atm, maybe some day i'll make a mini asm class as you're trying to do.
I'm working on it right now It will probably only support the mov, add, inc and push/pop commands (2-3 more). Should be enough for the codecaves I make. We'll see in a couple days.
I should probably just look at the CE source code (or any open source compiler/assembler), but I thought doing it myself would be a good learning exercise.
I might be wrong, but at least for java, from what I see from the disassembly is that the bytecode executed by JIT is not compatible with the Intel instruction set. I was just wondering how you would go about actually executing the code with JIT.

Code:
// Bytecode stream: 03 3b 84 00 01 1a 05 68 3b a7 ff f9
// Disassembly:
iconst_0      // 03
istore_0      // 3b
iinc 0, 1     // 84 00 01
iload_0       // 1a
iconst_2      // 05
imul          // 68
istore_0      // 3b
goto -7       // a7 ff f9
If you keep it simple you should be ok.
Caves shouldn't be an issue for you.

samuri25404 over at the CE forum made an opcode dll in C#.
Might be something in it you could use
@virtualVoid huh? What about bytecode? (Sorry, sometimes I say 'bytecode' when really I mean ..native code? raw cpu instructions. Can't think of the word.)
Anyway, to run the codecave I write a jmp at some game_code location that I know gets called often.
Possibly make codecave patch game_code back to orig. when it's finished.


I know I'll have to take cpu architecture /syntax/endianness into consideration. For now it's only targeting [my] x86.
.
.
@Pingo when I run into trouble / looking for improvements, I'll def. check that out, thank you. I have been using someone else's .dll to do it, but I think it's time I write my own.
Well, considering that .NET runs in a virtual machine, and that it is JIT also, I would think a problem would arise, which is how would you get your instructions to the processor? The virtual machine takes in the code, which is not native, and then outputs the instructions to your processor. So I was just wondering how would you pass the native processor instructions through the virtual machine to the processor?
Quote Originally Posted by Auxilium View Post
Well, considering that .NET runs in a virtual machine, and that it is JIT also, I would think a problem would arise, which is how would you get your instructions to the processor? The virtual machine takes in the code, which is not native, and then outputs the instructions to your processor. So I was just wondering how would you pass the native processor instructions through the virtual machine to the processor?
It's quite possible using Marshal.GetDelegateForFunctionPointer. Something along the lines of (in C# cause I cbf in VB.NET):

Code:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void AssemblyStubDelegate();

void ExecuteStub(IntPtr address) // Address of stub allocated via VirtualAlloc with execute rights
{
    var stub = Marshal.GetDelegateForFunctionPointer(address, typeof(AssemblyStubDelegate));
    stub();
}
Of course, this limits the stub to the current architecture of the processor and the bitness of the running process.

Also, refer to these for conversion:
https://en.wikibooks.org/wiki/X86_As...age_Conversion
http://wiki.osdev.org/X86-64_Instruction_Encoding

You might seriously consider using FasmManaged which allows inline ASM in .NET.
@virtualvoid "So I was just wondering how would you pass the native processor instructions through the virtual machine to the processor?"

Dim myCodeCaveAddr as IntPtr = VirtualAllocEx(...)
WriteProcessMemory(mycodeCaveAddr, myCodeCaveBytes)
It's not the best way to go about doing it, but.
.
.
@master131 thanks for the ideas / links, 2nd linkwas useful.

---------- Post added at 08:17 AM ---------- Previous post was at 07:30 AM ----------

--
So many "Select Case"s Will post some actual code later. It's not very object-oriented (a few too many variables named 'tmpString'), but it'll get there.

vv some of what I'm trying to replicate.
Those instructions in your picture wouldn't be hard to replicate.
You could just parse the opcode(string) and return the bytes maybe?

I'm interested in seeing some code bro?
haha, "You could just parse the opcode(string) and return the bytes maybe?" is exactly what I'm 'trying' to do.
Currently my code has a lot of switches/ifs and isn't very pretty. Basically I'm not sure how to go about structuring it. I should make a proper syntax analyzer, but since this is my first time seriously working on it, I'm using .SubString(), split(), mid() etc. It's rough. Anyway, here's a piece. It got a lot more complex once I wanted to start adding [ ] 's, but I'll tackle that tomorrow, it's about 8am now and I work at 5
.
 
Assemble()

Code:
Public Class abasm 
..
Public Function Assemble() As Byte()
        Dim _rtnBytes As New List(Of Byte)
        Dim _asmInstruction As String = ""
        Dim _currentLineCount As Int32 = 0
        Dim _tmpFirstSpaceLoc As Int32 = 0  ''first occurance of a space character, Chr(32), in the string. If it has one*
        Dim _tmpFirstCommaLoc As Int32 = 0  ''first occurancce of a comma character (,) in the string. If it has one*
        Dim _tmpInt32 As Int32 = 0

        For Each asmCmd As String In _asmLines.ToArray
            If Not String.IsNullOrWhiteSpace(asmCmd) Then 'silly programmer
                _currentLineCount += 1
                _tmpFirstSpaceLoc = asmCmd.IndexOf(" ")
                If _tmpFirstSpaceLoc = -1 Then
                    'no spaces, it's must be a single command.
                    Select Case asmCmd
                        Case "rtn"
                            _rtnBytes.Add(&HC3) '?
                        Case "nop"
                            _rtnBytes.Add(&H90)
                        Case "pushad"
                            _rtnBytes.Add(&H60)
                        Case "popad"
                            _rtnBytes.Add(&H61)
                        Case Else
                            Throw New Exception("Assemble: asmCmd is single command (no operands), but is UNKNOWN command." & Environment.NewLine _
                                                & "Actual asm command issued: " & asmCmd & Environment.NewLine _
                                                & "On line #: " & _currentLineCount.ToString)
                    End Select
                Else 'asmCmd has space(s) in it: an instruction with operands.
                    _asmInstruction = asmCmd.Substring(0, _tmpFirstSpaceLoc)
                    Dim _rightSideOp As String = asmCmd.Substring(_tmpFirstSpaceLoc + 1)
                    Select Case _asmInstruction
                        Case "push"
                            Select Case _rightSideOp
                                Case "eax"
                                    _rtnBytes.Add(&H50)
                                Case "ecx"
                                    _rtnBytes.Add(&H51)
                                Case "edx"
                                    _rtnBytes.Add(&H52)
                                Case "ebx"
                                    _rtnBytes.Add(&H53)
                                Case "esp"
                                    _rtnBytes.Add(&H54)
                                Case "ebp"
                                    _rtnBytes.Add(&H55)
                                Case "esi"
                                    _rtnBytes.Add(&H56)
                                Case "edi"
                                    _rtnBytes.Add(&H57)
                                Case Else
                                    'was it a number
                                    If IsHexString(_rightSideOp) Then
                                        _tmpInt32 = Int32.Parse(_rightSideOp, Globalization.NumberStyles.HexNumber)
                                        If _tmpInt32 <= SByte.MaxValue And _tmpInt32 >= SByte.MinValue Then
                                            'keep as 1 byte, else make 32 bit by default. Code bloated with 00's. 
                                            _rtnBytes.Add(&H6A)
                                            _rtnBytes.Add(CByte(_tmpInt32))
                                        Else
                                            _rtnBytes.Add(&H68)
                                            Dim _bytes() As Byte = BitConverter.GetBytes(_tmpInt32)
                                            For Each bb As Byte In _bytes
                                                _rtnBytes.Add(bb)
                                            Next
                                        End If
                                    Else
                                        Throw New Exception("Assemble: asmCmd PUSH : operand not a register, must be numeric value?" & Environment.NewLine _
                                        & "Unknown Numeric: " & _rightSideOp & Environment.NewLine _
                                         & "On line #: " & _currentLineCount.ToString)
                                    End If
                            End Select
                        Case "pop"
                            ''can only have 1 operand: must be a register
                            Select Case asmCmd.Substring(_tmpFirstSpaceLoc + 1)
                                Case "eax"
                                    _rtnBytes.Add(&H58)
                                Case "ecx"
                                    _rtnBytes.Add(&H59)
                                Case "edx"
                                    _rtnBytes.Add(&H5A)
                                Case "ebx"
                                    _rtnBytes.Add(&H5B)
                                Case "esp"
                                    _rtnBytes.Add(&H5C)
                                Case "ebp"
                                    _rtnBytes.Add(&H5D)
                                Case "esi"
                                    _rtnBytes.Add(&H5E)
                                Case "edi"
                                    _rtnBytes.Add(&H5F)
                                Case Else
                                    Throw New Exception("Assemble: asmCmd POP : operand must be a REGISTER, but you pass in.." & Environment.NewLine _
                                                        & _rightSideOp & Environment.NewLine _
                                                        & "On line #: " & _currentLineCount.ToString)
                            End Select
                        Case "mov"
                            'quite a few case scenerios
                            ' reg:reg, reg:val , [reg]:reg , [reg]:val , [reg+offset]: etc etc

                        Case "add"
                        Case "sub"
                        Case "inc"
                        Case "dec"
                        Case "jmp"
                        Case "call"
                        Case Else
                            Throw New Exception("Assemble: asmCmd, UNKNOWN COMMAND." & Environment.NewLine _
                                                & "Actual asm command issued: " & _asmInstruction & Environment.NewLine _
                                                & "On line #: " & _currentLineCount.ToString)
                    End Select
                End If
            End If
            
        Next


        Return _rtnBytes.ToArray
    End Function
''obviously not very efficient, or complete, or even remotely good for anything, I know that.
''Could also make a static method. Will do.

 
Boilerplate

Code:
Public Shared Function IsHexString(ByVal sString As String) As Boolean
        sString = sString.ToLower()

        For Each cc As Char In sString
            If cc >= "0" And cc <= "9" Then
                'char is 0-9
                Continue For
            Else
                If cc >= "a" And cc <= "f" Then
                    'char is a-f
                    Continue For
                Else
                    'some random character
                    Return False
                End If
            End If
        Next
        Return True
    End Function

.
used as
Code:
        Dim myAssembler As New abasm
        Dim codeCaveCode() As Byte
        With myAssembler
            .AddLine("push eax")
            .AddLine("push ebx")
            .AddLine("pop ebx")
            .AddLine("pop eax")
            .AddLine("rtn")
        End With
        codeCaveCode = myAssembler.Assemble()
.
output: &H50, &H53, &H5B, &H58, &HC3
Good Good! keep at it sunshine.

It'l get alittle more tricky when using jmp call.
Code:
            .AddLine("push eax")
            .AddLine("push ebx")
            .AddLine("pop ebx")
            .AddLine("call 01234567")
            .AddLine("pop eax")
You would need know the location in memory before calculating the bytes.
Something like..
Code:
        Dim myAssembler As New abasm
        Dim codeCaveCode() As Byte
        Dim _Cave As Integer = Alloc() <-So we know where to start
        With myAssembler
            .AddLine("push eax")
            .AddLine("push ebx")
            .AddLine("pop ebx")
            .AddLine("call 01234567") <-Add the byte length of those first 3 lines to _Cave so the call can be calculated.
            .AddLine("pop eax")
            .AddLine("rtn")
        End With
        codeCaveCode = myAssembler.Assemble()
I'm think you know this already though..
Thank you, thank you. Just woke up, work in 2 hours. Tbh I've only messed with it a few times (written a couple* codecaves, mostly just to copy registers), but from what I remember, yes. I thought about it for 1ms, because the jmp commands need to know where the codecave is in ram (to calculate relative offset), so I either force the programmer to figure it out, or I wrap it up nicely into a class, but haven't analyzed it much yet (possibly use push/call/rtn instead of jmp maybe? Cross that bridge when I come to it). I see where my code is headed, and it's going to be a huge collection of nested select cases, and I don't like it, there has to be a more elegant way of doing it, but I'll refine it once I get more code.
Well call and jump won't take much effort.
Its alittle easier with call cause you only need to return.
But if i were you, i'd add both.

I'll try to put together a simple example for ya. Creating the cave, parsing the opcode blah blah.
I'm not sure if this is relevant but i was thinking what if you're calling a function from the process that is static but codeshift.
So you would also need to make it read modules too.
Like
.AddLine("call Game.exe+012345")
or
.AddLine("call Game.dll+012345")

Ah its late here, i might not be thinking straight!
Na, I see what you're talking about. Hopefully it'll all get in there eventually Will work on it more tonight, and update thread sometime soon.

edit: home again. Going to store for caffeine, then back to this project. It's 10:54pm, will have code update around 4-5 or so
Posts 1–15 of 36 · Page 1 of 3

Post a Reply

Similar Threads

Tags for this Thread

None

Talk with us