现在我正在尝试从这里解决r5

我已经尝试从Hooper中理解伪代码了

function check_password {
    var_28 = arg0;
    if (strlen(var_28) != strlen("this_is_not_even_interesting_its_garbage")) {
            rax = 0xffffffff;
    }
    else {
            strcpy("this_is_not_even_interesting_its_garbage", var_28);
            var_18 = 0x1;
            while (var_18 != 0x0) {
                    var_18 = 0x0;
                    for (var_14 = 0x0; var_14 <= 0x27; var_14 = var_14 + 0x1) {
                            if ((*(int8_t *)(sign_extend_32(var_14) + 0x6010a0) & 0xff) != 0x0) {
                                    rax = random();
                                    rcx = *(int8_t *)(sign_extend_64(var_14) + 0x6010a0) & 0xff & 0xff;
                                    temp_3 = rax % rcx;
                                    *(int8_t *)(sign_extend_32(var_14) + 0x6010a0) = (*(int8_t *)(sign_extend_32(var_14) + 0x6010a0) & 0xff) - temp_3 + 0x1;
                                    var_18 = var_18 | *(int8_t *)(sign_extend_32(var_14) + 0x6010a0) & 0xff & 0xff;
                                    *(int8_t *)(sign_extend_32(var_14) + "this_is_not_even_interesting_its_garbage") = (*(int8_t *)(sign_extend_32(var_14) + "this_is_not_even_interesting_its_garbage") & 0xff) - temp_3 + 0x1;
                            }
                    }
            }
            rax = *master;
            rax = strcmp(rax, "this_is_not_even_interesting_its_garbage");
    }
    return rax;
}


现在对我来说太复杂了。所以我知道密码长度应该为40,但是代码的另一部分如何工作?

不清楚的部分是unt8_t强制类型转换。我已经使用gdb遍历了代码,并且看到了某些指令的结果,但无法理解为什么是这些结果?

评论

开始了解这些类型的事物的最佳方法是编写自己的伪代码或模拟器。这样,您将迫使自己真正阅读并理解您面前的代码。您尝试过这样做吗?难点是什么?

@Nirlzr首先,我尝试在带有断点的gdb中运行此代码。我可以在asm代码中看到两个循环,但是接下来发生的事情对我来说有些不可思议。使用gdb运行它时,我发现rcx在循环中的第一个值是3。但是我不确定那个数字从哪里来

因此,您可能会遇到麻烦的那一行是rcx = *(int8_t *)(sign_extend_64(var_14)+ 0x6010a0)&0xff&0xff ;?您介意编辑吗?您是否还在苦苦挣扎?

@Nirlzr所有强制转换为int8_t的行对我来说都很奇怪

@NirIzr我认为(int8_t *)正在将(sign_extend + offset)转换为有符号的8位int之后,它从该指针获取值并按位进行运算。但是我不知道它将给我什么结果。看起来像int和0xff总是返回int

#1 楼

尽管OP澄清了内部for对他来说不可读,但我将写一个答案,彻底解释前几行,然后突然停在内部for循环的最关键部分。尽管相信示例是一种很好的学习方法,但我这样做是为了使它尽可能具有教育意义,而又不干扰独立解决练习的学习过程。我也不熟悉特定的练习集,并希望避免在创作者未打算提供完整答案的情况下提供完整答案。

我希望我能获得足够的教育,但又不要过多。

祝你好运,练习如下:

var_18 = 0x1;

将内部状态设置为1。

while (var_18 != 0x0) {

状态为True时,继续执行循环的内容。状态实际上是一个布尔值,指示处理尚未完成。

var_18 = 0x0;

在每个外循环迭代中将内部状态设置为零。这意味着每次迭代都必须设置“尚未完成”标志。

for (var_14 = 0x0; var_14 <= 0x27; var_14 = var_14 + 0x1) {

内部迭代0x28次,十进制为40。因为我们知道这是整个字符串的长度,所以我们可以假设内部循环以某种方式遍历字符串的所有字符。这可能是一个巧合,但我们应该注意一下。

if ((*(int8_t *)(sign_extend_32(var_14) + 0x6010a0) & 0xff) != 0x0) {

现在,它变得有点复杂了,因此我们将其分为几个部分零件:

sign_extend_32(var_14)

由于我们知道var_14是0到39(包括)之间的非负整数,因此没有符号扩展的含义。符号扩展基本上是将符号长度考虑在内的将较短的长度值转换为较长的值的操作。请参阅此以获取有关符号扩展的更多信息。这是编译器或反编译器工件。更高级的反编译器可能已删除了此文件。

(int8_t *)(sign_extend_32(var_14) + 0x6010a0)

将我们的var_14添加到相对较长的十六进制偏移中。从外观上看,它可能是40字节表的偏移量。这是从经验中学到的,查看该地址的值可能会清除它。添加var_14,然后将其强制转换为int8指针,则进一步说明了这种情况,请使用var_14作为该表中的索引。

(*(int8_t *)(sign_extend_32(var_14) + 0x6010a0) & 0xff)

如果我们还不确定,现在很清楚了,因为我们从结果偏移量中读取了一个字节。将其与0xff进行“与”运算是另一个反编译器工件,这是由编译器如何读取64位intel处理器中的字节引起的。

if ((*(int8_t *)(sign_extend_32(var_14) + 0x6010a0) & 0xff) != 0x0) {

回到整行,这正在从表中读取字节,并跳过内部循环的当前迭代。

rax = random();

简单。在rax中设置一个随机值。

rcx = *(int8_t *)(sign_extend_64(var_14) + 0x6010a0) & 0xff & 0xff;

这实际上与以前的条件完全相同,只是现在表中该索引的值存储在rcx中。

剩余的代码行

                                temp_3 = rax % rcx;
                                *(int8_t *)(sign_extend_32(var_14) + 0x6010a0) = (*(int8_t *)(sign_extend_32(var_14) + 0x6010a0) & 0xff) - temp_3 + 0x1;
                                var_18 = var_18 | *(int8_t *)(sign_extend_32(var_14) + 0x6010a0) & 0xff & 0xff;
                                *(int8_t *)(sign_extend_32(var_14) + "this_is_not_even_interesting_its_garbage") = (*(int8_t *)(sign_extend_32(var_14) + "this_is_not_even_interesting_its_garbage") & 0xff) - temp_3 + 0x1;
                        }
                }
        }
        rax = *master;
        rax = strcmp(rax, "this_is_not_even_interesting_its_garbage");
}
return rax;