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

奇葩的编译器 ULONG 为啥要movsx byte ptr?

真的是第一次遇到这种编译器解释,年轻人,见识少啊。

if(*(DWORD*)&nInstructions[0] == 0x878af88bUL)

结果是:

1: kd> u b126f1e5
xxxxxx!TryToX+0x1c5 [e:\drv\xxxx\xxxx.c @ 639]:
b126f1e5 0fbe1590e926b1  movsx   edx,byte ptr [xxxxxx!nInstructions (b126e990)]
b126f1ec 81fa8b000000    cmp     edx,8Bh
b126f1f2 0f8598000000    jne     xxxxxx!TryToHookNtWriteVirtualMemory+0x270 (b126f290)
b126f1f8 0fbe0591e926b1  movsx   eax,byte ptr [xxxxxx!nInstructions+0x1 (b126e991)]
b126f1ff 3df8000000      cmp     eax,0F8h
b126f204 0f8586000000    jne     xxxxxx!TryToHookNtWriteVirtualMemory+0x270 (b126f290)
b126f20a 0fbe0d92e926b1  movsx   ecx,byte ptr [xxxxxx!nInstructions+0x2 (b126e992)]
b126f211 81f98a000000    cmp     ecx,8Ah

从movsx开始我就隐约有点蛋疼了,不是ULONG互相比较吗,为啥要一个字节一个字节的movsx + cmp?接着果然蛋疼了:

1: kd> db nInstructions
b126e990  8b f8 8a 87 40 01 00 00-00 00 00 00 94 53 5b 80  ....@........S[.
b126e9a0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
b126e9b0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

果不其然:

Breakpoint 2 hit
xxxxxxx!TryX+0x1c5:
b138b1e5 0fbe1590a938b1  movsx   edx,byte ptr [xxxxxxx!nInstructions (b138a990)]
1: kd> r edx
edx=ffffff8b

条件不满足,然后呢?改成这样就过了,你逗我?

if((ULONG)*(DWORD*)&nInstructions[0] == (ULONG)0x878af88bUL)

这回判断正常了:

1: kd> u b13931e5
xxxxxxx!TryX+0x1c5 [e:\drv\***.c @ 639]:
b13931e5 813d902939b18bf88a87 cmp dword ptr [xxxxxxx!nInstructions (b1392990)],878AF88Bh