首页
社区
课程
招聘
[讨论]用默认浏览器在新窗口或新标签中打开URL链接的方法
发表于: 2011-9-3 17:18 9794

[讨论]用默认浏览器在新窗口或新标签中打开URL链接的方法

2011-9-3 17:18
9794
【讨论】用默认浏览器在新窗口或新标签中打开URL链接的方法
用ShellExecute打开链接,对于IE,基本上会覆盖已经打开的页面;直接创建iexplorer进程,参数填URL,则未必是默认浏览器。
目前我知道可以通过explorer来实现这个目的,假设要打开的URL是http://127.0.0.1,那么可以创建explorer.exe进程,参数是http://127.0.0.1;
如果URL里面有空格,例如http://127.0.0.1/ abc,那么参数可以加上双引号,也就是"http://127.0.0.1/ abc";
如果URL里面既有空格,又有双引号(囧),例如http://127.0.0.1/ "abc,那么可以用双双引号转移双引号,也就是"http://127.0.0.1/ ""abc"。
这个方法,从win98到win7x64,都可以实现“用默认浏览器在新窗口或新标签中打开URL链接”。
但是这个方法也有缺点,对于x64版本,所创建的explorer进程不会退出,虽然不断打开并不会导致explorer不断增多(貌似有上限),但总归是留下了一些垃圾。另外打开一个URL链接,还要借他人之手,实在是技术含量太低。
搜寻直接实现的方法,貌似找不到什么有用的结果,于是我自己跟踪了一遍explorer(系统xp-sp3),逆出部分代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <shtypes.h>

typedef struct BROWPARAM {
	HLOCAL hLocal;			//外网链接包含unicode链接地址,本地路径链接是NULL
	LPITEMIDLIST pidl;		//外网链接是NULL,本地路径链接指向路径位置
	DWORD dwFlag;			//外网链接是0x02000000,本地路径链接是0x00020000(纠错,新发现0x02000000是调用后直接返回,0x00020000等待窗口关闭后返回)
	DWORD dwUnknown;		//总是10,不知道是不是SW_SHOWDEFAULT
} BROWPARAM;

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	HMODULE hMod = LoadLibrary("browseui.dll");
	if (hMod != NULL)
	{
		BOOL (__stdcall* lpApi)(BROWPARAM*) = (BOOL (__stdcall*)(BROWPARAM*))GetProcAddress(hMod, (LPCSTR)106);
		if (lpApi != NULL)
		{
			LPCWSTR lpUrl = L"http://www.google.com";
			const size_t szUrl = (wcslen(lpUrl) + 1) * sizeof(WCHAR);
			HLOCAL hLocal = LocalAlloc(LMEM_FIXED, szUrl);
			if (hLocal != NULL)
			{
				void* p = LocalLock(hLocal);
				if (p != NULL)
				{
					memcpy(p, lpUrl, szUrl);
					LocalUnlock(hLocal);
					BROWPARAM bp = {hLocal, NULL, 0x02000000, 10};
					lpApi(&bp);
				}
				LocalFree(hLocal);
			}
		}
		FreeLibrary(hMod);
	}
	return 0;
}

经过虚拟机测试,win98、2k、xp均可运作,而vista、win7则不行,原因是GetProcAddress取不到106序号的导出函数(返回NULL),在vista上,用LordPE看了下browseui.dll,发现导出表里面倒是有106序号,但是对应部分却不是什么函数内容,而是一个字符串shunimpl.#110,不知是什么意思?另外跟踪了遍vista的explorer,发现打开链接是用COM实现的,虽然代码不长,不过有点累了,先不跟了,上来问问有没有人跟踪得出结论过,这样也就不用重复造轮子了。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
vista的已逆出代码
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <shtypes.h>
#include <shlobj.h>

class BROWINTERFACE : public IUnknown
{
public:
	virtual void __stdcall navigate(LPITEMIDLIST, DWORD dwShow, DWORD dwUnknown, DWORD dwUnknown1, HANDLE, DWORD dwUnknown2) = 0;
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	if (SUCCEEDED(CoInitialize(NULL)))
	{
		GUID nInterface, nClass;
		memcpy(&nInterface, "\x74\x84\x42\x78\x3B\x47\x60\x46\x90\x68\xF2\xAA\x7F\x6C\xB2\x27", sizeof(nInterface));
		memcpy(&nClass, "\xA7\x04\x63\xA8\xCA\x17\x95\x45\x99\xAB\x52\x30\x43\xA9\xC4\xAC", sizeof(nClass));
		BROWINTERFACE* p = NULL;
		if (SUCCEEDED(CoCreateInstance(nInterface, NULL, 1, nClass, (void**)&p)))
		{
			LPITEMIDLIST lpIDList = ILCreateFromPath("http://www.google.com");
			if (lpIDList != NULL)
			{
				p->navigate(lpIDList, 10, 0, 0, NULL, 0);
				ILFree(lpIDList);
			}
			p->Release();
		}
		CoUninitialize();
	}
}

win7的还不通用,囧!
2011-9-3 18:16
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
win7的如下:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <shtypes.h>
#include <shlobj.h>

