AHK 机器码(MCode)的制作

许多实用脚本和封装函数, 可以让您编写脚本更加便捷高效

Moderators: tmplinshi, arcticir

feiyue
Posts: 348
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.5  By FeiYue
;
;   使用方法:
;
;   1、下载安装【TDM-GCC】的64位版到D盘的TDM-GCC-64目录,下载网址为:
;      https://sourceforge.net/projects/tdm-gcc/files/latest/download
;
;   2、下载安装【TCC】的32位和64位版到AHK的TCC-32和TCC-64目录,下载网址为:
;      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{Ctrl Up}
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, s%i%:="`r`n    " (i ? "x64":"x32") ":="""""
  . RegExReplace(Tcc(s,i,A_ThisLabel="!c"), ".{1,64}", "`r`n    . ""$0""")
}
MsgBox, 4096, MCode has been generated! (32 + 64), % Clipboard:=s0 . s1
  . "`r`n    MCode(MyFunc, A_PtrSize=8 ? x64:x32)"
s:=s0:=s1:=""
return

Tcc(s, win64=0, gcc=0, add=0)
{
  dir:=A_IsCompiled ? A_ScriptDir : RegExReplace(A_AhkPath,"\\[^\\]+$")
  if (gcc=1)
    exe1:="D:\TDM-GCC-64\bin\gcc.exe"
  else
    exe1:=dir (win64 ? "\TCC-64":"\TCC-32") "\tcc.exe"
  IfNotExist, %exe1%
  {
    MsgBox, 4096, Tip, Can't Find %exe1% !
    return
  }
  if (add=1)
  {
    Loop, 4
      s%A_Index%:="int _add" A_Index "_() { return 0x11111111; }"
    s:=s1 "`n" s2 "`n" s3 "`n" s "`n" s4 "`n"
  }
  dir:=A_Temp
  FileDelete, % cpp:=dir "\~5.c"
  FileDelete, % obj:=dir "\~5.obj"
  FileDelete, % log:=dir "\~5.log"
  FileAppend, % StrReplace(s,"`r"), %cpp%
  killcmd(1)
  arg:=(win64 ? " -m64 ":" -m32 ")  " -O2 "
  RunWait, %ComSpec% /c ""%exe1%" %arg%
    -c -o "%obj%" "%cpp%" 2>"%log%"",, Hide
  killcmd(0)
  hex:=(add=1) ? bin2hex(obj) : obj2hex(obj)
  FileRead, s, %log%
  FileDelete, %cpp%
  FileDelete, %obj%
  FileDelete, %log%
  if StrLen(hex)<2
  {
    MsgBox, 4096, Tip, C Compile Error`n`n%s%
    return
  }
  if (add=1)
  {
    p1:=RegExMatch(hex, "i)B811111111.{0,8}?C3", r)
    p2:=InStr(hex,r,0,p1+1), p3:=InStr(hex,r,0,p2+1)
    p4:=InStr(hex,r,0,0), len:=p3-p2, i:=0
    Loop, % (len-StrLen(r))//2
      if !(SubStr(hex,p1-2-i,2)=SubStr(hex,p3-2-i,2)
      && SubStr(hex,p1-2-i,2)=SubStr(hex,p4-2-i,2) && (i+=2))
        Break
    if (p1 && p2 && p3)
      hex:=SubStr(hex, p3+len-i, p4-p3-len)
  }
  return hex
}

killcmd(f=0)
{
  SplitPath, ComSpec, cmd
  Loop
  {
    Process, Exist, %cmd%
    if !(pid:=ErrorLevel)
      Break
    Process, Close, %pid%
    Process, WaitClose, %pid%, 3
  }
  SetTimer, killcmd, % f ? 5000 : "Off"
}

bin2hex(obj, addr=0, size=0)
{
  if (addr=0)
  {
    if !(r:=FileExist(obj)) or InStr(r,"D")
      return
    FileGetSize, size, %obj%
    FileRead, bin, *c %obj%
    addr:=&bin
  }
  ListLines, % (lls:=A_ListLines=0?"Off":"On")?"Off":"Off"
  SetBatchLines, % (bch:=A_BatchLines)?"-1":"-1"
  SetFormat, IntegerFast, % (fmt:=A_FormatInteger)?"H":"H"
  VarSetCapacity(hex, (2*size+1)*(1+!!A_IsUnicode))
  Loop, %size%
    hex.=SubStr(0x100+(*addr++),-1)
  SetFormat, IntegerFast, %fmt%
  SetBatchLines, %bch%
  ListLines, %lls%
  return hex
}

