2015年2月

看看AxMan的源代码是怎么获取COM组件的信息的

主要看AxMan枚举所有ActiveX的属性的地方。

是个坑,但是偶尔也会填填。

1、如何确定机器上有哪些ActiveX已经装上了?

很明智的做法:

    RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("Software\\Classes\\CLSID"), 0, KEY_READ, &hKey);
    RegQueryInfoKey(
        hKey, // key handle 
        NULL, // buffer for class name 
        NULL, // size of class string 
        NULL, // reserved 
        &cSubKeys, // number of subkeys 
        NULL, // longest subkey size 
        NULL, // longest class string 
        NULL, // number of values for this key 
        NULL, // longest value name 
        NULL, // longest value data 
        NULL, // security descriptor 
        NULL  // last write time 
    );

    for (j = 0; j<cSubKeys; j++)
    {
        cbName=MAX_PATH;
        achKey[0] = '\0';
        RegEnumKeyEx(hKey, j,
            achKey, 
            &cbName, 
            NULL, 
            NULL, 
            NULL, 
            &ftime); 
        _ftprintf(output, _T("\t'%s'%s\n"), achKey, j == (cSubKeys-1) ? _T("") : _T(","));
        fflush(output);
        scan_clsid(achKey);
    }

针对找到的每个CLSID主键都调用一次“自己 GO {CLSID}”,很明智的递归方式,因为我发现在枚举的时候它就崩了无数次了。搁在一个进程里面估计这程序就完了。

2、看看GO CLSID的时候它做了啥:
(a)先设置一个异常处理程序,以便出错的时候做报告。 虽然我一次都没见它报告过。

(b)调用CLSIDFromString将传来的CLSID转为CLSID类型,简单来说就是转成这样:

typedef struct {
    unsigned long  Data1;
    unsigned short Data2;
    unsigned short Data3;
    byte           Data4[ 8 ];
} GUID;

(c)读取HKLM\SOFTWARE\CLASSES\CLSID{SOME-CLSID}\的默认值,通常它像是:

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000000-12C9-4305-82F9-43058F20E8D2}
(默认)    QQDownload IE Left Helper   REG_SZ

是的,这里有描述。

(d)再读HKLM\SOFTWARE\CLASSES\CLSID{SOME-CLSID}\ProgId的默认值,通常它的值像是:
还是上面的例子,

HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{00000000-12C9-4305-82F9-43058F20E8D2}\ProgID
(默认)  QQIEHelper.QQCycloneHelper.1   REG_SZ

对,就是ProgId,字面意思。

(e)再读HKLM\SOFTWARE\CLASSES\CLSID{SOME-CLSID}\InProc32的默认值,通常它就是要加载的DLL,至于ThreadingModel,大家不是都默认Both或者Apartment了吗,它也没管。

(f)然后就到了最重要的部分,它怎么枚举属性和方法?
[I] 先CoCreateInstance创建一个实例,查询其IObjectSecurity接口;
[II] 如果实现了这个接口,查询是否设置了Safe for init和Safe for script位,这个是它待会儿要写到测试的配置里面去的;
[III] 调用IDispatch中的GetTypeInfo获取ITypeInfo接口用来展开相关的内容;

The ITypeInfo interface provides access to the following: 
 The set of function descriptions associated with the type. For interfaces, this contains the set of member functions in the interface.

 The set of data member descriptions associated with the type. For structures, this contains the set of members of the type.

 The general attributes of the type, such as whether it describes a structure, an interface, and so on.

简单的说就是ITypeInfo接口提供了对这个接口中的成员函数、成员变量、通用属性(是否定义了一个结构体,一个接口等等)。

[IV] 对TypeInfo调用GetDocumentation获取函数数量,然后对各个函数调用GetFuncDesc获取函数描述,然后这里就可以获得函数名,返回值,参数数量和参数。

COM接口实现的随意的一点小记录

1、所有的COM接口的vtbl前三项都是一样的。
COM接口和C++编译器生成的抽象基类的内存接口是相同的。
vtbl的初始位置保存着IUnknown的御三家的地址,take an example:

在VS里面的例子,实例化IWebBrowser2之后,查看其地址的数据:

>dd 0x00821ae8
0x00821AE8  63362618(vtbl) 005d25a8 005d87fc abababab  
0x00821AF8  abababab       feeefeee 00000000 00000000  
0x00821B08  45b71a23       00001234 008237f8 008200c4  
0x00821B18  feeefeee       feeefeee feeefeee feeefeee  

f2.png

很容易就能找到御三家。

示例:

#include <ObjBase.h>
#include <iostream>

static IID IID_IA = {0x12345678, 0x1234, 0x1234, {0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12}};

