2012年12月26日星期三

IWebBrowserApp.Cpp


/*

本文取名为:IWebBrowserApp.Cpp

下载数据有很多种办法,如:
1.URLDownloadToFile或者URLDownloadToCacheFile
2.HttpOpenRequest
3.WinHttpReadData
4.IWinHttpRequest
5.脚本的"WinHttp.WinHttpRequest.5.1"
6.SOCKET,自己写http头。
7.其他接口,如本文的,就有可能。
8.驱动
9.其他。

类似的上传数据也和上面的大同小异

首先搭建服务器,并且成功。

其次,建立一个asp文件,用于处理接收到的数据,命名为data.asp,内容如下:

<%
Dim vntPostedData, lngCount

Response.AddHeader "Request-Method", Request.ServerVariables("REQUEST_METHOD")

lngCount = Request.TotalBytes
if (lngCount <> 0) then
vntPostedData = Request.BinaryRead(lngCount)
Response.BinaryWrite vntPostedData
end if
%>

以上代码摘自:Microsoft SDKs\Windows\v7.1\Samples\web\winhttp\winhttppostsample\data.asp。

并把此文件放到iis服务器中,例如:C:\inetpub\wwwroot\data.asp.
此文件不必放在浏览器中主动的打开,因为你主动的打开是看不到啥的。

运行下面的代码,既可以看到你发送的数据。

下面的代码修改自:
如何自动发送表单数据到 Internet Explorer
http://support.microsoft.com/kb/q167658
*/

#include <windows.h>
#define INITGUID
#include <initguid.h>
#include <exdisp.h>
#include <memory.h>

HRESULT GetPostData(LPVARIANT pvPostData);

void main()
{
    HRESULT hr;
    IWebBrowserApp* pWBApp = NULL; // Derived from IWebBrowser
    BSTR bstrURL = NULL, bstrHeaders = NULL;
    VARIANT vFlags = {0},
        vTargetFrameName = {0},
        vPostData = {0},
        vHeaders = {0};

    if (FAILED(hr = CoInitialize(NULL)))
    {
        return;
    }

    if (FAILED(hr = CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_SERVER, IID_IWebBrowserApp, (LPVOID*)&pWBApp)))
    {
        goto Error;
    }

    bstrURL = SysAllocString(L"http://127.0.0.1/data.asp");//http://<server>/scripts/navpost.asp
    if (!bstrURL)
    {
        goto Error;
    }

    bstrHeaders = SysAllocString(L"Content-Type: application/x-www-form-urlencoded\r\n");
    if (!bstrHeaders)
    {
        goto Error;
    }

    V_VT(&vHeaders) = VT_BSTR;
    V_BSTR(&vHeaders) = bstrHeaders;

    hr = GetPostData(&vPostData);
    hr = pWBApp->Navigate(bstrURL, &vFlags, &vTargetFrameName, &vPostData, &vHeaders);
    pWBApp->put_Visible(VARIANT_TRUE);//显示。

Error:
    if (bstrURL) SysFreeString(bstrURL);
    if (bstrHeaders) SysFreeString(bstrHeaders);
    VariantClear(&vPostData);
    if (pWBApp) pWBApp->Release();
    CoUninitialize();
}

// Pack some data into a SAFEARRAY of BYTEs. Return in a VARIANT
HRESULT GetPostData(LPVARIANT pvPostData)
{
    HRESULT hr;
    LPSAFEARRAY psa;
    LPCTSTR cszPostData = "made by correy";//FName=Matt&Flavor=Mocha+Chip
    UINT cElems = lstrlen(cszPostData);
    LPSTR pPostData;

    if (!pvPostData)
    {
        return E_POINTER;
    }

    VariantInit(pvPostData);

    psa = SafeArrayCreateVector(VT_UI1, 0, cElems);
    if (!psa)
    {
        return E_OUTOFMEMORY;
    }

    hr = SafeArrayAccessData(psa, (LPVOID*)&pPostData);
    memcpy(pPostData, cszPostData, cElems);
    hr = SafeArrayUnaccessData(psa);

    V_VT(pvPostData) = VT_ARRAY | VT_UI1;
    V_ARRAY(pvPostData) = psa;
    return NOERROR;
}

2012年12月19日星期三

CDO.Message.vbs


'一直以为只有在服务端或者安装有iis等的电脑上才有CDO.Message组件,才可以发送邮件。
'其实有时候.send失败,原因好久没有查出。
'这次试验成功,特保存。

Const Email_From = "leguanyuan@163.com" '发件人邮箱
Const Password = "XXXXXXXX" '发件人邮箱密码
Const Email_To = "112426112@qq.com" '收件人邮箱

Set CDO = CreateObject("CDO.Message") '创建CDO.Message对象
CDO.Subject = "test" '邮件主题
CDO.From = Email_From '发件人地址
CDO.To = Email_To '收件人地址
CDO.TextBody = "Hello world!" '邮件正文
'cdo.AddAttachment = "C:\hello.txt" '邮件附件文件路径
Const schema = "http://schemas.microsoft.com/cdo/configuration/" '规定必须是这个,我也不知道为什么

With CDO.Configuration.Fields '用with关键字减少代码输入
.Item(schema & "sendusing") = 2 '使用网络上的SMTP服务器而不是本地的SMTP服务器
.Item(schema & "smtpserver") = "smtp.163.com" 'SMTP服务器地址
.Item(schema & "smtpauthenticate") = 1 '服务器认证方式
.Item(schema & "sendusername") = Email_From '发件人邮箱
.Item(schema & "sendpassword") = Password '发件人邮箱密码
.Item(schema & "smtpserverport") = 465 'SMTP服务器端口
.Item(schema & "smtpusessl") = True '是否使用SSL
.Item(schema & "smtpconnectiontimeout") = 60 '连接服务器的超时时间
.Update '更新设置
End With

CDO.Send '发送邮件

2012年12月12日星期三

Win32_Process.vbs


'在远程电脑运行远程电脑上的一个文件(程序)
'made at 2012.07.07
'email:kouleguan at hotmail dot com
'homepage:http://correy.webs.com

strComputer ="10.101.0.99"
strUserName="administrator"
strPassword="123456"

Set swbeml=createobject("wbemscripting.swbemlocator")
set rcimv2=swbeml.connectserver(strComputer,"root/cimv2",strUserName,strPassword)
Set Process=rcimv2.get("Win32_Process")
Process.create("secedit /export /cfg inf.inf") '不会显示界面。文件生成在系统目录。

2012年12月10日星期一

KeSetTimerEx.C


