存档

‘技术心得’ 分类的存档
865 views

STL 中用 erase() 方法遍历删除元素

2010年5月10日

      STL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector 、deque);另一类是以不连续的节点形式存储的容器(如:list、set、map)。在使用erase方法来删除元素时,需要注意一些问题。
      在使用 list、set 或 map遍历删除某些元素时可以这样使用:

正确使用方法1

      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); )
      {
            if( WillDelete( *itList) )
            {
               itList = List.erase( itList);
            }
            else
               itList++;
      }

       或

正确使用方法2

      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); )
      {
            if( WillDelete( *itList) )
            {
               List.erase( itList++);
            }
            else
               itList++;
      }

      
      下面是两个错误的使用方法:

错误使用方法1

      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); itList++)
      {
            if( WillDelete( *itList) )
            {
               List.erase( itList);
            }
      }

         或

错误使用方法2

      std::list< int> List;
      std::list< int>::iterator itList;
      for( itList = List.begin(); itList != List.end(); )
      {
            if( WillDelete( *itList) )
            {
               itList = List.erase( ++itList);
            }
            else
               itList++;
      }

      正确使用方法1:通过erase方法的返回值来获取下一个元素的位置
      正确使用方法2:在调用erase方法之前先使用 “++”来获取下一个元素的位置
      错误使用方法1:在调用erase方法之后使用“++”来获取下一个元素的位置,由于在调用erase方法以后,该元素的位置已经被删除,如果在根据这个旧的位置来获取下一个位置,则会出现异常。
      错误使用方法2:同上。

      这里“++”运算符与我们平常的理解刚好相反,erase( itList++) 是先获取下一个元素的位置在删除; erase( ++itList) 是删除以后再获取下一个元素的位置。
阅读全文…

技术心得

1,041 views

文件路径匹配功能的 C 代码

2010年4月20日

用于与给出的模式串匹配,判断文件路径是否是模式的子集。
模式串里用 “*?”作为包含子文件夹的标记。
比如:模式串 “c:\\path1\\path2\\*?\\*.*” 就匹配 “c:\\path1\\path2\\dd.txt” 和 “c:\\path1\\path2\\path3\\sdf.exe”

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

BOOL fmac_path_match(const char * pszPattern, const char * pszPath)
{
	const static char * pStarAsk = "*?";
	const static char * pStarStar = "*.*";
	const static char * pBackslashStarDot = "\\*.";
	char *pPassThru = NULL;
	BOOL bResult = FALSE;

	do
	{
		pPassThru = strstr(pszPattern, pStarAsk);

		if (pPassThru)
		{
			// ...\\*?\\
			if (*(pPassThru-1) != '\\' || *(pPassThru+2) != '\\')
			{
				break;
			}
			char * pWildCard = strstr(pPassThru, pStarStar);
			if (pWildCard)
			{
				// ...\\*?\\... *.*
				if(0 == strnicmp(pszPattern, pszPath, pPassThru-pszPattern))
				{
					bResult = TRUE;
				}
			}
			else
			{
				// ...\\*?\\*.txt
				if ( *(pPassThru+3) == '*' && *(pPassThru+4) == '.' )
				{
					char * pExt = pPassThru + 5;
					char * pTargetExt = strrchr(pszPath, '.');
					if (0 == strnicmp(pszPattern, pszPath, pPassThru-pszPattern) &&
                                            pTargetExt)
					{
						pTargetExt++;
						if (0 == stricmp(pTargetExt, pExt))
						{
							bResult = TRUE;
						}
					}
				}

			}
		}
		else
		{
			// "..\\*.*" or "..\\*.txt"
			char * pWildCard = strstr(pszPattern, pStarStar);
			if (pWildCard)
			{
				// "..\\*.*"
				if (0 == strnicmp(pszPattern, pszPath, pWildCard-pszPattern) &&
					NULL == strchr(pszPath+(pWildCard-pszPattern), '\\'))
				{
					bResult = TRUE;
				}
			}
			else
			{
				// "..\\*.txt"
				char * pPattern2 = strstr(pszPattern, pBackslashStarDot);
				if (pPattern2)
				{
					char * pExt = pPattern2 + strlen(pBackslashStarDot);

					if (0 == strnicmp(pszPattern, pszPath, pPattern2-pszPattern) &&
						NULL == strchr(pszPath + (pPattern2-pszPattern) + 1, '\\'))
					{
					char * pFileExt = strrchr(pszPath + (pPattern2-pszPattern), '.');
						if (pFileExt)
						{
							pFileExt++;
							if (0 == stricmp(pExt, pFileExt))
							{
								bResult = TRUE;
							}
						}

					}
				}
			}
		}
	} while(FALSE);

	return bResult;
}

