2012年10月20日星期六

mini_mfc.cpp


/*
mfc就从这个小程序开始吧!
下面摘自:AllVCLanguageSamples\C++\MFC\general\helloapp工程。
mfc目录下还有更多有用的东西呢!需要去学习分析原理。
把这个工程理解透了,也就大概知道了mfc,分析那些类的关系和实现吧!

如果是新建的空工程要有如下设置:
debug模式的设置:工程属性->配置属性->c/c++->code generation->runtime library->/MTd
release模式的设置:工程属性->配置属性->c/c++->code generation->runtime library->/MT

如果是新建的空工程无论是debug模式还是release模式都要加上:
#pragma comment(linker, "/subsystem:windows")

备注:use of mfc选项可以不设置。
*/


#include <afxwin.h>

class CHelloWindow : public CFrameWnd
{
public:
    CHelloWindow() //构造函数。
    {
        Create(NULL, _T("made by correy!"), WS_OVERLAPPEDWINDOW, rectDefault);
    }
};

class CHelloApp : public CWinApp
{
public:
    virtual BOOL InitInstance()
    {
        m_pMainWnd = new CHelloWindow();
        m_pMainWnd->ShowWindow(m_nCmdShow);
        m_pMainWnd->UpdateWindow();
        return TRUE;
    }
};

CHelloApp HelloApp; //程序从这里开始。

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

//或者下面的也可以。

/*
#include <afxwin.h>

extern "C" void _setenvp() { }
extern "C" void _setargv() { }

class CHelloWindow : public CWnd
{
public:
    CHelloWindow()
    {
        CreateEx(WS_EX_CLIENTEDGE, AfxRegisterWndClass(0, ::LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW+1)),
            _T("Hello World!"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, 0);
    }
};

class CHelloApp : public CWinApp
{
public:
    virtual BOOL InitInstance()
    {
        m_pMainWnd = new CHelloWindow();
        m_pMainWnd->ShowWindow(m_nCmdShow);
        m_pMainWnd->UpdateWindow();
        return TRUE;
    }
};

CHelloApp HelloApp;
*/

InternetGetCookie.Cpp


/*
获取cookie的函数困扰了我几个星期,网上很少找到示例。
微软的示例让人很难理解,很繁琐。

最终还是靠自己大胆的实验来证明,用自己的方法,所以:
made by correy
made at 2012.10.20
homepage:http://correy.webs.com
以前也许知道这,认为小事一桩,不削一顾,
可真正实现的时候,发现还是有点麻烦。
脚本的就不说了。很简单。
*/

#include <windows.h>

#include <Wininet.h>
#pragma comment(lib, "Wininet.lib")

#include <Shlobj.h>
#pragma comment(lib, "Shell32.lib")

