// 使用" 参数化基类" 和" 成员函数指针" 模拟实现虚函数--在实际中的应用。
#include <stdio.h>
#include <string.h>
/*
病毒或许可以使用这种技术有效地实现,不过这是我在写 Windows PE 文件
加壳程序的时候总结出来的技术。当然可以被用在恶意程序上,任何事情总有两面性!
***注意***
在 VC 中测试时,必须去掉“启用增量连接”,即(/INCREMENTAL:NO)
如果在 ShellCode 或者 Virus 中使用该技术,字符串文字量(string literal)
也必须进行地址转化,即:convert_address("string literal").
使用 "参数化基类 "和 "成员函数指针 "模拟实现虚函数。
可能大家都以为只有疯子才会这么干,好好的虚函数干吗不用,而偏要拐弯抹角地
搞得这么复杂,但有时候这可能是最好地选择。举个例子吧,我写 Windows PE 文件
加壳程序的时候,遇到一个问题:
1. 我开发了一个框架,可以只用 C++ 来写 "壳程序 ",大家很难想到吧!
2. 但不能使用一些 C++ 功能:虚函数,异常处理,还有 switch-case 语句
3. C++ 异常处理可以不用,但是不能使用虚函数可能太过苛刻。
当我看了 "generative programming"以后,觉得 "参数化继承 "
或许可以满足这个需求,模拟实现虚函数。
以下是使用 "参数化继承 "实现虚函数的框架,以及要注意的事项。
BaseClass 显然,实际上是 "抽象基类 ",因为如果实例化
"InstantialClass<ConcreteClass>" 时,ConcreteClass 中
必须定义响应的 "虚函数 ",否则编译就报错。如果相应的
BaseClass 和 InstantialClass 定义正确无误(从代码可以
看到,这很简单,但比较麻烦,必须注意一些细节)。因此
ConcreteClass 编译期错误不会被推迟到运行时才发现,
而使用其它方式模拟,就很难有这个保证。
其实,如果了解 C++ 的底层对象模型,这些需要注意的细节
很容易理解!
//-------
另外有一种 C 语言模拟 C++ 虚函数的方法,可以在我以前
(2002年 )一篇文章中看到。
*/
struct Context
{
int (*printf)(const char *, ...);
// other external fuctions...
};
// construct these codes...
int entry(const Context* context)
{
int imp_entry(const Context* context);
return imp_entry(context);
}
template< typename AddressType >
AddressType convert_address(AddressType address)
{
// if used in shell code, this must return another valid address.
#define SUPPORT_RECLOCATION
#ifdef SUPPORT_RECLOCATION
__asm {
call LL
LL: pop eax
sub eax, offset LL
add eax, address
mov address, eax
}
#endif
return address;
}
class BaseClass
{
#define DEFINE_VIRTUAL(ret , name, param_list, call_list ) \
protected : \
typedef ret (BaseClass ::*T## name) param_list ; \
T## name p ##name; \
public : \
ret name param_list \
{ return ( this->*this ->p## name)call_list ; }
//
// expansion of :
/* DEFINE_VIRTUAL(int, Func1,
(int x1, int x2),
( x1, x2)
);
*/
protected :
typedef int (BaseClass ::*TFunc1)( int x1 , int x2);
TFunc1 pFunc1;
public :
int Func1(int x1, int x2 )
{
return ( this->*this ->pFunc1)( x1, x2 );
// return (this->*pFunc1)(x1, x2); // can be simplified as this line.
}
// end expansion
//
DEFINE_VIRTUAL( int, Func2 ,
(int x1, int x2, int x3 ),
( x1 , x2 , x3 )
);
public :
template< typename BaseFuncType , typename ConcreteFuncType>
void assign(BaseFuncType & x, ConcreteFuncType y )
{
// if use C Style cast like "(BaseFunType)(y)", it is danger!!
// any member function can be assigned to x!!
// x = convert_address((BaseFuncType)(y)); // danger!!
x = convert_address(static_cast <BaseFuncType>(y));
}
BaseClass()
{
pFunc1 = 0;
pFunc2 = 0;
}
};
class ConcreteClass1
{
private :
const Context* context;
int x1, x2 , x3;
public :
ConcreteClass1(const Context* context)
{
this->context = context;
}
int Func1(int x1, int x2)
{
this-> x1 = x1 ;