Strategies of Dump Files & etc

刚刚在DebugInfo.com上看完了Effective minidumps系列文章,看得是相当的亢奋。想到其中很多知识点在工作中可以用到,以提高咱CER系统的效率,就感到一阵兴奋。原来MiniDumpWriteDump API还可以这样来使用的。
 
首先是用户数据流(User Date Streams),这个功能对于自定义Dump文件内容相当有用。Dump文件一般提取的信息都是Executable的进程内部的一些状态,但是如果能够加上一些诸如:应用程序的配置文件,应用程序所访问的注册表,等信息的话,就会对我们的调式提供更多有帮助的信息。实现起来也很方便,几乎就是对几个Struct进行填充:
  char Message1[] = "This is the first data stream…"; // 这个就是要写入到Dump文件中的用户信息
  const ULONG32 cFirstStreamID = LastReservedStream + 1; 
  MINIDUMP_USER_STREAM UserStreams[1];
  UserStreams[0].Type        = cFirstStreamID;
  UserStreams[0].Buffer      = Message1;
  UserStreams[0].BufferSize  = sizeof(Message1);
  MINIDUMP_USER_STREAM_INFORMATION musi;
  musi.UserStreamCount   = 2;
  musi.UserStreamArray   = UserStreams;
  BOOL rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, (pep != 0) ? &mdei : 0, &musi, 0 );
不过这些信息貌似并不是在调式器中可见的,而且我还没有发现有什么命令可以提取出这个我们插进去的数据。一般还是通过MiniDumpReadDumpStream函数来获取。尽管不是很方便,但是至少也提供了一些让我们在Dump文件中添加额外信息的一种方法。
 
其次就是关于策略的问题。这个问题相对还是比较重要的,因为它直接影响到了我们开发人员对于Dump文件的分析。这让我联想到最近我在做的一个CER bucket: 920861,出错的原因可以很容易地分析出来是一个heap corruption,但是由于我们的CER都没有抓取heap上的内存内容,所以就无法察看到底是什么样的一个heap结构,破坏这个堆的是哪种类型的数据对象。郁闷了半天,还是没办法解决。另外一个关于dll和symbol文件不匹配的处理方式,以后我会在这里share一些。
对于Dump文件的抓取策略,主要是在文件的内容是否充足和文件的大小进行折中,不同的应用程序一般应该选择不同的策略来满足开发以及日后产品发布后的排错工作
 
共有4种常用的类型:
1. TinyDump:是使文件尺寸最小的一种策略。
Type:MiniDumpNormal;
Callback:IncludeThreadCallback,去除了所有的线程信息;IncludeModuleCallback,去除了所有的模块信息。
所以这种Dump文件尺寸极端的小,使用debugger是无法打开的。一般使用MiniDumpReadDumpStream来获取信息。
 
2. MiniDump:不是普通意义上的minidump,它还包含了一部分对于Heap的内存信息。通常是异常栈中每个函数帧中,某一指针所指向的内存区域会被Dump下来,这样就可以解决我上面题到的那种heap corruption的错误。所以我觉得这个对于我们的CER特别有用,也许我该和boss提起这方面的事情。
 
3. MidiDump:提供的内存信息更多,甚至会包含进一些代码段中的内容。不过这个对CER作用提高不是很明显,因为许多模块以及它对应的Symbol文件我们都可以去微软的Symbol Server上去下载。
 
4. MaxiDump:这个几乎就是包含了该有的一切,所以产生的Dump文件非常大,虽然对于调试帮助很明显,但是不便于在网络上传输。客户如果发现一个Dump文件的发送要那么长时间,估计肯定就Cancel操作了。
 
OK,就总结这么多。懒得结尾|||

Yesterday at Office…

IMG_0037

终于忍不住买了iPhone,花了血本,所以最近穷了。(好在昨天Vendor Code终于拿到手,所以今天赶紧先分批把2000CNY发票的1/2拿去报销。一打发票,涂糨糊贴发票就搞了半天。)至于N93i的去向:“被我老爸给用了”。Neo说iPhone是200w象素,不过感觉拍摄效果还不错(可惜不能变焦,不能拍视频)。见上图。屏幕后面是我的boss。嗯,屏幕下面的烂香蕉清晰可见。呃,脸上痘痘也可以看见|||