void main(int, char **, char **)
{
	BOOL bResult = FALSE;
	char * pPattern1 = "c:\\sdfsdf\\sdfsdfsdfsdf\\*?\\*.*";
	char * pPattern2 = "c:\\sdfsdf\\*?\\*.sdf";
	char * pPattern3 = "c:\\sdfsdf\\sdfsdfsdfsdf\\*.*";
	char * pPattern4 = "c:\\sdfsdf\\*.sdf";

	char * path1 =     "c:\\sdfsdf\\sdfsdfsdfsdf\\adsfsadf\\sdfsdf.sdf";
	char * path2 =     "c:\\sdfsdf\\sdfsdfsdfsdf\\sdfsdf.sdf";
	char * path3 =     "c:\\sdfsdf\\sdfsdf.sdf";

	{
		bResult = fmac_path_match(pPattern1, path1);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern1, path1, bResult);

		bResult = fmac_path_match(pPattern2, path1);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern2, path1, bResult);

		bResult = fmac_path_match(pPattern3, path1);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern3, path1, bResult);

		bResult = fmac_path_match(pPattern4, path1);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern4, path1, bResult);

		printf("===========================\n\n");
	}

	{
		bResult = fmac_path_match(pPattern1, path2);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern1, path2, bResult);

		bResult = fmac_path_match(pPattern2, path2);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern2, path2, bResult);

		bResult = fmac_path_match(pPattern3, path2);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern3, path2, bResult);

		bResult = fmac_path_match(pPattern4, path2);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern4, path2, bResult);

		printf("===========================\n\n");
	}

	{
		bResult = fmac_path_match(pPattern1, path3);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern1, path3, bResult);

		bResult = fmac_path_match(pPattern2, path3);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                   pPattern2, path3, bResult);

		bResult = fmac_path_match(pPattern3, path3);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern3, path3, bResult);

		bResult = fmac_path_match(pPattern4, path3);
		printf("pattern = \t%s\r\npath    = \t%s\r\nresult  = %d\r\n\r\n",
                  pPattern4, path3, bResult);

		printf("===========================\n\n");
	}

	printf("result = %d\n", bResult);

}

技术心得

1,444 views

Detours: 在二进制代码上截获Win32函数调用

2010年4月10日

Galen Hunt and Doug Brubacher
Microsoft Research
One Microsoft Way
Redmond, WA 98052
detours@microsoft.com

http://research.microsoft.com/sn/detours

注:这篇论文首次发表是授权给USENIX。作者保留著作权。本文允许出于非商业性目的拷贝,例如教育和研究目的。第一次发表在 Proceedings of the 3rd USENIX Windows NT Symposium. Seattle, WA, July 1999。

摘录
具有创意的系统级检测研究的关键,在于使得截获函数调用变得更简单以及用来扩展已经存在的操作系统和应用程序的功能。通过得到源代码,我们可以轻而易举的通过重建(Rebuilding)操作系统或者应用程序的方法在它们中间插入新的功能或者做功能扩展。然而,在今天这个商业化的开发世界里,以及在只有二进制代码发布的系统中,研究人员几乎没有可能可以得到程序的源代码。

我们开发的Detours 是一个在x86平台上截获任意Win32函数调用的工具库。Detours通过重写目标函数的映像来达到插入到Win32 函数中执行的目的。Detours开发包中同样保留了描述如何附着到任意的Win32二进制文件的DLLs和data节表(被称为一种有效负荷,“payloads”)的文档。

虽然以前的开发人员曾经使用重写二进制代码的方法将调试和性能测试的代码加入到应用程序中,但是据我们所知,Detours是第一个在任意平台(译注:指Windows平台)都提供了可以将目标函数做为一个截获函数的子过程来调用的开发包。我们独特的trampoline设计是扩展已存在的二进制软件的关键。

我们将介绍我们使用Detours来生成一个自动化的分布式系统的经验,这个系统被用来分析 DCOM 协议栈,并且被用来为基于COM的OS API生成一个thunking层。它从一个微观的基准上证明了Detours库的有效性。

1 介绍
具有创意的系统级检测研究的关键,在于使截获函数更简单可行以及扩展已经存在的操作系统和应用程序的功能,不论这个函数存在于一个应用程序,一个库,或者一个系统的动态链接库中。我们截获函数执行最直接的原因就是为函数增添功能,修改返回值,或者为调试以及性能测试加入附加的代码。通过访问源代码,我们可以轻而易举的使用重建(Rebuilding)操作系统或者应用程序的方法在它们中间插入新的功能或者做功能扩展。然而,在今天这个商业化的开发世界里,以及在只有二进制代码发布的系统中,研究人员几乎没有机会可以得到源代码。

Detours是一个在x86平台上截获任意Win32函数调用的工具库。中断代码可以在运行时动态加载。Detours使用一个无条件转移指令来替换目标函数的最初几条指令,将控制流转移到一个用户提供的截获函数。而目标函数中的一些指令被保存在一个被称为“trampoline” (译注:英文意为蹦床,杂技)的函数中,这些指令包括目标函数中被替换的代码以及一个转移到目标函数的无条件分支。而截获函数可以替换目标函数,或者通过执行“trampoline”的时候将目标函数作为子程序来调用的办法来扩展功能。