int  main( int  argc,  char *  argv[])
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //这个我就不再写函数了,函数的声明可以定义为:bool get_cookie(IN TCHAR wsz_url, OUT TCHAR wsz_cookie);

    TCHAR szURL[256] = L"http://www.163.com";//注意:http://不可却。
    LPTSTR lpszData = 0;//这个也可以预先定义大小,但最好是动态获取。
    DWORD dwSize=0;

    //获取大小。
    bool b = InternetGetCookie(szURL, NULL, lpszData, &dwSize);
    if (!dwSize && b == false)
    {
        MessageBox(0,L"没有Cookie",szURL,0);//并非都有,有的没有。
        return 0;
    }

    lpszData = new TCHAR[dwSize];

    b = InternetGetCookie(szURL, NULL, lpszData, &dwSize);
    if (b && dwSize) //此时的dwSize的值是上面获取的一半。
    {
        MessageBox(0,lpszData,szURL,0);
    }

    delete[]lpszData;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //一下是设置或者改变Cookie,可以有两种形式,但必须配对使用方可成功。不能混合使用。
    //这个也可以写为函数,里面多一个日期的设置。
    //函数原型建议为:bool set_cookie(IN TCHAR wsz_url, IN TCHAR wsz_cookie);

    b = InternetSetCookie(szURL, NULL, TEXT("TestData = Test"));//这个方式,最后一个参数里面必须有等号。
    b = InternetSetCookie(szURL, NULL, TEXT("TestData = Test; expires = Sat,01-Jan-2015 00:00:00 GMT"));//显示用的。

    b = InternetSetCookie(szURL, L"QQ", TEXT("112426112"));  //这个会自动加等号。
    //b = InternetSetCookie(szURL, NULL, TEXT("QQ = 112426112"));
    b = InternetSetCookie(szURL, NULL, TEXT("QQ = 112426112; expires = Sat,01-Jan-2015 00:00:00 GMT"));

    //b = InternetSetCookie(szURL, L"email", TEXT("kouleguan@hotmail.com"));
    b = InternetSetCookie(szURL, NULL, TEXT("email = kouleguan@hotmail.com"));
    b = InternetSetCookie(szURL, NULL, TEXT("email = kouleguan@hotmail.com; expires = Sat,01-Jan-2015 00:00:00 GMT"));

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /*
    关于cookie的位置,

    1.SHGetSpecialFolderPath函数的CSIDL_COOKIES参数应该能获取。
      例如:在win 7 32里面是:C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Cookies
      这个Cookies文件夹默认是隐藏的。
      这里的名字带后缀.txt,但名字好像加密了。
      里面有个Low目录。

    2.internet选项->常规选项卡的浏览历史记录的设置按钮->internet临时文件的当前位置。
      例如:在win 7 32里面是:C:\Users\Administrator\AppData\Local\Microsoft\Windows\Temporary Internet Files。
      这个文件夹Temporary Internet Files,默认页式隐藏的。
      这里的名字例如:Cookie:administrator@163.com/
      其实这里的文件指向上面。也许是因为上面的不好找,加密了。

    */

    TCHAR sz_cookie[MAX_PATH] = {0};
    b = SHGetSpecialFolderPath(0,sz_cookie,CSIDL_COOKIES,0);
    if (b)
    {
        MessageBox(0,sz_cookie,L"cookie的目录是:",0);//或者直接打开目录。
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    return   0 ;
}

/*
参考:
InternetGetCookie:
http://msdn.microsoft.com/en-us/library/aa384710(v=vs.85).aspx

InternetSetCookie:
http://msdn.microsoft.com/en-us/library/aa385107(v=vs.85).aspx

Managing Cookies:
http://msdn.microsoft.com/en-us/library/aa385326(v=vs.85).aspx

HTTP Cookies:
http://msdn.microsoft.com/en-us/library/aa384321(v=vs.85).aspx

还有扩展的:InternetGetCookieEx,InternetSetCookieEx就不说了。
*/

2012年10月16日星期二

IsNetworkAlive.Cpp


//判断是否联网的几种办法。

#include <windows.h>

#include <Intshcut.h>
#pragma comment (lib,"Url.lib")

#include <Sensapi.h>
#pragma comment (lib,"Sensapi.lib")

#include <Wininet.h>
#pragma comment (lib,"Wininet.lib")

