AHK 机器码(MCode)的制作

许多实用脚本和封装函数, 可以让您编写脚本更加便捷高效
feiyue
Posts: 125
Joined: 08 Aug 2014, 04:08

AHK 机器码(MCode)的制作

28 May 2016, 21:26

最早从官网看到大神们在使用机器码(MCode)的时候,惊为天人,极为仰慕。
可惜一看介绍,需要先下载安装VC或者GCC,还有各种参数配置,总感觉很难,
因此很长时间都没有使用过。

后来慢慢尝试使用GCC,发现并不难,因为都是用命令行调用的,下载安装
GCC后根本不用配置,找到gcc.exe程序就可以在命令行使用了。
我推荐使用 TDM-GCC 64位版,可以在百度搜索 TDM-GCC 或在 官网 下载。

我成功地实现了自己写C语言代码并快速转化为机器码(MCode),真令人高兴。
比较了多种方法后,我把最简单的转化方式分享给大家,让大家也来使用机器码。 :dance:

Code: Select all

;===========================================
;   【AHK机器码生成器】 v2.0  By FeiYue
;
;   使用方法:
;
;   1、下载安装 TDM-GCC 64位版 到默认的安装目录,下载网址为:
;      https://sourceforge.net/projects/tdm-gcc/files/latest/download
;
;   2、下载安装 TCC 的 32位 和 64位版 到AHK的目录,下载网址为:
;      https://bellard.org/tcc/
;
;   3、选择C代码后,按【 Alt+C 】热键生成 GCC 编译的机器码,
;      或者按【 Ctrl+Alt+C 】热键生成 TCC 编译的机器码
;
;===========================================


!c::    ; 选择C代码后用 GCC 编译

^!c::   ; 选择C代码后用 TCC 编译

ClipSaved:=ClipboardAll
Clipboard=
Send {Ctrl Down}c{CtrlUp}
ClipWait, 3
s:=Clipboard, Clipboard:=ClipSaved
if s=
{
  MsgBox, 4096, Error, The contents of the copy are empty!
  Exit
}
Loop, 2 {
  i:=A_Index-1
  hex:=A_ThisLabel="!c" ? Gcc(s,i) : Tcc(s,i)
  hex:=RegExReplace("xxx" hex, ".{1,50}", "`r`n    . ""$0""")
  s%i%:=StrReplace(hex, ". ""xxx", (i ? "x64":"x32") ":=""")
}
MsgBox, 4096, MCode has been generated! (32 + 64)
  , % Clipboard:=s0 . s1
  . "`r`n    MCode(MyFunc, A_PtrSize=8 ? x64:x32)"
s:=s0:=s1:=""
return

Gcc(s, win64=0)
{
  dir:=A_IsCompiled ? A_ScriptDir : RegExReplace(A_AhkPath,"\\[^\\]+$")
  ;-----------------------------
  exe1=C:\TDM-GCC-64\bin\gcc.exe
  exe2=C:\TDM-GCC-64\bin\objcopy.exe
  ;-----------------------------
  IfNotExist, %exe1%
  {
    MsgBox, 4096, Tip, Can't Find %exe1% !
    return
  }
  FileDelete, % cpp:=dir "\5.c"
  FileDelete, % obj:=dir "\5.obj"
  FileDelete, % log:=dir "\5.log"
  FileDelete, % bin:=dir "\5.bin"
  FileAppend, %s%, %cpp%
  arg:=(win64 ? "-m64":"-m32") ;" -O2"
  killcmd(1)
  RunWait, %ComSpec% /c ""%exe1%" %arg% -c -o "%obj%" "%cpp%" 2>"%log%""
    ,, Hide
  killcmd(0)
  IfNotExist, %obj%
  {
    FileRead, s, %log%
    FileDelete, %cpp%
    FileDelete, %log%
    MsgBox, 4096, C Compile Error, %s%
    return
  }
  RunWait, "%exe2%" -j .text -O binary "%obj%" "%bin%",, Hide
  hex:=bin2hex(bin)
  FileDelete, %cpp%
  FileDelete, %obj%
  FileDelete, %log%
  FileDelete, %bin%
  return, hex
}

