C - 仅使用 ntdll 的堆栈分配
C - Stack allocation using only ntdll
是否有 API 调用或任何其他类似方式,仅使用 ntdll.dll
在堆栈上分配内存?
我知道 alloca()
会这样做,但我不能使用它,因为我只能使用 ntdll.dll
中的函数。
谢谢!
alloca 是部分内部函数,由编译器实现。但在内部它调用 _alloca_probe_16
(对于 x86)或 __chkstk
(x64) 将保护页面向下移动到堆栈上。此函数的实现存在于 alloca16.obj
和 chkstk.obj
中,它们可以在 VC
子文件夹中找到(其中完全依赖于 VC 版本) - 您可以为 [=55 添加此对象=]处理甚至先将其转换为lib。同样在最新的 WDK 库中 - 存在 ntdllp.lib
(不要与 ntdll.lib
混淆) - 它也包含所有实现需求(ntdll.dll
导出 _chkstk
(对于 x86)和 __chkstk
(对于 x64))
再次详细介绍:
当你在 src 代码中写入时
alloca(cb)
CL
x86 编译器生成
mov eax,cb
call _alloca_probe_16 ; do actual stack allocation and probe
在 x64 版本中
mov ecx,eax
add rcx,0Fh
cmp rcx,rax
ja @@0
mov rcx,0FFFFFFFFFFFFFF0h
@@0:
and rcx,0FFFFFFFFFFFFFFF0h
mov rax,rcx
call __chkstk ; probe only
sub rsp,rax ; actual stack allocation
所以 _alloca_probe_16
and/or __chkstk
必须在某处实现,否则你会遇到 link 错误 - 无法解析的外部符号。
在最新的 WDK 版本中存在包含此实现的 ntdllp.lib
(注意 p
- 而不是 ntdll.lib
)。在这种情况下,您的 PE 将从 ntdll.dll
导入 __chkstk
或 _alloca_probe
(此函数从 XP 导出的最小值 - 这两个函数指向相同的代码,只是别名)
另一个解决方案 - 在 VC
文件夹中可以找到 alloca16.obj
和 chkstk.obj
- 你可以使用这个对象作为 link 输入(或合并 alloca16.obj
+ chkstk.obj
在单个 lib 文件中)。在这种情况下,您的 PE 将毫无意义。
您不需要依赖架构的东西,因为堆栈上的分配(通常)是独立于架构的。
如果你使用的是 C99,你有一个标准的方法,使用可变长度数组:https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
你会很简单地写这样的东西:
char mybuffer[my_size];
并且会分配到栈上
因为 alloca
操作堆栈指针,所以它不是 "real" 函数,而是 "compiler intrinsic"。如果将使用 alloca
的函数编译为汇编语言,您 应该 看到它被直接翻译成 sub esp, NNN
而不是 call alloca
。 (除了 和 sub esp, NNN
之外,可能还调用了一个函数 。在这种情况下,您需要找出该函数的作用,它通常在哪里定义,并安排你的应用程序提供了一个替代品。你已经跳过了各种不寻常的箍,只使用 NTDLL,这只是一个。)
如果你看到call alloca
而没有sub esp, NNN
,这很可能意味着你的编译器只有[=10的假实现=] 那是 不是 给你从堆栈分配的内存,你根本不应该使用它。
是否有 API 调用或任何其他类似方式,仅使用 ntdll.dll
在堆栈上分配内存?
我知道 alloca()
会这样做,但我不能使用它,因为我只能使用 ntdll.dll
中的函数。
谢谢!
alloca 是部分内部函数,由编译器实现。但在内部它调用 _alloca_probe_16
(对于 x86)或 __chkstk
(x64) 将保护页面向下移动到堆栈上。此函数的实现存在于 alloca16.obj
和 chkstk.obj
中,它们可以在 VC
子文件夹中找到(其中完全依赖于 VC 版本) - 您可以为 [=55 添加此对象=]处理甚至先将其转换为lib。同样在最新的 WDK 库中 - 存在 ntdllp.lib
(不要与 ntdll.lib
混淆) - 它也包含所有实现需求(ntdll.dll
导出 _chkstk
(对于 x86)和 __chkstk
(对于 x64))
再次详细介绍:
当你在 src 代码中写入时
alloca(cb)
CL
x86 编译器生成
mov eax,cb
call _alloca_probe_16 ; do actual stack allocation and probe
在 x64 版本中
mov ecx,eax
add rcx,0Fh
cmp rcx,rax
ja @@0
mov rcx,0FFFFFFFFFFFFFF0h
@@0:
and rcx,0FFFFFFFFFFFFFFF0h
mov rax,rcx
call __chkstk ; probe only
sub rsp,rax ; actual stack allocation
所以 _alloca_probe_16
and/or __chkstk
必须在某处实现,否则你会遇到 link 错误 - 无法解析的外部符号。
在最新的 WDK 版本中存在包含此实现的 ntdllp.lib
(注意 p
- 而不是 ntdll.lib
)。在这种情况下,您的 PE 将从 ntdll.dll
导入 __chkstk
或 _alloca_probe
(此函数从 XP 导出的最小值 - 这两个函数指向相同的代码,只是别名)
另一个解决方案 - 在 VC
文件夹中可以找到 alloca16.obj
和 chkstk.obj
- 你可以使用这个对象作为 link 输入(或合并 alloca16.obj
+ chkstk.obj
在单个 lib 文件中)。在这种情况下,您的 PE 将毫无意义。
您不需要依赖架构的东西,因为堆栈上的分配(通常)是独立于架构的。
如果你使用的是 C99,你有一个标准的方法,使用可变长度数组:https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
你会很简单地写这样的东西:
char mybuffer[my_size];
并且会分配到栈上
因为 alloca
操作堆栈指针,所以它不是 "real" 函数,而是 "compiler intrinsic"。如果将使用 alloca
的函数编译为汇编语言,您 应该 看到它被直接翻译成 sub esp, NNN
而不是 call alloca
。 (除了 和 sub esp, NNN
之外,可能还调用了一个函数 。在这种情况下,您需要找出该函数的作用,它通常在哪里定义,并安排你的应用程序提供了一个替代品。你已经跳过了各种不寻常的箍,只使用 NTDLL,这只是一个。)
如果你看到call alloca
而没有sub esp, NNN
,这很可能意味着你的编译器只有[=10的假实现=] 那是 不是 给你从堆栈分配的内存,你根本不应该使用它。