测试文件生成器

测试文件生成器

这个工具可以生成指定大小的随机内容文件以供测试。生成的内容是完全没有规律的随机数,压缩软件甚至无法对其进行压缩,是用来测试拷贝等等有力的工具。

使用方法:

fg /s /n /r

/s 指定生成文件的大小,单位是KB

/n 指定生成文件的数量

/r 完全随机内容(每次生成随机内容不同)

例如,fg /s4096 /n10 将会生成10个大小为 4096KB 的文件。

因为是内存直接写入文件的,因此目前的限制大约只能生成最大2G的内容。

fg

===============================================================

2023年10月 在 Windows 下可以直接通过fsutil命令完成相同的工作

fsutil file createnew 文件名 大小

例如:fsutil file createnew test.txt 1024 将会生成一个内容为全 00 的 1024字节的 test.txt文件。

获得当前系统增加/移除USB设备名称的方法 Delphi (1)

根据 http://delphi.cjcsoft.net/viewthread.php?tid=48860 文章内容,将类似 \\?\USB#Vid_4146&Pid_d2b5#0005050400044#{a5dcbf10-6530-11d2-901f-00c04fb951ed} 转化为更易读的类型,例如

USB Inserted
Device Type = USB Mass Storage Device
Driver Name = Disk drive
Friendly Name = I0MEGA UMni1GB*IOM2J4 USB Device

之前《关于监视插入U盘的问题(1)》中给出了接收 WM_DEVICECHANGE 消息的方法。从资料中可以看出,直接处理这个消息能够获得当前系统发生变化的盘符,但是无法处理未产生盘符变化(未分区或者其他USB设备)。对于这样的问题,可以使用RegisterDeviceNotification来向系统注册一个回调函数,并且设置好只通知USB设备变化,通过这样的方法能够取得发生变化的USB设备的信息,之后再通过查询注册表对照出更易读的信息。

文章还指出这样的转换是通过读取注册表来完成的。

我编写了如下例子,实践证明这个程序工作很好。除了普通的U盘,我还地尝试了一个 USB2UART 的 Cable,可以看出工作正常。