int _tmain(int argc, char* argv[])
{
    ////////////////////////////////////////////////////////////////////////////////

    /*
    Determines whether the system is connected to the Internet.
    Returns TRUE if the local system is not currently connected to the Internet.
    Returns FALSE if the local system is connected to the Internet or
    if no attempt has yet been made to connect to the Internet.
    总是返回false。不准确,不可用。
    */

    bool b = InetIsOffline(0);
    /*if (b == true)
    {
        MessageBox(0,L"没有联网",0,0);
    }
    else
    {
        MessageBox(0,L"已经联网",0,0);
    }*/

    ////////////////////////////////////////////////////////////////////////////////

    DWORD d;
    b = IsNetworkAlive(&d);  
    if (GetLastError() == 0)
    {
        if (b == true)
        {        

            if ((d & NETWORK_ALIVE_LAN) == NETWORK_ALIVE_LAN)
            {
                MessageBox(0,L"联网方式:NETWORK_ALIVE_LAN",L"已经联网",0);
            }

            if ((d & NETWORK_ALIVE_WAN) == NETWORK_ALIVE_WAN)
            {
                MessageBox(0,L"联网方式:NETWORK_ALIVE_WAN",L"已经联网",0);
            }

            if ((d & NETWORK_ALIVE_AOL) == NETWORK_ALIVE_AOL)
            {
                MessageBox(0,L"联网方式:NETWORK_ALIVE_AOL",L"已经联网",0);
            }

        }
        else if (b == false)
        {
            MessageBox(0,L"没有联网",0,0);
        }/**/
    }

    ////////////////////////////////////////////////////////////////////////////////

    b = InternetGetConnectedState(&d,0);
    if (b == true)
    {      

        if ((d & INTERNET_CONNECTION_MODEM) ==INTERNET_CONNECTION_MODEM)
        {
            MessageBox(0,L"联网方式:拨号上网",L"已经联网",0);
        }

        if ((d & INTERNET_CONNECTION_LAN) ==INTERNET_CONNECTION_LAN)
        {
            MessageBox(0,L"联网方式:通过局域网",L"已经联网",0);
        }

        if ((d & INTERNET_CONNECTION_PROXY) ==INTERNET_CONNECTION_PROXY)
        {
            MessageBox(0,L"联网方式:代理",L"已经联网",0);
        }

        //if ((d & INTERNET_CONNECTION_MODEM_BUSY) ==INTERNET_CONNECTION_MODEM_BUSY) //这个不会出现。
        //{
        //    MessageBox(0,L"联网方式:调制调解器繁忙",L"已经联网",0);
        //}      

        if ((d & INTERNET_CONNECTION_CONFIGURED) ==INTERNET_CONNECTION_CONFIGURED)
        {
            MessageBox(0,L"联网方式:INTERNET_CONNECTION_CONFIGURED",L"已经联网",0);
        }

    }
    else if (b == false)
    {
        MessageBox(0,L"没有联网",0,0);

        //下面这两个有可能会出现。

        if ((d & INTERNET_RAS_INSTALLED) ==INTERNET_RAS_INSTALLED)
        {
            MessageBox(0,L"原因:INTERNET_RAS_INSTALLED",L"没有联网",0);//这个会运行。
        }

        if ((d & INTERNET_CONNECTION_OFFLINE) ==INTERNET_CONNECTION_OFFLINE)
        {
            MessageBox(0,L"断网",0,0); //这个不会显示。
        }

    }/**/

    ////////////////////////////////////////////////////////////////////////////////

    //这个函数也不行,总是返回ERROR_SUCCESS。
    b = InternetAttemptConnect(0);
    /*if(b == ERROR_SUCCESS)
    {
        MessageBox(0,L"已经联网",0,0);
    }
    else
    {
        MessageBox(0,L"没有联网",0,0);
    }*/

    ////////////////////////////////////////////////////////////////////////////////

   //这个函数也不行
   //BOOL InternetGoOnline(_In_  LPTSTR lpszURL, _In_  HWND hwndParent, _In_  DWORD dwFlags);

}

2012年10月13日星期六

MiniDumpWriteDump.Cpp


/*
能分析dump文件很重要,但不完美,还要会生成dmp文件。
windbg的分析就不说了,vs中的配置如下:
1.把dmp文件和pdb文件放置在同一个文件夹中
2.设置dmp文件用vs打开,然后双击dmp文件
3.在解决方案上右键->选择调试->二选一(选择任意一个即可)。
*/

#include <windows.h>
#include <DbgHelp.h>

#pragma comment (lib,"DbgHelp.lib")

LONG TopLevelExceptionFilter(_In_  struct _EXCEPTION_POINTERS * ExceptionInfo)
{  
    //这里还可以利用传递过来的参数得到调用栈信息.

    HANDLE hFile = CreateFile(L"dump.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if( ( hFile == NULL ) && ( hFile == INVALID_HANDLE_VALUE ) )
    {
        return EXCEPTION_EXECUTE_HANDLER;
    }

    //这个结构也可以不填写,相应的MiniDumpWriteDump函数的这个位置应填写0,这主要用于dump正在正常运行的进程。
    MINIDUMP_EXCEPTION_INFORMATION mei;
    mei.ExceptionPointers = ExceptionInfo;
    mei.ThreadId = GetCurrentThreadId();
    mei.ClientPointers = false;//TRUE 微软建议设置为0

    MINIDUMP_TYPE DumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo |
        MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules | MiniDumpWithFullAuxiliaryState);
    //tiny的配置:MiniDumpNormal
    //mini的配置:MINIDUMP_TYPE mdt  = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory);
    //midi的配置:MINIDUMP_TYPE mdt  = (MINIDUMP_TYPE)(MiniDumpWithPrivateReadWriteMemory | MiniDumpWithDataSegs |
    //    MiniDumpWithHandleData | MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules );
    //全部的组合是:(MINIDUMP_TYPE)0x0007ffff

    //这个函数还有回调,用户自定义等信息,这里没有使用。
    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, DumpType, &mei, NULL, NULL);
    CloseHandle(hFile);

    //正规的程序,再弹出个框,加上发送的功能。发送成功与否,设置标志,以便失败的时候,以后再发送。

    return EXCEPTION_EXECUTE_HANDLER;
}