/*
时间很重要,在现实中如是,在计算机中亦是,如时钟中断。
时间怎能不会,特别是阴阳历转换。
此文展示几种用法,暂命名为KeSetTimerEx.C,
因为IoInitializeTimer需要一个设备对象。
KeSetTimerEx对dpc可有可无,使用更方便。

本文的不足之处,可能是定时器对象的删除等,
不然内存泄露,verifier.exe报错。

made by correy
made at 2012.12.10
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>

PVOID g_pkThread;

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    PDEVICE_OBJECT pdoNextDeviceObj;

    KeWaitForSingleObject(g_pkThread, Executive, KernelMode, FALSE, NULL);
    ObDereferenceObject(g_pkThread);

    pdoNextDeviceObj = DriverObject->DeviceObject;//pdoGlobalDrvObj
    //IoDeleteSymbolicLink(&usSymlinkName);//本程序没有创建符号链接。

    while(pdoNextDeviceObj) // Delete all the device objects
    {
        PDEVICE_OBJECT pdoThisDeviceObj = pdoNextDeviceObj;
        pdoNextDeviceObj = pdoThisDeviceObj->NextDevice;
        IoDeleteDevice(pdoThisDeviceObj);
    }
}

KSTART_ROUTINE ThreadStart;
VOID ThreadStart(__in PVOID  StartContext)
{
    KdPrint(("创建线程的完整规范示例用法,注意卸载的时候!\n"));
    PsTerminateSystemThread(STATUS_SUCCESS);
}

IO_TIMER_ROUTINE IoTimer;
VOID IoTimer(__in PDEVICE_OBJECT DeviceObject, __in_opt PVOID  Context)
{
    DbgPrint("i am in IoTimer!\n");
    KeSetEvent((PKEVENT)Context, 0, FALSE);
}

KDEFERRED_ROUTINE CustomDpc;
VOID CustomDpc(
               __in struct _KDPC  *Dpc,
               __in_opt PVOID  DeferredContext,
               __in_opt PVOID  SystemArgument1,
               __in_opt PVOID  SystemArgument2)
{
    DbgPrint("i am in CustomDpc!\n");
    KeSetEvent((PKEVENT)DeferredContext, IO_NO_INCREMENT, FALSE);//结束。
    //还可以再调用KeSetTimer,但是要注意次数,和参数。  特别注意时间。  
}

DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    LARGE_INTEGER   li;
    HANDLE  ThreadHandle;
    UNICODE_STRING usDeviceName;
    PDEVICE_OBJECT pdoDeviceObj = 0;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    KEVENT  ke;
    KTIMER kt;
    BOOLEAN b;
    KDPC  dpc;
    int i;

    //KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = Unload;

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

    KdPrint(("暂停5秒:KeStallExecutionProcessor\n"));
    KeStallExecutionProcessor(5000000);//5秒钟。

    //////////////////////////////////////////////////////////////////////////
    KdPrint(("暂停5秒:KeDelayExecutionThread\n"));
    li.QuadPart = (5 * (((-10) * 1000) * 1000)); //负数是暂停5秒钟。
    status = KeDelayExecutionThread(KernelMode, FALSE, &li);
    if (status != STATUS_SUCCESS)
    {
        KdPrint(("KeDelayExecutionThread return:%d\n", status));
        //return r;
    }
    //////////////////////////////////////////////////////////////////////////
    RtlInitUnicodeString(&usDeviceName, L"\\Device\\correy"); //必须创建设备。
    status = IoCreateDevice(DriverObject, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pdoDeviceObj);
    if(!NT_SUCCESS(status))
    {
        return status;
    }

    KeInitializeEvent(&ke, NotificationEvent, FALSE);

    IoInitializeTimer(pdoDeviceObj, IoTimer, &ke);//感觉和WorkItem差不多,只不过把方法改名为开始和结束。
    IoStartTimer(pdoDeviceObj);

    KeWaitForSingleObject(&ke, Executive, KernelMode, FALSE, NULL);
    IoStopTimer(pdoDeviceObj);
    //////////////////////////////////////////////////////////////////////////
    KeInitializeTimerEx(&kt, SynchronizationTimer);

    li.QuadPart = (5 * (((-10) * 1000) * 1000));

    //第三个参数,如果是负数,会失败,并且蓝屏。并且不能大于#define MAXLONG     0x7fffffff  // winnt
    b = KeSetTimerEx(&kt, li, 5000000, 0);//其实有5个参数。如kmdkit里面的用法,ida里面也是的。
    if (b == 1)
    {
        KdPrint(("the timer object was already in the system timer queue\n"));
        //继续前进,千万不要退出。注意,注意,再注意。
    }

    for (i = 0; i < 3; i++)
    {
        KeWaitForSingleObject(&kt, Executive, KernelMode, FALSE, NULL);
        KdPrint(("KeSetTimer:5秒%d次\n", i+1));
        KeSetTimerEx(&kt, li, 5000000, 0);
    }

    b = KeCancelTimer(&kt);
    if (b == 0)
    {
        return b;
    }
    //////////////////////////////////////////////////////////////////////////
    KeResetEvent(&ke);
    KeInitializeTimerEx(&kt, SynchronizationTimer);
    KeInitializeDpc(&dpc, CustomDpc, &ke);//最后一个参数是传递用的。

    li.QuadPart = (5 * (((-10) * 1000) * 1000));

    KdPrint(("5秒后调用CustomDpc函数\n", i));

    //第三个参数,如果是负数,会失败,并且蓝屏。并且不能大于#define MAXLONG     0x7fffffff  // winnt
    b = KeSetTimerEx(&kt, li, 5000000, &dpc);//其实有5个参数。
    if (b == 1)
    {
        KdPrint(("the timer object was already in the system timer queue\n"));
        //继续前进,千万不要退出。注意,注意,再注意。
    }

    KeWaitForSingleObject(&ke, Executive, KernelMode, FALSE, NULL);

    b = KeCancelTimer(&kt);
    if (b == 0)
    {
        return b;
    }

    KeClearEvent(&ke);
    KeCancelTimer(&kt);
    //////////////////////////////////////////////////////////////////////////
    status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, ThreadStart, NULL);
    if (status != STATUS_SUCCESS)
    {
        KdPrint(("PsCreateSystemThread return:%d\n", status));
        //return r;
    }
    else
    {
        ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &g_pkThread, NULL);
        ZwClose(ThreadHandle);
    }
    //////////////////////////////////////////////////////////////////////////

    return 0;
}

2012年12月8日星期六

工作线程两例

/*
工作线程或者劳务线程,很重要,比起一般的内核线程。
它的运行环境不一般,在system中,特别是IRQL。
适用于小的任务,很方便。

made by correy
made at 2012.12.08
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>

VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
    PDEVICE_OBJECT pdoNextDeviceObj = DriverObject->DeviceObject;//pdoGlobalDrvObj
    //IoDeleteSymbolicLink(&usSymlinkName);//本程序没有创建符号链接。
   
    while(pdoNextDeviceObj) // Delete all the device objects
    {
        PDEVICE_OBJECT pdoThisDeviceObj = pdoNextDeviceObj;
        pdoNextDeviceObj = pdoThisDeviceObj->NextDevice;
        IoDeleteDevice(pdoThisDeviceObj);
    }
}

IO_WORKITEM_ROUTINE WorkItem;
VOID WorkItem(__in PDEVICE_OBJECT  DeviceObject, __in_opt PVOID  Context)
{//如果不是同步的,有可能在DriverEntry函数运行结束后才运行到这里。
    DbgPrint("i am in WorkItem!\n");
    KeSetEvent((PKEVENT)Context, 0, FALSE);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    UNICODE_STRING usDeviceName;
    PDEVICE_OBJECT pdoDeviceObj = 0;
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    PIO_WORKITEM g_piowi;
    KEVENT       g_ke;

    KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = OnUnload;
   
    RtlInitUnicodeString(&usDeviceName, L"\\Device\\correy"); //必须创建设备,特别是Vista以前。
    status = IoCreateDevice(DriverObject, 0, &usDeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pdoDeviceObj);
    if(!NT_SUCCESS(status))
    {
        return status;
    }
 
    g_piowi = IoAllocateWorkItem(pdoDeviceObj); //参数是设备对象的指针,不是驱动对象的指针。不然WorkItem退出的时候,蓝屏。
    if (g_piowi == 0)
    {
        return STATUS_INSUFFICIENT_RESOURCES;
    }
   
    //IoInitializeWorkItem和IoAllocateWorkItem的功能差不多。
    //If the caller will later pass the work item to IoQueueWorkItem, IoObject must point to a device object.
    //IoInitializeWorkItem(DriverObject, &g_piowi);//Versions: Available on Windows Vista and later versions of Windows.

    KeInitializeEvent(&g_ke, SynchronizationEvent, FALSE);//设置事件以便同步,也可以不同步。就多3行代码。
    IoQueueWorkItem(g_piowi, &WorkItem, DelayedWorkQueue, &g_ke);
    KeWaitForSingleObject(&g_ke, Executive,KernelMode, FALSE, NULL);

    if (g_piowi)
    {
        IoFreeWorkItem(g_piowi);
    }

    return STATUS_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
其实这个办法跟简单,没有和设备关联,而且暂时没有被软件废弃。

made by correy
made at 2012.08.13
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntifs.h>

#define TAG 'tset' //本驱动在内存中的标志,即test.

typedef struct WorkItemContext{
    PWORK_QUEUE_ITEM Item;
    HANDLE Pid;
}WorkItemContext;

PVOID allocate(IN SIZE_T NumberOfBytes)
{
    PVOID p = NULL;

    //PAGED_CODE();
    if (KeGetCurrentIrql() > DISPATCH_LEVEL)
    {
        KdBreakPoint();//DbgBreakPoint()
    }

    /*
    Callers of ExAllocatePoolWithTag must be executing at IRQL <= DISPATCH_LEVEL.
    A caller executing at DISPATCH_LEVEL must specify a NonPagedXxx value for PoolType.
    A caller executing at IRQL <= APC_LEVEL can specify any POOL_TYPE value, but the IRQL and environment must also be considered for determining the page type.
    */

    p = ExAllocatePoolWithTag(NonPagedPool, NumberOfBytes, TAG);
    if (p == NULL ) {
        return p;
    }

    /*
    Warning  Memory that ExAllocatePoolWithTag allocates is uninitialized.
    A kernel-mode driver must first zero this memory if it is going to make it visible to user-mode software (to avoid leaking potentially privileged contents).
    */

    RtlZeroMemory(p, NumberOfBytes);

    return p;
}