class BROWINTERFACE : public IUnknown
{
public:
	virtual void __stdcall navigate(const GUID& nUnknown, LPITEMIDLIST, DWORD dwUnknown, DWORD dwUnknown1, DWORD dwUnknown2, DWORD dwShow) = 0;
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	if (SUCCEEDED(CoInitialize(NULL)))
	{
		GUID nInterface, nClass, nUnknown;
		memcpy(&nInterface, "\xCE\x9C\x84\x1F\x46\x25\x9F\x4B\xB0\x3E\x40\x04\x78\x1B\xDC\x40", sizeof(nInterface));
		memcpy(&nClass, "\x60\x46\x8E\x57\x03\xE4\x8F\x4E\x9F\xD4\x6D\x55\x9F\x7A\x0E\xDC", sizeof(nClass));
		memcpy(&nUnknown, "\xB7\xF2\xDF\x75\x36\x69\x06\x4C\xA8\xBB\x67\x6A\x7B\x00\xB2\x4B", sizeof(nUnknown));
		BROWINTERFACE* p = NULL;
		if (SUCCEEDED(CoCreateInstance(nInterface, NULL, 1, nClass, (void**)&p)))
		{
			LPITEMIDLIST lpIDList = ILCreateFromPath("http://www.google.com");
			if (lpIDList != NULL)
			{
				p->navigate(nUnknown, lpIDList, 0, 0, 0, 10);
				ILFree(lpIDList);
			}
			p->Release();
		}
		CoUninitialize();
	}
}


貌似没有通用的方法,
2011-9-5 10:43
0
雪    币: 1259
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
stu
4
cmd /c start "" bbs.pediy.com
或者读注册表获得默认浏览器的路径,然后加参数运行之.
另,空格可以用%20之类的代替试试.

不知道是否各个版本都支持。
2011-9-5 11:55
0
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
请教LZ是怎么跟踪explorer进程的,采用的什么工具,IDA还是OD,还是别的什么???
2011-9-5 17:41
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
OD跟踪。

过段时间,我准备再继续跟踪XP的BROWSEUI.DLL.#106函数,看看有什么技巧没有。
2011-9-6 13:02
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
无力了,跟踪XP的BROWERUI.#106,除了一大堆检测代码外,关键代码就是往ShellWindow发消息,精简后如下:
#include <stdio.h>
#include <stdlib.h>
#define _WIN32_WINNT	0x0500
#include <windows.h>
#include <shtypes.h>
#include <shlobj.h>
#include <shlwapi.h>

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	HMODULE hMod = LoadLibrary("shlwapi.dll");
	if (hMod != NULL)
	{
		HANDLE (__stdcall* lpSHAllocShared)(LPCVOID lpData, DWORD dwSize, DWORD dwProcessId) = \
			(HANDLE (__stdcall *)(LPCVOID , DWORD, DWORD))GetProcAddress(hMod, (LPCSTR)7);
		BOOL (__stdcall* lpSHFreeShared)(HANDLE hData, DWORD dwProcessId) = \
			(BOOL (__stdcall*)(HANDLE, DWORD))GetProcAddress(hMod, (LPCSTR)10);
		LPVOID (__stdcall* lpSHLockShared)(HANDLE hData, DWORD dwProcessId) = \
			(LPVOID (__stdcall*)(HANDLE, DWORD))GetProcAddress(hMod, (LPCSTR)8);
		BOOL (__stdcall* lpSHUnlockShared)(LPVOID lpData) = \
			(BOOL (__stdcall*)(LPVOID))GetProcAddress(hMod, (LPCSTR)9);
		HWND hWnd = GetShellWindow();
		DWORD dwPid = 0;
		GetWindowThreadProcessId(hWnd, &dwPid);
		if (AllowSetForegroundWindow(dwPid))
		{
			LPCWSTR lpUrl = L"http://www.google.com";
			const DWORD dwUrl = (lstrlenW(lpUrl) + 1) * sizeof(WCHAR);
			const DWORD dwSize = dwUrl + 0x44;
			HANDLE hl = lpSHAllocShared(NULL, dwSize, dwPid);
			if (hl != NULL)
			{
				DWORD* p = (DWORD*)lpSHLockShared(hl, dwPid);
				p[0] = dwSize;
				p[1] = 0x02000000;
				p[2] = 10;
				p[0x10] = 0x44;
				memcpy(p + 0x11, lpUrl, dwUrl);
				lpSHUnlockShared(p);
				if (!PostMessage(hWnd, 0x40B, 0, (LPARAM)hl))
					lpSHFreeShared(hl, dwPid); 
			}
		}
		FreeLibrary(hMod);
	}
	return 0;
}

而且这段代码在vista下一点反应都没有。再跟踪桌面explorer就费事了,再说吧……
2011-9-6 17:19
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
这个会覆盖已经存在的浏览器页面。

********************************

跟踪过Explorer代码,最终是调用browseui.#127,但是如果自己伪造参数调用,虽然可以用默认浏览器打开,但是浏览器窗口竟然是属于自己的进程的?!而不是新创建一个浏览器进程或者附属于已存在浏览器进程。

********************************

跟踪Vista的,结果在RPCRT4.DLL的空间跑来跑去,貌似没有跟踪价值。

********************************

发现在64位Win7下直接用com打开新链接,而不借助explorer,仍然有滞留的explorer进程。后来发现这个explorer是有参数的,“/factory,{75dff2b7-6936-4c06-a8bb-676a7b00b24b} -Embedding”,它是由某个svchost.exe创建的。也就是说即便是借助explorer完成这一任务,所滞留的explorer进程也不是所借助的那个进程

既然如此,也没有必要再追寻下去了……
2011-9-8 16:41
0
游客
登录 | 注册 方可回帖
返回
//