assembly 在ARMv7中调用payload中的函数

aemubtdh  于 2023-08-06  发布在  其他
关注(0)|答案(1)|浏览(82)

我想为我的ARMv7平台编写一个简单的有效负载。首先,我尝试了一个通过UART发送字符的简单循环:

void payload()
{
  while(1)
  {
    USART3->DR = 0x68;
  }
}

08000358 <payload>:
 8000358:   b480        push    {r7}
 800035a:   af00        add r7, sp, #0
 800035c:   4b01        ldr r3, [pc, #4]    ; (8000364 <payload+0xc>)
 800035e:   2268        movs    r2, #104    ; 0x68
 8000360:   809a        strh    r2, [r3, #4]
 8000362:   e7fb        b.n 800035c <payload+0x4>
 8000364:   40004800    andmi   r4, r0, r0, lsl #16

字符串
这是我想要的有效载荷,一次在C中,一次在汇编中。

int main()
{
  uint32 buffer[4];
  buffer[0] = 0xaf00b480;
  buffer[1] = 0x22684b01;
  buffer[2] = 0xe7fb809a;
  buffer[3] = 0x40004800;
  memcpy(0x20004000,&buffer,4*sizeof(uint32));
  goto *(void *)((uint32_t) buffer | 1);

  return 0;
}


这工作得很好,字符通过UART发送。现在,我想在payload中调用一个函数:

void payload()
{
  while(1)
    {
      USART3->DR = 0x68;
    asm volatile(
      "bl 0x08000348\n"
    );
  }
}

08000358 <payload>:
 8000358:   b480        push    {r7}
 800035a:   af00        add r7, sp, #0
 800035c:   4b02        ldr r3, [pc, #8]    ; (8000368 <payload+0x10>)
 800035e:   2268        movs    r2, #104    ; 0x68
 8000360:   809a        strh    r2, [r3, #4]
 8000362:   f7ff fff1   bl  8000348 <function>
 8000366:   e7f9        b.n 800035c <payload+0x4>
 8000368:   40004800    andmi   r4, r0, r0, lsl #16


同样,我想要的有效载荷,一次在C中,一次在汇编中。

void function()
{
    asm volatile(
      "nop\n"
      "nop\n"
    );
}

int main()
{
  uint32 buffer[5];
  buffer[0] = 0xaf00b480;
  buffer[1] = 0x22684b02;
  buffer[2] = 0xf7ff809a;
  buffer[3] = 0xe7f9fff1;
  buffer[4] = 0x40004800;

  memcpy(0x20004000,&buffer,5*sizeof(uint32));
  goto *(void *)((uint32_t) buffer | 1);

  return 0;
}


字符现在只发送3次,然后我会崩溃(处理器的故障处理程序)。我检查了函数的内存区域和我的缓冲区,两者看起来是一样的:

0x8000358 <payload>:    0xaf00b480  0x22684b02  0xf7ff809a  0xe7f9fff1
0x8000368 <payload+16>: 0x40004800  0xb082b580  0xf001af00  0x2102f863

0x20004000 <_heap+3144>:    0xaf00b480  0x22684b02  0xf7ff809a  0xe7f9fff1
0x20004010 <_heap+3160>:    0x40004800  0x00000000  0x00000000  0x00000000

mm9b1k5b

mm9b1k5b1#

后藤 *(void *)((uint32_t)buffer| 1);
奇怪的是,对于使用不必要的内联汇编的人来说,这里可以使用一些。
当我编译它时,我得到:

38:   2201        movs    r2, #1
  3a:   4313        orrs    r3, r2
  3c:   469f        mov pc, r3
  3e:   46c0        nop

字符串
这应该马上就会失败
来自手臂文件:
ADD(寄存器)和MOV(寄存器)分支,无互通。
你能做的就是用一些真实的的asm

.thumb
.thumb_func
.globl HOP
HOP:
   orr r0,#1
   bx r0

void HOP ( uint32_t *);
void function()
{
    asm volatile(
      "nop\n"
      "nop\n"
    );
}

int main()
{
  uint32_t buffer[5];
  buffer[0] = 0xaf00b480;
  buffer[1] = 0x22684b02;
  buffer[2] = 0xf7ff809a;
  buffer[3] = 0xe7f9fff1;
  buffer[4] = 0x40004800;

//  memcpy(0x20004000,&buffer,5*sizeof(uint32));
//  goto *(void *)((uint32_t) buffer | 1);
  HOP(buffer);
  return 0;
}

  38:   0018        movs    r0, r3
  3a:   f7ff fffe   bl  0 <HOP>


现在,如果你不想要分支链接,而是一个分支,因为你是自由和松散的内联汇编,这更像你的风格,不应该有mov问题,至少我的编译器生成。顺便说一句,我们需要看看你的编译器生成了什么,看看为什么你没有立即崩溃。

void function()
{
    asm volatile(
      "nop\n"
      "nop\n"
    );
}
int main()
{
  uint32_t buffer[5];
  buffer[0] = 0xaf00b480;
  buffer[1] = 0x22684b02;
  buffer[2] = 0xf7ff809a;
  buffer[3] = 0xe7f9fff1;
  buffer[4] = 0x40004800;
  asm (
      "add r3,r7,#4\n"
      "mov pc,r3\n"
  );
  return 0;
}

  36:   1d3b        adds    r3, r7, #4
  38:   469f        mov pc, r3


bx可以用来这让它感觉更好

int main()
{
  uint32_t buffer[5];
  buffer[0] = 0xaf00b480;
  buffer[1] = 0x22684b02;
  buffer[2] = 0xf7ff809a;
  buffer[3] = 0xe7f9fff1;
  buffer[4] = 0x40004800;
  asm (
      "add r3,r7,#5\n"
      "bx r3\n"
  );
  return 0;
}

  36:   1d7b        adds    r3, r7, #5
  38:   4718        bx  r3


一旦fifo不再填充字符,您就不能那样对待uart数据寄存器。
你也不能复制这段代码并那样运行它。

8000362:   f7ff fff1   bl  8000348 <function>


只要8000348保持功能所在位置,就可以内置在闪存中,但BL是PC相关的,因此如果您想将其复制到SRAM(我知道我自己问题的答案,将让您弄清楚我是如何知道的,这是一个微控制器,因此您的意思是询问armv7-m而不是armv7)。

20004000:   b480        push    {r7}
 20004002:   af00        add r7, sp, #0
 20004004:   4b02        ldr r3, [pc, #8]    ; 20004010 
 20004006:   2268        movs    r2, #104    ; 0x68
 20004008:   809a        strh    r2, [r3, #4]
 2000400A:   f7ff fff1   bl  20003FF0
 2000400E:   e7f9        b.n 20004004
 20004010:   40004800


我想你没有把function()复制到0x 20003 FF 0?运行此程序时,在该地址上有哪些数据?拆开后看起来像什么?
所以你是“得到它”的大部分与汇编语言,但错过了一些事情。
现在你可以做的就是编写你想要的代码:

.thumb
top:
ldr r3,=0x40004800
mov r2,#68
str r2,[r3,#4]
ldr r0,=function
blx r0
b top


无需链接

00000000 <top>:
   0:   4b02        ldr r3, [pc, #8]    ; (c <top+0xc>)
   2:   2244        movs    r2, #68 ; 0x44
   4:   605a        str r2, [r3, #4]
   6:   4802        ldr r0, [pc, #8]    ; (10 <top+0x10>)
   8:   4780        blx r0
   a:   e7f9        b.n 0 <top>
   c:   40004800    andmi   r4, r0, r0, lsl #16
  10:   00000000    andeq   r0, r0, r0


用你的风格

void function()
{
    asm volatile(
      "nop\n"
      "nop\n"
    );
}
int main()
{
uint32_t buffer[10];
buffer[0]=0x22444b02;
buffer[1]=0x4802605a;
buffer[2]=0xe7f94780;
buffer[3]=0x40004800;
buffer[4]=((uint32_t)function)|1;
  asm (
      "add r3,r7,#5\n"
      "bx r3\n"
  );
  return 0;
}


用我的编译器给出:

08000000 <function>:
 8000000:   b580        push    {r7, lr}
 8000002:   af00        add r7, sp, #0
...
 8000016:   af00        add r7, sp, #0
 8000018:   003b        movs    r3, r7
 800001a:   4a0c        ldr r2, [pc, #48]   ; (800004c <main+0x3a>)
 800001c:   601a        str r2, [r3, #0]
...
 800003a:   1d7b        adds    r3, r7, #5
 800003c:   4718        bx  r3
...
 800004c:   22444b02
 8000050:   4802605a
 8000054:   e7f94780
 8000058:   40004800
 800005c:   08000001


仍然有点像你的代码,但现在你可以重新定位这段代码,从一个4字节对齐的地址开始,它不会有不能调用函数的问题。
是的,我在这个例子的链接上作弊了,我没有 Bootstrap 。还有一点让我很困扰,他们默认使用堆栈帧,真是浪费。我想知道我是否可以在没有它的情况下构建我的工具链。它确实使这个黑客解决方案更好地工作,否则:

08000000 <function>:
 8000000:   46c0        nop         ; (mov r8, r8)
 8000002:   46c0        nop         ; (mov r8, r8)
 8000004:   46c0        nop         ; (mov r8, r8)
 8000006:   4770        bx  lr

08000008 <main>:
 8000008:   b08a        sub sp, #40 ; 0x28
 800000a:   466b        mov r3, sp
 800000c:   4a0a        ldr r2, [pc, #40]   ; (8000038 <main+0x30>)
 800000e:   601a        str r2, [r3, #0]
 8000010:   466b        mov r3, sp
 8000012:   4a0a        ldr r2, [pc, #40]   ; (800003c <main+0x34>)
 8000014:   605a        str r2, [r3, #4]


然后可以使用

void function()
{
    asm volatile(
      "nop\n"
      "nop\n"
    );
}
int main()
{
uint32_t buffer[10];
buffer[0]=0x22444b02;
buffer[1]=0x4802605a;
buffer[2]=0xe7f94780;
buffer[3]=0x40004800;
buffer[4]=((uint32_t)function);
  asm (
      "mov r3,sp\n"
      "orr r3,r3,#1\n"
/*    "add r3,#1\n" */
      "bx r3\n"
  );
  return 0;
}


是的,duh,你不需要orr a 1来运行工具链应该已经处理好了。

08000008 <main>:
 8000008:   b08a        sub sp, #40 ; 0x28
 800000a:   4b09        ldr r3, [pc, #36]   ; (8000030 <main+0x28>)
 800000c:   9300        str r3, [sp, #0]
 800000e:   4b09        ldr r3, [pc, #36]   ; (8000034 <main+0x2c>)
 8000010:   9301        str r3, [sp, #4]
 8000012:   4b09        ldr r3, [pc, #36]   ; (8000038 <main+0x30>)
 8000014:   9302        str r3, [sp, #8]
 8000016:   4b09        ldr r3, [pc, #36]   ; (800003c <main+0x34>)
 8000018:   9303        str r3, [sp, #12]
 800001a:   4b09        ldr r3, [pc, #36]   ; (8000040 <main+0x38>)
 800001c:   9304        str r3, [sp, #16]
 800001e:   466b        mov r3, sp
 8000020:   f043 0301   orr.w   r3, r3, #1
 8000024:   4718        bx  r3
 8000026:   2300        movs    r3, #0
 8000028:   4618        mov r0, r3
 800002a:   b00a        add sp, #40 ; 0x28
 800002c:   4770        bx  lr
 800002e:   bf00        nop
 8000030:   22444b02    subcs   r4, r4, #2048   ; 0x800
 8000034:   4802605a    stmdami r2, {r1, r3, r4, r6, sp, lr}
 8000038:   e7f94780    ldrb    r4, [r9, r0, lsl #15]!
 800003c:   40004800    andmi   r4, r0, r0, lsl #16
 8000040:   08000001    stmdaeq r0, {r0}


现在有一个内联的asm魔术,你可以把buffer的地址加载到r3中,而不必依靠反汇编代码来解决这个问题。请注意,因为您似乎使用的是armv7-m,尽管将其称为armv7。你可以使用thumb 2指令或r3,r3,#1,这在心理上是正确的,你想或在那里的位不添加它。但是如果这是一个armv 6-m,比如cortex-m0,或者你想要可移植性,那么就像add r3,#1一样丑陋地执行add,因为这不是一个thumb 2指令,而且是可移植的。
所以,如果你得到了一些字符,我怀疑你的后藤工作不知何故,再次听起来像你是使用qemu也许?也许这就是为什么?但不是试图在sram中运行代码的副本,你向后分支找到function(),但在那里找到了数据,这要么使你崩溃,要么因为这是在复制代码之前,它再次运行了几次复制的代码,无论是什么,最终都偏离了轨道。或者可能是因为你没有正确使用uart,你使缓冲区溢出,在这些品牌中的至少一个上,这可能导致uart停止工作,直到你清除缓冲区溢出标志。假设您依赖于uart输出来查看成功或失败。(你会看到,当运行这个程序时,没有调用函数,这使我相信这是一个模拟,而不是真实的的硬件,或真正的硬件,你只是看到一小部分的值,你是推到uart)。
试试这个

void payload()
{
  uint32_t ra; 
  for(ra=0x30;;ra++)
  {
    ra&=0x37;
    USART3->DR = ra;
  }
}


作为你的起点,看看我在说什么,如果你看到0123456701234567永远,那么我怀疑你是在使用模拟器,而不是硬件。
编辑:
orr 1是后藤的问题,你可以这样做:

void function()
{
    asm volatile(
      "nop\n"
      "nop\n"
    );
}
int main()
{
    uint32_t buffer[10];
    buffer[0]=0x22444b02;
    buffer[1]=0x4802605a;
    buffer[2]=0xe7f94780;
    buffer[3]=0x40004800;
    buffer[4]=((uint32_t)function);

    goto *(void *)((uint32_t) buffer);
    return 0;
}


EDIT2
程序已经在SRAM中,你只是简单地将它从SRAM复制到SRAM......如果复制是“利用”,那么好,但在微控制器上,你不会将此复制到其他代码之上,大多数时候,所有代码都会耗尽闪存,所以一个SRAM位置和另一个一样好。不管怎样,这个术语不是问题所在。
在您下面的评论中
在main中,我分支到地址0x 20004001。
不,这是同一个错误,如果你想用一个地址或你需要使用正确的指令。

void function()
{
    asm volatile(
      "nop\n"
      "nop\n"
    );
}
int main()
{
    uint32_t buffer[10];
    buffer[0]=0x22444b02;
    buffer[1]=0x4802605a;
    buffer[2]=0xe7f94780;
    buffer[3]=0x40004800;
    buffer[4]=((uint32_t)function);

    //memcpy...
    //goto *(void *)((uint32_t) buffer);
    goto *(void *)(0x20004000);
    return 0;
}


我电脑上的编译器

36:   4b06        ldr r3, [pc, #24]   ; (50 <main+0x3e>)
  38:   469f        mov pc, r3
  3a:   46c0        nop         ; (mov r8, r8)
  3c:   22444b02    subcs   r4, r4, #2048   ; 0x800
  40:   4802605a    stmdami r2, {r1, r3, r4, r6, sp, lr}
  44:   e7f94780    ldrb    r4, [r9, r0, lsl #15]!
  48:   40004800    andmi   r4, r0, r0, lsl #16
  4c:   00000000    andeq   r0, r0, r0
  50:   20004000    andcs   r4, r0, r0


当链接时,它仍然可以工作。
但如果你这么做

goto *(void *)(0x20004001);

  36:   4b06        ldr r3, [pc, #24]   ; (50 <main+0x3e>)
  38:   469f        mov pc, r3
  3a:   46c0        nop         ; (mov r8, r8)
  3c:   22444b02    subcs   r4, r4, #2048   ; 0x800
  40:   4802605a    stmdami r2, {r1, r3, r4, r6, sp, lr}
  44:   e7f94780    ldrb    r4, [r9, r0, lsl #15]!
  48:   40004800    andmi   r4, r0, r0, lsl #16
  4c:   00000000    andeq   r0, r0, r0
  50:   20004001    andcs   r4, r0, r1


与此答案的顶部相同的bug:
ADD(寄存器)和MOV(寄存器)分支,无互通。
在arm文档中搜索该行和/或该术语。

相关问题