VOID free(IN PVOID p)
{
    unsigned long r;

    /*
    Callers of ExFreePoolWithTag must be running at IRQL <= DISPATCH_LEVEL.
    A caller at DISPATCH_LEVEL must have specified a NonPagedXxx PoolType when the memory was allocated.
    Otherwise, the caller must be running at IRQL <= APC_LEVEL.
    */

    //PAGED_CODE();

    if (KeGetCurrentIrql() > DISPATCH_LEVEL)
    {
        KdBreakPoint();//DbgBreakPoint()
    }

    if (p) //防止多次释放导致的蓝屏。
    {      
        __try //防止传入非法的地址。
        {
            r = MmIsAddressValid(p);
            ExFreePoolWithTag(p, TAG);//KeGetCurrentIrql() > DISPATCH_LEVEL时依旧蓝屏。
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {          
            r = GetExceptionCode();//啥也不做。
        }

        p = NULL;
    }
}

VOID MY_PWORKER_THREAD_ROUTINE (IN PVOID Parameter)
{
    WorkItemContext * pwic = (WorkItemContext *)Parameter;

    //做一些事。


    free(pwic->Item);
    free(pwic);
}

DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{  

}

#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;
    WorkItemContext * wic;

    KdBreakPoint();// == DbgBreakPoint()

    DriverObject->DriverUnload = Unload;  

    //之所以采用结构是因为传递的参数不是一个(实际应用的也不是一个),并且不是同步控制的。
    wic = (WorkItemContext *)allocate(sizeof(WorkItemContext));
    if (wic == NULL) {
        return status;
    }

    wic->Pid = 0;
    wic->Item = (PWORK_QUEUE_ITEM)allocate(sizeof(WORK_QUEUE_ITEM));
    if (wic->Item == NULL) {
        free(wic);
        return status;
    }

    ExInitializeWorkItem(wic->Item,MY_PWORKER_THREAD_ROUTINE,wic);
    ExQueueWorkItem(wic->Item, DelayedWorkQueue);
   
    return status;
}

2012年12月7日星期五

ExInterlockedInsertTailList.C

/*
链表一个重要的概念,
数据结构里面有,内核里面有双链表。

本文主要操作的是同步安全的双链表。
不用单链表的原因是,内核里面的结构大多是双链表。

应用层的有stl等。
那几个应用层的链表API不适用,还不如自己实现链表的结构和操作。

内核中的主要操作安全性的双链表的函数有:
KeInitializeSpinLock
InitializeListHead
ExInterlockedInsertTailList //插入尾,这是正常的思维。
ExInterlockedInsertHeadList //这个不常用,特殊的情况下使用。
ExInterlockedRemoveHeadList //带锁的双链表没有尾删除的。所以使用的用途第队列不是堆栈。
IsListEmpty //这个可以不用。

本文是简单的示例,要使用,还要进一步的加强。
链表怎能不会,光看别人的代码是不行的,必须自己体验:编码调试。
微软没有完整的例子,所以自己写。
made by correy
made at 2012.12.07
QQ:112426112
Email:kouleguan at hotmail dot com
Homepage:http://correy.webs.com
*/

#include <ntddk.h>

KSPIN_LOCK g_sl;
LIST_ENTRY g_le;

#define TAG 'tset' //test

typedef struct _dl{ //加不加下划线都可以。
    LIST_ENTRY le;
    int x;
}dl;//定义指针会出错。不知啥原因。*dl

VOID OnUnload(IN PDRIVER_OBJECT DriverObject) { }

void InsertTail()
{
    int i = 0;

    for (i = 0; i < 9; i++)
    {
        dl * dl1 = (dl *)ExAllocatePoolWithTag(NonPagedPool, sizeof(dl), TAG);//不能用栈内空间,否则移除会蓝屏。
        if (dl1 == NULL)
        {
            return;
        }

        dl1->x = i;
        ExInterlockedInsertTailList(&g_le, &dl1->le, &g_sl);//前两个个参数的顺序翻了会蓝屏的,并且注意第二个参数的用法。
        DbgPrint("%08x\n",dl1->x);
    }
}

void Ergodic_chain_table()
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }
        DbgPrint("%08x\n",temp->x);
    } while (p != g_le.Flink);
}

void RemoveHead()
{
    PLIST_ENTRY temp;

    do
    {
        temp = ExInterlockedRemoveHeadList(&g_le, &g_sl);
        if (temp)
        {
            dl * dl2 = CONTAINING_RECORD(temp, dl, le);//是一个宏,用于取自己定义的结构的指针。
            DbgPrint("%08x\n",dl2->x);
            ExFreePoolWithTag(dl2, TAG);
        }
    } while (temp != 0);//为啥是不等呢?还有分号。
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
{
    KdBreakPoint();//#define KdBreakPoint() DbgBreakPoint()
    DriverObject->DriverUnload = OnUnload;

    KeInitializeSpinLock(&g_sl);
    InitializeListHead(&g_le);

    InsertTail();//插入,形成一个双链表示例
    Ergodic_chain_table();//遍历示例。查询就是添加个比较的条件而已。
    RemoveHead();//从全部头删除示例

    return STATUS_SUCCESS;
}


//添加一些函数.
int InsertTail(HANDLE pid) //插入一个到尾部 HANDLE DWORD
{
    dl * dl1;

    dl1 = (dl *)ExAllocatePoolWithTag(NonPagedPool, sizeof(dl), TAG);//不能用栈内空间,否则移除会蓝屏。
    if (dl1 == NULL)
    {
        return 0 /*false*/;
    }

    dl1->x = pid;

    if (ExInterlockedInsertTailList(&g_le, &dl1->le, &g_sl) == 0)//前两个个参数的顺序翻了会蓝屏的,并且注意第二个参数的用法。
    { //第一次操作,链表为空,ExInterlockedInsertTailList返回值为0。
        return 1 /*false*/;
    }

    KdPrint(("成功插入:%d\n",pid));

    return 1 /*true*/;
}

int delete_node(HANDLE pid) //DWORD
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//
    dl * head = CONTAINING_RECORD(p, dl, le);

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }

        if (temp->x == pid)
        {
            //没有删除特定节点的函数,所以自己实现:
            /*
            1.替换链表的节点的指针,把本节点释放掉。
            * p = temp->le;
            ExFreePoolWithTag(temp, TAG);
            2.把第一个节点的值赋值给指定的节点,然后ExInterlockedRemoveHeadList删除第一个。
            3.把指定的节点的值赋值给0,这个值是没有用的。但这样做浪费内存。
            4.删除链表的特定的节点:
              遍历,从头删除,不是就添加到尾部,
                              是就直接删除,不再添加.
              不过要先判断一下存在不,以防使循环.
              还可以先添加在删除(看看允许重复添加不).
            */

            temp->x = head->x;//注意这个结构的一些操作最好加锁同步。
            ExInterlockedRemoveHeadList(&g_le, &g_sl);//IsListEmpty

            KdPrint(("成功删除:%d\n",pid));

            return 1;
        }      

    } while (p != g_le.Flink);

    KdPrint(("删除失败:%d\n",pid));
    return 0;
}

BOOLEAN find (HANDLE pid) //查询  DWORD
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            //KdPrint(("没有找到:%d\n",temp->x));//这个显示的频率太多.
            break;
        }

        if (temp->x == pid)
        {
            //KdPrint(("成功找到:%d\n",temp->x));//这个显示的频率太多.
            return 1;
        }
    } while (p != g_le.Flink);

    return 0;
}

