首页
论坛
课程
招聘
将js代码注入到第三方CEF应用程序的一点浅见
2021-7-23 22:41 10482

将js代码注入到第三方CEF应用程序的一点浅见

2021-7-23 22:41
10482

高考后的第一次发帖^-^

前言

CEFChromium Embedded Framework的缩写,即“Chromium嵌入式框架”,采用c++编写,地位类似于Electron,是web开发应用程序的重要框架,被许多软件包括微信,网易云,生死狙击等采用,是一款十分优秀的嵌入式框架

 

由于一些原因,需要把js注入到某款使用CEF的应用中,通过js代码与应用web进行一些交互,于是乎研究了一下CEF这个框架,并分享注入js代码到第三方CEF应用的一些经验

CEF应用典型特征

文件目录特征很明显

1
2
3
4
cef.pak
cef_100_percent.pak
cef_200_percent.pak
libcef.dll

着手点

既然CEF功能核心全部都在libcef.dll里面,那么自然首选也是从这个dll入手

 

网上简单搜索CEF的教程后发现,CEF的框架在基础libcef.dll的导出函数的基础上,增加了一层c++类的实现,实现了c2cpp接口的对接

 

观察官方给出的demo发现,创建浏览器对象,最终会调用libcef.dll!cef_browser_host_create_browser来创建出浏览器

 

而一旦得到浏览器对象,我们就可以根据CEF框架中的头文件,非常方便的执行js代码了

 

所以很自然想到把libcef.dll!cef_browser_host_create_browser给hook掉,然后从中间偷出 cef_browser_t*对象

1
2
3
4
5
6
int cef_browser_host_create_browser(
    const cef_window_info_t* windowInfo,
    struct _cef_client_t* client,
    const cef_string_t* url,
    struct _cef_browser_settings_t* settings,
    struct _cef_request_context_t* request_context);

然而新的问题马上出现,cef_browser_host_create_browser 是使用异步的方法创建浏览器,因此cef_browser_t*对象只会在创建成功的回调函数中才能得到,于是我准备设法从_cef_client_t* client这个参数中得到回调地址,然后inline hook掉回调函数(直接改回调地址失败了,估计是地址不可写)

 

很不幸的是,虽然获取回调地址很顺利,但是不知什么原因,回调函数始终没有得到调用,因此此路不通,只能另辟蹊径

 

此时完全没有头绪,根本不知道该如何下手了,毕竟cef_browser_t*得不到,想执行js代码根本不可能,无聊之余打开了ApiMonitor,想看看能否从应用的libcef.dll的调用情况中得到一点启发

 

ApiMonitor监视自定义dll的调用情况也非常方便,设置监视的函数为libcef.dll中的全部函数
1

 

然后启动应用,由于浏览器内核特性,应用自然也是多进程的,一个个查看后,其中一个进程调用的api引起我的兴趣

 

2
3

 

cef_v8context_get_current_context这个函数的调用瞬间将思路打开
看到V8,那这个函数传参或者返回值多半和Javascript分不开了,再去CEF的源码里找找参数或者返回值的含义

1
2
3
4
///
// Returns the current (top) context object in the V8 context stack.
///
CEF_EXPORT cef_v8context_t* cef_v8context_get_current_context();

惊喜的发现居然没有参数,直接反汇当前V8引擎上下文中最前的context

 

由于browser是与V8js引擎绑定的,所以也可以通过返回值cef_v8context_t*得到browser对象了

1
2
3
4
5
6
7
8
9
10
11
12
13
cef_browser_t* browser = NULL;
cef_v8context_t* my_cef_v8context_get_current_context() {
    cef_v8context_t* js_context = ori_cef_v8context_get_current_context();
    Print("my_cef_v8context_get_current_context js_context: %X!!\n", js_context);
    browser = js_context->get_browser(js_context);
    //Print("[!!!] browser = %X\n", browser);
    _cef_frame_t* frame = browser->get_main_frame(browser);
    //Print("[!!!] frame = %X\n", frame);
    CefString script = payload;
    CefString url = xorstr("app/wd").crypt_get();
    frame->execute_java_script(frame, script.GetStruct(), url.GetStruct(), 0);
    return js_context;
}

接下来的事也就水到渠成了,按照网上教程的方法,得到browser过后一切变得简单明了起来

 

而且写完后我发现这样的写法还有个好处,就是可以考虑到页面刷新的情况,因为浏览器一旦页面刷新,重启js虚拟环境,那么浏览器又会主动调取cef_v8context_get_current_context,因此只要我们hook这个函数过后,所有的页面,不管是否刷新,我们都能够注入自己想要的js代码

总结

在时间有限,没有足够时间去完整系统学习一个框架的时候,例如这里的CEF框架,我们依然想快速的实现目标,就必须要开拓思路,不要始终拘泥于网上别人教授的正常/官方方法,有时另辟蹊径反而可以带来意料之外的惊喜

 

研究CEF的前大半部分时间,我始终困在网上一些无比老旧,东搬西凑,复制粘贴的教程中,边抱怨作者的脑瘫,边复制着脑瘫的代码,最后还实现不了脑瘫的功能,最后干脆还是只能放弃,进行独立思考,将成果分享给大家

参考

https://blog.csdn.net/gaga392464782/article/details/49490101?spm=1001.2014.3001.5502

 

