Assembly 在ARMv7的有效负载中调用函数
我想为我的ARMv7平台编写一个简单的负载。首先,我尝试了一个通过UART发送字符的简单循环:Assembly 在ARMv7的有效负载中调用函数,assembly,arm,shellcode,cortex-m3,thumb,Assembly,Arm,Shellcode,Cortex M3,Thumb,我想为我的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
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
这非常有效,字符是通过UART发送的。现在,我想在我的有效负载中调用一个函数:
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
这个角色现在只发送了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
0x8000358:0xaf00b480 0x22684b02 0xf7ff809a 0xe7f9fff1
0x8000368:0x40004800 0xb082b580 0xf001af00 0x2102f863
0x20004000:0xaf00b480 0x22684b02 0xf7ff809a 0xe7f9fff1
0x20004010:0x40004800 0x00000000 0x00000000 0x00000000
goto*(void*)((uint32)缓冲区1)
奇怪的是,使用不必要的内联程序集的人可能会在这里使用一些
当我编译这个时,我得到:
38: 2201 movs r2, #1
3a: 4313 orrs r3, r2
3c: 469f mov pc, r3
3e: 46c0 nop
这应该马上失败
从arm文档中:
添加(寄存器)和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>
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>
我想您没有将function()复制到0x20003FF0?运行此程序时,您在该地址有哪些数据?拆开后看起来像什么
因此,您在大多数情况下都是通过汇编语言“理解”的,但错过了一些东西
现在,您只需编写所需的代码:
.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
使用我的编译器提供:
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
是的,你不需要或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}
作为你了解我所说内容的起点,如果你永远看到0123456701234567,那么我怀疑你使用的是模拟器,而不是硬件
编辑:
orr 1是goto的问题,您可以这样做:
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;
}
编辑2
该程序已经在SRAM中,您只需将其从SRAM复制到SRAM…如果该复制是“利用”的,则可以,但在微控制器上,您不会将其复制到其他代码之上,大多数情况下,所有代码都会耗尽闪存,因此一个SRAM位置与另一个位置一样好。
无论如何,这个术语在这里不是问题
在你下面的评论中
大体上,我的分支地址是0x20004001
不,这是同一个错误,如果你想用一个或地址,你需要使用正确的指令
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
36:4b06 ldr r3,[pc,#24];(50 )
38:469f mov pc,r3
3a:46c0 nop;(mov r8,r8)
3c:22444b02分包r4、r4、#2048;0x800
40:4802605a stmdami r2,{r1,r3,r4,r6,sp,lr}
44:e7f94780 ldrb r4,[r9,r0,lsl#15]!
48:40004800和MI r4、r0、r0、lsl#16
4c:00000000安第克r0,r0,r0
50:20004000和CS 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
goto*(void*)(0x2000001);
36:4b06 ldr r3,[pc,#24];(50 )
38:469f mov pc,r3
3a:46c0 nop;(mov r8,r8)
3c:22444b02分包r4、r4、#2048;0x800
40:4802605a stmdami r2,{r1,r3,r4,r6,sp,lr}
44:e7f94780 ldrb r4,[r9,r0,lsl#15]!
48:40004800和MI r4、r0、r0、lsl#16
4c:00000000安第克r0,r0,r0
50:20004001和CS r4、r0、r1
与此答案顶部的错误相同:
添加(寄存器)和MOV(寄存器)分支,但不互通
在arm文档中搜索该行和/或该术语 这是什么编译器这看起来很旧不符合当前的abi,这不是一件坏事…这是一个微控制器armv7-m而不是armv7?冲击uart数据寄存器不是你如何发送字符出uart,除非这是一个qemu模拟。你的有效负载代码看起来没有优化,所以我没有优化我的。优化时,它不使用帧指针。尝试让gcc在没有作为未优化默认值的情况下构建,将看到这是否有效。您的ram是否在0x200004000或以上?是否正在包装?谢谢,不,这不是家庭作业-只想从编写漏洞开始。我还有一些问题。假设我的函数()始终为0x8000348。我的有效负载应该位于SRAM中,有效负载的地址应该是0x20004000。现在,我将其复制到SRAM:ldr r3,=0x40004800 mov r2,#68 str r2,[r3,#4]ldr r0,=0x08000349 blx r0 b 0x20004000(主),我分支到地址0x20004001。它应该可以工作,因为我用blx 0x08000349调用函数,返回后用b 0x20004000跳回代码的开头(ldr r3)。但同样,不确定您为什么会将其称为一个漏洞,仍然感觉像是有人问的另一个问题。您为什么要分支到0x20004001?您使用什么指令来实现这一点,该指令是否支持交互,arms文档对使用该指令进行交互或不进行交互有何说明?
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;
}
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}
void payload()
{
uint32_t ra;
for(ra=0x30;;ra++)
{
ra&=0x37;
USART3->DR = ra;
}
}
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;
}
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