我将WinDbg附加到我没有源代码的进程中。我已经用bm ADVAPI32!_RegOpenKeyExW@20设置了一个断点。 dv的输出是:

Unable to enumerate locals, HRESULT 0x80004005
Private symbols (symbols.pri) are required for locals.
Type ".hh dbgerr005" for details.


kP的输出是:

0:000> kP
ChildEBP RetAddr  
001ae174 5b73a79c ADVAPI32!_RegOpenKeyExW@20
001ae1cc 5b77bb20 msenv!?ReadSecurityAddinSetting@@YG_NPAGK@Z+0x8a
001ae468 5b781aad msenv!?    QueryStatusCmd@CVSCommandTarget@@QAEJPBVCIcmdGuidCmdId@@PBU_GUID@@KQAU_tagOLECMD@@PAU_tagOLECMDTEXT@@@Z+0x254
001ae49c 5b786073 msenv!?IsCommandVisible@CVSShellMenu@@QAEJPBVCIcmdGuidCmdId@@_N@Z+0xbf
001ae4e4 5b785fd2 msenv!?IsCommandVisible@CSurfaceCommandingSupport@@UAGJABU_COMMANDTABLEID@@_NPAH@Z+0xa0
. . .


我该怎么办看一下传递的参数值(特别是第二个参数:LPCTSTR lpSubKey)?另外,我该怎么做才能基于该值设置条件断点?

我有Visual Studio调试器和WinDbg。我也愿意尝试其他工具。

#1 楼

这在WinDbg中是可行的,但是语法不是最好的。如果您只是想快速获得结果,其他答案可能会更好。就是说,这是您的操作方法。

RegOpenKeyExW是一个stdcall函数,看起来您使用的是32位版本的Windows,因此,当您输入该函数时,第一个参数将位于ESP+4,第二个位于ESP+8,依此类推。它的签名是:字符串(ESP+8)。您可以通过在RegOpenKeyExW上设置无条件断点,然后使用lpSubKey来打印字符串来进行测试。

要做下一部分–当du poi(esp+8)的值等于某个模式时停止,可以检查MSDN的文档,其中包含一个执行此操作的示例。我目前无法使用Windows计算机,但是以下操作可以满足您的要求(改编自MSDN示例):

LONG WINAPI RegOpenKeyEx(
  _In_        HKEY hKey,
  _In_opt_    LPCTSTR lpSubKey,
  _Reserved_  DWORD ulOptions,
  _In_        REGSAM samDesired,
  _Out_       PHKEY phkResult
);


然后创建lpSubKey具有以下内容:

bp advapi32!RegOpenKeyExW "$$<c:\commands.txt"


您可以用任何有效的字符串通配符替换上面的c:\commands.txt

"Foo*"设置了一个名为.if的别名,该别名等于SubKey上的Unicode字符串的内容。第二行将该字符串与模式esp+8匹配;如果不匹配,则使用"Foo*"继续执行而不停止。如果匹配,则gc打印出字符串,然后中断。

评论


好答案。我鄙视WinDbg脚本的奥秘语法,但您确实对此很满意:)

– 0xC0000022L♦
13年5月1日在22:28



这很酷。我认为,如果无法访问标头,则无法预测参数类型,因此,如果我想制作一个windbg插件来自动执行此操作,则需要所有标头版本。

–贾斯汀·迪林(Justin Dearing)
13年5月1日23:53

是的,很遗憾,这是正确的。在MS内部,他们可以访问专用符号,从而为它们提供了参数类型。有时您会看到这种情况,因为某些内置的WinDbg扩展在Microsoft之外运行时会失败...

–布伦丹·多兰·加维特(Brendan Dolan-Gavitt)
13年5月1日在23:58

@JustinDearing:Sven B. Schreiber IIRC编写的“ Undocumented Windows 2000 Secrets”一书已经实现了一个方案,该方案需要一个“格式字符串”表,然后可以为您提供参数。该书现在免费提供PDF文件。另外,我很想取消删除我的答案,但是我不确定您的确切要求。

