【问题标题】:Convert integer to array of bytes [closed]将整数转换为字节数组[关闭]
【发布时间】:2016-05-25 11:18:14
【问题描述】:

我正在尝试将一个10位的整数值转换为字节,但该函数只返回4个值,我需要6个点,如何解决?

我用来将整数转换为字节的函数

var
  i, j: integer;
  bbI : array[1.. sizeof(integer)] of byte;
begin
  i := 2337669003;
  Move(i, bbI[1], SizeOf(Integer));
  for j := Low(bbI) to High(bbI) do
  Memo1.Lines.Append(IntToHex(bbI[j],2))
end;

函数返回我

8B 法郎 55 8B

values that are returned 但我需要更多 2 个值

EC 51

函数应该返回我

8B 法郎 55 8B 欧共体 51

correct value according to cheat engine

【问题讨论】:

  • Ints 的长度为 4 字节,your conversion is fine,已根据您计算机的字节序进行了调整。
  • 从哪里获得 EC 51? 2337669003 (dec) 正好是 8B FF 55 8B (hex)
  • 问题是值 2.337.669.003 大于 MaxInt (2.147.483.647),你必须使用 Int64。
  • @mezen 1) 2 337 669 003 适合无符号 32 位整数。 2) Int64 不是 6 个字节,所以 OP 的问题中仍然缺少一些东西。

标签: arrays delphi cheat-engine


【解决方案1】:

我正在尝试将一个10位的整数值转换为字节,但该函数只返回4个值,我需要6个点,如何解决?

你不能。 Integer 的大小只有 4 个字节。 Integer2337669003 是字节序列8B FF 55 8B。您无法从中获得额外的 EC 51 字节。

Int64 的大小为 8 个字节。字节序列8B FF 55 8B EC 51 将是一个Int645903246413051658240,其高2 字节(00 00) 被截断。

从截图中我们可以清楚的看到8B FF 55 8B EC 51这个字节序列其实对应了Win32BitBlt()函数的前4个x86汇编指令。为什么要使用整数值来表示汇编指令?这不是解决这个问题的好方法。你了解 x86 指令集的实际工作原理吗?你了解整数的工作原理吗?

在这种情况下,我建议使用实际的字节数组而不是整数数组:

var
  Instructions: array[0..5] of byte;
  i: Integer;
begin
  // mov edi,edi
  Instructions[0] := $8B;
  Instructions[1] := $FF;

  // push ebp
  Instructions[2] := $55;

  // mov ebp,esp
  Instructions[3] := $8B;
  Instructions[4] := $EC;

  // push ecx
  Instructions[5] := $51;

  for i := Low(Instructions) to High(Instructions) do
    Memo1.Lines.Append(IntToHex(Instructions[i], 2));
end;

或者甚至使用记录来代替:

type
  BitBltInstructions = packed record
    MovEdiEdi: array[0..1] of byte; // $8B $FF
    PushEbp: byte; // $55
    MovEbpEsp: array[0..1] of byte; // $8B $EC
    PushEcx: byte; // $51
  end;

var
  Instructions: BitBltInstructions;
  bytes: array[0..Sizeof(BitBltInstructions)-1] of byte absolute Instructions;
  i: Integer;
begin
  Instructions.MovEdiEdi[0] := $8B;
  Instructions.MovEdiEdi[1] := $FF;
  Instructions.PushEbp      := $55;
  Instructions.MovEbpEsp[0] := $8B;
  Instructions.MovEbpEsp[1] := $EC;
  Instructions.PushEcx      := $51;

  for i := Low(bytes) to High(bytes) do
    Memo1.Lines.Append(IntToHex(bytes[i], 2));
end;

【讨论】:

  • 谢谢解释 我想这次我明白了 起初我以为我要写6个字节,但我错了,我只需要写4个,告诉我一件事,所有无论 Windows 版本如何,x86 指令都有固定字节,对吧?
  • 在这种情况下,只写 4 个字节是没有意义的,因为那样你将只写 mov ebp,esp 指令的一半。您真正想要完成什么?至于 x86 指令集,是的,它的许多指令使用固定字节(有些指令具有可变字节)。 x86 与 Windows 完全没有关系。你知道 x86 是什么,不是吗?它是直接在 CPU 本身上运行的指令,与操作系统无关。
  • 一个软件在我的函数中创建了一个 WINAPI Hook(在本例中为 BitBlt),我在 FormCreate 中捕获了原始值(其他程序需要几秒钟才能挂钩),然后在我的函数的地址。
  • 如果您的目标是阻止安装挂钩,那么您为什么要为您询问的方法烦恼?您已经拥有原始字节,只需将它们保存到变量中,然后在需要时将它们写回函数地址。或者,更好的是,使用VirtualProtect() 一开始就防止安装挂钩。
  • 我正在使用替代函数来写入字节,我没有使用 WPM,您有一些我可以研究使用 VirtualProtect() 来不允许完成挂钩的东西吗?跨度>
【解决方案2】:

你可以使用指令absolute:

procedure Main;
var
  i: Integer;
  x: array[0..3] of Byte absolute i;
begin
  i := 123456;
  Writeln(x[0]);
  Writeln(x[1]);
  Writeln(x[2]);
  Writeln(x[3]);
end;

【讨论】:

  • 这与问题中的代码行为相同
  • 除了这段代码中没有Move操作复制内存,直接访问值。
  • @DavidHeffernan 哦..“表现”(错过了那个词)。是的,这是肯定的。
【解决方案3】:

您为此使用变体记录。在这种情况下,记录的两个字段共享相同的内存:

program Test;
uses
  System.SysUtils;

type
  TInteger = record
    case Byte of
      0: (AsValue: Integer);
      1: (AsArray: array [0..3] of Byte);
  end;

var
  X: TInteger;
begin
  X.AsValue := 123456;
  Writeln(X.AsArray[0]);
  Writeln(X.AsArray[1]);
  Writeln(X.AsArray[2]);
  Writeln(X.AsArray[3]);
end.

【讨论】:

  • 不要重新声明这个类型。它已经在SysUtils 中声明为LongRec。您提供的答案与问题中的代码行为相同,这也有点奇怪。
  • 您不能为 LongRec 变量分配整数值!我没有重新声明那种类型。 LongRec = 打包记录案例 0 的整数:(Lo,Hi:Word); 1:(字:字的数组[0..1]); 2:(字节:字节数组[0..3]);结束;
  • 我主要是向他展示了可用于任何固定二进制结构的可能方法。
  • @ZesNAN 你错了。您可以在 lhs 和 rhs 上完美地将 Integer 变量转换为 LongRec。否则它到底为什么存在?在您的情况下,代码如下所示:var X: Integer; X := 123456; Writeln(LongRec(X).Bytes[0])l。再说一次,您为什么不解决答案中的代码与问题中的代码行为相同的事实?
  • @DavidHeffernan:同意。你说的对。没有像那样使用 LongRec,因为我从来不需要像问题的作者那样做任务(我的意思是使用整数)。我只是展示了实现这一目标的一种简单方法。感谢您的评论。
猜你喜欢
  • 1970-01-01
  • 2018-05-27
  • 1970-01-01
  • 2023-04-02
  • 2018-11-19
  • 1970-01-01
  • 2018-05-18
  • 2017-03-13
相关资源
最近更新 更多