|
请管理员将帖子删除了吧
就像STL那样, 以适配器的形式把基础容器包装成stack吗? |
|
[求助]虚继承中的析构函数
这是我以前看这里时自己分析的 class A { public: __declspec(noinline) A() { printf("ctor in A\n"); } __declspec(noinline) virtual void A1() { printf("A1 in A\n"); } __declspec(noinline) virtual void A2() { printf("A2 in A\n"); } __declspec(noinline) virtual ~A() { printf("dtor in A\n"); } }; class B : virtual public A { public: __declspec(noinline) B() { printf("ctor in B\n"); } __declspec(noinline) virtual void B1() { printf("B1 in B\n"); } __declspec(noinline) virtual ~B() { printf("dtor in B\n"); } }; class C : virtual public A { public: __declspec(noinline) C() { printf("ctor in C\n"); } __declspec(noinline) virtual void C1() { printf("C1 in C\n"); } __declspec(noinline) ~C() { printf("dtor in C\n"); } }; class X { public: __declspec(noinline) X() { printf("ctor in X\n"); } __declspec(noinline) virtual void X1() { printf("X1 in X\n"); } __declspec(noinline) virtual ~X() { printf("dtor in X\n"); } }; class Y : virtual public X { public: __declspec(noinline) Y() { printf("ctor in Y\n"); } __declspec(noinline) virtual void Y1() { printf("Y1 in Y\n"); } __declspec(noinline) virtual ~Y() { printf("dtor in Y\n"); } }; class Z : virtual public X { public: __declspec(noinline) Z() { printf("ctor in Z\n"); } 013019D0 push ebp 013019D1 mov ebp,esp 013019D3 push ecx 013019D4 push esi 013019D5 mov esi,ecx 013019D7 push 13032F4h 013019DC mov eax,dword ptr [esi+4] ; 此时虚基类表指针已经被子类设置好了 013019DF mov dword ptr [esi],13033ACh ; 设置自己的虚表 013019E5 mov eax,dword ptr [eax+4] 013019E8 mov dword ptr [ebp-4],0 013019EF mov dword ptr [eax+esi+4],130341Ch ; 设置虚基类的虚表 013019F7 call dword ptr ds:[130303Ch] 013019FD add esp,4 01301A00 mov eax,esi 01301A02 pop esi 01301A03 mov esp,ebp 01301A05 pop ebp 01301A06 ret 4 __declspec(noinline) virtual void Z1() { printf("Z1 in Z\n"); } __declspec(noinline) virtual ~Z() { printf("dtor in Z\n"); } 00171A20 mov eax,dword ptr [ecx-4] ; ecx指向的是对象首地址+8处, 所以这里实际上是在取虚基类表指针 00171A23 mov dword ptr [ecx-8],1733ACh ; 设置虚表指针 00171A2A mov eax,dword ptr [eax+4] 00171A2D push 17330Ch 00171A32 mov dword ptr [eax+ecx-4],17341Ch ; 设置虚基类的虚表指针 00171A3A call dword ptr ds:[17303Ch] 00171A40 pop ecx 00171A41 ret }; class D : public B, public C, public Y, public Z { int val_; public: __declspec(noinline) D() { printf("ctor in D, %d\n", &val_); } 01301A80 push ebp 01301A81 mov ebp,esp 01301A83 sub esp,8 01301A86 push ebx 01301A87 push esi 01301A88 mov esi,ecx 01301A8A push edi 01301A8B lea ecx,[esi+28h] 01301A8E mov dword ptr [ebp-8],0 01301A95 mov dword ptr [esi+4],1303424h 01301A9C mov dword ptr [esi+0Ch],13033F8h 01301AA3 mov dword ptr [esi+14h],13033F8h 01301AAA mov dword ptr [esi+1Ch],1303438h ; 设置4个直接父类的虚基类表指针 01301AB1 call A::A (013016B0h) 01301AB6 lea ecx,[esi+30h] 01301AB9 call X::X (013018A0h) 01301ABE push ecx 01301ABF mov ecx,esi 01301AC1 call B::B (01301740h) 01301AC6 push ecx 01301AC7 lea ecx,[esi+8] 01301ACA call C::C (013017F0h) 01301ACF push ecx 01301AD0 lea ecx,[esi+10h] 01301AD3 call Y::Y (01301920h) 01301AD8 push ecx 01301AD9 lea ecx,[esi+18h] 01301ADC call Z::Z (013019D0h) 01301AE1 mov edx,esi 01301AE3 mov dword ptr [esi+8],1303394h ; 设置C类虚表指针 01301AEA mov eax,dword ptr [edx+4] 01301AED mov dword ptr [edx],13033F0h ; 设置B类和子类共用的虚表指针 01301AF3 mov dword ptr [esi+10h],130338Ch ; 设置Y类虚表指针 01301AFA mov dword ptr [esi+18h],1303414h ; 设置Z类虚表指针 01301B01 mov eax,dword ptr [eax+4] 01301B04 mov dword ptr [eax+edx+4],1303404h ; 设置A类虚表指针 01301B0C mov eax,dword ptr [edx+4] 01301B0F mov eax,dword ptr [eax+8] 01301B12 mov dword ptr [eax+edx+4],13033E4h ; 设置X类虚表指针 01301B1A mov eax,dword ptr [edx+4] 01301B1D mov ecx,dword ptr [eax+4] 01301B20 lea eax,[ecx-24h] 01301B23 mov dword ptr [ecx+edx],eax ; vtordisp 01301B26 mov eax,dword ptr [edx+4] 01301B29 mov ecx,dword ptr [eax+8] 01301B2C lea eax,[ecx-2Ch] 01301B2F mov dword ptr [ecx+edx],eax ; vtordisp 01301B32 lea eax,[edx+20h] 01301B35 push eax 01301B36 push 1303318h 01301B3B call dword ptr ds:[130303Ch] 01301B41 add esp,8 01301B44 mov eax,esi 01301B46 pop edi 01301B47 pop esi 01301B48 pop ebx 01301B49 mov esp,ebp 01301B4B pop ebp 01301B4C ret 4 __declspec(noinline) virtual void A2() { printf("A2 in D\n"); } __declspec(noinline) virtual void B1() { printf("B1 in D\n"); } __declspec(noinline) virtual void X1() { printf("X1 in D\n"); } __declspec(noinline) virtual void Y1() { printf("Y1 in D\n"); } __declspec(noinline) virtual void Z1() { printf("Z1 in D\n"); } __declspec(noinline) virtual void D1() { printf("C1 in D\n"); } __declspec(noinline) virtual ~D() { printf("dtor in D\n"); } 01301BB0 push ebx 01301BB1 push esi 01301BB2 push edi 01301BB3 mov edi,ecx ; ecx是A类子对象首地址, 也就是D类对象首地址+28h处 01301BB5 push 1303370h 01301BBA mov eax,dword ptr [edi-24h] ; 这里实际是取+4h处的虚基类表指针 01301BBD mov dword ptr [edi-28h],13033F0h ; 设置D类和B类共用的虚表指针 01301BC4 mov dword ptr [edi-20h],1303394h ; 设置C类的虚表指针 01301BCB mov dword ptr [edi-18h],130338Ch ; 设置Y类虚表指针 01301BD2 mov dword ptr [edi-10h],1303414h ; 设置Z类虚表指针 01301BD9 mov eax,dword ptr [eax+4] 01301BDC mov dword ptr [eax+edi-24h],1303404h ; 设置A类虚表指针 01301BE4 mov eax,dword ptr [edi-24h] 01301BE7 mov eax,dword ptr [eax+8] 01301BEA mov dword ptr [eax+edi-24h],13033E4h ; 设置X类虚表指针 01301BF2 mov eax,dword ptr [edi-24h] 01301BF5 mov ecx,dword ptr [eax+4] 01301BF8 lea eax,[ecx-24h] 01301BFB mov dword ptr [ecx+edi-28h],eax ; vtordisp 01301BFF mov eax,dword ptr [edi-24h] 01301C02 mov edx,dword ptr [eax+8] 01301C05 lea eax,[edx-2Ch] 01301C08 mov dword ptr [edx+edi-28h],eax ; vtordisp 01301C0C call dword ptr ds:[130303Ch] 01301C12 add esp,4 01301C15 lea ecx,[edi-8] ; 传入这几个析构函数的this实际指向的是this+8的位置 01301C18 call Z::~Z (01301A20h) 01301C1D lea ecx,[edi-10h] 01301C20 call Y::~Y (01301970h) 01301C25 lea ecx,[edi-18h] 01301C28 call C::~C (01301840h) 01301C2D lea ecx,[edi-20h] 01301C30 pop edi 01301C31 pop esi 01301C32 pop ebx 01301C33 jmp B::~B (01301790h) ; 按继承列表相反的顺序析构各直接父类子对象 }; // 这里是delete调用的A类虚表中的析构代理 00171D20 sub ecx,dword ptr [ecx-4] ; 此处ecx是A类子对象的首地址, ecx-4处是vtordisp, 在构造函数中被初始化为0 00171D23 jmp D::`scalar deleting destructor' (0171C40h) 00171C40 push ebp 00171C41 mov ebp,esp 00171C43 push esi 00171C44 push edi 00171C45 lea edi,[ecx-28h] 00171C48 lea ecx,[edi+28h] ; 传递给D类析构函数的this是指向A类子对象的 01301C4B call D::~D (01301BB0h) ; 先执行子类的析构函数 01301C50 lea ecx,[edi+30h] 01301C53 call X::~X (013018D0h) ; 然后才是虚基类析构 01301C58 lea ecx,[edi+28h] 01301C5B call A::~A (013016F0h) ; 虚基类析构按照继承的相反顺序 01301C60 test byte ptr [ebp+8],1 01301C64 je D::`scalar deleting destructor'+30h (01301C70h) 01301C66 push edi 01301C67 call dword ptr ds:[13030B4h] ; 释放堆空间 00171C6D add esp,4 00171C70 mov eax,edi 00171C72 pop edi 00171C73 pop esi 00171C74 pop ebp 00171C75 ret 4 int main() { D *pd = new D; pd->D1(); B *pb = pd; pb->B1(); C *pc = pd; pc->C1(); A *pa = pd; 01301CB4 mov eax,dword ptr [edi+4] ; 取虚子类和B类共用的虚基类表的指针 01301CB7 mov ecx,dword ptr [eax+4] ; 取虚基类表中第二项, 也就是A类的偏移 01301CBA add ecx,4 ; 再加上虚基类表指针距对象首地址的偏移, 得到虚基类子对象距子类对象首地址的偏移 01301CBD add ecx,edi ; 再加上子类对象首地址, 最终计算出虚基类子对象首地址 pa->A1(); 01301CBF mov eax,dword ptr [ecx] 01301CC1 call dword ptr [eax] A *paa = pc; 01301CC3 mov eax,dword ptr [edi+0Ch] ; 取C类的虚基类表指针 01301CC6 mov ecx,dword ptr [eax+4] ; 取出表中第二项 01301CC9 add ecx,0Ch ; 加上指针到子类对象首地址的偏移 01301CCC add ecx,edi ; 加上子类对象首地址, 得到虚基类子对象首地址 paa->A2(); 01301CCE mov eax,dword ptr [ecx] 01301CD0 call dword ptr [eax+4] Y *py = pd; py->Y1(); Z *pz = pd; pz->Z1(); X *px = pd; 01301CE3 mov eax,dword ptr [edi+4] 01301CE6 mov ecx,dword ptr [eax+8] ; 取出表中的第三项, 也就是第二个虚基类的偏移 01301CE9 add ecx,4 01301CEC add ecx,edi px->X1(); 01301CEE mov eax,dword ptr [ecx] 01301CF0 call dword ptr [eax] X *pxx = py; 01301CF2 mov eax,dword ptr [edi+14h] 01301CF5 mov ecx,dword ptr [eax+4] ; X是Y类的唯一一个虚基类, 所以使用Y类的虚基类表时, 它依旧是第二项 01301CF8 add ecx,14h 01301CFB add ecx,edi pxx->X1(); 01301CFD mov eax,dword ptr [ecx] 01301CFF call dword ptr [eax] delete pd; 01301D01 mov eax,dword ptr [edi+4] 01301D04 lea ecx,[edi+4] 01301D07 mov eax,dword ptr [eax+4] 01301D0A add ecx,eax 01301D0C push 1 01301D0E mov eax,dword ptr [ecx] 01301D10 call dword ptr [eax+8] ; 析构时用的析构代理是从第一个虚基类的虚表中查到的 01301D13 pop edi return 0; } |
|
[转帖]寒门再难出贵子
如此说来, 大公司只有家里有背景的才能进, 能力无所谓? 你见哪家大公司会放弃一个github中堆满代码的人而去找hello world水平的员工来? |
|
[原创]发一个c++ hook库, 主要用来测试和调试
呵呵 我那个复杂的是库里的类型推导, 用户实际用的接口上是不用自己手敲一遍函数签名的 |
|
[建议]能否都在新选项卡中打开主题链接
chrome的话用鼠标中键点链接就行了 |
|
[原创]发一个c++ hook库, 主要用来测试和调试
没考虑性能, 因为这个库没打算用在发布版本中 |
|
[分享]根据国外的开源B树写了一份C++版本。
试试google的 https://code.google.com/p/cpp-btree/ |
|
|
|
有汇编开发程序能用的界面库什么的吗?汇编语言搞界面怎么解决?
估计没有针对汇编的吧, 也没有公司会用汇编开发整套软件啊, 效率太低下了 |
|
怎么打印出include 栈
msvc下, 输出预编译文件的话, #line开头的行是包含文件. 不知道有没有现成的提取办法, 没有的话自己写个脚本把这种行都提取出来也不难 |
|
[求助]问一个以前一直忽视的GUI问题!?<控件编程领域>
LZ应该另雇一个人做UI, 自己专心搞算法什么的 |
|
修改函数名称
vb在导入的时候不是可以定义别名的吗 |
|
多线程编程,可以不依赖平台API吗?
有库可以封装掉各平台间的差异, 比如c++11标准库的thread, 还有boost.thread |
|
要命的除法,看不懂啊
除法 两个操作数都是变量的情况无法优化, 只能用div/idiv mov eax, dword ptr [ebp-4] ;将被除数放入eax cdq ;将eax中的符号位扩展到edx, 即将edx:eax扩展成一个值与eax相同的64位有符号整数 idiv dword ptr [ebp-8] ;用除数去除edx:eax, 商保存在eax中, 余数在edx中 除数是2的幂 这种情况用sar优化. sar是算术右移, 即右移后左边空出来的位用符号位填充. sar相当于向下取整, 这在被除数非负时是符合要求的, 但是在被除数是负数时, 按照C的除法规则, 应该是向上取整的, 所以需要对被除数做一些调整. x<0 时, x/2^n 中的x应该被调整为 x+(2^n-1), 即把商+1, 这样再对商向下取整就符合要求了 ;除2时 mov eax, dword ptr [ebp-4] ;将被除数放入eax cdq ;将eax中的符号位扩展到edx, 即将edx:eax扩展成一个值与eax相同的64位有符号整数 sub eax, edx ;非负时, edx为0, 不改变eax; 为负数时, edx为-1, 相当于eax+1, 符合x+(2^1-1) sar eax, 1 ;算术右移, 即左边空出来的位用符号位填充 ;除数大于2时, 这里是8 mov eax, dword ptr [ebp-4] ;将被除数放入eax cdq ;将eax中的符号位扩展到edx, 即将edx:eax扩展成一个值与eax相同的64位有符号整数 and edx, 7 ;除数非负时, edx为0, and后edx仍为0; 除数为负数时, edx为0xFFFFFFFF, and后为7 add eax, edx ;加上edx, 如果非负, edx为0, 对eax无影响; 如果为负数, 相当于eax+7, 符合x+(2^8-1) sar eax, 3 除数不是2的幂 情况1 mov ecx, dword ptr [ebp-4] ;ecx中是被除数 mov eax, 38E38E39h imul ecx ;x*c ,乘法结果放在edx:eax中 sar edx, 1 ;edx是乘法结果的高32位, 直接操纵它等价于乘积已经右移了32位, 因此这是乘积右移33位 mov eax, edx shr eax, 1Fh ;右移31位, 目的是取符号位 add edx, eax ;至此, edx中就是除法的计算结果了 在这种情况下, 假设除数是o, 编译器会事先计算一个常量c=(2^n)/o, 然后对于被除数x, (x*c)>>n 就是除法的结果了. 对于n的取值, 编译器始终保证这是一个大于32的值, 这样在做乘法的时候可以提高效率. 套用公式, 上面的代码是在计算 (x*38E38E39h)>>33, 并且在结果上又加上了符号位的值, 之所以要加符号位, 是因为我们依然用的是向下取整的sar, 这在结果是非负数的时候是正确的, 但是在结果是负数时比正确值少1(比如 -3.5 本来应该取 -3 的, 它取成 -4 了), 所以结果再加上一个符号位的值就正确了. ;总结, 当遇到以下形式的语句时, 基本可判断为除法运算 mov eax, MagicNumber imul 被除数 sar edx, a mov eax, edx shr eax, 1Fh add edx, eax ;之后, 直接使用edx的值 ;n=a+32, (2^n)/MagicNumber 的结果就是除数的近似值 情况2 mov ecx, dword ptr [ebp-4] ;ecx中是被除数 mov eax, 24924925h mul ecx sub ecx, edx shr ecx, 1 add ecx, edx shr ecx, 2 ;至此, ecx中是除法结果 这种情况会在编译器选定的魔数超过4字节大小时出现, 编译器会将魔数调整为2^(32+n)/o-2^32 . 化简整理上面的运算过程, 结果是 ecx * ((2^32+c) / 2^35), 如果把上面的魔数c的计算式代入的话, 还差一个n就能化简为 ecx/o 的形式了, 这个n就是ecx右移的位数, 这里是3位, 所以n=3. 代入魔数的计算式, o≈7. 验算一下, 2^35/7-2^32 正好等于魔数 ;总结, 当遇到以下形式的语句时, 基本可判断为除法运算 mov reg, dword ptr [ebp-4] ;reg中是被除数 mov eax, MagicNumber mul reg sub reg, edx shr reg, 1 add reg, edx shr reg, a ;这句可能没有. 这里的a的值应该为n-1, 如果n为1, 这句没有. 至此, reg中是除法结果 ;n=a+1, 除数的近似值为 (2^(32+n))/(2^32+MagicNumber) 情况3 mov esi, dword ptr [ebp-4] ;esi中是被除数 mov eax, 92492493h imul esi add edx, esi sar edx, 2 mov eax, edx shr eax, 1Fh ;负数调整+1 add edx, eax ;至此, edx中是除法结果 这种情况会在魔数大于0x80000000时出现. 魔数本应是一个无符号数, 但是参与了有符号运算, 这时符号位不计为值, 导致参与运算的实际值为 MagicNumber-2^32 ;总结, 当遇到以下形式的语句时, 基本可判断为除法运算 mov reg, dword ptr [ebp-4] ;reg中是被除数 mov eax, MagicNumber ;MagicNumber大于7fffffffh mul reg add edx, reg sar edx, a mov reg, edx shr reg, 1Fh add edx, reg ;至此, edx是除法结果 ;n=a+32, (2^n)/MagicNumber 的结果就是除数的近似值 除数为负的2的幂 mov eax, dword ptr [ebp-4] ;将被除数放入eax cdq and edx, 7 add eax, edx sar eax, 3 ;上面是除数为2的幂时的运算 neg eax ;对结果取反 ;这相当于把 n/(-o) 变成了 -(n/o) 除数为负的非2的幂 情况1 mov ecx, dword ptr [ebp-4] ;将被除数放入ecx mov eax, 99999999h imul ecx sar edx, 1 mov eax, edx shr eax, 1Fh add edx, eax ;至此, edx中为除法结果 首先注意这和除数大于0且不为2的幂时的区别: 虽然魔数大于0x7fffffff, 但是imul和sar直接并没有调整语句, 此时基本可以判断这是除数为负数的情况. 此时的魔数实际上补码形式. 当除数o为正数时, 设魔数c=2^n/o; 当o为负数时, -c=2^32-2^n/|o| ==> |o|=2^n/(2^32-c) ;总结, 当遇到以下形式的语句时, 基本可判断为除法运算 mov reg, dword ptr [ebp-4] ;reg中是被除数 mov eax, MagicNumber ;MagicNumber大于7fffffffh且imul与sar之间没有调整语句 imul reg sar edx, a mov reg, edx shr reg, 1Fh add edx, reg ;至此, edx是除法结果 ;n=a+32, -((2^n)/(2^32-MagicNumber)) 的结果就是除数的近似值 情况2 mov ecx, dword ptr [ebp-4] ;将被除数放入ecx mov eax, 6DB6DB6Dh imul ecx sub edx, ecx sar edx, 2 mov eax, edx shr eax, 1Fh add edx, eax ;至此, edx中为除法结果 上面的运算过程化简之后可得 ecx* ((eax-2^32)/2^34) = edx, 因为edx中是除法结果, 所以 ecx* ((eax-2^32)/2^34) = ecx/o . 可得 |o| = 2^n / (2^32 - c) = 2^34 / 92492493h ≈ 7 ;总结, 当遇到以下形式的语句时, 基本可判断为除法运算 mov reg, dword ptr [ebp-4] ;reg中是被除数 mov eax, MagicNumber ;MagicNumber小于7fffffffh且imul与sar之间有调整语句sub imul reg sub edx, reg sar edx, a mov reg, edx shr reg, 1Fh add edx, reg ;至此, edx是除法结果 ;n=a+32, -((2^n)/(2^32-MagicNumber)) 的结果就是除数的近似值 |
|
这个是什么壳?EP区段里面有.detour的字样(有图)
.detour段是detours库用来储存数据的 To modify a Windows binary, Detours creates a new .detours section between the export table and the debug symbols, as shown in Figure 4.Note that debug symbols must always reside last in a Windows binary.The new section contains a detours header record and a copy of the original PE header.If modifying the import table, Detours creates the new import table, appends it to the copied PE header, then modifies the original PE header to point to the new import table. Finally, Detours writes any user payloads at the end of the .detours section and appends the debug symbols to finish the file.?Detours can reverse modifications to the Windows binary by restoring the original PE header from the .detours section and removing the .detours section. |
|
从磁盘加载文件到内存,都有哪几种方式???
是不是logo不是以位图形式存在在资源里的啊 |
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值