obj2hex(obj)
{
  if !(r:=FileExist(obj)) or InStr(r,"D")
    return
  FileGetSize, size, %obj%
  FileRead, bin, *c %obj%
  p:=&bin
  if !(NumGet(p+0,"uchar")=0x7f && StrGet(p+1,3,"CP0")="ELF")
  {
    if (StrGet(p,2,"CP0")="MZ")
    && (StrGet(p+NumGet(p+0x3C,"uint"),4,"CP0")="PE")
      return
    usOptHdrSZ := NumGet(p+0, 16, "ushort")
    Loop % usNumSec := NumGet(p+0, 2, "ushort")
    {
      sh := 20+usOptHdrSZ+(A_Index-1)*40
      if (sh>size || A_Index>100)
        return
      sh_flags := NumGet(p+0, sh+36, "uint")
      name:=StrGet(p+sh, 8, "CP0")
      if (name=".text") && (sh_flags & 0x20)
      {
        sh_offset := NumGet(p+0, sh+20, "uint")
        sh_size := NumGet(p+0, sh+16, "uint")
        return bin2hex("", p+sh_offset, sh_size)
      }
    }
    return
  }
  x64:=(EI_CLASS := NumGet(p+0, 4, "char"))=2
  ptr:=(x64 ? "uint64" : "uint")
  e_ehsize:=NumGet(p+0, (x64?52:40), "ushort")
  if (e_ehsize!=(x64?64:52))
    return
  e_shoff := NumGet(p+0, (x64?40:32), ptr)
  e_shentsize := NumGet(p+0, (x64?58:46), "ushort")
  e_shnum := NumGet(p+0, (x64?60:48), "ushort")
  e_shstrndx := NumGet(p+0, (x64?62:50), "ushort")
  sh := e_shoff+e_shstrndx*e_shentsize
  pstr := NumGet(p+0, sh+(x64?24:16), ptr) + p
  Loop % e_shnum
  {
    sh := e_shoff+(A_Index-1)*e_shentsize
    if (sh>size || A_Index>100)
      return
    sh_flags := NumGet(p+0, sh+8, ptr)
    sh_name := NumGet(p+0, sh+0, "uint")
    name := StrGet(pstr+sh_name, 8, "CP0")
    if (name=".text") && (sh_flags & 0x4)
    {
      sh_offset := NumGet(p+0, sh+(x64?24:16), ptr)
      sh_size := NumGet(p+0, sh+(x64?32:20), ptr)
      return bin2hex("", p+sh_offset, sh_size)
    }
  }
}

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

Last edited by feiyue on 27 Dec 2020, 17:46, edited 41 times in total.
feiyue
Posts: 348
Joined: 08 Aug 2014, 04:08

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

28 May 2016, 21:49

生成的机器码需要调用MCode函数,这是基于官网中前辈们的函数修改的,感谢前辈们! :)

Code: Select all


MCode(ByRef code, hex)
{
  ListLines, % "Off" (lls:=A_ListLines=0 ? "Off":"On")/0
  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,"uchar")
  DllCall("VirtualProtect","ptr",&code,"ptr",len,"uint",0x40,"ptr*",0)
  SetBatchLines, %bch%
  ListLines, %lls%
}

Last edited by feiyue on 01 Jan 2020, 00:07, edited 2 times in total.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

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

28 May 2016, 23:48

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

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

29 May 2016, 07:45

下面是一个AHK机器码(MCode)调用WinAPI的例子:

Code: Select all


/****** C source code ******

#include <windows.h>

typedef int (WINAPI * _MessageBoxA)(
  HWND   hWnd,
  LPCSTR lpText,
  LPCSTR lpCaption,
  UINT   uType
);

typedef BOOL (WINAPI * _GetUserNameA)(
  LPSTR   lpBuffer,
  LPDWORD pcbBuffer
);

typedef void * (WINAPI * _GetWinAPI)(char * str);

int WINAPI TestWinAPI(_GetWinAPI GetWinAPI, char * name, int * size)
{
  char str1[] = "User32.dll\\MessageBoxA";
  _MessageBoxA MessageBoxA = (_MessageBoxA)GetWinAPI(str1);
  if (NULL == MessageBoxA)
    return -1;

  char str2[] = "Advapi32.dll\\GetUserNameA";
  _GetUserNameA GetUserNameA = (_GetUserNameA)GetWinAPI(str2);
  if (NULL == GetUserNameA)
    return -2;

  char text[] = "Hello World!";
  char title[] = "Machine Code Call WinAPI";
  MessageBoxA(0, text, title, 1);

  GetUserNameA(name, size);
  MessageBoxA(0, name, title, 1);

  return 0;
}

*/

