为什么这段代码有效?
http://www.int80h.org/strlen/说字符串地址必须在EDI寄存器中才能scasb工作,但这个汇编函数似乎没有这样做。
汇编代码mystrlen:
global mystrlen
mystrlen:
sub ecx, ecx
not ecx
sub al, al
cld
repne scasb
neg ecx
dec ecx
dec ecx
mov eax, ecx
ret
Run Code Online (Sandbox Code Playgroud)
C主:
int mystrlen(const char *);
int main()
{
return (mystrlen("1234"));
}
Run Code Online (Sandbox Code Playgroud)
汇编:
nasm -f elf64 test.asm
gcc -c main.c
gcc main.o test.o
Run Code Online (Sandbox Code Playgroud)
输出:
./a.out
echo $?
4
Run Code Online (Sandbox Code Playgroud) 来自 Intel 对 x64 汇编的介绍https://software.intel.com/en-us/articles/introduction-to-x64-assemble,
虽然我了解如何将 RCX、RDX、R8、R9 用作函数参数,但我见过使用 4 个以上参数的函数会恢复为使用堆栈(如 32 位代码)。示例如下:
sub_18000BF10 proc near
lpDirectory = qword ptr -638h
nShowCmd = dword ptr -630h
Parameters = word ptr -628h
sub rsp, 658h
mov r9, rcx
mov r8, rdx
lea rdx, someCommand ; "echo "Hello""...
lea rcx, [rsp+658h+Parameters] ; LPWSTR
call cs:wsprintfW
xor r11d, r11d
lea r9, [rsp+658h+Parameters] ; lpParameters
mov [rsp+658h+nShowCmd], r11d ; nShowCmd
lea r8, …Run Code Online (Sandbox Code Playgroud) 在这篇关于寄存器保存的维基百科文章中,我读到调用者函数负责某些寄存器(以防止其先前的数据被更改),而被调用者则负责其他寄存器。
我的问题是为什么我们必须让事情复杂化?为什么不让所有寄存器成为调用者的责任,在调用函数之前备份现有值并在之后重新加载它们?
我没有看到执行这些步骤有任何性能提升,有人可以帮助我理解吗?
我试图根据 godbolt.org 上 c++ 中的平方函数来理解这一点。显然,返回、参数和局部变量使用 \xe2\x80\x9crbp -alignment\xe2\x80\x9d 来实现此函数。\n有人可以解释一下这是如何实现的吗?\n在这种情况下 rbp +alignment 会做什么?
\nint square(int num){\n int n = 5;// just to test how locals are treated with frame pointer\n return num * num;\n}\nRun Code Online (Sandbox Code Playgroud)\n编译器(x86-64 gcc 11.1)
\n生成的程序集:
\nsquare(int):\n push rbp\n mov rbp, rsp \n mov DWORD PTR [rbp-20], edi. ;\\\\Both param and local var use rbp-*\n mov DWORD PTR[rbp-4], 5. ;//\n mov eax, DWORD PTR [rbp-20]\n imul eax, eax\n pop rbp\n ret\n\nRun Code Online (Sandbox Code Playgroud)\n 所以我正在阅读 SYSTEM V AMD64 ABI,其中写道我们必须使用向量寄存器来保存 stdargs 并设置AL为用于放置参数的寄存器的数量。
为什么需要使用向量寄存器?我们不能将它们放入堆栈并将AL寄存器设置为堆栈中的参数数量吗?
这不是关于EasyHook的特定功能,而是关于一般的挂钩.我想用这个签名挂钩一个函数:
public: int __thiscall Connection_t::Send(unsigned int,unsigned int,void const *)
Run Code Online (Sandbox Code Playgroud)
这显然是非托管代码,我正在尝试使用EasyHook将其与我的托管c#代码挂钩.但我认为这不是EasyHook导致问题,但我知道调用约定等...
这就是我如何定义DllImport并删除:
public static int Send_Hooked(uint connection, uint size, IntPtr pDataBlock)
{
return Send(connection, size, pDataBlock);
}
[DllImport("Connection.dll", EntryPoint = "?Send@Connection_t@@QAEHIIPBX@Z", CallingConvention = CallingConvention.ThisCall)]
static extern int Send(uint connection, uint size, IntPtr pDataBlock);
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Unicode, SetLastError = true)]
delegate int DSend(uint connection, uint size, IntPtr pDataBlock);
Run Code Online (Sandbox Code Playgroud)
但是一旦我注入钩子,钩住的程序就会继续崩溃 - 没什么大惊喜.我认为它是调用约定的问题,并且我的钩子函数以某种方式干扰了钩子程序的堆栈.
所以我看看另一个项目谁挂钩相同的功能,但在c ++中弯路(挂钩部分):
Func = (int (__stdcall *)(unsigned int, unsigned short, void const ))::GetProcAddress(::GetModuleHandle("Connection.dll"), "?Send@Connection_t@@QAEHIIPBX@Z");
PVOID DetourPtr;
PVOID TargetPtr;
DetourTransactionBegin();
DetourAttachEx(&Func, …Run Code Online (Sandbox Code Playgroud) 我正在使用MASM和Visual C++,我正在使用x64进行编译.这是我的C++代码:
// include directive
#include "stdafx.h"
// external functions
extern "C" int Asm();
// main function
int main()
{
// call asm
Asm();
// get char, return success
_getch();
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
和我的汇编代码:
extern Sleep : proc
; code segment
.code
; assembly procedure
Asm proc
; sleep for 1 second
mov ecx, 1000 ; ecx = sleep time
sub rsp, 8 ; 8 bytes of shadow space
call Sleep ; call sleep
add rsp, 8 ; get rid …Run Code Online (Sandbox Code Playgroud) 我使用MSVC++ 2012用C++编写,我的代码针对的是x86平台.我有一种情况,写一个函数(除其他外)可以在CALLING函数的堆栈上分配一些内存是有利的.我不打算在这篇文章中辩论这样做的智慧,而只是考虑技术可行性.
我的实现计划是将我的函数编写为裸函数,并在内联汇编中使用自定义prolog代码.在prolog中,我首先确定我需要多少内存,然后将返回地址,参数和此指针向下移动到该堆栈中.最后,我会根据该数量调整堆栈指针.如果我没有弄错,这将在调用函数的堆栈上创建一个区域.
有没有人看到该计划中有任何漏洞?
假设我们得到一个简单的程序
#include <cstdio>
int main(int argc, char* argv[]) {
int n = argc;
if (n > 1) {
n = 1;
}else {
n = -1;
}
printf("%d\n", n);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
g++ main.cpp -S -O1在ubuntu x64下使用Windows子系统生成的汇编代码和汇编代码段
subq $8, %rsp
cmpl $1, %edi
setg %dl
movzbl %dl, %edx
leal -1(%rdx,%rdx), %edx
movl $.LC0, %esi
movl $1, %edi
movl $0, %eax
call __printf_chk
movl $0, %eax
addq $8, %rsp
ret
Run Code Online (Sandbox Code Playgroud)
既push没有访问内存的指令,也没有访问内存的指令。因此,n必须通过传递参数%edx。现在,我想知道c库函数如何__printf_chk知道其中%edx …