测试环境为 Win7+Delphi10,不需要管理员权限运行程序即可。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,MahUSB;

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
     { Private declarations }
     FUsb : TUsbClass;
     procedure UsbIN(ASender : TObject; const ADevType,ADriverName,
                     AFriendlyName : string);
     procedure UsbOUT(ASender : TObject; const ADevType,ADriverName,
                     AFriendlyName : string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
   FreeAndNil(FUsb);
end;

procedure TForm1.FormShow(Sender: TObject);
begin
   FUsb := TUsbClass.Create;
   FUsb.OnUsbInsertion := UsbIN;
   FUsb.OnUsbRemoval := UsbOUT;
end;

procedure TForm1.UsbIN(ASender : TObject; const ADevType,ADriverName,
                       AFriendlyName : string);
begin
  showmessage('USB Inserted - Device Type = ' + ADevType + #13#10 +
              'Driver Name = ' + ADriverName + #13+#10 +
              'Friendly Name = ' + AFriendlyName);
end;

procedure TForm1.UsbOUT(ASender : TObject; const ADevType,ADriverName,
                         AFriendlyName : string);
begin
  showmessage('USB Removed - Device Type = ' + ADevType + #13#10 +
               'Driver Name = ' + ADriverName + #13+#10 +
               'Friendly Name = ' + AFriendlyName);
end;

end.

============================================================================================

unit MahUSB;
interface
uses Windows, Messages, SysUtils, Classes, Registry, Masks;

type
  { Event Types }
  TOnUsbChangeEvent = procedure(AObject : TObject;
                                const ADevType,ADriverName,
                                      AFriendlyName : string) of object;

  { USB Class }
  TUsbClass = class(TObject)
  private
    FHandle : HWND;
    FOnUsbRemoval,
    FOnUsbInsertion : TOnUsbChangeEvent;
    procedure GetUsbInfo(const ADeviceString : string;
                         out ADevType,ADriverDesc,
                            AFriendlyName : string);
    procedure WinMethod(var AMessage : TMessage);
    procedure RegisterUsbHandler;
    procedure WMDeviceChange(var AMessage : TMessage);
  public
    constructor Create;
    destructor Destroy; override;
    property OnUsbInsertion : TOnUsbChangeEvent read FOnUsbInsertion
                                           write FOnUsbInsertion;
    property OnUsbRemoval : TOnUsbChangeEvent read FOnUsbRemoval
                                         write FOnUsbRemoval;
  end;

// -----------------------------------------------------------------------------
implementation

type
  // Win API Definitions
  PDevBroadcastDeviceInterface  = ^DEV_BROADCAST_DEVICEINTERFACE;
  DEV_BROADCAST_DEVICEINTERFACE = record
    dbcc_size : DWORD;
    dbcc_devicetype : DWORD;
    dbcc_reserved : DWORD;
    dbcc_classguid : TGUID;
    dbcc_name : char;
  end;

const
  // Miscellaneous
  GUID_DEVINTF_USB_DEVICE : TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
  USB_INTERFACE                = $00000005; // Device interface class
  USB_INSERTION                = $8000;     // System detected a new device
  USB_REMOVAL                  = $8004;     // Device is gone

  // Registry Keys
  USBKEY  = 'SYSTEM\CurrentControlSet\Enum\USB\%s\%s';
  USBSTORKEY = 'SYSTEM\CurrentControlSet\Enum\USBSTOR';
  SUBKEY1  = USBSTORKEY + '\%s';
  SUBKEY2  = SUBKEY1 + '\%s';

constructor TUsbClass.Create;
begin
  inherited Create;
  FHandle := AllocateHWnd(WinMethod);
  RegisterUsbHandler;
end;

destructor TUsbClass.Destroy;
begin
  DeallocateHWnd(FHandle);
  inherited Destroy;
end;

procedure TUsbClass.GetUsbInfo(const ADeviceString : string;
                               out ADevType,ADriverDesc,
                                   AFriendlyName : string);
var sWork,sKey1,sKey2 : string;
    oKeys,oSubKeys : TStringList;
    oReg : TRegistry;
    i,ii : integer;
    bFound : boolean;
begin
  ADevType := '';
  ADriverDesc := '';
  AFriendlyName := '';

  if ADeviceString<>'' then begin
    bFound := false;
    oReg := TRegistry.Create;
    oReg.RootKey := HKEY_LOCAL_MACHINE;

    // Extract the portions of the string we need for registry. eg.
    // \\?\USB#Vid_4146&Pid_d2b5#0005050400044#{a5dcbf10- ..... -54334fb951ed}
    // We need sKey1='Vid_4146&Pid_d2b5' and sKey2='0005050400044'
    sWork := copy(ADeviceString,pos('#',ADeviceString) + 1,1026);
    sKey1 := copy(sWork,1,pos('#',sWork) - 1);
    sWork := copy(sWork,pos('#',sWork) + 1,1026);
    sKey2 := copy(sWork,1,pos('#',sWork) - 1);

    // Get the Device type description from \USB key
    if oReg.OpenKeyReadOnly(Format(USBKEY,[skey1,sKey2])) then begin
      ADevType := oReg.ReadString('DeviceDesc');
      oReg.CloseKey;
      oKeys := TStringList.Create;
      oSubKeys := TStringList.Create;

      // Get list of keys in \USBSTOR and enumerate each key
      // for a key that matches our sKey2='0005050400044'
      // NOTE : The entry we are looking for normally has '&0'
      // appended to it eg. '0005050400044&0'
      if oReg.OpenKeyReadOnly(USBSTORKEY) then begin
        oReg.GetKeyNames(oKeys);
        oReg.CloseKey;

        // Iterate through list to find our sKey2
        for i := 0 to oKeys.Count - 1 do begin
          if oReg.OpenKeyReadOnly(Format(SUBKEY1,[oKeys[i]])) then begin
            oReg.GetKeyNames(oSubKeys);
            oReg.CloseKey;

            for ii := 0 to oSubKeys.Count - 1 do begin
              if MatchesMask(oSubKeys[ii],sKey2 + '*') then begin
                // Got a match?, get the actual desc and friendly name
                if oReg.OpenKeyReadOnly(Format(SUBKEY2,[oKeys[i],
                                        oSubKeys[ii]])) then begin
                  ADriverDesc := oReg.ReadString('DeviceDesc');
                  AFriendlyName := oReg.ReadString('FriendlyName');
                  oReg.CloseKey;
                end;

                bFound := true;
              end;
            end;
          end;

          if bFound then break;
        end;
      end;

      FreeAndNil(oKeys);
      FreeAndNil(oSubKeys);
    end;

    FreeAndNil(oReg);
  end;
end;

procedure TUsbClass.WMDeviceChange(var AMessage : TMessage);
var iDevType : integer;
    sDevString,sDevType,
    sDriverName,sFriendlyName : string;
    pData : PDevBroadcastDeviceInterface;
begin
  if (AMessage.wParam = USB_INSERTION) or
     (AMessage.wParam = USB_REMOVAL) then begin
    pData := PDevBroadcastDeviceInterface(AMessage.LParam);
    iDevType := pData^.dbcc_devicetype;

    // Is it a USB Interface Device ?
    if iDevType = USB_INTERFACE then begin
      sDevString := PChar(@pData^.dbcc_name);
      GetUsbInfo(sDevString,sDevType,sDriverName,sFriendlyName);

      // Trigger Events if assigned
      if (AMessage.wParam = USB_INSERTION) and
        Assigned(FOnUsbInsertion) then
          FOnUsbInsertion(self,sDevType,sDriverName,sFriendlyName);
      if (AMessage.wParam = USB_REMOVAL) and
        Assigned(FOnUsbRemoval) then
          FOnUsbRemoval(self,sDevType,sDriverName,sFriendlyName);
    end;
  end;
end;

procedure TUsbClass.WinMethod(var AMessage : TMessage);
begin
  if (AMessage.Msg = WM_DEVICECHANGE) then
    WMDeviceChange(AMessage)
  else
    AMessage.Result := DefWindowProc(FHandle,AMessage.Msg,
                                     AMessage.wParam,AMessage.lParam);
end;

procedure TUsbClass.RegisterUsbHandler;
var rDbi : DEV_BROADCAST_DEVICEINTERFACE;
    iSize : integer;
begin
  iSize := SizeOf(DEV_BROADCAST_DEVICEINTERFACE);
  ZeroMemory(@rDbi,iSize);
  rDbi.dbcc_size := iSize;
  rDbi.dbcc_devicetype := USB_INTERFACE;
  rDbi.dbcc_reserved := 0;
  rDbi.dbcc_classguid  := GUID_DEVINTF_USB_DEVICE;
  rDbi.dbcc_name := #0;
  RegisterDeviceNotification(FHandle,@rDbi,DEVICE_NOTIFY_WINDOW_HANDLE);
end;

end.

detecusb

DetectUSB1

如何判断当前程序是直接运行还是从CMD窗口中运行(下)

继续前一篇提到的问题。仍然是根据天杀的建议更专业一点的方法是通过判断当前进程的父进程来得知是如何运行的。比如,双击运行父进程就是Explore.exe,命令行运行,父进程就是 cmd.exe 。

代码如下:

program Project2;

{$APPTYPE CONSOLE}

uses
SysUtils,
windows,
Tlhelp32,
PsApi;

//检查自己的进程的父进程
procedure CheckParentProc;
var //检查自己的进程的父进程
Pn: TProcesseNtry32;
sHandle:THandle;
H,hMod:Hwnd;
Found:Boolean;
Buffer:array[0..1023]of Char;
cbNeeded:DWORD;
begin
//得到所有进程的列表快照
sHandle:= CreateToolhelp32Snapshot(TH32CS_SNAPALL,0);
Found:= Process32First(sHandle,Pn);//查找进程
while Found do //遍历所有进程
begin
//比较枚举出来的ID是否是当前的ID
if Pn.th32ProcessID = GetCurrentProcessId then
begin
//父进程的句柄
H:= OpenProcess(PROCESS_ALL_ACCESS,True,Pn.th32ParentProcessID);

if EnumProcessModules( H,@hMod,sizeof(hMod),cbNeeded) then
begin
ZeroMemory(@Buffer,MAX_PATH+1);
GetModuleFileNameEx(H, hMod,Buffer,MAX_PATH+1); //枚举进程文件所在路径
//只是简单把它打印出来而已
writeln(strpas(Buffer));
end;
CloseHandle(H);
end;
Found:= Process32Next(sHandle,Pn);//查找下一个
end;
CloseHandle(sHandle);
end;

begin
CheckParentProc;
readln;
end.

下图是这个程序分别在cmd窗口,直接双击和Delphi IDE环境中的运行结果。

完整代码下载

cmd2

=============================================================

2022年01月24日补充 VC 下的实现方法

#include "stdafx.h"

#include <Windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <Psapi.h>

int getProcessName(DWORD pid, LPWSTR fname, DWORD sz)
{
	HANDLE h = NULL;
	int e = 0;
	h = OpenProcess
	(
		PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
		FALSE,
		pid
	);
	if (h)
	{
		if (GetModuleFileNameEx(h, NULL, fname, sz) == 0)
			e = GetLastError();
		CloseHandle(h);
	}
	else
	{
		e = GetLastError();
	}
	return (e);
}

DWORD getParentPID(DWORD pid)
{
	HANDLE h = NULL;
	PROCESSENTRY32 pe = { 0 };
	DWORD ppid = 0;
	pe.dwSize = sizeof(PROCESSENTRY32);
	h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (Process32First(h, &pe))
	{
		do
		{
			if (pe.th32ProcessID == pid)
			{
				ppid = pe.th32ParentProcessID;
				break;
			}
		} while (Process32Next(h, &pe));
	}
	CloseHandle(h);
	return (ppid);
}

boolean IsRuninCMD() {
	DWORD pid, ppid;
	int e;
	wchar_t fname[256];
	pid = GetCurrentProcessId();
	ppid = getParentPID(pid);
	e = getProcessName(ppid, fname, MAX_PATH);
	wprintf(L"PPID=%d\nErr=%d\nEXE={%s}\n", ppid, e, fname);
	if ((wcsstr(fname, L"cmd.exe") != NULL) ||
		(wcsstr(fname, L"powershell.exe") != NULL)) {
		return true;
	} else return false;
}
void main(int argc, char* argv[])
{
	if (IsRuninCMD()) {
		printf("in cmd\n");
	}
	else {
		printf("NOT in cmd\n");
		getchar();
	}
}

如何判断当前程序是直接运行还是从CMD窗口中运行(上)

前几天在写console程序的时候忽然想起来“如何判断当前程序是直接运行还是从CMD窗口中运行”的问题,网上搜索了一下,并无明确结果,为此我请教了一下天杀,他给我出了2个办法。第一个办法是通过GetStartupInfo得到当前窗口的 Title,从下图可以看到直接运行的时候是只有文件名,如果从cmd下面运行会有完整的路径和文件名

result

例程:
program Project1;

{$APPTYPE CONSOLE}

uses
SysUtils,
windows;

var
Info:STARTUPINFO;
begin
GetStartupInfo(Info);
writeln(Info.lpTitle);
readln;
end.

上面 STARTUPINFO结构体的 dwFlags 位也能反映这个差别:

STARTF_TITLEISLINKNAME 0x00000800
The lpTitle member contains the path of the shortcut file (.lnk) that the user invoked to start this process. This is typically set by the shell when a .lnk file pointing to the launched application is invoked. Most applications will not need to set this value.
This flag cannot be used with STARTF_TITLEISAPPID.

完整程序下载 cmd1

检查当前可执行文件是否为64位的工具

检查当前可执行文件是否为64位的工具

很多时候我们经常发现拿到手的某个EXE或者EFI文件无法执行,出现的错误信息也很少,无法得知是因为文件损坏还是这个程序只能在64位Windows下运行。

因此编写了一个简单的工具用来检查EXE或者EFI程序是否是64位的。

用法很简单:直接拖拽到cc64.exe 上或者在命令行下用 cc64 文件名来运行。

原理上是分析PE结构,Machine Types 字段,有如下定义

Constant Value Description
IMAGE_FILE_MACHINE_UNKNOWN 0x0 The contents of this field are assumed to be applicable to any machine type
IMAGE_FILE_MACHINE_AM33 0x1d3 Matsushita AM33
IMAGE_FILE_MACHINE_AMD64 0x8664 x64 《—————– 64 bit
IMAGE_FILE_MACHINE_ARM 0x1c0 ARM little endian
IMAGE_FILE_MACHINE_ARMV7 0x1c4 ARMv7 (or higher) Thumb mode only
IMAGE_FILE_MACHINE_EBC 0xebc EFI byte code
IMAGE_FILE_MACHINE_I386 0x14c Intel 386 or later processors and compatible processors《———– 32 bit
IMAGE_FILE_MACHINE_IA64 0x200 Intel Itanium processor family 《———– 64 bit
IMAGE_FILE_MACHINE_M32R 0x9041 Mitsubishi M32R little endian
IMAGE_FILE_MACHINE_MIPS16 0x266 MIPS16
IMAGE_FILE_MACHINE_MIPSFPU 0x366 MIPS with FPU
IMAGE_FILE_MACHINE_MIPSFPU16 0x466 MIPS16 with FPU
IMAGE_FILE_MACHINE_POWERPC 0x1f0 Power PC little endian
IMAGE_FILE_MACHINE_POWERPCFP 0x1f1 Power PC with floating point support
IMAGE_FILE_MACHINE_R4000 0x166 MIPS little endian
IMAGE_FILE_MACHINE_SH3 0x1a2 Hitachi SH3
IMAGE_FILE_MACHINE_SH3DSP 0x1a3 Hitachi SH3 DSP
IMAGE_FILE_MACHINE_SH4 0x1a6 Hitachi SH4
IMAGE_FILE_MACHINE_SH5 0x1a8 Hitachi SH5
IMAGE_FILE_MACHINE_THUMB 0x1c2 ARM or Thumb (“interworking”)
IMAGE_FILE_MACHINE_WCEMIPSV2 0x169 MIPS little-endian WCE v2

64Bit .EXE and .EFI file checking utilty

This is autility which can be use to check if a EXE or EFI is a64bit image.

Usage: Drag and drop the file to this utilty in Windows file manager or run cc64 filename in the console window.

It will check the PE header when running. In the Machine type of PE header, you can find the the specified CPU that the PE image can be run.

cc64

www.lab-z.com
zoologist
2013-03-28

机器码对汇编指令的转换工具

偶然间发现 Win7 64位并不提供debug.exe工具,这给反汇编机器码带来一些困难(特别是公司只容许安装正版软件)。在网上搜索发现一个很好用的反汇编引擎 BeaEngine。利用这个引擎编写了一个简单的命令行工具用来实现机器码到汇编指令的转换。

第一步:给定反汇编默认的地址,这对于跳转指令特别重要.按”u”之后输入地址;如果不需要,直接回车即可

第二步:输入欲编译的机器码,回车后即开始转换为汇编指令

特别情况:

1.有可能出现无法识别的指令

2.0×0087 和 0x87 0x00 这样的机器码是等价的,但是0x87 并不等于 0x0087。

3.默认的反编译指令集是32位的,通过修改源程序可以变成8086或者x64的

This is a utility which can covert machine code to assemble code (disassemble). It is based on a disassemble engine which named BeaEngine.
Both source code and executable files are in the package. You can rebuild it with Delphi10.

step1:input a virtual EIP which will be set as the beginning address of the assemble code

step2:input the machine code in Hex. It will be transferred to assemble code after pressing Enter

Note:

1. Some hex number may not be recognized

2. The number ’00’ is meaningful as the prefix of a Hex. Ex. 0x0087 will be recognized as 0x87 and 0x00. It’s different with 0x87.

3. Default instruction is 32 Bits. It can be switched to 8086 or x64 by modifying and rebuilding the source code.

m2a

Delphi 调用BeaEngine 反汇编的例子 (DLL版)

/////////////////////////////////////////////////////////////////////////
//
// Delphi 调用BeaEngine 反汇编的例子
// 这是使用 DLL 的版本,Release程序的时候需要将 BeaEngine.dll一同发布
//
// By Zoologist
// www.lab-z.com
// 2013-02-21
/////////////////////////////////////////////////////////////////////////
program BeaConsoleTest;

{$APPTYPE CONSOLE}

uses
SysUtils,BeaEngineDelphi32;

procedure DisasmCode;
var
MyDisasm:TDISASM;
i,len:integer;
begin
// ======== Init the TDisasm structure (important !)
FillChar(MyDisasm,sizeof(TDISASM),0);

// ======== Init EIP
MyDisasm.EIP:=Int64(@DisasmCode);
MyDisasm.Archi:=0;
MyDisasm.Options:=NoTabulation + MasmSyntax;

// ======== Loop for Disasm
for i:=1 to 20 do
begin
len:=Disasm(MyDisasm);
Writeln(IntToHex(MyDisasm.EIP,2)+’ ‘+MyDisasm.CompleteInstr);
MyDisasm.EIP:=MyDisasm.EIP+len;
end;
end;

begin
Writeln(‘This is a BeaEngine Test program for delphi.’);
DisasmCode;
Writeln(‘Press Enter to exit…’);
Readln;
end.

特别的需要修改 BeaEngineDelphi32.pas 打开使用 DLL 反编译方式

// ====================================================================
// [+] BranchTaken,BranchNotTaken added in TPREFIXINFO v3.1.0
unit BeaEngineDelphi32;
// ====================================================================
// Default link type is static lib
// comment below line to switch link with DLL
// ====================================================================
{$DEFINE USEDLL}
// ====================================================================
// Copyright 2006-2009, BeatriX
// File coded by BeatriX

编译之后的EXE需要连同 DLL 一起发布才能正常工作。下面是完整的例子

Bea1

Delphi 调用BeaEngine 反汇编的例子 (OBJ加入编译)

/////////////////////////////////////////////////////////////////////////
//
// Delphi 调用BeaEngine 反汇编的例子
// 这是直接和Obj进行链接的例子,Release程序的时候直接发布EXE文件即可
//
// By Zoologist
// www.lab-z.com
// 2013-02-22
/////////////////////////////////////////////////////////////////////////

program BeaConsoleTest;

{$APPTYPE CONSOLE}

uses
SysUtils,BeaEngineDelphi32;

procedure DisasmCode;
var
MyDisasm:TDISASM;
i,len:integer;
begin
// ======== Init the TDisasm structure (important !)
FillChar(MyDisasm,sizeof(TDISASM),0);

// ======== Init EIP
MyDisasm.EIP:=Int64(@DisasmCode);
MyDisasm.Archi:=0;
MyDisasm.Options:=NoTabulation + MasmSyntax;

// ======== Loop for Disasm
for i:=1 to 20 do
begin
len:=Disasm(MyDisasm);
Writeln(IntToHex(MyDisasm.EIP,2)+’ ‘+MyDisasm.CompleteInstr);
MyDisasm.EIP:=MyDisasm.EIP+len;
end;
end;

begin
Writeln(‘This is a BeaEngine Test program for delphi.’);
DisasmCode;
Writeln(‘Press Enter to exit…’);
Readln;
end.

使用原来的 BeaEngineDelphi32.pas 无法编译(我用 Delphi 2006),需要加入一些代码,下面斜体显示

implementation
{$IFNDEF USEDLL}
{$L BeaEngineLib.obj}

function strcmp(dest, src: PAnsiChar): DWORD;cdecl;
begin
Result := SysUtils.CompareStr(dest, src);
end;

function strcpy(dest, src: PAnsiChar): PAnsiChar;cdecl;
begin
Result := SysUtils.StrCopy(dest, src);
end;

更具体的修改,请参考附件。

Bea2

介绍一个反汇编引擎 BeaEngine

介绍一个反编译引擎 BeaEngine

来自 http://www.beaengine.org/ 是一个免费的反汇编引擎,能够支持多种语言,比如:Python VC MASM32 Delphi 等等

主要函数

1.Disasm 函数

语法:

int Disasm(
pDisasmStruc pMonDisasm
);

参数:

pMonDisasm

[out] 返回指向 DisasmStruc 结构体的指针

函数返回值:

返回值有3种可能。如果遇到无法识别的opcode,返回 UNKNOWN_OPCODE (-1);如果读取出界(也就是读取超过安全区范围),那么返回OUT_OF_RANGE (0);其余情况返回指令长度。

——————————————————————————–
2.BeaEngineVersion 函数

返回当前引擎的版本信息

语法:

char* BeaEngineVersion(void);

返回值:

返回一个指向以0结尾的字符串,其中是当前版本信息。

——————————————————————————–
2.BeaEngineVersion 函数

返回当前引擎的修订版信息。(我不清楚 version和revision的差别.也许是因为我不用SVN之类的版本控制软件吧:)

The BeaEngineRevision function allows you to retrieve the current revision of the engine. Revisions come from our google SVN and can be considered like indicators about last bug fixes.

语法

char* BeaEngineRevision(void);Return

返回一个指向以0结尾的字符串,其中是当前修订版信息。

一些用到的结构体

_Disasm = packed record
EIP : longint; //引擎开始Decode的位置
VirtualAddr : int64; //反编译起始处的虚拟IP
SecurityBlock : longint; //为了防止在反编译过程中出现溢出,需要多指定一些字节作为缓冲
CompleteInstr : array[0..(INSTRUCT_LENGTH)-1] of AnsiChar; //输出的完整指令
Archi : longint; //指定指令集的类型
Options : int64; //定义一些指令显示的方法
Instruction : TINSTRTYPE;
Argument1 : TARGTYPE;
Argument2 : TARGTYPE;
Argument3 : TARGTYPE;
Prefix : TPREFIXINFO;
Reserved_ : array[0..39] of longint;
end;
TDISASM = _Disasm;
PDISASM = ^_Disasm;
LPDISASM = ^_Disasm;

TINSTRTYPE = packed record
Category : longint; //指令集的家族,比如:MMX
Opcode : longint; //OPcode
Mnemonic : array[0..15] of AnsiChar; //助记符
BranchType : longint; //如果是分支指令,那么给出跳转条件,例如:无条件跳转
Flags : TEFLStruct; //对 EFLAGS 的影响
AddrValue : int64; //如果解码之后的指令是一个分支指令,并且目标地址能够计算出(非运行期才能计算出来的),例如: jmp eax 会让这个位置为0
Immediat : int64; //指令中使用的常数
ImplicitModifiedRegs : longint; //该指令影响的寄存器
end;

TARGTYPE = packed record
ArgMnemonic : array[0..31] of AnsiChar; //返回ASCII形式的参数
ArgType : longint; //返回参数类型
ArgSize : longint; //返回参数大小
ArgPosition : longint; //参数类型为 REGISTER_TYPE 并且只使用了8位
//寄存器(Legacy模式)。ArgPosition=1 表示使用的是
//AH CH BH或者DH,反之为 AL BL CL 或者DL
AccessMode : longint; //表明参数是否为可修改(WRITE=0x02)或者(READ=0x01)
Memory : TMEMORYTYPE; //返回寻址模式
SegmentReg : longint; //寻址使用的段寄存器
end;

下载:

32位 beaengine-win32

64位 beaengine-win64

帮助文档(为了防止某天,这个网站被墙) beahelp

bea