Tcc(s, win64=0)
{
  dir:=A_IsCompiled ? A_ScriptDir : RegExReplace(A_AhkPath,"\\[^\\]+$")
  tcc:=dir (win64 ? "\TCC-64\tcc.exe" : "\TCC-32\tcc.exe")
  IfNotExist, %tcc%
  {
    MsgBox, 4096, Tip, Can't Find %tcc% !
    return
  }
  ;-----------------------------
  add1=`n int _add1_() { return 0x11111111; } `n
  add2=`n int _add2_() { return 0x11111111; } `n
  add3=`n int _add3_() { return 0x11111111; } `n
  s:=StrReplace(add1 . add2 . s . add3, "`r")
  ;-----------------------------
  FileDelete, % cpp:=dir "\5.c"
  FileDelete, % obj:=dir "\5.obj"
  FileDelete, % log:=dir "\5.log"
  FileAppend, %s%, %cpp%
  killcmd(1)
  RunWait, %ComSpec% /c ""%tcc%" -c -o "%obj%" "%cpp%" 2>"%log%""
    ,, Hide
  killcmd(0)
  IfNotExist, %obj%
  {
    FileRead, s, %log%
    FileDelete, %cpp%
    FileDelete, %log%
    MsgBox, 4096, C Compile Error, %s%
    return
  }
  hex:=bin2hex(obj)
  ;-----------------------------
  re:="i)B811111111.{0,16}?C3"
  p1:=RegExMatch(hex,re,r), n:=StrLen(r)
  p2:=InStr(hex,r,0,p1+n), p3:=InStr(hex,r,0,0), i:=0
  Loop, % (p2-(p1+n))//2
    if SubStr(hex,p2-i-2,2)!=SubStr(hex,p1-i-2,2)
      Break
    else i+=2
  j:=InStr(hex,SubStr(hex,p2-i,2),0,p2+n)
  hex:=(p1 and p2 and p3>p2) ? SubStr(hex,j,p3-i-j) : ""
  ;-----------------------------
  FileDelete, %cpp%
  FileDelete, %obj%
  FileDelete, %log%
  return, hex
}

bin2hex(obj)
{
  VarSetCapacity(bin,1024), VarSetCapacity(bin,0)
  FileRead, bin, *c %obj%
  size:=VarSetCapacity(bin), p:=&bin
  VarSetCapacity(hex, (2*size+1)*(1+!!A_IsUnicode))
  SetBatchLines, % "-1" (bch:=A_BatchLines)/0
  SetFormat, IntegerFast, % "H" (fmt:=A_FormatInteger)/0
  Loop, %size%
    hex.=SubStr(0x100+(*p++),-1)
  SetFormat, IntegerFast, %fmt%
  SetBatchLines, %bch%
  return, hex
}

killcmd(onoff=1) {
  if (onoff=0)
    SetTimer, kill_cmd, Off
  else
  {
    Gosub, kill_cmd
    SetTimer, kill_cmd, -5000
  }
  return
  kill_cmd:
  SplitPath, ComSpec, cmd
  Loop, 10 {
    Process, Exist, %cmd%
    if (pid:=ErrorLevel)
      Process, Close, %pid%
    else Break
    Sleep, 500
  }
  return
}

;
Last edited by feiyue on 29 Aug 2018, 20:31, edited 30 times in total.
feiyue
Posts: 125
Joined: 08 Aug 2014, 04:08

Re: AutoHotkey 机器码(MCode)的制作

28 May 2016, 21:49

再附上调用MCode需要的函数,这是基于官网中前辈们的函数修改的,感谢前辈们! :)

Code: Select all