– 0xC0000022L♦
13年5月2日,11:20

@ 0xC0000022L我的一个朋友在我们的Windows内部研究小组期间引起了我的注意。我已经下载了。我会去那里。我正在考虑的另一种选择是使用Rohit的XML,其中包含所有标头信息。

–贾斯汀·迪林(Justin Dearing)
13年5月2日,12:10

#2 楼

我已经获得了与PaiMei(尤其是PyDbg)有关的最佳经验。 《 Grayhat Python》这本书引起了我的注意,我决定尝试一下。

脚本

这里是我在使用的通用骨架。动态分析(dynamic-analysis)的努力。我已经对其进行了调整,以使其能够挂接您感兴趣的函数的Unicode版本。

但是,答案可能并不明确,因为您可以有条件地实现中断,但是您会必须将交互式调试器部分添加到脚本中。如果您想破坏而不是继续,则必须告诉调试器通过修改行return DBG_CONTINUE来做到这一点。

import sys
import ctypes
import traceback
try:
    from pydbg import *
    from pydbg.defines import *
    from utils import hooking
except:
    print "ERROR: you need pydbg and utils.hooking from PAIMEI."
    sys.exit(-1)

reg = None

class reg_pydbg(pydbg):
    @staticmethod
    def __getlen(mbi, address):
        # What's the maximum number of bytes we can read?
        _maxlen = 64*1024
        absmaxlen = (mbi.BaseAddress + mbi.RegionSize) - address
        if absmaxlen > _maxlen:
            return _maxlen
        return absmaxlen

    def rootkey_const(self, key):
        if 0x80000000 == key:
            return "HKCR"
        elif 0x80000001 == key:
            return "HKCU"
        elif 0x80000002 == key:
            return "HKLM"
        elif 0x80000003 == key:
            return "HKU"
        elif 0x80000004 == key:
            return "HKEY_PERFORMANCE_DATA"
        elif 0x80000050 == key:
            return "HKEY_PERFORMANCE_TEXT"
        elif 0x80000060 == key:
            return "HKEY_PERFORMANCE_NLSTEXT"
        elif 0x80000005 == key:
            return "HKEY_CURRENT_CONFIG"
        elif 0x80000006 == key:
            return "HKEY_DYN_DATA"
        elif 0x80000007 == key:
            return "HKEY_CURRENT_USER_LOCAL_SETTINGS"
        return "0x%08X" % (key)

    def readmem(self, address, len = 0):
        try:
            mbi = self.virtual_query(address)
        except:
            return None, "%08X <invalid ptr>" % (address)

        if mbi.Protect & PAGE_GUARD: # no way to display contents of a guard page
            return None, "%08X <guard page>" % (address)

        if 0 == len: # try to make a good guess then
            len = self.__getlen(mbi, address)

        try:
            explored = self.read_process_memory(address, len)
        except:
            return None, "%08X <ReadProcessMemory failed>" % (address)

        return explored, None

    def readstring(self, address, unicodeHint = False, returnNone = False):
        if 0 == address:
            if returnNone:
                return None
            return "<nullptr>"

        explored, retval = self.readmem(address)

        if not explored:
            if returnNone:
                return None
            return retval

        explored_string = None

        if not unicodeHint:
            explored_string = self.get_ascii_string(explored)

        if not explored_string:
            explored_string = self.get_unicode_string(explored)

        if not explored_string:
            explored_string = self.get_printable_string(explored)

        return explored_string

def exit_RegOpenKeyExW(dbg, args, ret):
    keyname = dbg.readstring(args[1], True)
    print "RegOpenKeyExW(%s, %s, ...) -> %s (%d)" % (dbg.rootkey_const(args[0]), keyname, ctypes.FormatError(ret), ret)
    return DBG_CONTINUE