int main()
{
    //用此函数:_CrtSetReportMode,下面的函数可能会无效,不过这个函数只在debug下才有效。
    //如果要监控服务的异常处理,需要加入服务的入口,而非正常的各种main函数。
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)TopLevelExceptionFilter);

    int * p = 0;
    *p = 0;

    return 0;
}


/*
在服务中可以使用的选项有:
tiny的配置:MiniDumpNormal
mini的配置:MINIDUMP_TYPE mdt  = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory);

可能在任何情况下都与:启动和故障恢复的写入调试信息的设置有关。经测试与这无关。
失败的情况下一定结合上面的配置要看MiniDumpWriteDump的GetLastError()信息内容。

例如:0x0000012B 是 仅完成部分的 ReadProcessMemory 或 WriteProcessMemory 请求。
          0x00000012 没有更多文件。
          还有一个是参数错误。
*/

2012年10月11日星期四

_CrtSetDbgFlag.Cpp


/*
内存泄露检查
是应用层的,仅限于调试模式(可能也可以用于发行版加_DEBUG)的new,malloc等操作。
对于申请内存的VirtualAlloc和HeapAlloc无效,主要用hook的办法实现。
我从来不用new,delete,malloc,free,所以此办法对我用处不大。
本文参考自:http://msdn.microsoft.com/zh-cn/library/e5ewb1h3(v=vs.90).aspx(启用内存泄漏检测)
*/

//检测内存泄漏的主要工具是调试器和 C 运行时库 (CRT) 调试堆函数。若要启用调试堆函数,请在程序中包括以下语句:

//#include 语句必须采用上文所示顺序。如果更改了顺序,所使用的函数可能无法正确工作。
#define _CRTDBG_MAP_ALLOC //会显示在其中分配泄漏的内存的文件。文件名后括号中的数字是该文件内的行号
#include <stdlib.h>
#include <crtdbg.h>

//通过包括 crtdbg.h,将 malloc 和 free 函数映射到其“Debug”版本 _malloc_dbg 和 _free_dbg,这些函数将跟踪内存分配和释放。
//此映射只在调试版本(在其中定义了 _DEBUG)中发生。发布版本使用普通的 malloc 和 free 函数。

//#define 语句将 CRT 堆函数的基版本映射到对应的“Debug”版本。
//并非绝对需要该语句,但如果没有该语句,内存泄漏转储包含的有用信息将较少。

#include <windows.h>

int main()
{  
    //该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。
    //必须同时设置 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_ALLOC_MEM_DF 两个位域
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

    volatile char * vch = new volatile char[20];
    char * p1 = (char *)malloc( 34 );//这个会显示代码的行号

    LPVOID lpvBase  = VirtualAlloc(NULL, 4096, MEM_RESERVE, PAGE_NOACCESS);
    ULONG_PTR * aPFNs = (ULONG_PTR *) HeapAlloc(GetProcessHeap(), 0, 512);  

    //_CrtDumpMemoryLeaks();//转储内存泄漏信息,加上这一行会重复输出到输出窗口。
    //当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“输出”窗口中显示内存泄漏信息

    //可以使用以下语句将输出位置设置回“输出”窗口:
    //_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );//加上这一行会重复输出到输出窗口。

    return 0;
}

/*
未定义 _CRTDBG_MAP_ALLOC 时,显示格式的说明:
内存分配编号(在大括号内)。
块类型(普通、客户端或 CRT)。
十六进制形式的内存位置。
以字节为单位的块大小。
前 16 字节的内容(亦为十六进制)。
例如:
Detected memory leaks!
Dumping objects ->
{57} normal block at 0x003D4A30, 20 bytes long.//主要是看这一行。
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

转到源文件中分配内存的行的两种办法:注意是:包含文件名和行号的行
1.在“输出”窗口中双击包含文件名和行号的行。
2.在“输出”窗口中选择包含文件名和行号的行,然后按 F4 键。
*/