int ListAll() //遍历示例。
{
    LIST_ENTRY * p = g_le.Flink;//&g_le;//

    KdPrint(("开始显示\n"));

    do
    {
        dl * temp = CONTAINING_RECORD(p, dl, le);      
        p = p->Flink;
        if (p == g_le.Flink)//不加这一句的后果是:这样会再最后一次多现实第一个一次。
        {
            break;
        }

        KdPrint(("pid:%d\n",temp->x));

    } while (p != g_le.Flink);

    KdPrint(("显示结束\n\n"));

    return 0;
}

void RemoveAll() //从全部头删除示例
{
    PLIST_ENTRY temp;
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    do
    {
        temp = ExInterlockedRemoveHeadList(&g_le, &g_sl);
        if (temp)
        {
            dl * dl2 = CONTAINING_RECORD(temp, dl, le);//是一个宏,用于取自己定义的结构的指针。
            ExFreePoolWithTag(dl2, TAG);
        }
    } while (temp != 0);//为啥是不等呢?还有分号。
}

//以后添加单链表的操作,因为但链表的操作更多,只不过要加个同步的处理而已.

2012年12月5日星期三

SHFileOperation.Cpp


/*
删除文件夹有两种办法:
1.递归遍历加RemoveDirectory(移除空目录)。只读属性需要去掉。
2.SHFileOperation函数的FO_DELETE。
修改自:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200(v=vs.85).aspx等。

If you are writing a 32-bit application to list all the files in a directory and the application may be run on a 64-bit computer,
you should call the Wow64DisableWow64FsRedirectionfunction before calling FindFirstFile and call Wow64RevertWow64FsRedirection after the last call to FindNextFile.
*/

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#pragma comment(lib, "User32.lib")

#include "Shlwapi.h"
#pragma comment (lib,"Shlwapi.lib")

#include <locale.h>

void DisplayErrorBox(LPTSTR lpszFunction);

bool deldir(TCHAR * path)
{  
    // Check that the input path plus 3 is not longer than MAX_PATH.
    // Three characters are for the "\*" plus NULL appended below.
    size_t length_of_arg;
    StringCchLength(path, MAX_PATH, &length_of_arg);//argv[1]
    if (length_of_arg > (MAX_PATH - 3))  {
        _tprintf(TEXT("\nDirectory path is too long.\n"));
        return (-1);
    }

    // Prepare string for use with FindFile functions.  First, copy the string to a buffer, then append '\*' to the directory name.
    TCHAR szDir[MAX_PATH];
    StringCchCopy(szDir, MAX_PATH, path);//argv[1]
    StringCchCat(szDir, MAX_PATH, TEXT("\\*"));

    // Find the first file in the directory.
    WIN32_FIND_DATA ffd;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    hFind = FindFirstFile(szDir, &ffd);
    if (INVALID_HANDLE_VALUE == hFind) {
        DisplayErrorBox(TEXT("FindFirstFile"));
        return false;
    }

    // List all the files in the directory with some info about them.
    do
    {
        if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            //_tprintf(TEXT("  %s   <DIR>\n"), ffd.cFileName);
            if (lstrcmpi(ffd.cFileName,L".") == 0 ||
                lstrcmpi(ffd.cFileName,L"..") == 0)
            {
                //这里不操作。
            }
            else
            {
                TCHAR sztemp[MAX_PATH] = {0};
                StringCchCopy(sztemp, MAX_PATH, path);//argv[1]
                PathAppend(sztemp, ffd.cFileName);
                deldir(sztemp);

                /*_tprintf(TEXT("  %s   <DIR>\n"), ffd.cFileName);*/
            }
        }
        else
        {
            //LARGE_INTEGER filesize;//这几行显示信息用的,无实际用途。
            //filesize.LowPart = ffd.nFileSizeLow;
            //filesize.HighPart = ffd.nFileSizeHigh;
            //_tprintf(TEXT("  %s   %ld bytes\n"), ffd.cFileName, filesize.QuadPart);

            TCHAR sztemp[MAX_PATH] = {0};
            StringCchCopy(sztemp, MAX_PATH, path);//argv[1]
            PathAppend(sztemp, ffd.cFileName);
            bool b = DeleteFile(sztemp);
            if (b == 0)
            {
                int x = GetLastError();
                x = x;//查看x的值用的。
            }
        }
    } while (FindNextFile(hFind, &ffd) != 0);

    //dwError = GetLastError();
    //if (dwError != ERROR_NO_MORE_FILES) {
    //    DisplayErrorBox(TEXT("FindFirstFile"));
    //}

    FindClose(hFind);

    return RemoveDirectory(path);//里面有空文件夹依旧任务是空目录。返回0失败。
}

void DelDir2(TCHAR * dir)
{
    if (!PathFileExists(dir))
    {
        return;
    }

    TCHAR DelDir[MAX_PATH] = {0};
    lstrcpy(DelDir,dir);
    int len = lstrlen(dir);
    DelDir[len] = 0;
    DelDir[len+1] = 0;

    SHFILEOPSTRUCT FileOp;
    ZeroMemory((void*)&FileOp, sizeof(SHFILEOPSTRUCT));

    FileOp.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
    FileOp.hNameMappings = NULL;
    FileOp.hwnd = NULL;
    FileOp.lpszProgressTitle = NULL;
    FileOp.pFrom = DelDir;
    FileOp.pTo = NULL;
    FileOp.wFunc = FO_DELETE;

    int err = SHFileOperation(&FileOp);
    if (0 != err)
    {
        //失败。
    }
}

int _tmain(int argc, TCHAR *argv[])
{
    setlocale(LC_CTYPE, ".936");

    TCHAR path[MAX_PATH] = L"e:\\test";

    bool b = deldir(path);

    DelDir2(L"e:\\test2");

    return 0;
}

void DisplayErrorBox(LPTSTR lpszFunction) //这个函数封装的还不错的,以后就拿来用吧!
{
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    DWORD dw = GetLastError();

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );

    // Display the error message and clean up
    LPVOID lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s failed with error %d: %s"), lpszFunction, dw, lpMsgBuf);
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

2012年12月4日星期二

ReportEvent.Cpp


/*
日志,怎能不会?
特别是系统的,这些基本的功能。
有时它还是特有用的。
所以有此文。

参考:
http://msdn.microsoft.com/en-us/library/aa363680(v=vs.85).aspx等相关的内容。
http://www.aogosoft.com/downpage.asp?mode=viewtext&id=220
*/

#include <windows.h>

int main()
{
    HANDLE hEventLog = RegisterEventSource(NULL, L"来源");
    if (NULL == hEventLog) {
        return 1;
    }

    CONST LPWSTR pBadCommand = L"data";//这里不准用汉字,是不会显示汉字的,是以字节显示的字母的。以双0字节结尾。
    DWORD dwEventDataSize = ((DWORD)wcslen(pBadCommand) + 1) * sizeof(WCHAR);
    if (!ReportEvent(hEventLog,
        EVENTLOG_INFORMATION_TYPE, //类型(级别)是信息。
        (WORD)0x00000003L, //分类或者任务类别。
        (DWORD)0xC0020100L, //低16位是事件或者事件ID,
        NULL,//A pointer to the current user's security identifier. This parameter can be NULL if the security identifier is not required
        0, //The number of insert strings in the array pointed to by the lpStrings parameter. A value of zero indicates that no strings are present.
        dwEventDataSize, //数据的长度。
        NULL, //另一种情况使用,是数组用的,与上上个参数配合使用,有大小的限制。
        pBadCommand))//数据的内容。
    {
        return 1;
    }

    if (hEventLog) {
        DeregisterEventSource(hEventLog);
    }
}

2012年11月24日星期六

调试服务

本文主要讲服务的调试。


标准的微软的方法是:
http://support.microsoft.com/kb/824344/zh-cn
注释:这个办法有的地方不适宜windows 7和windows server 2008.


一、附加法调试已经启动的进程
1、通过任务管理器或tlist.exe(WinDBG中的一个命令行工具:C:\Program Files\Debugging Tools for Windows
)命令查看调试进程的PID;
2、启动调试器附加进程,方法:
1)运行命令行,进入WinDbg调试器目录,运行:WinDBG -p ProcessID /g 附加到进程PID
2)运行命令行,进入WinDbg调试器目录,运行:WinDBG -pn ImageName /g 附加到进程名
3)运行命令行,进入WinDbg调试器目录,运行:WinDBG /g 启动调试器,然后在文件菜单中选择附加到进程,选择要调试的进程名。

