草庐IT

c++ - 如何从汇编代码中找出函数原型(prototype)?

coder 2024-02-04 原文

我有一些汇编代码,我想找出调用函数的原型(prototype),以便我可以从 C++ 代码中调用所有函数。

我真正想做的是将一个 dll 注入(inject)到正在运行的进程中,并从我的 dll 中调用正在运行的进程的函数。现在我已经成功注入(inject)了我的 dll 但不知道如何进行“调用”。

我是新手,对汇编代码了解不多。我的 dll 是用 visual c++ 2012 编写的。

这是运行过程的代码:

CPU Disasm
Address   Hex dump          Command                                  Comments
6013BE24  /$  53            PUSH EBX
6013BE25  |.  8B1D 10461860 MOV EBX,DWORD PTR DS:[60184610]
6013BE2B  |.  8B1B          MOV EBX,DWORD PTR DS:[EBX]
6013BE2D  |.  8B40 04       MOV EAX,DWORD PTR DS:[EAX+4]
6013BE30  |.  FFD3          CALL EBX
6013BE32  |.  5B            POP EBX
6013BE33  \.  C3            RETN

你可以看到 6013BE30 正在调用函数,而函数(EBX)在 004BAFAC

CPU Disasm
Address   Hex dump          Command                                  Comments
004BAFAC  /$  55            PUSH EBP                                 ; Test.004BAFAC(guessed void)
004BAFAD  |.  8BEC          MOV EBP,ESP
004BAFAF  |.  53            PUSH EBX
004BAFB0  |.  8BD8          MOV EBX,EAX
004BAFB2  |.  8B43 08       MOV EAX,DWORD PTR DS:[EBX+8]
004BAFB5  |.  E8 3EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFBA  |.  8B43 0C       MOV EAX,DWORD PTR DS:[EBX+0C]
004BAFBD  |.  E8 36F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFC2  |.  8B43 14       MOV EAX,DWORD PTR DS:[EBX+14]
004BAFC5  |.  E8 2EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFCA  |.  8B43 18       MOV EAX,DWORD PTR DS:[EBX+18]
004BAFCD  |.  E8 26F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFD2  |.  8B43 1C       MOV EAX,DWORD PTR DS:[EBX+1C]
004BAFD5  |.  E8 1EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFDA  |.  8B43 10       MOV EAX,DWORD PTR DS:[EBX+10]
004BAFDD  |.  E8 16F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFE2  |.  8B43 20       MOV EAX,DWORD PTR DS:[EBX+20]
004BAFE5  |.  E8 0EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFEA  |.  8B43 44       MOV EAX,DWORD PTR DS:[EBX+44]
004BAFED  |.  E8 06F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFF2  |.  8B43 44       MOV EAX,DWORD PTR DS:[EBX+44]

那么如何在 Visual C++ 中调用 004BAFAC 处的函数呢?

最佳答案

在汇编函数中,参数从栈中弹出,从最后一个开始。因此,要将参数传递给函数,首先将它们压入堆栈,然后调用函数。在 MASM 中,这看起来类似于显示消息框:

.data 
MsgBoxCaption  db "Attention",0 
MsgBoxText     db "Hello Message Box!",0 

.code
start:
push 0
mov eax, offset MsgBoxCaption
push eax
push offset MsgBoxText
push 0
call MessageBoxA
call ExitProcess
end start

虽然在 C++ 中它看起来像这样:

int retval = MessageBox(NULL, "Hello Message Box!", "Attention", 0);

用 OllyDbg 反汇编你会得到:

CPU Disasm
Address   Hex dump          Command                                  Comments
011D13C0  |.  6A 00         PUSH 0                                   ; /Type = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
011D13C2  |.  68 54571D01   PUSH OFFSET 011D5754                     ; |Caption = "Attention"
011D13C7  |.  68 3C571D01   PUSH OFFSET 011D573C                     ; |Text = "Hello Message Box!"
011D13CC  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
011D13CE  |.  FF15 40831D01 CALL DWORD PTR DS:[<&USER32.MessageBoxA> ; \USER32.MessageBoxA

返回值存储在 eax 中。您会看到,如果数据类型大于 DWORD(4 字节),您实际上不是在传递值,而是在传递引用。每个参数实际上只是一个 DWORD。这是因为堆栈在 32 位系统中是 32 位对齐的,因此只能保存 32 位值。寄存器的情况也是如此。在 32 位系统中,寄存器是 32 位宽。如果传递字符串,则传递的是对该字符串的引用,而不是字符串,也不是可变宽度的字符/字节数组。在 Integer 的情况下,它很可能作为值而不是引用传递。当在 MASM 中对函数进行原型(prototype)设计时,将所有参数作为 DWORD 进行原型(prototype)设计(但在 C++ 中则不行)。

因此在您上面的示例中,似乎有一个参数被传递到堆栈上(push ebx)。我说看起来像,因为它很可能只是将 ebx 推送到存储它以供以后检索(即,在再次弹出调用 ebx 之后 - 也许存储在 ebx 中的值需要保留)。您只能在实际运行实时调试 session 并观察堆栈/寄存器时才能确定。跳过调用并检查前后的堆栈指针 (esp) 以查看有多少参数传递给函数(同样:1 个参数 = 1 个 DWORD = 4 个字节)。

要在 C++ 中对您的函数进行原型(prototype)设计,您需要弄清楚参数的数据类型,可能是通过单步执行汇编代码并在围绕相关函数遍历代码时检查寄存器和/或堆栈。 eax 中的返回值也是如此。所以 eax 永远不会保存字符串,而可能是对字符串的引用,但它可能保存 32 位或更小的整数。您还必须通过逆向周围的代码来找出 eax 指向的数据类型。

编辑:实际上我写的东西有一半是错误的,最值得注意的是参数总是引用,所以请重读我写的东西。对于给您带来的不便,我们深表歉意 - 累了就不应该回答问题:)

关于c++ - 如何从汇编代码中找出函数原型(prototype)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15323056/

有关c++ - 如何从汇编代码中找出函数原型(prototype)?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  10. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

随机推荐