【问题标题】:Methods to form and check bitmasks形成和检查位掩码的方法
【发布时间】:2013-07-05 10:49:12
【问题描述】:

这很可能已经被问过并回答过,但我的搜索是徒劳的。

问题是关于位、字节掩码和检查。

假设一个有两个“触发器”0xC40xC5

196: 1100 0100  0xc4
197: 1100 0101  0xc5

检查var 是否是其中一个的简单方法是:

if (var == 0xc5 || var == 0xc4) {

}

但有时人们会看到这个(或类似的):

if ( ((var ^ magic) & mask) == 0)  {

}

我的问题是如何找到 magicmask。将使用哪些方法、过程、技巧等来形成这些值并断言是否存在?


编辑:

澄清一下。是的,在这个确切的例子中,前者会比后者更好,但我的问题更像是生成和检查这些类型的掩码。总体来说有点绕。我省略了很多,并试图使问题变得简单。但是……

作为一个例子,我查看了 OllyDbg 反编译器的源代码,在其中可以找到:

if (((code ^ pd->code) & pd->mask) == 0) 
    FOUND

其中code 是从指令中转换的 0 - 3 个字节的命令。

unsigned long code = 0;
if (size > 0) *(((char *)&code) + 0) = cmd[0];
if (size > 1) *(((char *)&code) + 1) = cmd[1];
if (size > 2) *(((char *)&code) + 2) = cmd[2];

就像只屏蔽 cmd 的字节部分一样

pd 是:

struct t_cmddata {
    uint32_t mask;          Mask for first 4 bytes of the command
    uint32_t code;          Compare masked bytes with this
        ...
}

将一个长数组保存为:

const t_cmddata cmddata[] = {
/*      mask      code  */
  { 0x0000FF, 0x000090, 1,00,  NNN,NNN,NNN, C_CMD+0,        "NOP" },
  { 0x0000FE, 0x00008A, 1,WW,  REG,MRG,NNN, C_CMD+0,        "MOV" },
  { 0x0000F8, 0x000050, 1,00,  RCM,NNN,NNN, C_PSH+0,        "PUSH" },
  { 0x0000FE, 0x000088, 1,WW,  MRG,REG,NNN, C_CMD+0,        "MOV" },
  { 0x0000FF, 0x0000E8, 1,00,  JOW,NNN,NNN, C_CAL+0,        "CALL" },
  { 0x0000FD, 0x000068, 1,SS,  IMM,NNN,NNN, C_PSH+0,        "PUSH" },
  { 0x0000FF, 0x00008D, 1,00,  REG,MMA,NNN, C_CMD+0,        "LEA" },
  { 0x0000FF, 0x000074, 1,CC,  JOB,NNN,NNN, C_JMC+0,        "JE,JZ" },
  { 0x0000F8, 0x000058, 1,00,  RCM,NNN,NNN, C_POP+0,        "POP" },
  { 0x0038FC, 0x000080, 1,WS,  MRG,IMM,NNN, C_CMD+1,        "ADD" },
  { 0x0000FF, 0x000075, 1,CC,  JOB,NNN,NNN, C_JMC+0,        "JNZ,JNE" },
  { 0x0000FF, 0x0000EB, 1,00,  JOB,NNN,NNN, C_JMP+0,        "JMP" },
  { 0x0000FF, 0x0000E9, 1,00,  JOW,NNN,NNN, C_JMP+0,        "JMP" },
  { 0x0000FE, 0x000084, 1,WW,  MRG,REG,NNN, C_CMD+0,        "TEST" },
  { 0x0038FE, 0x0000C6, 1,WW,  MRG,IMM,NNN, C_CMD+1,        "MOV" },
  { 0x0000FE, 0x000032, 1,WW,  REG,MRG,NNN, C_CMD+0,        "XOR" },
  ...

这将是一个典型的 live 用法示例。再说一遍:方法。一直在查看Karnaugh map 等-但认为对于同一操作区还有其他等方法。

【问题讨论】:

  • "None" 将是我的快速回答,考虑到两者在可读性上的巨大差异! :)
  • 您对哪些位感兴趣?只需检查这些位,无需使用任何异或操作。
  • 我怀疑你看到的是 XOR。我宁愿认为它是&,而是按位与。
  • 我试着写一个答案。但我的大脑现在不工作。 :(
  • @luserdroog:感谢您的努力,不幸的是我没有看到它......因为大脑无法正常工作,我就在你身边。我处于静止状态。整整一个星期。在逻辑根本不符合的时期。

标签: c bit-manipulation bitmask


【解决方案1】:

我假设你的问题是:给定一组“触发器”,我们能否找到可以通过以下代码检查触发器的掩码和魔法

if ( ((var ^ magic) & mask) == 0)  {
}

或者是一样的

if ((var & mask) == (magic & mask))  {
}

“触发器”的一个例子是

196: 1100 0100  0xc4
197: 1100 0101  0xc5
204: 1100 1100  0xcc
205: 1100 1101  0xcd

如果可行,“触发器”的比特应该分为“特定比特”和“任意比特”两种。与前 4 位和第 6 位和第 7 位一样,每个触发器中的特定位都相同。如果您更改触发器的任意位,它仍然是触发器。

所以恰好有 2^N 个触发器,其中 N 表示任意位数。

这是我对 stackoverflow 的第一个回答。我不确定我是否正确理解了您的问题。还是你在问其他的小技巧?

【讨论】:

  • 严格来说它相当于(var & mask) == (magic & mask),但当然会选择魔法使(magic & mask) == magic
【解决方案2】:

鉴于你的两个价值观,

196: 1100 0100  0xc4
197: 1100 0101  0xc5

您希望屏蔽掉不同的位,在本例中为位 0。因此屏蔽值将是 0x01、0xFE 的倒数。

即。 0xC4 & 0xFE == 0xC4,以及 0xC5 & 0xFE == 0xC4。

这意味着两个值都变为 0xC4。然后,您可以通过对应保留的确切位模式进行异或检查来检查 0xC4。

     1100 0100  0xC4

即。 0xC4 ^ 0xC4 == 0。

     1100 0100    1100 0101
   & 1111 1110    1111 1110 
     ---- ----    ---- ----
     1100 0100    1100 0100
   ^ 1100 0100
     ---- ----
     0000 0000

请先戴口罩,否则会有完全混乱的风险。


查看实际的source file,我有点认为他试图被混淆。许多函数都需要分解。

【讨论】:

  • 太棒了。这很好。你知道有什么方法可以验证这些表达式(除了很快会变得有点庞大的真值表)或在一个过程中对其进行编码......这是一种“好吧,让我们试试这个”。以及我应该阅读的任何主题,以便更快地看到这些模式。 (方法、书籍、数学主题等)。
  • 还没有,但我受到启发想尝试找到一些。我正在查看反编译器代码。您引用的设置code 的部分完全不可移植(假设为小端),这有点让人分心。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-10
  • 1970-01-01
  • 2010-11-26
  • 1970-01-01
  • 2020-01-28
  • 1970-01-01
  • 2017-04-23
相关资源
最近更新 更多