2012年10月9日星期二

DebugBreak.Cpp


/*
以前知道检测调试器用微软的IsDebuggerPresent,这几天又发现微软提供的一个办法:用异常处理。

IsDebuggerPresent()的实现代码是:jmp到这里(下面)。
75D6F41B 64 A1 18 00 00 00 mov         eax,dword ptr fs:[00000018h]
75D6F421 8B 40 30         mov         eax,dword ptr [eax+30h]
75D6F424 0F B6 40 02      movzx       eax,byte ptr [eax+2]
75D6F428 C3               ret

其实DebugBreak()就是几个jmp,然后jmp到这里:
75D93E2C 8B FF            mov         edi,edi
75D93E2E CC               int         3  
75D93E2F C3               ret
*/

#include <windows.h>

BOOL CheckForDebugger()
{
    __try
    {
        DebugBreak();
    }
    __except(GetExceptionCode() == EXCEPTION_BREAKPOINT ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
    {   // No debugger is attached, so return FALSE and continue.
        return FALSE;
    }
    return TRUE;
}

VOID main(VOID)
{
    bool b = IsDebuggerPresent();
    if (b == 0)
    {
        MessageBox(0,L"不在调试器中",0,0);      
    }
    else
    {
        MessageBox(0,L"在调试器中",0,0);      
    }

    b = CheckForDebugger();
    if (b == 0)
    {
        MessageBox(0,L"不在调试器中",0,0);      
    }
    else
    {      
        MessageBox(0,L"在调试器中",0,0);
    }
}
//made by correy
//made at 2012.10.09

2012年10月7日星期日

FSCTL_QUERY_USN_JOURNAL.Cpp


//ntfs的冰山一角:Change Journal Records,更多的功能有待发掘和理解。
//本文稍微修改自:http://msdn.microsoft.com/en-us/library/aa365736%28v=VS.85%29.aspx
#include <Windows.h>
#include <WinIoCtl.h>
#include <stdio.h>

void main()
{
    HANDLE hVol = CreateFile( TEXT("\\\\.\\c:"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
    if( hVol == INVALID_HANDLE_VALUE )   {
        return;
    }

    //获取JournalData结构及dwBytes个数。
    DWORD dwBytes;
    USN_JOURNAL_DATA JournalData;
    if( !DeviceIoControl( hVol, FSCTL_QUERY_USN_JOURNAL, NULL, 0, &JournalData, sizeof(JournalData), &dwBytes, NULL) )   {
        return;
    }

    READ_USN_JOURNAL_DATA ReadData = {0, 0xFFFFFFFF, FALSE, 0, 0};
    ReadData.UsnJournalID = JournalData.UsnJournalID;

    printf( "Journal ID: %I64x\n", JournalData.UsnJournalID );
    printf( "FirstUsn: %I64x\n\n", JournalData.FirstUsn );

    for(int I=0; I<=10; I++)
    {
        CHAR Buffer[4096] = {0};

        //dwBytes有返回值。
        if( !DeviceIoControl( hVol, FSCTL_READ_USN_JOURNAL, &ReadData, sizeof(ReadData), &Buffer, sizeof (Buffer), &dwBytes, NULL) )    {
            return;
        }

        DWORD dwRetBytes = dwBytes - sizeof(USN);      
        PUSN_RECORD UsnRecord = (PUSN_RECORD)(((PUCHAR)Buffer) + sizeof(USN)); // Find the first record

        printf( "****************************************\n");
       
        while( dwRetBytes > 0 )// This loop could go on for a long time, given the current buffer size.
        {
            printf( "USN: %I64x\n", UsnRecord->Usn );
            printf("File name: %.*S\n", UsnRecord->FileNameLength/2, UsnRecord->FileName );
            printf( "Reason: %x\n", UsnRecord->Reason );
            printf( "\n" );

            dwRetBytes -= UsnRecord->RecordLength;          
            UsnRecord = (PUSN_RECORD)(((PCHAR)UsnRecord) + UsnRecord->RecordLength); // Find the next record
        }
       
        ReadData.StartUsn = *(USN *)&Buffer; // Update starting USN for next call
    }

    CloseHandle(hVol);
}