tags: [Windows, 逆向, 网络安全] title: 逆向 COM dll slug: reverse-com-dll
ASP Server.CreateObject, COM reverse engineering
IDA Pro
New Bing (有Windows API问题直接问就行)
首先注册一下dll:regsvr32 PwdInfo.dll
准备好Visual Studio 2022,选中“使用C++的桌面开发”,并选择MSVC v143 - VS2022 C++ x64/x86 生成工具
、Windows 11 SDK
、适用于最新 v143 生成工具的 C++ ATL (x86 和 x64)
开启Developer PowerShell for VS 2022
,注意用Hostx86\x86\cl.exe
或者Hostx86\x64\cl.exe
,这样产生的32位exe才可以调用32位的dll。具体可以用file查看:
/mnt/e$ file PwdInfo.dll test.exe
PwdInfo.dll: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows
test.exe: PE32 executable (console) Intel 80386, for MS Windows
File
-> Load Type Library
, 选择PwdInfo.dll
,可以找到包含的函数、各个函数参数及返回值。
注意先安装相关库。具体名称搜索ATL把看着像的装了就行。
如果无法加载COM dll,可以用火绒剑或Procmon看一下注册表访问,看看是不是没有注册或者参数打错了。
// cl /Zi /Od /DEBUG:FULL -IE:\VisualStudio\2022\BuildTools\VC\Tools\MSVC\14.16.27023\atlmfc\lib\x86 -IE:\VisualStudio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\atlmfc\include /EHsc .\test.cpp /link /libpath:"E:\VisualStudio\2022\BuildTools\VC\Tools\MSVC\14.16.27023\atlmfc\lib\x86" atls.lib /DEBUG:FULL ; .\test.exe
#pragma comment(lib, "Ole32.lib")
#include <Windows.h>
#include <objbase.h>
#include <combaseapi.h>
#include <comdef.h>
#include <iostream>
#include <atlbase.h>
using std::cin;
using std::cout;
using std::endl;
// failfast macro with a function name if hr failed
#define FAIL_FAST(name) \
if (FAILED(hr)) \
{ \
cout << "FAIL_FAST: " << #name << " failed " << hr << endl; \
return 0; \
} \
else \
{ \
cout << #name << " success" << endl; \
}
#define FAIL_FAST_IF_NULL(name) \
if (name == NULL) \
{ \
cout << "FAIL_FAST: " << #name << " is NULL" << endl; \
return 0; \
} \
else \
{ \
cout << #name << " success" << endl; \
}
#define WAIT_FOR_ENTER \
{ \
cout << "press enter to continue..."; \
std::getchar(); \
}
struct CoInitHelper
{
CoInitHelper() { CoInitialize(NULL); }
~CoInitHelper() { CoUninitialize(); }
};
int main()
{
CoInitHelper coInitGuard;
{
HRESULT hr;
CLSID clsid;
// hr = CLSIDFromString(L"{410C6850-4C6F-11D4-8654-0000E8E6E355}", &clsid);
// FAIL_FAST(CLSIDFromString);
hr = CLSIDFromProgID(L"PwdInfo.Password", &clsid);
FAIL_FAST(CLSIDFromProgID);
IDispatch *pOR;
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void **)&pOR);
FAIL_FAST(CoCreateInstance);
DISPID PropertyID[1] = {0};
BSTR PropName[1];
PropName[0] = SysAllocString(L"UnLockPwd");
hr = pOR->GetIDsOfNames(IID_NULL, PropName, 1, LOCALE_USER_DEFAULT, PropertyID);
FAIL_FAST(GetIDsOfNames);
// unlockpwd
BSTR account = SysAllocString(L"1234567");
BSTR pwd = SysAllocString(L"123456");
DISPPARAMS dp = {NULL, NULL, 0, 0};
VARIANT vResult;
EXCEPINFO ei;
UINT uArgErr;
// Allocate memory for the arguments array
dp.rgvarg = new VARIANT[2];
if (dp.rgvarg == NULL)
return E_OUTOFMEMORY;
// Set the number of arguments
dp.cArgs = 2;
// Initialize the arguments as empty variants
VariantInit(&dp.rgvarg[0]);
VariantInit(&dp.rgvarg[1]);
// Set the arguments as BSTRs
dp.rgvarg[0].vt = VT_BSTR;
dp.rgvarg[0].bstrVal = pwd;
dp.rgvarg[1].vt = VT_BSTR;
dp.rgvarg[1].bstrVal = account;
// Initialize the result as an empty variant
VariantInit(&vResult);
// Call the function using Invoke
WAIT_FOR_ENTER
hr = pOR->Invoke(PropertyID[0], IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dp, &vResult, &ei, &uArgErr);
FAIL_FAST(Invoke);
WAIT_FOR_ENTER
// Free the memory for the arguments array
delete[] dp.rgvarg;
// Convert the BSTR to a char*
char *strResult;
// hr = VariantChangeType(&vResult, &vResult, 0, VT_BSTR);
// FAIL_FAST(VariantChangeType);
strResult = _com_util::ConvertBSTRToString(vResult.bstrVal);
FAIL_FAST_IF_NULL(strResult)
// Use the char* result
cout << "result: " << strResult << endl; // 812121
// Free the memory for the BSTR and the char*
delete[] strResult;
VariantClear(&vResult);
}
}
出现了,胶水语言!
# pip install pywin32
import win32com.client
# com_error: (-2147221164, '没有注册类', None, None) 说明你的 Python 位数不对,本文提供的是 32 位的,则 Python 也应该是 32 位
# com_error: (-2147221005, '无效的类字符串', None, None) 则是 32 位也没有注册,需要用 regsvr32 注册一下
PwdInfo = win32com.client.DispatchEx("PwdInfo.Password")
# win32com.client.gencache.EnsureDispatch
# 上面这种写法会报:TypeError: This COM object can not automate the makepy process - please run makepy manually for this object
# 换成下面这个就好了
assert PwdInfo.UnLockPwd("1234567", "123456") == PwdInfo.UnLockPwd(1234567, "123456") == "812121"
# 入参类型貌似会自动转换,没有找到相关文档
直接在Invoke前打断点,然后把传入参数所在内存打读写断点,一直跟踪就行。