MCode(ByRef code, hex)
{
  SetBatchLines, % "-1" (bch:=A_BatchLines)/0
  VarSetCapacity(code, len:=StrLen(hex)//2)
  Loop, % len
    NumPut("0x" SubStr(hex,2*A_Index-1,2),code,A_Index-1,"char")
  DllCall("VirtualProtect","ptr",&code,"ptr",len,"uint",0x40,"ptr*",0)
  SetBatchLines, %bch%
}

Last edited by feiyue on 28 Aug 2018, 16:30, edited 1 time in total.
tmplinshi
Posts: 1278
Joined: 01 Oct 2013, 14:57

Re: AHK 机器码(MCode)的制作

28 May 2016, 23:48

赞!谢谢分享
feiyue
Posts: 125
Joined: 08 Aug 2014, 04:08

Re: AHK 机器码(MCode)的制作

29 May 2016, 07:45

下面是一个AHK 应用 MCode 的简单例子,使用C语言返回 Hello World 字符串:

Code: Select all


Msgbox, % helloWorld()

helloWorld() {
  static MyFunc  ; 利用静态变量使机器码在Ahk运行期间长期保留
  if !MyFunc
  {
    x32:="5589E583EC20C745EF48656C6CC745F36F20576FC745F77"
    . "26C6421C645FB00C745FC00000000EB198B55FC8B450801C28"
    . "D4DEF8B45FC01C80FB60088028345FC018D55EF8B45FC01D00"
    . "FB60084C075D88B45FCC9C3"
    x64:="554889E54883EC2048894D1048B848656C6C6F20576F488"
    . "945E0C745E8726C6421C645EC00C745FC00000000EB1D8B45F"
    . "C4863D0488B45104801C28B45FC48980FB64405E088028345F"
    . "C018B45FC48980FB64405E084C075D58B45FC4883C4205DC3"
    MCode(MyFunc, A_PtrSize=8 ? x64:x32)
  }
  VarSetCapacity(s, 100, 0)  ; C代码中用到的内存由AHK申请并传入内存地址
  len:=DllCall(&MyFunc, "ptr",&s, "Cdecl")  ; 明确使用C调用约定
  Return, StrGet(&s,"CP0")  ; C函数生成的AscII字符串要用StrGet读取
}

MCode(ByRef code, hex)
{
  SetBatchLines, % "-1" (bch:=A_BatchLines)/0
  VarSetCapacity(code, len:=StrLen(hex)//2)
  Loop, % len
    NumPut("0x" SubStr(hex,2*A_Index-1,2),code,A_Index-1,"char")
  DllCall("VirtualProtect","ptr",&code,"ptr",len,"uint",0x40,"ptr*",0)
  SetBatchLines, %bch%
}

/****** C语言源代码 ******

int helloworld(char * out) {
  int i; char str[]="Hello World!";
  for (i=0; str[i]!='\0'; i++)
    out[i]=str[i];
  return i;
}

*/

Last edited by feiyue on 28 Aug 2018, 16:32, edited 4 times in total.
kkss

Re: AHK 机器码(MCode)的制作

28 Jul 2017, 22:22

Thanks for feiyue
I solved this problem.^^
feiyue
Posts: 125
Joined: 08 Aug 2014, 04:08

Re: AHK 机器码(MCode)的制作

25 Apr 2018, 23:24

更新到 v1.6 版,不再需要 objcopy.exe 程序。现在可以使用小巧便携的TinyCC代替GCC,但它在Win32系统上不能同时生成32位和64位版本。
Last edited by feiyue on 28 Aug 2018, 23:26, edited 1 time in total.
feiyue
Posts: 125
Joined: 08 Aug 2014, 04:08

Re: AHK 机器码(MCode)的制作

28 Aug 2018, 10:54

利用TCC动态运行C语言代码的简单方式:
(必须在AHK目录下安装 “\TCC-64\tcc.exe” 和 “\TCC-32\tcc.exe”)

Code: Select all

;------------------------------------------
;  Using TCC to run C code  (By FeiYue)
;------------------------------------------

Goto, F1

F1::
Code=
(

char * __attribute__((stdcall)) hello(char * out) {
  char str[]="Hello World!";
  for (int i=0; str[i]!='\0'; i++)
    out[i]=str[i];
  return out;
}

)
VarsetCapacity(str,100,0)
MsgBox, 4096,, % StrGet(DllCall(c2f("hello",Code), "ptr",&str, "ptr"), "CP0")
return


;========== TCC Functions ==========


c2f(FuncName, C_Code="", Clear="") {
  static Address:=[]
  if (Clear)
  {
    if (addr:=Address[FuncName])
      DllCall("GlobalFree","ptr",addr)
    Address[FuncName]:=""
    return
  }
  if (addr:=Address[FuncName])
    return, addr
  if !(hex:=Tcc(C_Code, A_PtrSize=8))
    return
  if !(addr:=DllCall("GlobalAlloc","int",0,"ptr",len:=StrLen(hex)//2,"ptr"))
    return
  SetBatchLines, % "-1" (bch:=A_BatchLines)/0
  Loop, % len
    NumPut("0x" SubStr(hex,2*A_Index-1,2), addr+A_Index-1, "char")
  SetBatchLines, %bch%
  DllCall("VirtualProtect","ptr",addr,"ptr",len,"uint",0x40,"ptr*",0)
  Address[FuncName]:=addr
  return, addr
}

Tcc(s, win64=0)
{
  dir:=A_IsCompiled ? A_ScriptDir : RegExReplace(A_AhkPath,"\\[^\\]+$")
  tcc:=dir (win64 ? "\TCC-64\tcc.exe" : "\TCC-32\tcc.exe")
  IfNotExist, %tcc%
  {
    MsgBox, 4096, Tip, Can't Find %tcc% !
    return
  }
  ;-----------------------------
  add1=`n int _add1_() { return 0x11111111; } `n
  add2=`n int _add2_() { return 0x11111111; } `n
  add3=`n int _add3_() { return 0x11111111; } `n
  s:=StrReplace(add1 . add2 . s . add3, "`r")
  ;-----------------------------
  FileDelete, % cpp:=dir "\5.c"
  FileDelete, % obj:=dir "\5.obj"
  FileDelete, % log:=dir "\5.log"
  FileAppend, %s%, %cpp%
  killcmd(1)
  RunWait, %ComSpec% /c ""%tcc%" -c -o "%obj%" "%cpp%" 2>"%log%""
    ,, Hide
  killcmd(0)
  IfNotExist, %obj%
  {
    FileRead, s, %log%
    FileDelete, %cpp%
    FileDelete, %log%
    MsgBox, 4096, C Compile Error, %s%
    return
  }
  hex:=bin2hex(obj)
  ;-----------------------------
  re:="i)B811111111.{0,16}?C3"
  p1:=RegExMatch(hex,re,r), n:=StrLen(r)
  p2:=InStr(hex,r,0,p1+n), p3:=InStr(hex,r,0,0), i:=0
  Loop, % (p2-(p1+n))//2
    if SubStr(hex,p2-i-2,2)!=SubStr(hex,p1-i-2,2)
      Break
    else i+=2
  j:=InStr(hex,SubStr(hex,p2-i,2),0,p2+n)
  hex:=(p1 and p2 and p3>p2) ? SubStr(hex,j,p3-i-j) : ""
  ;-----------------------------
  FileDelete, %cpp%
  FileDelete, %obj%
  FileDelete, %log%
  return, hex
}

bin2hex(obj)
{
  VarSetCapacity(bin,1024), VarSetCapacity(bin,0)
  FileRead, bin, *c %obj%
  size:=VarSetCapacity(bin), p:=&bin
  VarSetCapacity(hex, (2*size+1)*(1+!!A_IsUnicode))
  SetBatchLines, % "-1" (bch:=A_BatchLines)/0
  SetFormat, IntegerFast, % "H" (fmt:=A_FormatInteger)/0
  Loop, %size%
    hex.=SubStr(0x100+(*p++),-1)
  SetFormat, IntegerFast, %fmt%
  SetBatchLines, %bch%
  return, hex
}

killcmd(onoff=1) {
  if (onoff=0)
    SetTimer, kill_cmd, Off
  else
  {
    Gosub, kill_cmd
    SetTimer, kill_cmd, -5000
  }
  return
  kill_cmd:
  SplitPath, ComSpec, cmd
  Loop, 10 {
    Process, Exist, %cmd%
    if (pid:=ErrorLevel)
      Process, Close, %pid%
    else Break
    Sleep, 500
  }
  return
}

;
Last edited by feiyue on 29 Aug 2018, 09:43, edited 5 times in total.
burque505
Posts: 626
Joined: 22 Jan 2017, 19:37

Re: AHK 机器码(MCode)的制作

28 Aug 2018, 17:48

嗨,我收到以下错误:
---------------------------
C Compile Error
---------------------------
C:/Program Files/AutoHotkey/5.c:4: error: redefinition of '_AddFlag_'


---------------------------
OK
---------------------------
最好的祝福,
burque505
hitman
Posts: 8
Joined: 10 Aug 2014, 06:47

Re: AHK 机器码(MCode)的制作

06 Sep 2018, 10:02

感谢飞跃大神分享,希望飞跃大神再研究下ahk+lua的混合编程!

Return to “脚本函数”

Who is online

Users browsing this forum: No registered users and 4 guests