class reghooks:
    fct2hook = {
        "advapi32.dll" :
            {
            "RegOpenKeyExW"                     : { "args" : 5, "entry" : None, "exit" : exit_RegOpenKeyExW },
            },
    }

    hooked = {}
    hookcont = None
    dbg = None

    def __init__ (self, dbg):
        self.hookcont = hooking.hook_container()
        self.hooked = {}
        self.dbg = dbg
        dbg.set_callback(LOAD_DLL_DEBUG_EVENT, self.handler_loadDLL)

    def hookByDLL(self, dll):
        if not dll.name.lower() in self.hooked:
            for key,value in self.fct2hook.items():
                if key.lower() == dll.name.lower():
                    self.hooked[dll.name.lower()] = 1
                    print "%s at %08x" % (dll.name, dll.base)
                    for func,fctprops in value.items():
                        entry = None; exit = None; args = 0
                        if "entry" in fctprops and None != fctprops["entry"]:
                            print "\tentry hook " + func
                            entry = fctprops["entry"]
                        if "exit" in fctprops and None != fctprops["exit"]:
                            print "\texit hook " + func
                            exit = fctprops["exit"]
                        if "args" in fctprops and None != fctprops["args"]:
                            args = fctprops["args"]
                        if None != entry or None != exit:
                            funcaddr = self.dbg.func_resolve(dll.name, func)
                            self.hookcont.add(self.dbg, funcaddr, args, entry, exit)
        else:
            self.hooked[dll.name.lower()] += 1
        return

    @staticmethod
    def handler_loadDLL(dbg):
        global reg
        dbg.hide_debugger()
        last_dll = dbg.get_system_dll(-1)
        reg.hookByDLL(last_dll)
        return DBG_CONTINUE

def main():
    dbg = reg_pydbg()
    dbg.load("C:\Windows\regedit.exe")
    global reg
    reg = reghooks(dbg)
    dbg.run()

if __name__ == "__main__":
    main()


示例输出

>C:\Python26\python.exe hookreg.py
advapi32.dll at 75840000
        exit hook RegOpenKeyExW
RegOpenKeyExW(HKCU, Software\Microsoft\Windows\CurrentVersion\Applets\Regedit, ...) -> The operation completed successfully. (0)
RegOpenKeyExW(HKLM, SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink, ...) -> The operation completed successfully. (0)
RegOpenKeyExW(HKLM, SOFTWARE\Microsoft\Windows NT\CurrentVersion\LanguagePack\DataStore_V1.0, ...) -> The operation completed successfully. (0)
RegOpenKeyExW(HKLM, SOFTWARE\Microsoft\Windows NT\CurrentVersion\LanguagePack\SurrogateFallback, ...) -> The operation completed successfully. (0)


说明

重要的部分是:

"RegOpenKeyExW" : { "args" : 5, "entry" : None, "exit" : exit_RegOpenKeyExW },


和功能exit_RegOpenKeyExW。您还可以修改上面的内容以仅在输入RegOpenKeyExW时钩住,而不是在退出时钩住或同时执行这两者。取决于您要实现的目标。

我已经使用此方法对通过SCSI_PASS_THROUGH_DIRECT发送的缓冲区(SCSI_PASS_THROUGHDeviceIoControl)进行解码,因此,到目前为止,这并不是您能做的最复杂的事情。 />
另一方面,我还迷上了诸如打开文件(或注册表项)之类的内容,并保留了返回句柄的列表以及它们的字符串形式。这样,我就可以实现非常复杂的人类可读的日志记录方案。

Rationale

之所以存在诸如嵌套字典之类的原因是为了可以轻松地扩展它以挂钩任何功能从任何我想要的DLL。当然也可以对其进行硬编码,但是在某些情况下,我挂钩了许多功能。

#3 楼

使用OllyDbg,您可以像这样

F:\odbg110>regedit & tasklist /fi "imagename eq rege*"

