You will need a dll (step1-2), my function (step3), and the knowledge of how to use said function (step4-5).
Let me know if anything doesn't work, I will make sure to immediately question my decision to continue learning programming given all these unpredictable errors that make me feel like I can't even evaluate 1+1 without some god damn computer out there throwing an error, and then possibly try to fix the issue.
Steps:
1. Go to www.keystone-engine.org/download/ and download the WIN-32 package (64 might work too).
2. Locate keystone.dll in the archive, take it and place it anywhere you want, but don't lose it, we'll need the path to this dll in just a sec.
3. Place this function in your code:
Code: Select all
;If second parameter is 1, then we return a space delimited hex string, otherwise we return an array that contains an index for each byte
Keystone(Code,Readable:=0) ;by Ħakito - uses a public domain LICENSE: choosealicense.com/licenses/unlicense
{
Local
Static DLLPath,DLLHandle,KS_OPEN,KS_ASM,KS_FREE,KS_CLOSE,kspointer , KS_ERR_OK:=0 , KS_ARCH_X86:=4 , KS_MODE_32:=4
iF not DLLPath ;Locate the dll, afterwards the function can be called normally, and the dll is also loaded on the first normal run
{
iF FileExist(Code) ;Using contents of Code as DLLPath
{
DLLPath:=Code
return Readable?"DLL HAS BEEN FOUND":1
}
else return Readable?"DLL NOT FOUND":0
}
else iF not DLLHandle ;We locate the DLL above, but we don't load it, we only do that when we are required to assemble some code.
{
iF FileExist(DLLPath)
{
DLLHandle:=DllCall("LoadLibrary", "Str",DLLPath, "Ptr")
KS_OPEN:=DllCall("GetProcAddress", "Ptr",DLLHandle, "AStr","ks_open", "Ptr")
KS_ASM:=DllCall("GetProcAddress", "Ptr",DLLHandle, "AStr","ks_asm", "Ptr")
KS_FREE:=DllCall("GetProcAddress", "Ptr",DLLHandle, "AStr","ks_free", "Ptr")
KS_CLOSE:=DllCall("GetProcAddress", "Ptr",DLLHandle, "AStr","ks_close", "Ptr")
VarSetCapacity(ks,8,0)
iF KS_ERR_OK != DllCall(KS_OPEN, "UInt",KS_ARCH_X86, "UInt",KS_MODE_32, "UPtr",&ks, "CDecl Int")
return Readable?"ERROR AT KS_OPEN":0
kspointer:=NumGet(&ks,0,"UInt")
}
else return Readable?"DLL NOT FOUND":0
}
VarSetCapacity(Count,4,0) , VarSetCapacity(Size,4,0) , VarSetCapacity(Encode,8,0)
Try ;This thing can crash autohotkey!
{
iF KS_ERR_OK != DllCall(KS_ASM, "UPtr",kspointer, "AStr",Code, "UInt64",0, "UPtr",&Encode, "UInt",&Size, "UInt",&Count, "CDecl Int")
return Readable?"ERROR AT KS_ASM":""
}
Catch
{
return Readable?"FATAL ERROR AT KS_ASM":""
}
Encodepointer:=NumGet(&Encode,0,"UInt")
Size:=NumGet(&Size,0,"UInt")
Count:=NumGet(&Count,0,"UInt")
iF Readable ;Creates a human readable hex string
{
Loop Size
Output.=(A_Index!=1?" ":"") Format("{1:02X}", NumGet(Encodepointer,A_Index-1,"UChar"))
}
else
{
;Old discarded method : Output:=[StrGet(Encodepointer,Size,"CP0"),Size]
Output:=[]
Loop Size
Output.Push(NumGet(Encodepointer,A_Index-1,"UChar"))
}
DllCall(KS_FREE, "UPtr",Encodepointer, "CDecl Int")
;DllCall(KS_CLOSE, "UPtr",kspointer, "CDecl Int") ;No need to close it, we can just keep reusing the same handle for future calls
return Output
}
4. Call the function like this in the auto-execute area of your script, this tells the function where the dll is located for when it needs it.
Code: Select all
Keystone("C:\Users\Hakito\Desktop\keystone.dll")
5. Now you can start converting Assembly to Machine-code! Here are some examples.
Code: Select all
;Return Machine-code as an array
Arr := Keystone("ADD EAX,0x2; CMP EAX,0x2; JG label; SUB EAX,0x1; label:; RET")
Msgbox Arr[1] " " Arr[2] " " Arr[3] " " Arr[4] ; etc...
;Return as a readable string
Msgbox Keystone("ADD EAX,0x2; CMP EAX,0x2; JG label; SUB EAX,0x1; label:; RET",True)
;Expected output: 83 C0 02 83 F8 02 7F 03 83 E8 01 C3
;Another readable string
Msgbox Keystone("
(
VAR1 = 0x05
CMP EAX,VAR1
JE label
CMP EAX,0x04
JE label
CMP EAX,0x03
JE label
MOV [ECX+EAX*0x4+0x000000C0],EDX
label:
RET
)",True)
;Expected output: "83 F8 05 74 11 83 F8 04 74 0C 83 F8 03 74 07 89 94 81 C0 00 00 00 C3"
(Written for AHKv2-a100)