if (!MyFunc)
{
    x32:="5557BA78410000565383EC7C8D4424268BB424900000008"
    . "BBC2494000000C744242655736572C744242A33322E64C7442"
    . "42E6C6C5C4DC744243265737361C74424366765426F6689542"
    . "43AC644243C00890424FFD683EC0485C00F840301000089C3B"
    . "841000000C744245641647661668944246E8D442456C744245"
    . "A70693332C744245E2E646C6CC74424625C476574C74424665"
    . "5736572C744246A4E616D65890424FFD683EC0485C089C60F8"
    . "4BE0000008D6C243D8D442419C744241948656C6CC744241D6"
    . "F20576FC7442421726C6421C644242500C744243D4D616368C"
    . "7442441696E6520C7442445436F6465C74424492043616CC74"
    . "4244D6C205769C74424516E415049C644245500C744240C010"
    . "00000896C240889442404C7042400000000FFD383EC108B842"
    . "498000000893C2489442404FFD683EC08C744240C010000008"
    . "96C2408897C2404C7042400000000FFD331C083EC1083C47C5"
    . "B5E5F5DC20C00B8FFFFFFFFEBEF8DB600000000B8FEFFFFFFE"
    . "BE2909090909090909090"
    x64:="4154555756534881EC9000000048B85573657233322E644"
    . "8894424304889D748B86C6C5C4D65737361BA784100004889C"
    . "E4D89C44889442438C74424406765426F488D4C24306689542"
    . "444C644244600FFD64885C04889C30F84E200000048B841647"
    . "66170693332488D4C2470488944247048B82E646C6C5C47657"
    . "4488944247848B8557365724E616D654889842480000000B84"
    . "10000006689842488000000FFD64885C04889C60F84A200000"
    . "048B848656C6C6F20576F488D6C245041B9010000004889442"
    . "42048B84D616368696E6520488D542420488944245048B8436"
    . "F64652043616C4989E8488944245848B86C2057696E4150493"
    . "1C9C7442428726C6421C644242C004889442460C644246800F"
    . "FD34C89E24889F9FFD641B9010000004989E84889FA31C9FFD"
    . "331C04881C4900000005B5E5F5D415CC30F1F440000B8FFFFF"
    . "FFFEBE6660F1F840000000000B8FEFFFFFFEBD690909090909"
    . "0909090"
    MCode(MyFunc, A_PtrSize=8 ? x64:x32)
    GetWinAPI:=RegisterCallback("GetWinAPI","Fast")
}
VarSetCapacity(str,100,0), size:=100
DllCall(&MyFunc, "Ptr",GetWinAPI, "Ptr",&str, "int*",size)
MsgBox, 1, AHK Command
  , % "UserName:`t" StrGet(&str,"CP0") "`nSize:`t`t" size
return

GetWinAPI(pstr)  ; 参数格式为:DLL文件名\\函数名
{
  static WinAPI:=[]
  if (addr:=WinAPI[ v:=StrGet(pstr,"CP0") ])
    return, addr
  i:=InStr(v,"\",0,0), v1:=SubStr(v,1,i-1), v2:=SubStr(v,i+1)
  if !(base:=DllCall("LoadLibrary", "Str",v1, "Ptr"))
    return, 0
  if !(addr:=DllCall("GetProcAddress", "Ptr",base, "AStr",v2, "Ptr"))
    return, 0
  WinAPI[v]:=addr
  return, addr
}

MCode(ByRef code, hex)
{
  ListLines, % "Off" (lls:=A_ListLines=0 ? "Off":"On")/0
  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,"uchar")
  DllCall("VirtualProtect","ptr",&code,"ptr",len,"uint",0x40,"ptr*",0)
  SetBatchLines, %bch%
  ListLines, %lls%
}

;
Last edited by feiyue on 01 Jan 2020, 03:31, edited 8 times in total.
kkss

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

28 Jul 2017, 22:22

Thanks for feiyue
I solved this problem.^^
feiyue
Posts: 348
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: 348
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(TccRun(code), "ptr",&str, "ptr"), "CP0")
return


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


