Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/css/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用汇编代码在C中设计函数_C_Assembly_X86 64_Reverse Engineering - Fatal编程技术网

用汇编代码在C中设计函数

用汇编代码在C中设计函数,c,assembly,x86-64,reverse-engineering,C,Assembly,X86 64,Reverse Engineering,我需要用C语言设计一个函数来实现机器代码中写的东西。我分步完成组装操作,但据说我的功能实现错误。我很困惑 这是函数的反汇编代码 (Hand transcribed from an image, typos are possible especially in the machine-code. See revision history for the image) 0000000000000000 <ex3>: 0: b9 00 00 00 00 mov

我需要用C语言设计一个函数来实现机器代码中写的东西。我分步完成组装操作,但据说我的功能实现错误。我很困惑

这是函数的反汇编代码

(Hand transcribed from an image, typos are possible
 especially in the machine-code.  See revision history for the image)
0000000000000000 <ex3>:
   0:   b9 00 00 00 00       mov    0x0,%ecx
   5:   eb 1b                jmp    L2  // 22 <ex3+0x22>
   7:   48 63 c1     L1:     movslq %ecx,%rax
   a:   4c 8d 04 07          lea    (%rdi,%rax,1),%r8
   e:   45 0f b6 08          movzbl (%r8),%r9d
  12:   48 01 f0             add    %rsi,%rax
  15:   44 0f b6 10          movzbl (%rax),%r10d
  19:   45 88 10             mov    %r10b,(%r8)
  1c:   44 88 08             mov    %r9b,(%rax)
  1f:   83 c1 01             add    $0x1,%ecx
  22:   39 d1        L2:     cmp    %edx,%ecx
  24:   7c e1                jl     L1   // 7 <ex3+0x7>
  26:   f3 c3                repz retq
我的代码未给出或结算函数的签名:


如果您认识到任何错误,请解释导致这些错误的原因。

编者注:这是一个仅针对循环结构的部分答案。它不包括movzbl字节加载,或者其中一些变量是指针或类型宽度。问题的其他部分还有其他答案的余地

C支持goto,尽管人们经常不赞成使用它们,但它们在这里非常有用。使用它们使其尽可能与部件相似。这允许您在开始引入更合适的控制流机制(如while循环)之前确保代码正常工作。所以我会这样做:

    goto L2;
L1:
    rax = ecx;
    r8 =rdi+rax;
    r9 =r8;
    rax =rsi;
    int r10=rax;
    r8=r10;
    rax =r9;
    ecx+=1;
L2:
    if(edx<ecx) 
        goto L1;
在这里,似乎有点不确定。while条件是edx对于那些喜欢GCC的.S格式的人,我使用了:

ex3:
  mov $0x0, %ecx
  jmp lpe
  lps:
      movslq %ecx, %rax
      lea (%rdi, %rax, 1), %r8
      movzbl (%r8), %r9d
      add %rsi, %rax
      movzbl (%rax), %r10d
      mov %r10b, (%r8)
      mov %r9b, (%rax)
      add $0x1, %ecx
  lpe:
  cmp %edx, %ecx
  jl lps
repz retq


.data
.text
.global _main
_main:
    mov $0x111111111111, %rdi
    mov $0x222222222222, %rsi
    mov $0x5, %rdx
    mov $0x333333333333, %r8
    mov $0x444444444444, %r9
    call ex3
    xor %eax, %eax
    ret
然后,您可以使用gcc main.S-o main编译它,并运行objdump-x86 asm syntax=intel-d main以英特尔格式查看它,或者在反编译器中运行生成的主可执行文件。。但是我。。让我们做些手工活

首先,我要将AT&T语法转换为更常见的Intel语法。。因此:

ex3:
  mov ecx, 0
  jmp lpe
  lps:
      movsxd rax, ecx
      lea r8, [rdi + rax]
      movzx r9d, byte ptr [r8]
      add rax, rsi
      movzx r10d, byte ptr [rax]
      mov byte ptr [r8], r10b
      mov byte ptr [rax], r9b
      add ecx, 0x1
  lpe:
  cmp ecx, edx
  jl lps
rep ret
现在我可以清楚地看到,从lps循环开始到lpe循环结束,是一个for循环

怎么做?因为它首先将计数器寄存器ecx设置为0。然后,它通过执行cmp ecx检查ecx是否小于edx,如果小于,edx随后执行jl跳转。。如果是,则运行代码并将ecx增加1 add ecx,1。。如果不是,则存在块

因此它看起来像:对于int32_t ecx=0;ecx 因此,现在我们用以下知识翻译其余部分:

r10是一个64位寄存器。r10d为高位32位,r10b为低位8位。 r9是一个64位寄存器。与r10相同的逻辑适用

因此,我们可以代表一个登记册,如下所示:

typedef union Register
{
    uint64_t reg;
    struct
    {
        uint32_t upper32;
        uint32_t lower32;
    };

    struct
    {
        uint16_t uupper16;
        uint16_t ulower16;
        uint16_t lupper16;
        uint16_t llower16;
    };

    struct
    {
        uint8_t uuupper8;
        uint8_t uulower8;

        uint8_t ulupper8;
        uint8_t ullower8;

        uint8_t luupper8;
        uint8_t lulower8;

        uint8_t llupper8;
        uint8_t lllower8;
    };
} Register;
哪个更好。。你可以自己选择。。 现在我们可以开始看说明书了。。 movsxd或movslq使用符号扩展将32位寄存器移动到64位寄存器中

现在我们可以编写代码:

uint8_t* ex3(uint8_t* rdi, uint64_t rsi, int32_t edx)
{
    uintptr_t rax = 0;
    for (int32_t ecx = 0; ecx < edx; ++ecx)
    {
        rax = ecx;
        uint8_t* r8 = rdi + rax;
        Register r9 = { .reg = *r8 }; //zero extend into the upper half of the register
        rax += rsi;

        Register r10 = { .reg = *(uint8_t*)rax }; //zero extend into the upper half of the register
        *r8 = r10.lllower8;
        *(uint8_t*)rax = r9.lllower8;
    }

    return rax;
}

希望我没有把事情搞砸。

我很确定是这样的:交换两个内存区域:

void memswap(unsigned char *rdi, unsigned char *rsi, int edx) {
        int ecx;
        for (ecx = 0; ecx < edx; ecx++) {
                unsigned char r9 = rdi[ecx];
                unsigned char r10 = rsi[ecx];
                rdi[ecx] = r10;
                rsi[ecx] = r9;
        }
}

r寄存器是64位的。int是x86-64 C实现中的32位类型。如果int edi实际上是int,就应该使用int edi,就像在edx中一样。更重要的是,asm包含一个向后的条件分支,但是您的C缺少一个循环。此外,asm从内存中加载了大量零扩展字节,但您的C没有任何指针变量。请编辑您的问题,以包含asm代码。不要发布图片链接,也不要用图片本身替换该链接。慢慢来,在问题中键入它。ASM代码看起来像一个循环。我已经否决了你的问题,因为你发布了代码的图片。一旦你将我的否决票替换为文本代码,它将被删除。@fuz:Steve Friedl努力将图片翻译成文本。我删除了图片,所以现在,问题应该没问题了。在C中实际使用goto的三种好方法?或者你的意思是作为逆向工程的一部分?问题中的asm是GCC如何编译C中位于-O0和-O1的while{}或for循环。在C++模式下,G++-O0喜欢用顶部的IFFACK和底部的无条件JMP来生成一个愚蠢的循环。另请参见-启用优化后,编译器剥离第一个测试,然后使用底部的条件进行正常的do{}while循环,如下图所示。顺便说一句,这只是一个非常部分的答案。您很好地介绍了循环结构,但类型和寻址模式仍然是一个巨大的问题。OP甚至还没有接近正确地获得movzbl字节加载。我现在意识到了跳跃和循环。但我更关心的是如何在C中显示不同长度的位寄存器,以及如何在C中显示类似movzbl的操作。我是否使用任何转换器?@PeterCordes,我的意思是作为逆向工程的一部分。是的,我知道这是部分答案。剩下的我觉得不舒服。我投了你提到的那部分的赞成票。这完全可以,只要我们避免暗示这是唯一的问题。否则OP会浪费他们的时间希望你的改变足够。非常感谢。我对这些很陌生,你知道如何用C写重新解释或者仅仅是int8 int64等等吗?我不知道如何显示不同的位寄存器。联合登记部分在开始时做什么?@ CuloEZQL添加C翻译代码和删除C++代码。int64_t是在IMO中声明的,您的注册联合应该更简单,并且只包括可以作为x86部分注册直接访问的成员。所以唯一的结构 您需要的t成员是一对8位AL/AH两半。您如何从OP的asm中获得int64_t*r8?我只看到字节指针uint8\u t*。甚至指针数学也是无标度的,所以还是char*或unsigned char*。你把这件事搞得太复杂了。哦,我看到你把movzbl误译成了mov r9d,dword ptr[r8]。实际上是movzxr9d,字节ptr[r8]
ex3:
  mov ecx, 0
  jmp lpe
  lps:
      movsxd rax, ecx
      lea r8, [rdi + rax]
      movzx r9d, byte ptr [r8]
      add rax, rsi
      movzx r10d, byte ptr [rax]
      mov byte ptr [r8], r10b
      mov byte ptr [rax], r9b
      add ecx, 0x1
  lpe:
  cmp ecx, edx
  jl lps
rep ret
typedef union Register
{
    uint64_t reg;
    struct
    {
        uint32_t upper32;
        uint32_t lower32;
    };

    struct
    {
        uint16_t uupper16;
        uint16_t ulower16;
        uint16_t lupper16;
        uint16_t llower16;
    };

    struct
    {
        uint8_t uuupper8;
        uint8_t uulower8;

        uint8_t ulupper8;
        uint8_t ullower8;

        uint8_t luupper8;
        uint8_t lulower8;

        uint8_t llupper8;
        uint8_t lllower8;
    };
} Register;
uint8_t* ex3(uint8_t* rdi, uint64_t rsi, int32_t edx)
{
    uintptr_t rax = 0;
    for (int32_t ecx = 0; ecx < edx; ++ecx)
    {
        rax = ecx;
        uint8_t* r8 = rdi + rax;
        Register r9 = { .reg = *r8 }; //zero extend into the upper half of the register
        rax += rsi;

        Register r10 = { .reg = *(uint8_t*)rax }; //zero extend into the upper half of the register
        *r8 = r10.lllower8;
        *(uint8_t*)rax = r9.lllower8;
    }

    return rax;
}
void memswap(unsigned char *rdi, unsigned char *rsi, int edx) {
        int ecx;
        for (ecx = 0; ecx < edx; ecx++) {
                unsigned char r9 = rdi[ecx];
                unsigned char r10 = rsi[ecx];
                rdi[ecx] = r10;
                rsi[ecx] = r9;
        }
}