二、在服务启动时用WinDBG附加
1、设置要调试的服务进程名,方法:
1)使用WinDBG的全局标志设置命令gflags.exe设置,在对话框中的Image File设置要调试                    的服务名称,Debugger选择设置调试器的路径;
2)使用注册表编辑器,打开注册表路径:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options ,添加一个主键,名称为要调试的服务名称,如 MyService.exe,在该主键下再新建一个字符串值,名称为“Debugger”,值为调试器路径;

2、设置要调试的服务与桌面交互,方法:
1)打开“管理工具”,选择“服务”,打开服务管理窗口,选择准备调试的服务名,右击选择“属性”,选择“登录”,勾选“允许服务与桌面交互”;
2)使用注册表编辑器,打开注册表路径:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services \ServiceName(要调试的服务名),选择“Type”,修改其值为:原值 OR 0×00000100(如原值为:0×00000010 OR 0×00000100 =0×00000110);

3、设置服务启动超时时间(系统默认为30秒),启动注册表编辑器,打开注册表路径:HKEY_LOCAL_MACHINE\SYSTEM \CurrentControlSet\Control,新建DWORD值“ServicesPipeTimeout”,其值为欲设置的超时时间,如设置 24小时,则值为86400000毫秒;
4、启动服务准备调试,打开“管理工具”,选择“服务”,打开服务管理窗口,选择准备调试的服务名,右击选择“启动”


windows 7和windows server 2008的服务调试心得,不敢说是秘籍:(操作系统和服务不限32位和64位)
首先:1.如果没有开启UI0Detect服务,建议开启,2.还有服务的超时时间设置长点,3.再有设置服务为可交互的。
其次在服务的入口,不是程序的入口加入消息框,这样在服务启动的时候能断下来。
第三步是用调试器附加。
第四步是,如果有消息框,进入"交互式服务检测"窗口,点击消息,注意消息框的下面要设置断点。
                如果没有开启UI0Detect服务,而在服务的入口下个断点(类似int3),是会死机的(2008会,win7不会)
这个办法是类似的,变相的调试服务启动,非附加,但用的是附加的办法。
困惑了好久,才解决,才成功。


ntsd


ntsd.exe是系统自带的,大家都知道用它来结束进程,
它还有一个功能是显示cpu的信息,可惜这个用法我忘记了(要操作寄存器,是自动的)。
还有一个是添加后门。

ntsd的生成dump文件的方式为: ntsd -pv -p  $PID   -c  ".dump /mf   d:\aaa.dmp"。
或者,先是ntsd -pv -p $PID进入交互式命令提示,然后再输入.dump /mf d:\aaa.dmp
其中$PID,是进程的PID。 可惜,win 7不自带了。

FindFirstUrlCacheEntryEx.Cpp


/*
本文摘自:Microsoft SDKs\Windows\v7.1\Samples\web\Wininet\CacheEnumerate工程。
还有GetUrlCacheEntryInfo,FindFirstUrlCacheGroup,DeleteUrlCacheGroup,FindNextUrlCacheGroup等函数的用法,以后补上。
*/

#include <windows.h>

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

VOID EnumerateCache(wchar_t * szUrlSearchPattern)
{  
    //这个函数有所改动,但大的结构没有改变。
   
    DWORD dwErr             = 0;
    DWORD cbCacheInfoSize   = 0;
    LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo = NULL;

    HANDLE hEnum  = NULL;
    hEnum = FindFirstUrlCacheEntryEx(szUrlSearchPattern, 0, URLCACHE_FIND_DEFAULT_FILTER, 0, NULL, &cbCacheInfoSize, NULL, NULL, NULL);
    if (!hEnum)
    {
        dwErr = GetLastError();
        switch (dwErr)
        {          
        case ERROR_NO_MORE_ITEMS:
            wprintf(L"There are no more entries.\n");//没有东西,这很少发生。
            goto cleanup;          
        case ERROR_INSUFFICIENT_BUFFER:
            lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFO)  malloc(cbCacheInfoSize);        
            if (!lpCacheEntryInfo)   {
                goto cleanup;
            }          
            ZeroMemory(lpCacheEntryInfo, sizeof(INTERNET_CACHE_ENTRY_INFO));// zero memory the structure
            lpCacheEntryInfo->dwStructSize = cbCacheInfoSize;
            break;          
        default://其他的默认都为失败处理。
            goto cleanup;
        }
    }

    hEnum = FindFirstUrlCacheEntryEx(szUrlSearchPattern, 0, URLCACHE_FIND_DEFAULT_FILTER, 0, lpCacheEntryInfo, &cbCacheInfoSize, NULL, NULL, NULL);
    if (!hEnum)   {
        goto cleanup;
    }
 
    BOOL bDone = FALSE;
    do
    {
        if (lpCacheEntryInfo->lpszSourceUrlName)
        {
            wprintf(L"URL is: %s\n\r", lpCacheEntryInfo->lpszSourceUrlName); //The cache entry's source

            if (lpCacheEntryInfo->lpszLocalFileName)
            {
                wprintf(L"file is: %s\n\r", lpCacheEntryInfo->lpszLocalFileName);          
            }
            else
            {
                wprintf(L"file is:not found\n");
            }

            //还有更多的内容可现实,类型,上次修改时间,过期时间,上次访问时间,结果,大小等。

            wprintf(L"\n");
        }    

        BOOL bRet  = FALSE;
        bRet = FindNextUrlCacheEntryEx(hEnum, lpCacheEntryInfo, &cbCacheInfoSize, NULL, NULL, NULL);
        if (!bRet)
        {
            dwErr = GetLastError();
            switch (dwErr)
            {
            case ERROR_NO_MORE_ITEMS:              
                wprintf(L"There are no more entries.\n"); //结束。
                bDone = TRUE;
                break;
            case ERROR_INSUFFICIENT_BUFFER:              
                free(lpCacheEntryInfo);
                lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFO) malloc(cbCacheInfoSize);              
                if (!lpCacheEntryInfo)   {
                    goto cleanup;
                }              
                ZeroMemory(lpCacheEntryInfo, sizeof(INTERNET_CACHE_ENTRY_INFO));
                lpCacheEntryInfo->dwStructSize = cbCacheInfoSize;
                continue;              
            default:
                goto cleanup;
            }
        }
    }
    while (!bDone);

cleanup:  
    if (lpCacheEntryInfo)    {
        free(lpCacheEntryInfo);
    }
   
    if (hEnum)    {
        FindCloseUrlCache(hEnum);
    }
}