Source Code for SDDLConvertor

[Copy rights reserved 大笑 Austin Dai @ Autodesk] – for SDDL, reference the previous post.
void MainLogic(LPCTSTR lpstr)
{
 PSECURITY_DESCRIPTOR SecurityDescriptor;
 PEXPLICIT_ACCESS pListOfExplicitEntries;
 do
 {
  if (!ConvertStringSecurityDescriptorToSecurityDescriptor(lpstr, SDDL_REVISION_1, &SecurityDescriptor, NULL))
  {
   if (::GetLastError() == ERROR_NONE_MAPPED)
   {
    std::cout << "SDDL ERROR_NONE_MAPPED." << std::endl;
    break;
   }
   else if (::GetLastError() == ERROR_UNKNOWN_REVISION)
   {
    std::cout << "SDDL ERROR_UNKNOWN_REVISION." << std::endl;
    break;
   }
  }
  if (IsValidSecurityDescriptor(SecurityDescriptor))
  {
   BYTE sidBuffer[100];
   PSID pSID = (PSID)&sidBuffer;
   BOOL bOwnerDefaulted;
   //////////////////////////////////////////////////////////////////////////
   std::cout << "Owner: " << std::endl;
   ZeroMemory(sidBuffer, 100);
   if (!GetSecurityDescriptorOwner(SecurityDescriptor, &pSID, &bOwnerDefaulted))
   {
    std::cout << "GetSecurityDescriptorOwner Failed." << std::endl;
    break;
   }
   if (pSID)
   {
    printSID(pSID);
   }
   //////////////////////////////////////////////////////////////////////////
   std::cout << "Group: " << std::endl;
   ZeroMemory(sidBuffer, 100);
   if (!GetSecurityDescriptorGroup(SecurityDescriptor, &pSID, &bOwnerDefaulted))
   {
    std::cout << "GetSecurityDescriptorGroup Failed." << std::endl;
    break;
   }
   if (pSID)
   {
    printSID(pSID);
   }
   //////////////////////////////////////////////////////////////////////////
   SECURITY_DESCRIPTOR_CONTROL sedescontrol;
   DWORD dwRevision;
   if (!GetSecurityDescriptorControl(SecurityDescriptor, &sedescontrol, &dwRevision))
   {
    std::cout << "GetSecurityDescriptorControl Failed." << std::endl;
    break;
   }
   std::cout << "Revision:\t" << std::hex << dwRevision << std::endl;
   printACLControl(sedescontrol);
   //////////////////////////////////////////////////////////////////////////
   BOOL bDaclPresent;
   BOOL bDaclDefaulted;
   PACL pDacl;
   if (!GetSecurityDescriptorDacl(SecurityDescriptor, &bDaclPresent, &pDacl, &bDaclDefaulted))
   {
    std::cout << "GetSecurityDescriptorDacl Failed." << std::endl;
    break;
   }
   if (bDaclPresent && IsValidAcl(pDacl))
   {
    ACL_REVISION_INFORMATION AclRevision;
    if (!GetAclInformation(pDacl, &AclRevision, sizeof(ACL_REVISION_INFORMATION), AclRevisionInformation))
    {
     std::cout << "GetAclInformation Failed." << std::endl;
     break;
    }
    std::cout << "DACL Revision:\t" << AclRevision.AclRevision << std::endl;
    ACL_SIZE_INFORMATION AclSize;
    if (!GetAclInformation(pDacl, &AclSize, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
    {
     std::cout << "GetAclInformation Failed." << std::endl;
     break;
    }
    std::cout << "DACL Size:\t" << (AclSize.AclBytesInUse + AclSize.AclBytesFree) << std::endl;
    std::cout << "DACL Count:\t" << AclSize.AceCount << std::endl;
    ULONG cCountOfExplicitEntries;
    if (ERROR_SUCCESS == GetExplicitEntriesFromAcl(pDacl, &cCountOfExplicitEntries, &pListOfExplicitEntries))
    {
     PEXPLICIT_ACCESS temp = pListOfExplicitEntries;
     int index = 0;
     while (cCountOfExplicitEntries != 0)
     {
      std::cout << "ACE[" << index << "]:" << std::endl;
      printAccessMask(temp->grfAccessPermissions);
      printAccessMode(temp->grfAccessMode);
      printInheritanceFlag(temp->grfInheritance);
      printTrustee(temp->Trustee);
      index++;
      temp++;
      cCountOfExplicitEntries–;
     }
     if (pListOfExplicitEntries)
     {
      LocalFree(pListOfExplicitEntries);
     }
    }
   }
  }
  else
  {
   std::cout << "This is not a valid security descriptor." << std::endl;
  }
 }while(0);
 if (SecurityDescriptor)
 {
  LocalFree(SecurityDescriptor);
 }
}

ACL Series Collection [Code Project]

Part 1 – Background and Core Concepts. The Access Control Structures

  • The Security Identifier (SID)
  • The Security Descriptor (SD)
  • The Access Control List (ACL)
  • Choosing a good discretionary access control list
  • Windows 2000 Inheritance Model
  • The Token
  • A Note on the Security Descriptor Definition Language
  • Coming Up

Part 2 – Basic Access Control programming

  • Choosing your language
  • Fun with SIDs
  • Which Groups are you a member of?
  • Enabling Token Privileges
  • Dissecting the Security Descriptor
  • Walking an Access Control List
  • Creating an Access Control List
  • Do I Have Access?
  • Creating and Editing a Secure Object
  • Making Your Own Classes Secure
  • Toy Programs Download

Part 3 – Access Control programming with .NET v2.0

  • A history of .NET security.
  • Reading a SID in .NET.
  • Whoami .NET.
  • Privilege handling in .NET.
  • Running as an unprivileged user in .NET.
  • Obtaining and editing a security descriptor in .NET, and applying it to an object.
  • Access checks in .NET.
  • NetAccessControl program and AccessToken class library.

Part 4 – The Windows 2000-style Access Control editor

  • Features of the ACL editor (ACLUI).
  • Getting Started.
  • Implementing the ISecurityInformation Interface.
  • ISecurityInformation::SetSecurity
  • Optional Interfaces.
  • Presenting the interface.
  • Filepermsbox – A program to display the security descriptor on an NTFS file or folder.
  • History

Foreach in C++

今天继续研读Kenny的Post,收获颇丰,学到了一个比较smart的遍历写法,foreach in C++。
 
岔开一句,先提点无关紧要的,但是也是蛮有意思的东西:goto语句不到最后关头不要在C++或者C#这样的高级语言中使用,因为这会破环代码的结构。goto作为一种条件分支或者是跳转指令的用途,其实主要还是为底层的语言进行服务的。Why?高级语言中已经有了更佳的语法,如if、switch、for等等。像汇编这种语言是因为没有直接对这种高级语法的支持,所以需要通过goto来实现的(这里的goto泛指各种跳转指令和条件分支指令)。
 
要讲的是foreach。foreach是C#中的语法,用来遍历容器对象。它本质上功能和for一致,但是它的优势是我们不用去关心索引越界的问题,foreach语句本身会为我们实现“哨兵”的功能。所以这样的语法相当方便+安全,至少我写C#代码基本用foreach。然而今天让我很意外,也很激动,发现C++的STL中也提供了for_each,它是一个算法,它是一个Template(那是废话,STL嘛),通过简单的封装基本感觉和C#的foreach一致了。下面代码不是我写的,抄MSDN的。拿来晒晒…
// #include <algorithm>
class Average {
private:
   long num;      // The number of elements
   long sum;      // The sum of the elements
public:
   Average ( ) : num ( 0 ) , sum ( 0 ) { }
   void operator ( ) ( int elem ) {
      num++;      // Increment the element count
      sum += elem;   // Add the value to the partial sum
   }
   operator double ( ) {
      return  static_cast <double> (sum) /
      static_cast <double> (num);
   }
};
double avemod2 = for_each ( v1.begin ( ) , v1.end ( ), Average ( ) ); // begin and end are the first and the last sapareterly…
所有的对iterator返回的对象上的操作都被封装在了Average类中,这个类实现了函数对象(Function Object)的功能。与传统的得到iterator然后while遍历的写法是,for_each更面向对象,语法结构上更干净利落。所以,以后开发过程中,适时地可以抛弃过去老土的写法了。哈哈~~