本文为看雪论坛精华文章
看雪论坛作者ID:橘喵Cat
一 前言
二 初步环境准备
去官网找对应的libcef+chromium版本即可:https://cef-builds.spotifycdn.com/index.html下载框架
在windows上下载好后,直接解压即可。
三 找到js资源文件所在
cef_stream_reader_create_for_data
cef_stream_reader_create_for_file
然后输入自己的账户密码登录,登录成功后,过了一会断点才来,经过测试,发现断点只断这么一次。根据寄存器ECX~EDI的值定位到内存,发现多个资源路径(所有寄存器对应内存都看一下)。
第二张和第三张图片可以省略,因为这俩资源文件在第一张路径里都有,找到第一张的路径,发现是个加密的zip。
四 解密资源文件
cef_zip_reader_create从zip文件读取数据。
///
// All ref-counted framework structures must include this structure first.
///
typedef
struct
_cef_base_ref_counted_t {
///
// Size of the data structure.
///
size_t size;
///
// Called to increment the reference count for the object. Should be called
// for every new copy of a pointer to a given object.
///
void
(CEF_CALLBACK* add_ref)(
struct
_cef_base_ref_counted_t*
self
);
///
// Called to decrement the reference count for the object. If the reference
// count falls to 0 the object should self-delete. Returns true (1) if the
// resulting reference count is 0.
///
int
(CEF_CALLBACK* release)(
struct
_cef_base_ref_counted_t*
self
);
///
// Returns true (1) if the current reference count is 1.
///
int
(CEF_CALLBACK* has_one_ref)(
struct
_cef_base_ref_counted_t*
self
);
///
// Returns true (1) if the current reference count is at least 1.
///
int
(CEF_CALLBACK* has_at_least_one_ref)(
struct
_cef_base_ref_counted_t*
self
);
} cef_base_ref_counted_t;
///
// Structure that supports the reading of zip archives via the zlib unzip API.
// The functions of this structure should only be called on the thread that
// creates the object.
///
typedef
struct
_cef_zip_reader_t {
///
// Base structure.
///
cef_base_ref_counted_t base;
///
// Moves the cursor to the first file in the archive. Returns true (1) if the
// cursor position was set successfully.
///
int
(CEF_CALLBACK* move_to_first_file)(
struct
_cef_zip_reader_t*
self
);
///
// Moves the cursor to the next file in the archive. Returns true (1) if the
// cursor position was set successfully.
///
int
(CEF_CALLBACK* move_to_next_file)(
struct
_cef_zip_reader_t*
self
);
///
// Moves the cursor to the specified file in the archive. If |caseSensitive|
// is true (1) then the search will be case sensitive. Returns true (1) if the
// cursor position was set successfully.
///
int
(CEF_CALLBACK* move_to_file)(
struct
_cef_zip_reader_t*
self
,
const
cef_string_t* fileName,
int
caseSensitive);
///
// Closes the archive. This should be called directly to ensure that cleanup
// occurs on the correct thread.
///
int
(CEF_CALLBACK* close)(
struct
_cef_zip_reader_t*
self
);
// The below functions act on the file at the current cursor position.
///
// Returns the name of the file.
///
// The resulting string must be freed by calling cef_string_userfree_free().
cef_string_userfree_t(CEF_CALLBACK* get_file_name)(
struct
_cef_zip_reader_t*
self
);
///
// Returns the uncompressed size of the file.
///
int64(CEF_CALLBACK* get_file_size)(
struct
_cef_zip_reader_t*
self
);
///
// Returns the last modified timestamp for the file.
///
cef_basetime_t(CEF_CALLBACK* get_file_last_modified)(
struct
_cef_zip_reader_t*
self
);
///
// Opens the file for reading of uncompressed data. A read password may
// optionally be specified.
///
int
(CEF_CALLBACK* open_file)(
struct
_cef_zip_reader_t*
self
,
const
cef_string_t* password);
///
// Closes the file.
///
int
(CEF_CALLBACK* close_file)(
struct
_cef_zip_reader_t*
self
);
///
// Read uncompressed file contents into the specified buffer. Returns < 0 if
// an error occurred, 0 if at the end of file, or the number of bytes read.
///
int
(CEF_CALLBACK* read_file)(
struct
_cef_zip_reader_t*
self
,
void
* buffer,
size_t bufferSize);
///
// Returns the current offset in the uncompressed file contents.
///
int64(CEF_CALLBACK* tell)(
struct
_cef_zip_reader_t*
self
);
///
// Returns true (1) if at end of the file contents.
///
int
(CEF_CALLBACK* eof)(
struct
_cef_zip_reader_t*
self
);
} cef_zip_reader_t;
///
// Writes the contents of |src_dir| into a zip archive at |dest_file|. If
// |include_hidden_files| is true (1) files starting with "." will be included.
// Returns true (1) on success. Calling this function on the browser process UI
// or IO threads is not allowed.
///
CEF_EXPORT
int
cef_zip_directory(
const
cef_string_t* src_dir,
const
cef_string_t* dest_file,
int
include_hidden_files);
///
// Create a new cef_zip_reader_t object. The returned object's functions can
// only be called from the thread that created the object.
///
CEF_EXPORT cef_zip_reader_t* cef_zip_reader_create(
struct
_cef_stream_reader_t* stream);
然后重新启动如流,登录,进入头像修改页面,结果直接给我乱码了。然后尝试了下啥也不改,只要是替换了,就会乱码。凉凉,估计加载资源文件的时候有校验,比如它的修改时间、MD5、编码等等。不过还是证明了修改文件会造成影响。
五 开启CEF框架调试功能
// dllmain.cpp : 定义 DLL 应用程序的入口点。
PVOID g_cef_browser_host_create_browser =
nullptr
;
PVOID g_cef_get_keyboard_handler =
NULL
;
PVOID g_cef_on_key_event =
NULL
;
void
SetAsPopup
(
cef_window_info_t
* window_info)
{
window_info->style =
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE;
window_info->parent_window =
NULL
;
window_info->x = CW_USEDEFAULT;
window_info->y = CW_USEDEFAULT;
window_info->width = CW_USEDEFAULT;
window_info->height = CW_USEDEFAULT;
}
int
CEF_CALLBACK
hook_cef_on_key_event
(
struct
_cef_keyboard_handler_t
* self,
struct
_cef_browser_t
* browser,
const
struct
_cef_key_event_t
* event,
cef_event_handle_t
os_event)
{
OutputDebugStringA(
"[detours] hook_cef_on_key_event n"
);
auto
cef_browser_host = browser->get_host(browser);
// 键盘按下且是F12
if
(event->type == KEYEVENT_RAWKEYDOWN && event->windows_key_code ==
123
) {
cef_window_info_t
windowInfo{};
cef_browser_settings_t
settings{};
cef_point_t
point{};
SetAsPopup(&windowInfo);
OutputDebugStringA(
"[detours] show_dev_tools n"
);
// 开启调试窗口
cef_browser_host->show_dev_tools
(cef_browser_host, &windowInfo,
0
, &settings, &point);
}
return
reinterpret_cast
<
decltype
(&hook_cef_on_key_event)>
(g_cef_on_key_event)(self, browser, event, os_event);
}
struct
_
cef_keyboard_handler_t
*
CEF_CALLBACK
hook_cef_get_keyboard_handler
(
struct
_
cef_client_t
*
self
) {
OutputDebugStringA(
"[detours] hook_cef_get_keyboard_handler n"
);
// 调用原始的修改get_keyboard_handler函数
auto
keyboard_handler =
reinterpret_cast
<
decltype
(&hook_cef_get_keyboard_handler)>
(g_cef_get_keyboard_handler)(self);
if
(keyboard_handler) {
// 记录原始的按键事件回调函数
g_cef_on_key_event = keyboard_handler->on_key_event;
// 修改返回值中的按键事件回调函数
keyboard_handler->on_key_event = hook_cef_on_key_event;
}
return
keyboard_handler;
}
int
hook_cef_browser_host_create_browser
(
const
cef_window_info_t
* windowInfo,
struct
_cef_client_t
* client,
const
cef_string_t
* url,
const
struct
_cef_browser_settings_t
* settings,
struct
_cef_dictionary_value_t
* extra_info,
struct
_cef_request_context_t
* request_context)
{
OutputDebugStringA(
"[detours] hook_cef_browser_host_create_browser n"
);
// 记录原始的get_keyboard_handler
g_cef_get_keyboard_handler = client->get_keyboard_handler;
// 修改get_keyboard_handler
client->get_keyboard_handler = hook_cef_get_keyboard_handler;
return
reinterpret_cast
<
decltype
(&hook_cef_browser_host_create_browser)>
(g_cef_browser_host_create_browser)(
windowInfo, client, url, settings, extra_info, request_context);
}
// Hook cef_browser_host_create_browser
BOOL APIENTRY
InstallHook
()
{
OutputDebugStringA(
"[detours] InstallHook n"
);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
g_cef_browser_host_create_browser =
DetourFindFunction(
"libcef.dll"
,
"cef_browser_host_create_browser"
);
DetourAttach(&g_cef_browser_host_create_browser,
hook_cef_browser_host_create_browser);
LONG ret = DetourTransactionCommit();
return
ret == NO_ERROR;
}
BOOL APIENTRY
DllMain
( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch
(ul_reason_for_call)
{
case
DLL_PROCESS_ATTACH:
InstallHook();
break
;
case
DLL_THREAD_ATTACH:
case
DLL_THREAD_DETACH:
case
DLL_PROCESS_DETACH:
break
;
}
return
TRUE;
}
于是我在exe运行的时候,使用远程线程注入dll,成功。
登录进去,尝试在某些页面里,按F12,可以开启Chrome调试窗口,非常的方便。
六 尝试做点什么功能+总结(未遂)
看了下页面元素构成,很明显不行,因为值是以文本形式夹在div标签里面,并不能触发脚本语言。
那好吧,我去找个存放在标签里面的值修改吧,可以看到,昵称是会写到value值下的。
那我们把它改成攻击代码,将value用"给闭合,然后设置一个鼠标事件,当鼠标移动到框内时,就会弹窗。
结果并没有弹,查看html源码,发现"已经被编码成"
看来安全措施做的挺到位嘛,那我也就止步于此了。
看雪ID:橘喵Cat
https://bbs.pediy.com/user-home-940656.htm
2.5折门票限时抢购
峰会官网:https://meet.kanxue.com/kxmeet-6.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!
原文始发于微信公众号(看雪学苑):针对某会议软件,简单研究其CEF框架
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论