int  main( int  argc,  char *  argv[])
{
    //这个包含全部。
    EnumerateCache(0);

    wprintf(L"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\");
    wprintf(L"\n");

    //这个只包含:visited
    EnumerateCache(L"visited:");//这个可能在内存中,没有对应的文件。

    wprintf(L"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\");
    wprintf(L"\n");

    //这个只包含:cookie
    EnumerateCache(L"cookie:" );
   
    wprintf(L"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\");
    wprintf(L"\n");

    //这个除了visited和cookie的剩下来的,都包含。空的应该也不会包含。
    EnumerateCache(L"");

    return   0 ;
}

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);
}

2012年9月12日星期三

ReadDirectoryChangesW.Cpp


/*
监控目录的变化的办法有:
1.SHChangeNotifyRegister,SHChangeNotify,没有路径信息。
2.FindFirstChangeNotification和FindNextChangeNotification没有变化的类型。
3.ReadDirectoryChangesW有时会遗漏信息,可以结合使用完成例程,i/o端口(CreateIoCompletionPort)等异步多线程措施。
4.Change Journal(USN Journal)只能在NTFS,REFS上。
5.文件系统过滤驱动
6.hook api and messages.
7.其他(如备份一份,周期的比较).
8.ICopyHokk接口的回调函数.
*/

#include <Windows.h>
#include <locale.h>

int _tmain(int argc, _TCHAR* argv[])
{
    setlocale(LC_CTYPE, ".936");
 
    int nBufferSize = 1024;
    char* buffer = new char[nBufferSize];

    HANDLE hDirectoryHandle = CreateFile(L"e:\\test",FILE_LIST_DIRECTORY,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        0,OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,0);
    if(!hDirectoryHandle)    return 0;

    while(1)
    {
        memset(buffer, 0, nBufferSize);

        DWORD dwBytes = 0;
        if(!::ReadDirectoryChangesW(hDirectoryHandle,buffer,nBufferSize,1,          
            FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SIZE,
            &dwBytes,NULL,NULL) || GetLastError() == ERROR_INVALID_HANDLE) {
                break;
        }

        if(!dwBytes)   {
            printf("Buffer overflow\r\n");
        }

        PFILE_NOTIFY_INFORMATION record = (PFILE_NOTIFY_INFORMATION)buffer;
        DWORD cbOffset = 0;

        do
        {
            switch (record->Action)
            {
            case FILE_ACTION_ADDED:
                printf("添加:");
                break;
            case FILE_ACTION_REMOVED:
                printf("移除:");
                break;
            case FILE_ACTION_MODIFIED:
                printf("修改:");
                break;
            case FILE_ACTION_RENAMED_OLD_NAME:
                printf("旧名字:");
                break;
            case FILE_ACTION_RENAMED_NEW_NAME:
                printf("新名字:");
                break;
            default:
                break;
            }

            wprintf(record->FileName); printf("\r\n");

            cbOffset = record->NextEntryOffset;
            record = (PFILE_NOTIFY_INFORMATION)((LPBYTE) record + cbOffset);
        }while(cbOffset);
    }

    delete buffer;
    if(hDirectoryHandle)   CloseHandle(hDirectoryHandle);

    return 0;
}

2012年8月24日星期五

IoAllocateIrp.C


/*
首先声明这段代码摘抄自网络:删除正在运行的文件的c驱动代码
这段代码放了很久了,网上了多得是。
不是因为功能牛屄。而是一种思路。
解决了重入的问题,不受好多的限制,缺点是数据结构不是公开的,通用性差。
用Nt和Zw系列也能实现,但有好多的限制,在某些情况下还会引起IRP的重入。
类似的功能还有发IRP改名,查询,新建,读写等。
我想类似的功能在WRK,reactos等里面会有的。
*/

#include <ntddk.h>

VOID SKillUnloadDriver(IN PDRIVER_OBJECT DriverObject) { }

NTSTATUS SkillSetFileCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
    Irp->UserIosb->Status = Irp->IoStatus.Status;
    Irp->UserIosb->Information = Irp->IoStatus.Information;
    KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
    IoFreeIrp(Irp);
    return STATUS_MORE_PROCESSING_REQUIRED;
}

BOOLEAN SKillStripFileAttributes(IN HANDLE    FileHandle)
{
    PFILE_OBJECT      fileObject;
    PDEVICE_OBJECT    DeviceObject;
    PIRP              Irp;
    KEVENT            event1;
    FILE_BASIC_INFORMATION    FileInformation = {0};
    IO_STATUS_BLOCK ioStatus;
    PIO_STACK_LOCATION irpSp;

    if (KeGetCurrentIrql() > PASSIVE_LEVEL)   {
        return FALSE;
    }

    ObReferenceObjectByHandle(FileHandle,DELETE,*IoFileObjectType,KernelMode,&fileObject,NULL);//我想知道的是这个文件句柄是在哪个进程的句柄表中
    if (fileObject == 0)   {
        return FALSE;
    }

    DeviceObject = IoGetRelatedDeviceObject(fileObject);
    Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);

    KeInitializeEvent(&event1,SynchronizationEvent,FALSE);

    FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
    Irp->AssociatedIrp.SystemBuffer = &FileInformation;
    Irp->UserEvent = &event1;
    Irp->UserIosb = &ioStatus;
    Irp->Tail.Overlay.OriginalFileObject = fileObject;
    Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
    Irp->RequestorMode = KernelMode;

    irpSp = IoGetNextIrpStackLocation(Irp);
    irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
    irpSp->DeviceObject = DeviceObject;
    irpSp->FileObject = fileObject;
    irpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
    irpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
    irpSp->Parameters.SetFile.FileObject = fileObject;

    IoSetCompletionRoutine(Irp,SkillSetFileCompletion,&event1,TRUE,TRUE,TRUE);
    IoCallDriver(DeviceObject, Irp);
    //调用这个设备对象的驱动对象,并且IO_StACK_LOCAtion会指向下一个,也就是刚刚设置的
    //如果没有文件系统驱动建立的设备对象没有Attacked的话,就调用文件系统驱动的IRP_MJ_SET_INFORMATION分派例程
    //会调用NTFS.sys驱动的NtfsFsdSetInformation例程,再会进入NtfsSetBasicInfo()函数,最后它会设置代表此文件的FCB(文件
    //控制块结构的一些信息,用来设置代表此文件的属性。最后不知道在哪里会调用IoCompleteRequest,它会依次调用先前设置的回调函数
    //回调函数会释放刚分配的IRP和设置事件对象为受信状态。

    KeWaitForSingleObject(&event1,Executive,KernelMode,TRUE,NULL);//一等到事件对象变成受信状态就会继续向下执行。

    ObDereferenceObject(fileObject);
    return TRUE;
}

BOOLEAN SKillDeleteFile(IN HANDLE FileHandle)
{
    NTSTATUS          ntStatus = STATUS_SUCCESS;
    PFILE_OBJECT      fileObject;
    PDEVICE_OBJECT    DeviceObject;
    PIRP              Irp;
    KEVENT            event1;
    FILE_DISPOSITION_INFORMATION    FileInformation;
    IO_STATUS_BLOCK ioStatus;
    PIO_STACK_LOCATION irpSp;
    PSECTION_OBJECT_POINTERS pSectionObjectPointer;

    if (KeGetCurrentIrql() > PASSIVE_LEVEL)   {
        return FALSE;
    }

    SKillStripFileAttributes(FileHandle); //去掉只读属性,才能删除只读文件
    ntStatus = ObReferenceObjectByHandle(FileHandle, DELETE, *IoFileObjectType, KernelMode, &fileObject, NULL);
    if (!NT_SUCCESS(ntStatus))   return FALSE;

    DeviceObject = IoGetRelatedDeviceObject(fileObject);//如果NTFS.sys驱动建立的设备对象上没有附加的设备对象的话,就返回NTFS.sys建立的设备对象 //否则返回的是这个设备对象的highest level设备对象。
    Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);//如果没有附加,StackSize为7

    KeInitializeEvent(&event1,SynchronizationEvent,FALSE);
    FileInformation.DeleteFile = TRUE;

    Irp->AssociatedIrp.SystemBuffer = &FileInformation;
    Irp->UserEvent = &event1;
    Irp->UserIosb = &ioStatus;
    Irp->Tail.Overlay.OriginalFileObject = fileObject;
    Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
    Irp->RequestorMode = KernelMode;

    irpSp = IoGetNextIrpStackLocation(Irp);            //得到文件系统NTFS.sys驱动的设备IO_STACK_LOCATION
    irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
    irpSp->DeviceObject = DeviceObject;
    irpSp->FileObject = fileObject;
    irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
    irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
    irpSp->Parameters.SetFile.FileObject = fileObject;

    IoSetCompletionRoutine(Irp, SkillSetFileCompletion, &event1, TRUE, TRUE, TRUE);

    //再加上下面这三行代码 ,MmFlushImageSection    函数通过这个结构来检查是否可以删除文件。
    pSectionObjectPointer = fileObject->SectionObjectPointer;
    pSectionObjectPointer->ImageSectionObject = 0;
    pSectionObjectPointer->DataSectionObject = 0;

    IoCallDriver(DeviceObject, Irp);
    //这里会依次进入NTFS.sys驱动的NtfsFsdSetInformation例程->NtfsSetDispositionInfo()->MmFlushImageSection(),
    //MmFlushImageSection()这函数是用来检查FILE_OBJECT对象的SECTION_OBJECT_POINTER结构的变量,检查这个文件
    //在内存有没有被映射。也就是有没有执行。如果上面那样设置了,也就是说文件可以删除了。我们也可以HOOK NTFS.sys导入表中的
    //的MmFlushImageSection(),来检查这个文件对象是不是我们要删除 的,是的话,返回TRUE就行了。

    KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);

    ObDereferenceObject(fileObject);
    return TRUE;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
    UNICODE_STRING        uniFileName;
    OBJECT_ATTRIBUTES     objectAttributes;
    HANDLE                ntFileHandle;
    IO_STATUS_BLOCK       ioStatus;
    NTSTATUS              ntStatus;

    _asm int 3

    DriverObject->DriverUnload = SKillUnloadDriver;  

    RtlInitUnicodeString(&uniFileName, L"\\Device\\HarddiskVolume1\\test.exe");//我虚拟机win 7上的HarddiskVolume1不是c盘。
    InitializeObjectAttributes(&objectAttributes,&uniFileName,OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,0,0);
    ntStatus = IoCreateFile(&ntFileHandle,FILE_READ_ATTRIBUTES,&objectAttributes,&ioStatus,0,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_DELETE,FILE_OPEN,0,0,0,0,0,IO_NO_PARAMETER_CHECKING);
    if (ntFileHandle == 0)   {
        return 0;
    }

    SKillDeleteFile(ntFileHandle);
    ZwClose(ntFileHandle);
    return STATUS_SUCCESS;
}