interface IA : IUnknown
{
    virtual void __stdcall foo() = 0;
};

class CA : public IA
{
public:
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    virtual ULONG __stdcall AddRef(){std::cout<<"addref\n"<<std::endl; return 0;}
    virtual ULONG __stdcall Release(){std::cout<<"release\n"<<std::endl; return 0;}
    virtual void __stdcall foo()
    {
        std::cout << "a" << std::endl;
    }
};

HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
{
    if (iid == IID_IUnknown || iid == IID_IA)
    {
        *ppv = static_cast<IA*>(this);
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef();
    return S_OK;
}

IUnknown* CreateInstance()
{
    IUnknown* pI = static_cast<IA*>(new CA);
    pI->AddRef();
    return pI;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr;
    IUnknown* pIUnknown = CreateInstance();

    IA* pIA = NULL;
    hr = pIUnknown->QueryInterface(IID_IA, (void**)&pIA);
    if (SUCCEEDED(hr))
    {
        pIA->foo();

    printf("%08x %08x %08x",*(DWORD*)pIA, 
        *((DWORD*)pIA+1), 
        *((DWORD*)pIA+2));
    }   

    return 0;
}

输出:
00a07834 fdfdfdfd abababab

其实事实上pIA此时内存也就这一个东西了,拿出VS的dd证明一下代码没错:

>dd 0x007c8c38
0x007C8C38  00a07834(vtbl) fdfdfdfd abababab abababab  
0x007C8C48  00000000 00000000 18fb7b76 1c00dcbf  
0x007C8C58  007c8c18 007c4810 0f9a22b0 0000041d  
0x007C8C68  00000010 00000002 000000ba fdfdfdfd 

00a07834解引用后,前三项为QueryInterface、AddRef、Release的地址。

跟这关系不大的一个,在添加了私有成员之后:

class CA : public IA
{
public:
………………
private:
    ULONG m_SomeLong;
};

vtbl后面才会多出数据来,以前只是看书知道这事儿,这回算是实践了吧:

{,,testInterface.exe}(*(CA*){*}pIA).m_SomeLong  3452816845  unsigned long

>dd 0x00888c38
0x00888C38  00377834 *cdcdcdcd* fdfdfdfd abababab  
0x00888C48  abababab feeefeee 00000000 00000000  
0x00888C58  0d743d6b 1c0082e0 00888c18 00884810  
0x00888C68  0fbf22b0 0000041d 00000010 00000002  

(备注: 3452816845 (dec) == 0xcdcdcdcd (hex))

2、IDispatch接口中GetIDsOfNames根据提供的函数名称返回DISPID,Invoke则内部实现了一组按索引访问的函数,有点像是vtbl。

春节14天小长假,该补的还是全部补上吧

去年最后悔的就是把一堆没看完的书打着“放假我能看完”的名号带回家里,回北京以后想看书的时候一摸啥都没有,这14天好好的补完吧。我可能会尽量先补上ie的那几篇文章的坑,开坑的时候,坑挖的太大了,趁着过节给填上。

fswebcam 实时监控系统

f1.png

cubietruck搭出来的,不管有没有用。。每张图片~200k,每天监控下来的数据差不多有1.7GB,正好有个空闲的SSD,120G空间足以监控10天,其实监控三个月都不为过。。

然后给它开启samba和vnc,顺便backup还把图片传到网站的某个文件夹里面,网站空间很小,所以我只能15分钟传一张,每天产生20M数据,10天200M,看起来还可以的样子。

其实晚上拍的照片一片黑 每张也就17k左右

可执行程序的变量存储到底有什么规律呢?

测试一下:
Windows x86 (vs2010)、 x64(gcc)
Linux ARM (gcc)

code:

unsigned long g_A = 0x11223344;
unsigned long g_B;

unsigned long function()
{
    static unsigned long s_A = 0xAABBCCDD;
    static unsigned long s_B;
    unsigned long A = 0x55667788;
    s_A ++;
    s_B = s_A;
    return A;
}

int main(int argc, char** argv) 
{
    unsigned long B = 0x99999999;
    B = function();
    return 0;
}

1、编译选项:Windows, x86, 优化全关闭(vs2010)

Dump of file E:\users\blastts\documents\visual studio 2010\Projects\testSection\Release\testSection.exe

PE signature found

File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
             14C machine (x86)
               5 number of sections
        54D6CDF6 time date stamp Sun Feb 08 10:46:14 2015
               0 file pointer to symbol table
               0 number of symbols
              E0 size of optional header
             102 characteristics
                   Executable
                   32 bit word machine

SECTION HEADER #1
   .text name
     82A virtual size
    1000 virtual address (00401000 to 00401829)
     A00 size of raw data
     400 file pointer to raw data (00000400 to 00000DFF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         Execute Read

SECTION HEADER #2
  .rdata name
     5C6 virtual size
    2000 virtual address (00402000 to 004025C5)
     600 size of raw data
     E00 file pointer to raw data (00000E00 to 000013FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         Read Only

SECTION HEADER #3
   .data name
     394 virtual size
    3000 virtual address (00403000 to 00403393)
     200 size of raw data
    1400 file pointer to raw data (00001400 to 000015FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         Read Write

SECTION HEADER #4
   .rsrc name
     1B4 virtual size
    4000 virtual address (00404000 to 004041B3)
     200 size of raw data
    1600 file pointer to raw data (00001600 to 000017FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         Read Only

SECTION HEADER #5
  .reloc name
     18E virtual size
    5000 virtual address (00405000 to 0040518D)
     200 size of raw data
    1800 file pointer to raw data (00001800 to 000019FF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
42000040 flags
         Initialized Data
         Discardable
         Read Only

  Summary

        1000 .data
        1000 .rdata
        1000 .reloc
        1000 .rsrc
        1000 .text

不出意外的话,全局变量unsigned long g_A = 0x11223344;,静态变量static unsigned long s_A = 0xAABBCCDD;应该都是存在一起的。

SECTION HEADER #3
   .data name
RAW DATA #3
  00403000: 44 33 22 11 DD CC BB AA 

而局部变量则又是在一起的

SECTION HEADER #1
   .text name
RAW DATA #1
  00401000: 55 8B EC 51 C7 45 FC **88 77 66 55** A1 04 30 40 00  U.имQ?Eи╣.wfU?.0@.
  00401010: 83 C0 01 A3 04 30 40 00 8B 0D 04 30 40 00 89 0D  .ид.бъ.0@....0@...
  00401020: 24 30 40 00 8B 45 FC 8B E5 5D C3 CC CC CC CC CC  $0@..Eи╣.?]?имимимимим
  00401030: 55 8B EC 51 C7 45 FC **99 99 99 99**

既然.text是Execute Read,那么必然有:

01021030          testSection!main (int, char **)

0:000> u testSection!main
testSection!main [e:\users\blastts\documents\visual studio 2010\projects\testsection\testsection\testsection.cpp @ 20]:
01021030 55              push    ebp
01021031 8bec            mov     ebp,esp
01021033 51              push    ecx
01021034 c745fc99999999  mov     dword ptr [ebp-4],99999999h
0102103b e8c0ffffff      call    testSection!function (01021000)
01021040 8945fc          mov     dword ptr [ebp-4],eax
01021043 33c0            xor     eax,eax
01021045 8be5            mov     esp,ebp

而没初值的s_B,(忘记关ASLR了,很容易就能算出RAW,所以先不管它)

0102101e 890d24300201    mov     dword ptr [testSection!s_B (01023024)],ecx


0:000> !dh 0x1020000
OPTIONAL HEADER VALUES
     10B magic #
   10.00 linker version
     A00 size of code
     C00 size of initialized data
       0 size of uninitialized data
    12D7 address of entry point
    1000 base of code
         ----- new -----
**01020000 image base**

SECTION HEADER #3
   .data name
     394 virtual size
    3000 virtual address
     200 size of raw data
    1400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

可见是位于.data中的。因为vs生成的这东西没有.bss,所以不完全像是他们所说,至少vs编译的c++程序,未初始化的全局变量不一定在.bss中。不过其实多个.bss也还不错,可能是没开优化的缘故?

其它的倒是很符合。全局变量在.data,局部变量跟着代码一起在.text中。

2、编译选项:Windows, x64, 优化全关闭(gcc 4.1)
跟vs的大同小异,只不过gcc生成的节是真的很多,挑一些重点发。

首先,全局变量,静态变量,跟之前一样。

SECTION HEADER #2
   .data name
     100 virtual size
    8000 virtual address (0000000000408000 to 00000000004080FF)
     200 size of raw data
    6E00 file pointer to raw data (00006E00 to 00006FFF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0500040 flags
         Initialized Data
         RESERVED - UNKNOWN
         RESERVED - UNKNOWN
         Read Write

RAW DATA #2
  0000000000408000: 0A 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  0000000000408010: 44 33 22 11 DD CC BB AA

局部变量、函数也是一样

SECTION HEADER #1
   .text name
    67D0 virtual size
    1000 virtual address (0000000000401000 to 00000000004077CF)
    6800 size of raw data
     600 file pointer to raw data (00000600 to 00006DFF)
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60500020 flags
         Code
         RESERVED - UNKNOWN
         RESERVED - UNKNOWN
         Execute Read

RAW DATA #1
  0000000000401500: 55 48 89 E5 48 83 EC 10 C7 45 FC 88 77 66 55 

剩余的,我看到了bss的存在!

SECTION HEADER #6
    .bss name
    1400 virtual size
    D000 virtual address (000000000040C000 to 000000000040D3FF)
       0 size of raw data
       0 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0600080 flags
         Uninitialized Data
         RESERVED - UNKNOWN
         RESERVED - UNKNOWN
         Read Write

先看看使用这个之前没初始化过的变量的地方:

0:002> u image00000000_00400000+0x1533
image00000000_00400000+0x1533:
00000000`00401533 8b05db7a0000    mov     eax,dword ptr [image00000000_00400000+0x9014 (00000000`00409014)]
00000000`00401539 83c001          add     eax,1
00000000`0040153c 8905d27a0000    mov     dword ptr [image00000000_00400000+0x9014 (00000000`00409014)],eax
00000000`00401542 8b05cc7a0000    mov     eax,dword ptr [image00000000_00400000+0x9014 (00000000`00409014)]
00000000`00401548 8905f6ba0000    mov     dword ptr [image00000000_00400000+0xd044 (00000000`0040d044)],eax

这个倒是很符合:

static unsigned long s_B;
0:002> ?[poi[image00000000_00400000+0xd044]]
Evaluate expression: 0 = 00000000`00000000

static unsigned long s_A = 0xAABBCCDD;
0:002> ?[poi[image00000000_00400000+0x9014]]
Evaluate expression: 2864434397 = 00000000`aabbccdd

看吧,文件中预留的是0字节,只在启动后才从这里初始化一片0内存给它用,本意是减少(……节的描述都不止4字节了,浪费了更多,其实我觉得VS这里的做法反而是对的)文件大小,但是实际上如果没初始化的全局变量或者静态变量本身就不多的话,我觉得还不如并到.data节呢。

3、Linux (ARM) ,编译器GCC,无优化。

pi@BLASTN2 ~/projects/testSection/testSections/bin/Release :( $ objdump -h testSections 

testSections:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000019  00008134  00008134  00000134  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .note.ABI-tag 00000020  00008150  00008150  00000150  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .note.gnu.build-id 00000024  00008170  00008170  00000170  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .hash         00000028  00008194  00008194  00000194  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .gnu.hash     00000024  000081bc  000081bc  000001bc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .dynsym       00000050  000081e0  000081e0  000001e0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .dynstr       00000077  00008230  00008230  00000230  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  7 .gnu.version  0000000a  000082a8  000082a8  000002a8  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .gnu.version_r 00000020  000082b4  000082b4  000002b4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .rel.dyn      00000008  000082d4  000082d4  000002d4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .rel.plt      00000018  000082dc  000082dc  000002dc  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 11 .init         0000000a  000082f4  000082f4  000002f4  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 12 .plt          0000003c  00008300  00008300  00000300  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 13 .text         00000134  0000833c  0000833c  0000033c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 14 .fini         00000006  00008470  00008470  00000470  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 15 .rodata       00000004  00008478  00008478  00000478  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 16 .ARM.exidx    00000008  0000847c  0000847c  0000047c  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 17 .eh_frame     00000004  00008484  00008484  00000484  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 18 .init_array   00000004  00010488  00010488  00000488  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 19 .fini_array   00000004  0001048c  0001048c  0000048c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 20 .jcr          00000004  00010490  00010490  00000490  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 21 .dynamic      00000108  00010494  00010494  00000494  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 22 .got          0000001c  0001059c  0001059c  0000059c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 23 .data         00000010  000105b8  000105b8  000005b8  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 24 .bss          0000000c  000105c8  000105c8  000005c8  2**2
                  ALLOC
 25 .comment      0000001d  00000000  00000000  000005c8  2**0
                  CONTENTS, READONLY
 26 .ARM.attributes 00000033  00000000  00000000  000005e5  2**0
                  CONTENTS, READONLY

可以看到也是有.bss节的,而且大小为0,看FileOffset可知.bss的起始大小是0x5c8,.comment也是0x5c8,所以.bss是一个字都没有占到,

        0    2    4    6      8    a    c    e
00005b0 8300 0000 0000 0000 | 0000 0000 0000 0000
00005c0 3344 1122 ccdd aabb | 4347 3a43 2820 6544

可见,它也是满足这个规律,也即全局变量放.data,没赋值的全局变量放.bss(只是占虚拟内存而已),代码和局部变量放.text。

对这俩静态变量的操作也是类似:
f1.png
f2.png