TccRun(s)
{
  static Address:=[]
  if (addr:=Address[hash:=GetHash(s)])
    return, addr
  if !(hex:=Tcc(s, A_PtrSize=8))
    return
  if !(addr:=DllCall("GlobalAlloc", "int",0, "ptr",len:=StrLen(hex)//2, "ptr"))
    return
  MCode(code,hex), DllCall("RtlMoveMemory", "ptr",addr, "ptr",&code, "ptr",len)
  DllCall("VirtualProtect", "ptr",addr, "ptr",len, "uint",0x40, "ptr*",0)
  Address[hash]:=addr
  return, addr
}

GetHash(s)
{
  ListLines, % "Off" (lls:=A_ListLines!=0 ? "On":"Off")/0
  SetBatchLines, % "-1" (bch:=A_BatchLines)/0
  hash1:=hash2:=hash3:=0, size:=VarSetCapacity(s,-1), p:=&s
  Loop, % size
    v:=*p++
    , hash1:=(hash1*31  +v)&0xFFFFFFFF
    , hash2:=(hash2*131 +v)&0xFFFFFFFF
    , hash3:=(hash3*1313+v)&0xFFFFFFFF
  SetBatchLines, %bch%
  ListLines, %lls%
  return, hash1 "-" hash2 "-" hash3
}

Tcc(s, win64=0)
{
  dir:=A_IsCompiled ? A_ScriptDir : RegExReplace(A_AhkPath,"\\[^\\]+$")
  ;-----------------------------
  exe1:=dir (win64 ? "\TCC-64\tcc.exe" : "\TCC-32\tcc.exe")
  ;-----------------------------
  IfNotExist, %exe1%
  {
    MsgBox, 4096, Tip, Can't Find %exe1% !
    return
  }
  ;-----------------------------
  add0=`n int _Flag0_%A_Now%() { return 0x11110000; } `n
  add1=`n int _Flag1_%A_Now%() { return 0x11111111; } `n
  add2=`n int _Flag2_%A_Now%() { return 0x11111111; } `n
  add3=`n int _Flag3_%A_Now%() { return 0x11111111; } `n
  s:=add0 . add1 . add2 . s . add3
  ;-----------------------------
  FileDelete, % cpp:=dir "\5.c"
  FileDelete, % obj:=dir "\5.obj"
  FileDelete, % log:=dir "\5.log"
  FileAppend, % StrReplace(s,"`r"), %cpp%
  SplitPath, ComSpec, cmd
  Loop
  {
    Process, Exist, %cmd%
    if !(pid:=ErrorLevel)
      Break
    Process, Close, %pid%
    Process, WaitClose, %pid%, 3
  }
  arg:=(win64 ? "-m64":"-m32") . " -O2"
  RunWait, %ComSpec% /c ""%exe1%" %arg% -c -o "%obj%" "%cpp%" 2>"%log%""
    ,, Hide
  IfNotExist, %obj%
  {
    FileRead, s, %log%
    FileDelete, %cpp%
    FileDelete, %log%
    MsgBox, 4096, Tip, C Compile Error`n`n%s%
    return
  }
  hex:=bin2hex(obj)
  ;-----------------------------
  p1:=RegExMatch(hex,"i)B811111111.{0,2}?C3",r)
  p2:=InStr(hex,r,0,p1+1), p3:=InStr(hex,r,0,0)
  len:=p2-p1, i:=(r="B811111111C3") ? p2+len : p2+StrLen(r)
  hex:=(p1 and p2) ? SubStr(hex,i,p3-p2-len) : ""
  ;-----------------------------
  FileDelete, %cpp%
  FileDelete, %obj%
  FileDelete, %log%
  return, hex
}

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

MCode(ByRef code, hex)
{
  ListLines, % "Off" (lls:=A_ListLines=0 ? "Off":"On")/0
  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,"uchar")
  DllCall("VirtualProtect","ptr",&code,"ptr",len,"uint",0x40,"ptr*",0)
  SetBatchLines, %bch%
  ListLines, %lls%
}

;
Last edited by feiyue on 03 Jan 2020, 03:28, edited 16 times in total.
burque505
Posts: 1731
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: 21
Joined: 10 Aug 2014, 06:47

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

06 Sep 2018, 10:02

感谢飞跃大神分享,希望飞跃大神再研究下ahk+lua的混合编程!
ash
Posts: 1
Joined: 14 Sep 2020, 02:16

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

14 Sep 2020, 02:25

能否介绍一下使用机器码的好处?

Return to “脚本函数”

Who is online

Users browsing this forum: No registered users and 10 guests