2012年8月1日星期三

nt!DebugService2


一般的断点都是断在:
nt!DbgBreakPointWithStatus:
                           fffff800`01883f60 cc              int     3
                           fffff800`01883f61 c3              ret
等地方的,
有时会出现在下面:
nt!DebugService2:
                           fffff800`01883fb0 418bc0          mov     eax,r8d
                           fffff800`01883fb3 cd2d            int     2Dh
                           fffff800`01883fb5 cc              int     3
                           fffff800`01883fb6 c3              ret
                           fffff800`01883fb7 90              nop
这是因为以前设置的断点,而自己的代码已经改变,并重新编译,调试,才出现的。
解决办法:删除所有的断点,然后继续运行既可以。
bc *
g
ok!

小东西,记住,以后忘了,来这里查看。
made by correy
made at 2012.08.01

2012年7月15日星期日

StdRegProv.Vbs


'这是一篇远程操作注册表的脚本.在已知ip,username,password的情况下.
'本文参考,改编自:http://www.44342.com/vbscript-f902-t8710-p1.htm
'用c++用了两天的时间,获取的内容却为为空,用脚本2分钟搞定.
'made at 2012.07.15

On Error Resume Next '相当于编译语言的异常处理.

Set objLocator = CreateObject("WbemScripting.SWbemLocator")
Set objService = objLocator.ConnectServer("10.101.0.133", "Root\DEFAULT","administrator", "123456")
Set objRegistry = objService.Get("StdRegProv")

strKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
strValueName = "ProductName"

const HKEY_LOCAL_MACHINE = &H80000002
objRegistry.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
WScript.Echo   strValue

strValueName = "InstallDate"
objRegistry.GetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
WScript.Echo   strValue
'made by correy.

2012年7月7日星期六

Win32_QuickFixEngineering.Vbs


'好久没有写脚本了.
'这是在已知ip,域名,用户名,密码的情况下通过wmi获取远程电脑上的补丁的信息.
'made at 2012.07.07
'email:kouleguan at hotmail dot com
'homepage:http://correy.webs.com

On Error Resume Next

strComputer = "10.101.0.133"

Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objSWbemServices = objSWbemLocator.ConnectServer(strComputer, "root\cimv2", "administrator", "123456", , "ntlmdomain:dp-correy-2003")
Set colSwbemObjectSet = objSWbemServices.ExecQuery("Select * from Win32_QuickFixEngineering")

For Each objItem in colSwbemObjectSet
    Wscript.Echo "//////////////////////////////////////////////////////////////////////////"
    Wscript.Echo "HotFixID: " & objItem.HotFixID '此值是"File 1"时,下面的就是kbXXXXXXXX,并且出重复.
    Wscript.Echo "ServicePackInEffect: " & objItem.ServicePackInEffect
Next
'made by correy.

2012年7月5日星期四

LookupAccountName.Cpp

/*
sid一个神秘的东西,本想是获取或者枚举用户和它的关系.
这里有两个从微软搬过来的函数,
一个是从句柄获得sid,这个好像有问题,难道是我使用的问题.
一个是从(用户)名字获取sid.这个经试验是好的.
这里主要用了两个函数:GetTokenInformation,LookupAccountNameW
因为用GetTokenInformation的函数获取的东西好像有点问题,所以此文就命名为:LookupAccountName.Cpp.
*/

#include "stdafx.h"
#include <windows.h>
#include "D:\Program Files\Microsoft Visual Studio 9.0\SmartDevices\SDK\Smartphone2003\Include\mq.h"
#include <Sddl.h>
#pragma comment(lib, "advapi32.lib")

//http://msdn.microsoft.com/en-us/library/windows/desktop/aa446670(v=vs.85).aspx
BOOL GetLogonSID (HANDLE hToken, PSID *ppsid)
{
    BOOL bSuccess = FALSE;
    DWORD dwIndex;
    DWORD dwLength = 0;
    PTOKEN_GROUPS ptg = NULL;
   
    if (NULL == ppsid)// Verify the parameter passed in is not NULL.
        goto Cleanup;
   
    if (!GetTokenInformation(// Get required buffer size and allocate the TOKEN_GROUPS buffer.
        hToken,         // handle to the access token
        TokenGroups,    // get information about the token's groups
        (LPVOID) ptg,   // pointer to TOKEN_GROUPS buffer
        0,              // size of buffer
        &dwLength       // receives required buffer size
        ))
    {
        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
            goto Cleanup;

        ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, dwLength);
        if (ptg == NULL)
            goto Cleanup;
    }
   
    if (!GetTokenInformation(hToken,TokenGroups,(LPVOID) ptg,dwLength,&dwLength)) {// Get the token group information from the access token.
        goto Cleanup;
    }

    // Loop through the groups to find the logon SID.
    for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) //这个没有大括号.
        if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)  ==  SE_GROUP_LOGON_ID)
        {   // Found the logon SID; make a copy of it.
            dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
            *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
            if (*ppsid == NULL)
                goto Cleanup;
            if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
            {
                HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
                goto Cleanup;
            }
            break;
        }

        bSuccess = TRUE;
Cleanup:
        if (ptg != NULL)// Free the buffer for the token groups.
            HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);

        return bSuccess;
}

//这个不要了.
//VOID FreeLogonSID (PSID *ppsid)
//{
//    HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
//}

//http://msdn.microsoft.com/en-us/library/windows/desktop/ms707085(v=vs.85).aspx
//还有一个函数:CreateQSecDescriptor
HRESULT GetSid(LPCWSTR wszAccName,PSID * ppSid) //此函数,还可以精简,我没有精简.
{  
    if (wszAccName == NULL || ppSid == NULL) {// Validate the input parameters.
        return MQ_ERROR_INVALID_PARAMETER;
    }

    // Create buffers that may be large enough.If a buffer is too small, the count parameter will be set to the size needed.
    const DWORD INITIAL_SIZE = 32;
    DWORD cbSid = 0;
    DWORD dwSidBufferSize = INITIAL_SIZE;
    DWORD cchDomainName = 0;
    DWORD dwDomainBufferSize = INITIAL_SIZE;
    WCHAR * wszDomainName = NULL;
    SID_NAME_USE eSidType;
    DWORD dwErrorCode = 0;
    HRESULT hr = MQ_OK;
   
    *ppSid = (PSID) new BYTE[dwSidBufferSize];// Create buffers for the SID and the domain name.
    if (*ppSid == NULL) {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }
    memset(*ppSid, 0, dwSidBufferSize);
    wszDomainName = new WCHAR[dwDomainBufferSize];
    if (wszDomainName == NULL) {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }
    memset(wszDomainName, 0, dwDomainBufferSize*sizeof(WCHAR));
   
    for ( ; ; )// Obtain the SID for the account name passed.
    {   // Set the count variables to the buffer sizes and retrieve the SID.
        cbSid = dwSidBufferSize;
        cchDomainName = dwDomainBufferSize;
        if (LookupAccountNameW(
            NULL,            // Computer name. NULL for the local computer
            wszAccName,
            *ppSid,          // Pointer to the SID buffer. Use NULL to get the size needed,
            &cbSid,          // Size of the SID buffer needed.
            wszDomainName,   // wszDomainName,//这个还能获取域名.
            &cchDomainName,
            &eSidType)) //其实这个函数就是返回sid和域名用的别的没啥,不要多想,下面的是垃圾,加上更完美.
        {
            if (IsValidSid(*ppSid) == FALSE)
            {
                wprintf(L"The SID for %s is invalid.\n", wszAccName);
                dwErrorCode = MQ_ERROR;
            }
            break;
        }
        dwErrorCode = GetLastError();
     
        if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER) // Check if one of the buffers was too small.
        {
            if (cbSid > dwSidBufferSize)
            {   // Reallocate memory for the SID buffer.
                wprintf(L"The SID buffer was too small. It will be reallocated.\n");
                FreeSid(*ppSid);
                *ppSid = (PSID) new BYTE[cbSid];
                if (*ppSid == NULL)
                {
                    return MQ_ERROR_INSUFFICIENT_RESOURCES;
                }
                memset(*ppSid, 0, cbSid);
                dwSidBufferSize = cbSid;
            }
            if (cchDomainName > dwDomainBufferSize)
            {   // Reallocate memory for the domain name buffer.
                wprintf(L"The domain name buffer was too small. It will be reallocated.\n");
                delete [] wszDomainName;
                wszDomainName = new WCHAR[cchDomainName];
                if (wszDomainName == NULL)
                {
                    return MQ_ERROR_INSUFFICIENT_RESOURCES;
                }
                memset(wszDomainName, 0, cchDomainName*sizeof(WCHAR));
                dwDomainBufferSize = cchDomainName;
            }
        }
        else
        {
            wprintf(L"LookupAccountNameW failed. GetLastError returned: %d\n", dwErrorCode);
            hr = HRESULT_FROM_WIN32(dwErrorCode);
            break;
        }
    }

    delete [] wszDomainName;
    return hr;
}

//http://msdn.microsoft.com/en-us/library/windows/desktop/aa379554(v=vs.85).aspx
#define MAX_NAME 256
BOOL SearchTokenGroupsForSID (VOID) //这个暂时放这里.不做讨论.
{
    DWORD i, dwSize = 0, dwResult = 0;
    HANDLE hToken;
    PTOKEN_GROUPS pGroupInfo;
    SID_NAME_USE SidType;
    char lpName[MAX_NAME];
    char lpDomain[MAX_NAME];
    PSID pSID = NULL;
    SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;

    // Open a handle to the access token for the calling process.
    if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ))
    {
        printf( "OpenProcessToken Error %u\n", GetLastError() );
        return FALSE;
    }

    // Call GetTokenInformation to get the buffer size.
    if(!GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize))
    {
        dwResult = GetLastError();
        if( dwResult != ERROR_INSUFFICIENT_BUFFER ) {
            printf( "GetTokenInformation Error %u\n", dwResult );
            return FALSE;
        }
    }

    // Allocate the buffer.
    pGroupInfo = (PTOKEN_GROUPS) GlobalAlloc( GPTR, dwSize );

    // Call GetTokenInformation again to get the group information.
    if(! GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSize, &dwSize ) )
    {
        printf( "GetTokenInformation Error %u\n", GetLastError() );
        return FALSE;
    }

    // Create a SID for the BUILTIN\Administrators group.
    if(! AllocateAndInitializeSid( &SIDAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSID) )
    {
        printf( "AllocateAndInitializeSid Error %u\n", GetLastError() );
        return FALSE;
    }

    // Loop through the group SIDs looking for the administrator SID.
    for(i=0; i<pGroupInfo->GroupCount; i++)
    {
        if ( EqualSid(pSID, pGroupInfo->Groups[i].Sid) )
        {   // Lookup the account name and print it.
            dwSize = MAX_NAME;
            if( !LookupAccountSid( NULL, pGroupInfo->Groups[i].Sid, (LPWSTR)lpName, &dwSize, (LPWSTR)lpDomain, &dwSize, &SidType ) )  //此函数能实现根据sid获取用户名的功能,进而可以想办法利用此函数进行枚举.
            {
                dwResult = GetLastError();
                if( dwResult == ERROR_NONE_MAPPED )
                    strcpy_s (lpName, dwSize, "NONE_MAPPED" );
                else
                {
                    printf("LookupAccountSid Error %u\n", GetLastError());
                    return FALSE;
                }
            }
            printf( "Current user is a member of the %s\\%s group\n", lpDomain, lpName );

            // Find out whether the SID is enabled in the token.
            if (pGroupInfo->Groups[i].Attributes & SE_GROUP_ENABLED)
                printf("The group SID is enabled.\n");
            else if (pGroupInfo->Groups[i].Attributes & SE_GROUP_USE_FOR_DENY_ONLY)
                printf("The group SID is a deny-only SID.\n");
            else
                printf("The group SID is not enabled.\n");
        }
    }

    if (pSID)
        FreeSid(pSID);
    if ( pGroupInfo )
        GlobalFree( pGroupInfo );
    return TRUE;
}

//更多的还有http://msdn.microsoft.com/en-us/library/windows/desktop/aa379608(v=vs.85).aspx

int _tmain(int argc, _TCHAR* argv[])
{
    wchar_t sz_UserNamew[260] = {0};
    int len = sizeof(sz_UserNamew);
    GetUserName(sz_UserNamew,(LPDWORD)&len);

    LPWSTR * wsz_sid = (LPWSTR *)HeapAlloc(GetProcessHeap(), 0, 0x200);
    PSID * ppSid = (PSID *)HeapAlloc(GetProcessHeap(), 0, 0x200);

    GetSid(sz_UserNamew,ppSid);//Administrator,Defaultapppool应该有枚举的办法.NetUserEnum,但不全.特殊的没有.
    bool  b = ConvertSidToStringSid(*ppSid,(LPWSTR *)wsz_sid);
    int x = GetLastError();
    MessageBox(0,(LPCWSTR)(* ( int *)wsz_sid),0,0);

    RtlZeroMemory(wsz_sid,0x200);
    RtlZeroMemory(ppSid,0x200);

    HANDLE hToken;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY_SOURCE | TOKEN_QUERY, &hToken)) return( FALSE );
    GetLogonSID(hToken,ppSid);//字面意思是登录的sid,用的是当前进程或者线程的句柄.
    b = ConvertSidToStringSid(*ppSid,(LPWSTR *)wsz_sid);
    x = GetLastError();
    MessageBox(0,(LPCWSTR)(* ( int *)wsz_sid),0,0);//得到的这个值在注册表中找不到.HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

    HeapFree(GetProcessHeap(), 0, wsz_sid);
    HeapFree(GetProcessHeap(), 0, ppSid);

    SearchTokenGroupsForSID();

 return 0;
}
//made by correy.


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
参考:Microsoft SDKs\Windows\v7.1\Samples\security\authorization\textsid这个工程.
获取当前用户(进程的)SID更简单.其实也就这么简单.
made at 2013.10.10
*/

#include <windows.h>
#include <Sddl.h>

int _tmain()
{
#define MY_BUFSIZE 256 // all allocations should be dynamic
    HANDLE hToken;
    BYTE buf[MY_BUFSIZE];
    PTOKEN_USER ptgUser = (PTOKEN_USER)buf;
    DWORD cbBuffer=MY_BUFSIZE;
    BOOL bSuccess;

    // obtain current process token
    if(!OpenProcessToken(
        GetCurrentProcess(), // target current process
        TOKEN_QUERY,         // TOKEN_QUERY access
        &hToken              // resultant hToken
        ))  {
            return 1;
    }

    // obtain user identified by current process' access token
    bSuccess = GetTokenInformation(
        hToken,    // identifies access token
        TokenUser, // TokenUser info type
        ptgUser,   // retrieved info buffer
        cbBuffer,  // size of buffer passed-in
        &cbBuffer  // required buffer size
        );
    CloseHandle(hToken);
    if(!bSuccess) {
        return 1;
    }

    LPWSTR lpSid = NULL;
    ConvertSidToStringSid(ptgUser->User.Sid, &lpSid);

    //这时已经获取到了,可以查看了.

    LocalFree(lpSid);

    return 1;
}