https://zhuanlan.zhihu.com/p/29077686

 

https://stackoverflow.com/questions/54398446/how-do-i-add-a-access-control-allow-origin-to-a-requested-resource-with-a-cust

 

https://blog.csdn.net/gaga392464782/article/details/49490101?spm=1001.2014.3001.5502


[公告] 欢迎大家踊跃尝试高研班11月试题,挑战自己的极限!

收藏
点赞5
打赏
分享
最新回复 (10)
雪    币: 5770
活跃值: 活跃值 (1785)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
v0id_ 活跃值 2021-7-23 23:27
2
0
牛逼啊,正好最近在研究 CEF ,学到了
雪    币: 7365
活跃值: 活跃值 (494)
能力值: ( LV5,RANK:71 )
在线值:
发帖
回帖
粉丝
joker陈 活跃值 2021-7-29 18:03
3
0
electron是不是也可以这么搞啊
雪    币: 15
活跃值: 活跃值 (101)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Dlnn 活跃值 2021-8-12 18:25
4
0
FBI open the door
雪    币: 156
活跃值: 活跃值 (20)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lanfengc 活跃值 2021-8-12 21:13
5
0
我就在百度搜了一下 JS 注入 第三方CEF,看雪就给我推荐了这个。
雪    币: 82
活跃值: 活跃值 (2441)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
suuuuu 活跃值 2021-9-2 15:33
6
0
秀~
雪    币: 9210
活跃值: 活跃值 (5141)
能力值: ( LV13,RANK:370 )
在线值:
发帖
回帖
粉丝
TkBinary 活跃值 5 2021-9-2 15:39
7
0
好文章
雪    币: 268
活跃值: 活跃值 (129)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
风铃i 活跃值 2021-9-2 17:40
8
0
直接hook onkey event 打开 DevTools, 跟浏览器F12一样多方便
雪    币: 5770
活跃值: 活跃值 (1785)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
v0id_ 活跃值 2021-9-2 21:10
9
0
风铃i 直接hook onkey event 打开 DevTools, 跟浏览器F12一样多方便
onkey event是什么函数 愿闻其详
雪    币: 268
活跃值: 活跃值 (129)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
风铃i 活跃值 2021-9-9 22:48
10
0
alphc onkey event是什么函数 愿闻其详
struct _cef_client_t* cef_client = NULL;    
PVOID o_cef_browser_host_create_browser = NULL;    
PVOID o_cef_get_keyboard_handler = NULL;    
PVOID o_cef_on_key_event = NULL;    
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) {    
// DbgLog::Log(TEXT("[CEF] hook_cef_on_key_event, key: %d."), event->windows_key_code);    
if (event->type == KEYEVENT_KEYUP && event->windows_key_code == 123) {    
DbgLog::Log(TEXT("[CEF] press: F12"));    
auto cef_browser_host = browser->get_host(browser);    
/*    
        struct _cef_browser_host_t* self,    
            const struct _cef_window_info_t* windowInfo,    
            struct _cef_client_t* client,    
            const struct _cef_browser_settings_t* settings,    
            const cef_point_t* inspect_element_at);    
            */    
CefWindowInfo windowInfo{};    
CefBrowserSettings settings{};    
CefPoint point{};    
windowInfo.SetAsPopup(NULL, "DevTools");    
cef_browser_host->show_dev_tools(cef_browser_host, &windowInfo, cef_client, &settings, &point);    
}    
return reinterpret_cast<decltype(&hook_cef_on_key_event)>(o_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) {    
// DbgLog::Log(TEXT("[CEF] hook_cef_get_keyboard_handler, self: 0x%p"), self);    
auto keyboard_handler = reinterpret_cast<decltype(&hook_cef_get_keyboard_handler)>(o_cef_get_keyboard_handler)(self);    
if (keyboard_handler) {    
cef_client = self;    
o_cef_on_key_event = keyboard_handler->on_key_event;    
keyboard_handler->on_key_event = hook_cef_on_key_event;    
// DbgLog::Log(TEXT("[CEF] hook -> keyboard_handler.on_key_event 0x%p -> 0x%p\r\n"), o_cef_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_request_context_t* request_context){    
DbgLog::Log(TEXT("[CEF] cef_browser_host_create_browser -- hwnd: %d \r\n"), windowInfo->window);    
o_cef_get_keyboard_handler = client->get_keyboard_handler;    
client->get_keyboard_handler = hook_cef_get_keyboard_handler;    
DbgLog::Log(TEXT("[CEF] hook -> cef_get_keyboard_handler  0x%p -> 0x%p\r\n"), o_cef_get_keyboard_handler, hook_cef_get_keyboard_handler);    
return reinterpret_cast<decltype(&hook_cef_browser_host_create_browser)>(o_cef_browser_host_create_browser)    
(windowInfo, client, url, settings, request_context);    
}

自己注入dll去hook,完事f12一按直接开发者控制台

雪    币: 5770
活跃值: 活跃值 (1785)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
v0id_ 活跃值 2021-9-11 09:29
11
0
风铃i struct&nbsp;_cef_client_t*&nbsp;cef_client&nbsp;=&nbsp;NULL;&nbsp;&nbsp;& ...
感谢
游客
登录 | 注册 方可回帖
返回