Detours是执行时被插入的。内存中的目标函数的代码不是在硬盘上被修改的,因而可以在一个很好的粒度上使得截获二进制函数的执行变得更容易。例如,一个应用程序执行时加载的DLL中的函数过程可以被插入一段截获代码(detoured),与此同时,这个DLL还可以被其他应用程序按正常情况执行(译注:也就是按照不被截获的方式执行,因为DLL二进制文件没有被修改,所以发生截获时不会影响其他进程空间加载这个DLL)。不同于DLL的重新链接或者静态重定向,Detours库中使用的这种中断技术确保不会影响到应用程序中的方法或者系统代码对目标函数的定位。

如果其他人为了调试或者在内部使用其他系统检测手段而试图修改二进制代码,Detours将是一个可以普遍使用的开发包。据我们所知,Detours是第一个可以在任意平台上将未修改的目标代码作为一个可以通过“trampoline”调用的子程序来保留的开发包。而以前的系统在逻辑上预先将截获代码放到目标代码中,而不是将原始的目标代码做为一个普通的子程序来调用。我们独特的“trampoline”设计对于扩展现有的软件的二进制代码是至关重要的。
出于使用基本的函数截获功能的目的,Detours同样提供了编辑任何DLL导入表的功能,达到向存在的二进制代码中添加任意数据节表的目的,向一个新进程或者一个已经运行着的进程中注入一个DLL。一旦向一个进程注入了DLL,这个动态库就可以截获任何Win32函数,不论它是在应用程序中或者在系统库中。

在下一节里我们将讲述Detours是如何工作的。第3节概述了如何使用Detours库,第4节描述了截获函数使用的一般技术以及如何通过一个微观标准来衡量Detours。第5节详细描述了如果使用Detours从本地应用程序产生分布式应用程序,用来量化DCOM的花费,为一个新的基于COM的Win32API建立一个thunking层,并且实现捕获第一次机会异常。我们会在第6节将Detours和其他人的相关工作做一个比较并且在第7节作出总结。
阅读全文…

技术心得 , ,

1,112 views

How to increment version information after each build in Visual C++

2010年4月2日

Visual C++ doesn’t have a feature to automatically increment the version resource
information of your project after each build.
This article describes one way to provide such a feature.

You can write a program to modify the resource compiler (.rc) file instead of
using the steps described here. However, the RC file is under the control of
Visual C++. Visual C++ modifies the RC file while saving, and this may affect
the version resource. The approach described in this section can be applied to
any Visual C++ project. This example uses a Microsoft Foundation Classes
project.


