获取使用内联汇编调用我的函数的函数的地址
我想知道如何检索使用内联汇编调用我的函数的函数的地址。我的想法是获取调用我的函数将返回的地址,并使用它之前的指令(即对调用我的函数的调用)检索调用我的函数的地址,并添加给该函数的偏移量call,到下一条指令的地址(调用我的函数将返回的地址)。到目前为止,我能够做到这一点,但要获取我的地址。它相当简单并且有效:
_asm
{
mov eax, [ebp+4]
mov returnTo,eax
}
long addressOfMine = (*((long*)(returnTo - sizeof(long)))) + returnTo)
这可以很好地检索我的地址。 (通过知道 [ebp+4] 是我的地址将返回的地址)
为了执行相同的操作,但比上面一步我尝试获取旧的 ebp 并执行相同的操作。我在一个网站上看到 [ebp+0] 是旧的 ebp,所以我尝试了:
_asm
{
mov eax, [ebp]
mov ebx, [eax+4]
mov returnTo,ebx
}
long addressOfCaller = (*((long*)(returnTo - sizeof(long)))) + returnTo)
但它不起作用。所以,我的假设是错误的,或者我做错了什么,所以我想请求你的帮助。
I would like to know how to retrieve the address of the function that called my function with inline assembly. My idea is to get the address to where the function that called mine will return and using the instruction before it (that is a call to the function that called mine) retrieving the address of the one that called mine adding to the offset given to that call, to the address of the next instruction (the address to where the function that called mine will return). So far I was able to make this but to get the address of mine. It is fairly simple and it works:
_asm
{
mov eax, [ebp+4]
mov returnTo,eax
}
long addressOfMine = (*((long*)(returnTo - sizeof(long)))) + returnTo)
This retrieves the address of mine just fine. (By knowing that [ebp+4] is the address to where mine will return)
To do the same but one step above I tried to get the old ebp and do the same. I saw in a site that [ebp+0] is the old ebp so I tried:
_asm
{
mov eax, [ebp]
mov ebx, [eax+4]
mov returnTo,ebx
}
long addressOfCaller = (*((long*)(returnTo - sizeof(long)))) + returnTo)
But it doesn't work. So, my assumption is wrong or I'm doing something wrong so I would like to ask your help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
为什么不直接使用操作系统提供的功能呢?这里有一对链接 如何获取堆栈跟踪C?
你可以尝试一些更复杂的http://www.yosefk.com/blog/getting-the-call-stack-without-a-frame-pointer.html
但是你必须注意,在 x86 模式下 调用约定并不容易,它取决于一些因素,例如您的操作系统、编译器、使用的调用约定, ETC。
Why don't just use the function provided by your OS? here are a pair of links How can one grab a stack trace in C?
You may try something more complicated http://www.yosefk.com/blog/getting-the-call-stack-without-a-frame-pointer.html
But you have to be aware that in x86 mode the calling conventions are not easier, it depends on some factors like your OS, your compiler, the calling convention used, etc.
这并不容易做到。您必须知道调用者有多少个参数和局部变量,在大多数情况下,以编程方式弄清楚这一点并不容易。如果您做出可能错误的假设,即编译器将
EBP
保留为堆栈帧持有者并且从不更改它(例如,这可能不适用于 -O3/2/1)在被调用函数内部,你可以这样做,
但这是非常不安全的。对编译器的优化可能会破坏它。它仅适用于 x86-32,并且根据操作系统和编译器,如果遵循不同的调用标准,它可能无法工作。
它的工作方式是这样的:
C 中的函数看起来像
这样 所以,如果说你有 _SumCall 它看起来像
这样 所以你看,它依赖于被调用者负责堆栈帧保存的事实。
如果您尝试但不起作用,请确保调用方和被调用方都至少有 1 个局部变量/参数。如果失败了,那么好吧,你就完蛋了,因为编译器做了一些优化,打破了这个假设。
再次。这是非常不安全且极其不可移植
参考:http://courses.ece.illinois.edu/ece390/books/labmanual/c-prog-mixing.html
It's not easy to do. You must know how many arguments and local variables the caller has, which in most cases, is not trivial to figure out programmatically. If you make the possibly wrong assumption that the compiler keeps
EBP
as the stackframe holder and never alters it(as in, this wouldn't work with -O3/2/1 probably)inside of the called function, you could do something like
This is very unsafe though. Optimizations on the compiler will probably break it. It will only work for x86-32, and depending on OS and compiler it may not work if it follows a different calling standard.
The way it works is this:
Functions in C look something like
So, if say you had _SumCall it'd look somethign like
So you see, it relies on the fact that the callee is responsible for stack frame preservation.
If you try it and it doesn't work, ensure both the caller and callee have at least 1 local variable/argument. Failing that, then well, your just screwed because the compiler made some optimization that broke this assumption.
Once again. This is very unsafe and is extremely not-portable
Reference: http://courses.ece.illinois.edu/ece390/books/labmanual/c-prog-mixing.html
我有一个想法给你“未知(谷歌)”。检索函数将返回的地址,修补该地址以执行“到达它返回的位置并调用您的函数传递该值”,返回,并在回调中使用您收到的参数并修复您修补的内容与原始值。
顺便说一句,我希望你不会用它来入侵五角大楼的计算机。
I had an idea for you "unknown (google)". Retrieve the address of where your function will return to, patch that address to do "get to where it returns and call a function of yours passing you that value", return, and in your callback use the argument you receive and fix what you patched with the original values.
By the way, I'm hoping you are not using this to invade the Pentagon computers.
来点更直一点的怎么样? *不确定它是否适用于任何平台/CPU:
What about something a bit more straight ? *Not sure if it works on any platform/CPU:
好吧,只要你知道你正在做一些不可移植的事情。你知道吗?
我的意思是,并不是有十几个人还没说过……
所以。对于 x86(但不是 X64)上的函数,当未启用帧指针省略和其他优化时,这应该可以工作。并不适用于所有调用约定,但它应该适用于标准 C/C++ 调用约定。
编辑:好吧,我现在很困惑。我再次查看了您的问题,据我所知,您的第一个代码片段在功能上与我刚刚编写的相同。但是你说该代码为你提供了函数的地址 - 但这不应该是真的。该代码片段应该将调用者的地址返回到您的函数。
edit2:添加代码以获取调用者的调用者。
顺便说一句,您在问题中显示的这段代码
将不起作用。它基于这样的假设:进行调用的唯一方法是
符号是函数的 4 字节绝对地址。
但这并不是拨打电话的唯一方式。也可以间接调用
or
也可以相对于当前指令调用
但是你不需要这样做,一旦你知道调用函数中的任何地址,你可以使用 调试帮助库查找调用您的函数的地址。
为了使用 DebugHelp,您必须拥有代码的调试符号。然后只需使用
SymFromAddr。
Ok, so as long as you know you are doing something non-portable. You know that right?
I mean, it's not like a dozen people haven't said it already...
so. for functions on x86 (but not X64) when frame pointer omission and other optimizations aren't enabled, this should work. doesn't work for all calling conventions, but it should work for standard C/C++ calling convention.
edit: Ok I'm officially confused now. I looked again at your question, and as far as I can tell, the your first code fragment is functionally the same as what I just wrote. But you say that that code gives you the address of your function - but that shouldn't be true. that code fragment should be returning the address of the caller to your function.
edit2: added code to get the caller of the caller.
By the way this code that you show in your question
won't work. It's based on the assumption that the only way to make a call is
where symbol is a 4 byte absolute address of a function.
But thats not the only way to make a call. it's also possible to call indirect
or
And it also possible to call relative to the current instruction
But you don't need to do this, once you know any address within the calling function, you can use the Debug Help Library to find the address of the function that called you.
In order to use DebugHelp, you must have the debug symbols for the code. then just use
SymFromAddr.