Image Name                   PID Session Name     Session#    Mem Usage
========================= ====== ================ ======== ============
regedit.exe                 2820 Console                 0      2,512 K

F:\odbg110>ollydbg -P 2820

F:\odbg110>


在OllyDbg中,按Alt + g(转到)键入advapi32.RegOpenKeyExW,然后按Enter。如果您使用的是Windows XP SP3,则其外观应如下所示:

77DD6AAF ADVAPI32.RegOpenKeyExW U>/$  8BFF          MOV     EDI, EDI


命中Ctrl + F4(条件日志断点)

在“条件”编辑框中输入说(没有通配符需要有效的转义模式)。

UNICODE [[esp+8]]  ==  "system\CurrentControlSet\Services\Beep" 

>
log RegOpenKeyExW subkey


在表达式编辑框中输入

[esp+8]


在“解码值”中选择“指向Unicode字符串的指针”

pause program on condition
log value of expression always
log function arguments on condition 


(所有这些都可以在不暂停调试对象的情况下完成)(动态中断插入)

现在转到regedit并使用它稍微选择“哔哔声服务”

OllyDbg会中断,并且也会记录函数参数;并且您也会记录所有其他字符串而不会暂停,例如下面的

Log data
Address    Message
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\aswMonFlt"
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\aswRdr"
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\aswRvrt"
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\aswSnx"
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\aswSP"
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\aswTdi"
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\aswVmm"
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\avast! Antivirus"
77DD6AAF   COND: log reop Subkey = 0007FBC8 "SYSTEM\CurrentControlSet\Services\Beep"
77DD6AAF   CALL to RegOpenKeyExW from regedit.01008B23
             hKey = HKEY_LOCAL_MACHINE
             Subkey = "SYSTEM\CurrentControlSet\Services\Beep"
             Reserved = 0
             Access = 2000000
             pHandle = regedit.01019098
77DD6AAF   Conditional breakpoint at ADVAPI32.RegOpenKeyExW


评论


请正确使用格式。到目前为止,您的两个答案均以其原始形式出现了可怕的格式化问题。

– 0xC0000022L♦
13年5月5日,2:14

#4 楼

下载Rohitab的API监视器,并仅在RegOpenKeyEx上设置API捕获过滤器。以下是屏幕快照的工作方式示例以及它提供的信息的示例屏幕快照。

根据您的描述,此操作完全可以满足您的需求。





评论


这确实向我显示了参数值。但是,这不能让我有条件地基于它们来破坏。我的问题是应用程序不断读取许多注册表值。我只在乎读取某些内容。

–贾斯汀·迪林(Justin Dearing)
13年5月2日,0:07

当前不支持正确的条件断点。 FWIW,作者在网站的论坛上提到,他计划将其添加到即将发布的版本中。

–米克
13年5月2日,12:34

此外,API Monitor确实允许您搜索捕获的API数据。虽然不完全是您要查找的内容(条件断点),但只要按一下CTRL + F和F3就能到达目的地。

–米克
13年5月2日在12:39



#5 楼

尽管它不支持断点,但Process Monitor是监视注册表访问的出色工具。使用筛选器,您可以轻松选择要包括,排除,突出显示等的键。它还允许您查看任何事件的堆栈跟踪。


Process Monitor是一种高级监视工具适用于显示实时文件系统,注册表和进程/线程活动的Windows。它
结合了两个传统的Sysinternals实用程序Filemon
和Regmon的功能,并添加了广泛的增强功能列表,包括丰富的
和非破坏性过滤,全面的事件属性,例如session ID和用户名,可靠的过程信息,全线程堆栈以及对每个操作的集成符号支持,同时
记录到文件等。它独特的强大功能将使Process Monitor成为系统故障排除和恶意软件搜索工具包中的核心实用工具。




评论


我确实使用ProcessMonitor。

–贾斯汀·迪林(Justin Dearing)
13年5月15日在15:23