Create a new project using the MFC (EXE) Appwizard and call it
MyProject. MyProject will have a MyProject.rc file,
which includes MyProject.rc2. The .rc2 file is meant for user-defined resources.
Follow these steps to increment MyProject’s version information after each
build:


  1. Remove the version resource from the .rc file and place it in the .rc2
    file:

    1. Open both MyProject.rc and MyProject.rc2 (found in the Res folder),
      in a text editor. To use the Visual C++ editor, click Open on the
      File menu and select Text in the Open As list for the
      MyProject.rc file.
    2. Find the version resource statements in MyProject.rc. It should look
      something like:

      ///////////////////////////////////////////////////////////////////////
      //
      // Version
      // 
      
      VS_VERSION_INFO VERSIONINFO
       FILEVERSION 1,0,0,1
       PRODUCTVERSION 1,0,0,1
       FILEFLAGSMASK 0×3fL
      #ifdef _DEBUG
       FILEFLAGS 0×1L
      #else
       FILEFLAGS 0×0L
      #endif
       FILEOS 0×4L
       FILETYPE 0×1L
       FILESUBTYPE 0×0L
      BEGIN
          BLOCK "StringFileInfo"
          BEGIN
              BLOCK "040904b0"
              BEGIN
                  VALUE "Comments", "Sample Application\0"
                  VALUE "CompanyName", "Microsoft Corp.\0"
                  VALUE "FileDescription", "MyProject MFC Application\0"
                  VALUE "FileVersion", "1, 0, 0, 1\0"
                  VALUE "InternalName", "MyProject\0"
                  VALUE "LegalCopyright", "Copyright (C) 1999\0"
                  VALUE "OriginalFilename", "MyProject.EXE\0"
                  VALUE "ProductName", "MyProject Application\0"
                  VALUE "ProductVersion", "1, 0, 0, 1\0"
              END
          END
          BLOCK "VarFileInfo"
          BEGIN
              VALUE "Translation", 0×409, 1200
          END
      END
      

    3. Cut the version resource from the MyProject.rc file and paste it into
      the MyProject.rc2 file below the comment “Add manually edited resources here.”
      For information about what each one of the fields in the resource means, see the
      VERSIONINFO resource statement in Help.


  2. Replace the FILEVERSION and PRODUCTVERSION data with macros FILEVER and
    PRODUCTVER. Similarly, replace the FileVersion and ProductVersion string data
    with the macros STRFILEVER and STRPRODUCTVER.
  3. Add a #include VersionNo.h immediately before
    the VS_VERSION_INFO resource statement. Now the version resource will look like:

    ///////////////////////////////////////////////////////////////////////
    //
    // Version
    //
    #include "VersionNo.h"
    VS_VERSION_INFO VERSIONINFO
     FILEVERSION FILEVER
     PRODUCTVERSION PRODUCTVER
     FILEFLAGSMASK 0x3fL
    #ifdef _DEBUG
     FILEFLAGS 0x1L
    #else
     FILEFLAGS 0x0L
    #endif
     FILEOS 0x4L
     FILETYPE 0x1L
     FILESUBTYPE 0x0L
    BEGIN
        BLOCK "StringFileInfo"
        BEGIN
            BLOCK "040904b0"
            BEGIN
                VALUE "Comments", "Sample Application\0"
                VALUE "CompanyName", "Microsoft Corp.\0"
                VALUE "FileDescription", "MyProject MFC Application\0"
                VALUE "FileVersion", STRFILEVER
                VALUE "InternalName", "MyProject\0"
                VALUE "LegalCopyright", "Copyright (C) 1997\0"
                VALUE "OriginalFilename", "MyProject.EXE\0"
                VALUE "ProductName", "MyProject Application\0"
                VALUE "ProductVersion", STRPRODUCTVER
            END
        END
        BLOCK "VarFileInfo"
        BEGIN
            VALUE "Translation", 0x409, 1200
        END
    END
    

  4. Create a header file called VersionNo.h in the same directory as your
    project. This file will contain the following statements, which are the
    definitions for macros used in step 2:

    #define FILEVER        1,0,0,1
    #define PRODUCTVER     1,0,0,1
    #define STRFILEVER     “1, 0, 0, 1\0″
    #define STRPRODUCTVER  “1, 0, 0, 1\0″
    

    NOTE: Add linefeed and carriage return characters on the last line.
    Now, MyProject.rc file includes MyProject.rc2, and MyProject.rc2 file includes VersionNo.h.

  5. The VersionNo.h file contents will be modified using a Visual Basic Script
    macro. The macro described below handles the Visual C++ BuildFinish event, so it
    will not be fired until a build completes. Whenever this VB Script code is
    called, it first increments the version numbers inside the header file by a
    fixed amount, then it saves the file and closes it. During a subsequent build,
    the new version number is included in the executable.

    To install and use
    the VB Script code, do the following:



    1. Open an existing DSM (macro) file or create a new DSM file in Visual
      C++. To create a new file, click New on the File menu, select
      Macro File on the Files tab, give it a name, and click OK.
    2. Paste the following VB Script code below (an empty DSM file cannot be
      installed in Visual C++; the next step explains installing):

      Function GetProjectDir(FullName)
      
      'VC++ doesn't provide any method for getting the path of the active project
      'See the VB Script reference for more information on the VB Script functions
      'used in this function
      
        Dim proj_path
        proj_path = Split(StrReverse(FullName),"\",-1,1)
      
        Dim count
        count = UBound(proj_path)
      
        Dim full_path
        full_path = ""
        Dim i
      
        for i = 1 to count
      	full_path = full_path & "\" & proj_path(i)
        next
      
        GetProjectDir = StrReverse(full_path)
      End Function
      
      Sub ReplaceText(selection, count, incrementby)
      
      'selection represents the TextSelection object
      'count represents the position of the version number to be incremented
      'incrementby represents a number that will be added to the existing version number
      
        selection.WordRight dsMove, count
        selection.WordRight dsExtend, 1
        Dim str
        str = selection.Text
        str = str + incrementby
      
        selection.Text = str
      
      End Sub
      
      Sub Application_BuildFinish(numError, numWarning)
      
        'This event will be triggered after every build of a project
        'You can check numError and/or numWarning to determine if you want to continue
        'If numError <> 0 Then
            'exit sub
        'Obtain the full path of the active project
        Dim full_path
        full_path = GetProjectDir(ActiveProject.FullName)
      
        full_path = full_path & "versionno.h"
      
        'Open the VersionNo.h file
        Documents.Open full_path
      
        'Obtain the TextSelection object
        Dim selection
        set selection = ActiveDocument.Selection
        selection.StartOfDocument 
      
        'Increment the version information
        ReplaceText selection, 9, 1
        selection.LineDown
        selection.StartOfLine
        ReplaceText selection, 9, 1
        selection.LineDown
        selection.StartOfLine
        ReplaceText selection, 10, 1
        selection.LineDown
        selection.StartOfLine
        ReplaceText selection, 10, 1
      
        ActiveDocument.Save
        ActiveDocument.Close
      End Sub
      

      NOTE: This code is an unsupported sample. You may modify it for your build scenario.

    3. Install the DSM file if it is not already installed. To install,
      click Customize on the Tools menu, click the Add-in and Macro
      Files
      tab, browse to select the DSM file, and click Close.

  6. Select Build MyProject.exe from the Build menu. After the
    build finishes, open the VersionNo.h file. It will contain the following
    statements:

    #define FILEVER        1,0,0,2
    #define PRODUCTVER     1,0,0,2
    #define STRFILEVER     "1, 0, 0, 2\0"
    #define STRPRODUCTVER  "1, 0, 0, 2\0"
    

    If you build the code again, this version information in included in the executable,
    and the version information is incremented.
    You can introduce some code in the macro described earlier to
    prevent incrementing version numbers if the build produced errors.

http://support.microsoft.com/?scid=kb%3Ben-us%3B237870&x=13&y=8

技术心得

691 views

“鬼子来了” 电影剧本

2010年3月28日

鬼子来了

根据尤凤伟小说《生存》改编
编剧:述平 史建全 姜文 尤凤伟
导演 姜文
摄影指导:顾长卫
作曲:崔健 李海鹰 刘星
美术师 唐世云
录音师:吴凌
剪辑师:张一凡 弗摩.温辛格
执行导演:赵一军
制片主任:张华 喜子
摄影师:王敏 赵晓时
中方主要演员:
姜文:村民马大三
姜鸿波:年轻寡妇鱼儿
陈强:老刽子手一刀刘
陈述:疯七爷,鱼儿的公公
丛志军:五舅姥爷,村中众望所归的长者
袁丁:董汉臣,日军翻译,汉奸
史建全:四表姐夫
吴大维:高少校,国军军官
蔡东东:村民二脖子
李丛喜:村民六旺
陈莲梅:八婶子,二脖子妈
周海超:小碌碡,鱼儿的儿子
日方主要演员:
香川照之:日军俘虏花屋小三郎
泽田谦也:日军陆军队长酒冢猪吉
宫路佳具:日军海军队长野野村耕二
长野客弘:日军老电话兵
井上弥生:日妓
 

《鬼子来了》剧本第一部分

序(随画面出主要演职员字幕)

黑底白字。投资单位,摄制单位渐隐,银幕一片漆黑。静——

“立正!”(日语)

随着一声野狼般的军令声,乐队奏响了《军舰进行曲》。此时一面充满了画面的日本海军军旗
迎着寒风猎猎升起。四个竖排的大字由军旗中蹦出。
《鬼子来了》

一双锃亮的军靴。“咔”地磕出铁声。带马刺的军靴猛地插入马蹬。野野村跨上黑马。抖缰跃
出,环绕着队伍小跑了一圈。

野野村:向左——转!(日语)

紧随野野村马后,一队背负各式工具袋,手持乐器的日本兵边走边奏。

野野村(画外):出发!(日语)

队伍步伐整齐地走出兵营,这是一支日本海军陆战队的后勤兵,驻扎在挂甲台村对面的山顶上。
每日准时去军用小码头迎送过往的船只。因队长野野村是音乐爱好者,便有了如今这副打扮的
军乐队。

军乐队行进在山道上。队伍后面跟着一头小毛驴,毛驴的身上担着两个空水桶。

挂甲台——水边山下只有几户人家的小村,此刻各家的烟筒里已经升起炊烟。村民二脖子从家
里跑出。

听到军乐声,孩子由各家出来向村口跑去。二脖子跑向村口井台,
孩子们跑过小桥,经过二脖子身边。

二脖子:小碌碡。

众小孩:二脖子,二脖子叔。

孩子们向村口继续狂奔。小碌碡坐上村口的矮墙上。村口矮墙上孩子们已坐成一排,摇头晃脚
地望着军乐队的方向——等待着。

野野村:二脖子!

二脖子:先生!(日语)

野野村:二脖子。

乐队迎面走下,二脖子向野野村鞠躬点头,打着招呼。

二脖子:先生!(日语)

二脖子向队尾跑去。乐队每天早晨都要从这里经过,黄昏的时候再回去,村民二脖子负责把两
个空水桶摘下来,等他们回去的时候再把装满水的水桶放到驴背上。

野野村:谁想当我的好孩子?分糖吃喽。来,来。(日语)

野野村边说边分着糖,微笑地看着孩子们,一副彼此混熟了的样子。

二脖子摘下水桶后,牵着驴向军乐队这边追来。

野野村面对小碌碡又拿出一颗糖果,魔术般地将糖变没了,他握着两只戴着白手套的拳头在小
碌碡眼前晃动,叫他来猜。

野野村:瞧这儿!在哪边?(日语)

小碌碡猜对了。

野野村:真聪明!(日语)

野野村如法又变了一次。小碌碡没猜对。野野村得意地大笑。

野野村:在哪边?(日语)没有…的。看,在这儿呢。(日语)

小碌碡一把抢走那块糖。惹得野野村又是一阵大笑。孩子们也更高兴起来,连二脖子也跟着笑
出了声。野野村瞟了一眼二脖子,他忽然收住笑严厉地指着二脖子。

野野村:水的干净!水的不干净!(汉语)一、二、三,扇你三耳光,明白?(日语)

二脖子:明白!晚上给你老预备干净水!

乐队渐渐远去,这时水面上有一艘日军的炮艇突突突地经过。野野村向艇上的人挥手致意。随
着乐队的声音结束,字幕完毕。

 

一、大三家 冬夜 外、内

夜空中一轮圆圆的明月。

字幕:一九四五年,华北,日军占领区。

一个只有十几户人家的村落沐浴在夜色中,日军炮楼上的探照灯不时地在村子上空掠过.,在一
片安详宁静的气氛中,隐隐传来男女喘息的声音。
这声音来自村里的某户人家。

一盏油灯跳动着鲜活的火苗。

一只女人的腿露在被子外面。被子里两个人在动。

女人的长发扫着地上的枕头。

大三(画外):让我看看!

鱼儿:看啥呀?

油灯的火苗被一只男人粗壮的手捻亮,随即又被一只女人的手捻暗,油灯被弄得明明灭灭的。

大三:让我看看!

鱼儿:看啥呀?别看了!

大三:我看看呢!

鱼儿:哎呀,快点儿的,别歇着!

两人推着扯着,突然外面传来咚咚敲门声,大三猛地坐起。

静静的窗户。

大三紧张的脸对画外:谁呀?

一个男人的声音:我!

大三:谁?

来人:我!

大三顾不上多想,翻身下炕。

鱼儿(画外):快穿衣裳!

大三:你咋办呢?

鱼儿:我去老地方。

鱼儿迅速地从炕上起来,急忙跑向墙角的大面柜。

大三抱起一堆衣裳给鱼儿,鱼儿熟练地盖上了柜盖。

大三撩帘从里屋出来开门,

大三:谁呀?

门外的人: 我!

门刚一打开,大三手中的油灯被来人”扑“地吹灭,一只乌黑的手枪顶在大三的脑门上,随着
噔噔的脚步声,来人把他逼到墙角。

持枪人身在暗影中,面目模糊。

持枪人:合上眼!

枪依然顶在大三的脑门上。

大三紧闭双眼。

持枪人(画外):叫啥?

大三冲画外:马大三。

持枪人(画外):村叫啥?

大三:挂……挂甲台。

持枪人(画外):黑更半夜点灯干啥?

大三:寻思事!

持枪人(画外):那……你就好好寻思寻思!听着,我们有两件东西,先搁你这儿,一样不能丢!
一样不能少!还不能让鬼子知道!出了半点闪失,要你命!

大三:那啥……这村头就有个炮楼子,怕不中吧?

持枪人(画外):啥不中?这叫灯下黑,明白不?

大三:明白了!那要是出事了,找谁呀?

持枪人(画外):你!

持枪人又用枪管使劲地顶了一下大三的脑门,然后缓缓地离开。

大三战战兢兢地睁开了眼,发现屋子里空空的已经没有了人。
门还开着,地上有两样物件。

鱼儿掀开柜盖。

大三关上屋门,返身坐在灶台边愣神。

鱼儿这时已穿好衣服,撩开门帘探头出来。

鱼儿:谁呀?

大三:知不道!

鱼儿划火柴,大三去解开麻袋上的绳子。麻袋里露出一个男人的脑袋,睁着大眼。

鱼儿吓得坐在了地上。

鱼儿:哎呀!活人!

大三又去解另一只,里面同样装着一个男人。

大三盖上麻袋。

大三:不中!我找他们去!

大三向门口冲去。

正当他准备打开门时,“扑”的一声,窗户纸被捅破了。
一只上了刺刀的长枪从外面探了进来,大三瞪着惊恐的眼睛盯着它。

持枪人(画外):马大三!

大三:哎!

大三扑通跪下。

持枪人 (画外)听着!这两人抓空替我们审审!

此时刺刀就在眼前,仿佛是它在说话。

持枪人(画外):年三十午夜黑间我们过来取人,

鱼儿惊恐地盯着窗户,

持枪人:(画外):连口供一块堆儿带走!

大三惊恐的表情。

持枪人(画外):明白不?

大三:明白了!

窗外的人迅速地抽出刺刀,窗户上只剩下一个残破的大洞。

大三:那……到时候,谁来取人呢?

大三看着窗户上的大洞。

持枪人(画外):我!

 

阅读全文…

技术心得

858 views

监视特定驱动器或文件夹的活动

2010年3月25日
902 views

监视远程线程的创建

2010年3月17日

标 题: 监视远程线程的创建
作 者: 一块三毛钱
邮件: zhongts@163.com
时 间: 2005-02-21,15:23:52
链 接: http://bbs.pediy.com/showthread.php?t=11347

远程线程技术被大量的使用在木马、蠕虫等软件当中,通过在别的进程中插入线程的方式运行代码,具有相当高的隐蔽性。比如常见的 Explorer.exe 进程中有十几个线程同时运行,在其中插入一个线程后,谁也分辨不出来哪个就是插入的远程线程。本文提供了一种方法可以监视远程线程的创建活动,记录下来远程线程的 ID 等重要数据,这样就可以方便大家查出哪个进程往哪个进程中插入了远程线程。

下面分别是 IceSword v1.06 和本文代码所记录下来的远程线程创建的情况:


由于本文需要编写驱动程序,所以不熟悉驱动程序编写的读者可以找一些驱动方面的书籍先看看,这里推荐大家到罗云彬的网站上去下载翻译的 KmdTut 来看。同时把 KmdKit 也下载下来,因为本文代码用到了这个软件包。安装好 Masm32 和 KmdKit 之后才能编译本文提供的代码。如果编译代码时提示 error LNK2001: unresolved external symbol _PsRemoveCreateThreadNotifyRoutine@4 错误,则把本文提供的 ntoskrnl.lib 复制到 lib\w2k 文件夹中覆盖原文件即可。我也是刚学驱动编程,下面提供的只是一个很简单的例子,要想实用还有很多事情要做。

首先是监视线程的创建问题,然后再区分哪些是远程线程。要想监视线程的创建需要用到这样的一个函数 PsSetCreateThreadNotifyRoutine。通过该函数我们注册一个回调函数,每次当系统中有新的线程创建的时候就会调用我们的回调函数。在这个回调函数中我们就可以把所有的线程的创建记录下来。如果要监视进程的创建则还有另外一个函数 PsSetCreateProcessNotifyRoutine 可以完成这个功能。监视线程创建的回调函数的函数原型如下:

VOID
(*PCREATE_THREAD_NOTIFY_ROUTINE) (
    IN HANDLE  ProcessId,
    IN HANDLE  ThreadId,
    IN BOOLEAN  Create
    );

ProcessId 是进程号,这里的进程号是指向包括该线程的进程,而不是创建该线程的进程。ThreadId 是将要创建的线程的线程号。 Create 用来指出是创建线程还是销毁线程。监视进程创建的回调函数的函数原型如下:

VOID
(*PCREATE_PROCESS_NOTIFY_ROUTINE) (
    IN HANDLE  ParentId,
    IN HANDLE  ProcessId,
    IN BOOLEAN  Create
    );

ParentId 是父进程号,ProcessId 是进程号,Create 表示创建还是销毁进程。

有了这两个函数我们就可以监视所有的进程和线程的创建和销毁活动了。下面来看看代码,我把主要的代码都列了出来。
阅读全文…

技术心得

731 views

一些正则表达式

2010年3月12日

1. 匹配文件通配符
^(\*\.(\*|(\w+)))$

2. 匹配文件路径有效性(含网络文件路径)
^(([a-zA-Z]:\\)|(\\\\((([^\\/:\*\?<>"\| ])|([^\\/:\*\?<>"\| ][^\\/:\*\?<>"\|]*[^\\/:\*\?<>"\| ]))\\){2}))((([^\\/:\*\?<>"\|]*)(\\?))*)$

匹配中文字符的正则表达式: [\u4e00-\u9fa5]
评注:匹配中文还真是个头疼的事,有了这个表达式就好办了

匹配双字节字符(包括汉字在内):[^\x00-\xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)

匹配空白行的正则表达式:\n\s*\r
评注:可以用来删除空白行

匹配 HTML 标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? />
评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力

匹配首尾空白字符的正则表达式:^\s*|\s*$
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式

匹配 Email 地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
评注:表单验证时很实用

匹配网址 URL 的正则表达式:[a-zA-z]+://[^\s]*
评注:网上流传的版本功能很有限,上面这个基本可以满足需求

匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
评注:表单验证时很实用

匹配国内电话号码:\d{3}-\d{8}|\d{4}-\d{7}
评注:匹配形式如 0511-4405222 或 021-87888822

匹配腾讯 QQ 号:[1-9][0-9]{4,}
评注:腾讯QQ号从10000开始

匹配中国邮政编码:[1-9]\d{5}(?!\d)
评注:中国邮政编码为6位数字

匹配身份证:\d{15}|\d{18}
评注:中国的身份证为15位或18位

匹配 ip 地址:\d+\.\d+\.\d+\.\d+
评注:提取ip地址时有用

匹配特定数字
^[1-9]\d*$    //匹配正整数
^-[1-9]\d*$   //匹配负整数
^-?[1-9]\d*$   //匹配整数
^[1-9]\d*|0$  //匹配非负整数(正整数 + 0)
^-[1-9]\d*|0$   //匹配非正整数(负整数 + 0)
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$   //匹配正浮点数
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$  //匹配负浮点数
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$  //匹配浮点数
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$   //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$  //匹配非正浮点数(负浮点数 + 0)
评注:处理大量数据时有用,具体应用时注意修正

匹配特定字符串
^[A-Za-z]+$  //匹配由26个英文字母组成的字符串
^[A-Z]+$  //匹配由26个英文字母的大写组成的字符串
^[a-z]+$  //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$  //匹配由数字和26个英文字母组成的字符串
^\w+$  //匹配由数字、26个英文字母或者下划线组成的字符串
评注:最基本也是最常用的一些表达式

匹配 Unicode 编码的中英文混合的字符串
(((\w*)([\u4e00-\u9fa5]*))*)

技术心得

1,006 views

获得当前线程的用户名和此用户的 SID (security identifier)

2010年3月4日
BOOL GetCurrentUserSID(LPTSTR lpszSID, UINT cchMax)
{
	typedef BOOL (WINAPI * PFN_ConvertSidToStringSidA)(PSID Sid, LPSTR * StringSid);
	typedef BOOL (WINAPI * PFN_ConvertSidToStringSidW)(PSID Sid, LPWSTR * StringSid);

	TCHAR szUserName[256] = { 0 };
	DWORD dwSize2=256, cbSID = 1024, cchDomainName = 80;
	BOOL ret = FALSE;
	PSID pSID = NULL;
	LPTSTR lpszDomain = NULL, StringSid = NULL;
	PSID_NAME_USE psnuType = NULL;
	PFN_ConvertSidToStringSidA pfn_ConvertSidToStringSidA = NULL;
	PFN_ConvertSidToStringSidW pfn_ConvertSidToStringSidW = NULL;
	HINSTANCE hAdvDll = NULL;

	do
	{
		hAdvDll = LoadLibrary(TEXT("Advapi32.dll"));
		if (NULL == hAdvDll) { break; }
		pfn_ConvertSidToStringSidA = (PFN_ConvertSidToStringSidA)
                                GetProcAddress(hAdvDll, "ConvertSidToStringSidA");
		pfn_ConvertSidToStringSidW = (PFN_ConvertSidToStringSidW)
                                GetProcAddress(hAdvDll, "ConvertSidToStringSidW");
		if (pfn_ConvertSidToStringSidA == NULL) {
			break;
		}

		ret = GetUserName(szUserName,&dwSize2);
		if(ret == FALSE) { break; } 

		pSID = (PSID) LocalAlloc(LPTR, cbSID);
		lpszDomain = (LPTSTR) LocalAlloc(LPTR, cchDomainName*sizeof(TCHAR));
		psnuType = (PSID_NAME_USE) LocalAlloc(LPTR, 1024);
		ret = LookupAccountName((LPTSTR)NULL, szUserName, pSID, &cbSID,
			lpszDomain, &cchDomainName, psnuType);
		if(ret == FALSE) { break; } 

		StringSid = (LPTSTR) LocalAlloc(LPTR, 1024*sizeof(TCHAR));
		// ret=ConvertSidToStringSid(pSID,&StringSid);
#if defined(UNICODE) || defined(_UNICODE)
		ret=pfn_ConvertSidToStringSidW(pSID,&StringSid);
#else
		ret=pfn_ConvertSidToStringSidA(pSID,&StringSid);
#endif
		if (ret) {
			lstrcpyn(lpszSID, StringSid, cchMax);
		}

		ret = TRUE;
	} while (FALSE);

	if (StringSid) { LocalFree((HLOCAL)StringSid); }
	if (pSID) { FreeSid(pSID); }
	if(psnuType != NULL) { LocalFree((HLOCAL) psnuType); }
	if(lpszDomain != NULL) { LocalFree((HLOCAL) lpszDomain); }
	if (hAdvDll) { FreeLibrary(hAdvDll); }

	return ret;
}

技术心得 , , ,

1,183 views

什么时候必须显式调用析构函数

2010年3月3日

析构函数可以自己调用

msdn says:
Calling a destructor explicitly is seldom necessary. However, it can be useful to perform cleanup of objects placed at absolute addresses. These objects are commonly allocated using a user-defined new operator that takes a placement argument. The delete operator cannot deallocate this memory because it is not allocated from the free store . A call to the destructor, however, can perform appropriate cleanup. To explicitly call the destructor for an object, s, of class String, use one of the following statements:

s.String::~String();     // Nonvirtual call
ps->String::~String();   // Nonvirtual call

s.~String();       // Virtual call
ps->~String();     // Virtual call

现在有个问题,除了知道 “析构函数可以自己调用” 外, 那么什么时候必须显式调用析构函数?

先看一段现实生活中的代码吧, mfc 源码:

BOOL CStatusBar::AllocElements(int nElements, int cbElement)
{
	int i;

	// destruct old elements
	AFX_STATUSPANE* pSBP = _GetPanePtr(0);
	for (i = 0; i < m_nCount; i++)
	{
		pSBP->strText.~CString(); // 注意看这里
		++pSBP;
	}

	// allocate new elements
	if (!CControlBar::AllocElements(nElements, cbElement))
		return FALSE;

	// construct new elements
	pSBP = _GetPanePtr(0);
	for (i = 0; i < m_nCount; i++)
	{
#pragma push_macro("new")
#undef new
		new( &pSBP->strText ) CString; // 注意看这里
#pragma pop_macro("new")
		++pSBP;
	}
	return TRUE;
}

阅读全文…

技术心得