Click here to Skip to main content
6,594,432 members and growing! (17,607 online)
Email Password   helpLost your password?
Desktop Development » Miscellaneous » General     Intermediate License: The Code Project Open License (CPOL)

The forceful implementation of features

By GD_Patrick

Apple’s Safari, unfortunately is missing some functionality that I require to surf the web. With the plugin API being currently unavailable, I decided to implement it on my own using DLL Injection and Hooking.
C++, Dev
Posted:4 Jul 2009
Views:3,003
Bookmarked:7 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
9 votes for this article.
Popularity: 4.70 Rating: 4.92 out of 5

1

2

3
1 vote, 11.1%
4
8 votes, 88.9%
5

Background

As a long time user of Firefox, I decided to switch to Apple’s Safari; unfortunately, the browser is missing some functionality that I require to surf the web, with the plug-in API being currently unavailable. I decided to implement it on my own by the usage of DLL-Injection and Hooking.

How it works

After our Dynamic Link Library is injected, we first have to import Apple’s Core Foundations in order to interface with the browser. Unfortunately, Apple unlinks their modules from the PEB, so that we have to do this in DllMain, or else we would have to jump through further hoops to get the Module Handles.

#define InitCFImport( x ) \
( *( FARPROC* )&##x ) = GetProcAddress( hmCoreFoundations, #x ); \
if( x == NULL ){ \
    ( *( FARPROC* )&##x ) = GetProcAddress( hmCFNetwork, #x );\
}\
if( x == NULL ){\
    MessageBoxA( 0, #x, "Unable to import", 0 );\
    return false;\
}

InitCFImport( CFStringGetSystemEncoding );
InitCFImport( CFStringGetCStringPtr );
InitCFImport( CFStringGetCharactersPtr );
InitCFImport( CFURLCopyAbsoluteURL );
InitCFImport( CFURLGetString );
InitCFImport( CFURLGetBaseURL );
InitCFImport( CFURLCreateWithString );
InitCFImport( CFStringGetCharacters );
InitCFImport( CFStringDelete );
InitCFImport( CFStringGetLength );
InitCFImport( CFURLRequestGetURL );

Now, with those imports, we can read which URL Safari is trying to access, and we also need a way to integrate ourselves into the Safari UI. I decided to use the “Page Button” because it seemed like the right place to me. But before we can place our entries there, we need to obtain the menu handle, which is why I hooked InsertMenuItemW. Basically, all I do there is to wait for Apple to add their entries so that I can insert mine. Please refer to “hkInsertMenuItemW” if you want to know more.

Now that we have inserted ourselves into Apple’s menu, we need to subclass their main-window. The problem with that is that Apple creates a multitude of windows of all kinds. In fact, they even create the MainWindow new for each “instance” of Safari. To handle that, I hooked “CreateWindowExW” to subclass the “Message-Handler” (please refer to “hkCreateWindowExW” if you want to know more ).

Last but not least, we need a way to figure out which URLs are being loaded and a way to prevent that from happening for undesired ones.

This is my solution:

Core::CFURLRef __cdecl hkCFURLRequestGetURL( Core::CFRequestRef refRequest )
{
    Core::CFURLRef pResult = Core::CFURLRequestGetURL( refRequest );

    DWORD dwReturnAddress = ( DWORD ) _ReturnAddress();
    DWORD dwModuleBase = ( DWORD ) Core::g_hmCFNetwork;

    if ( pResult && dwReturnAddress > dwModuleBase
    && dwReturnAddress < dwModuleBase + 0x57000 )
    {
        Core::CStringRef refUrlText = Core::CFURLGetString( pResult );
    
        if ( refUrlText )
        {
            wchar_t wszBuffer[2024];

            if ( Core::ConvertString( refUrlText, wszBuffer, 1024 ) )
            {
                // returns true if the content is to be blocked
                if ( ContentIndexer::Add( wszBuffer ) )
                {
                    return NULL;
                }
            }
        }
    }
    return pResult;
}

I check for the return address (location where the call to our hook originated from) to be within the boundaries of CFNetwork.dll because some callers of this function expect it to always return a valid value, although Apple’s SDK states that this function might fail. The only thing that’s left to do within the function is to check for URLs of interest and either index them or block them. The algorithms I use are very basic because speed matters here.

Thanks for reading.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

GD_Patrick


Member
i am patrick.
Occupation: Other
Location: Germany Germany

Other popular Miscellaneous articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 4 of 4 (Total in Forum: 4) (Refresh)FirstPrevNext
Generalthanks Pinmemberv3n0m44:29 25 Jul '09  
GeneralIrony who gives a rats arse.. Pinmemberstreetmedic3:44 25 Jul '09  
GeneralThe irony of all of this PinassociateJim Crafton8:55 8 Jul '09  
GeneralRe: The irony of all of this PinmemberLuka1:02 13 Jul '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 4 Jul 2009
Editor: Smitha Vijayan
Copyright 2009 by GD_Patrick
Everything else Copyright © CodeProject, 1999-2009
Web15 | Advertise on the Code Project