多线程 Pipeline 的改进

阅读更多关于《多线程 Pipeline 的改进》

 如果一个任务的执行分多个步骤,有些步骤慢,有些步骤快,如果在处理时间长的步骤上使用更多线程,那么因为队列的缓冲作用,在平均处理时间上,这些步骤就可以大致持平了,从而导致更大的吞吐量。

以前的 Pipeline 完全胜任这样的需求,但是,如果有一个这样的需求,考虑如下例子:
有若干篇文章(百万以上),需要对这些文章进行分析并索引,使用Pipeline,分成以下步骤:

继续阅读

WinApi 参数的层次

阅读更多关于《WinApi 参数的层次》

vista 中网上银行不能用的 bug 解决方案

阅读更多关于《vista 中网上银行不能用的 bug 解决方案》

我碰到过这个问题,一开始我把工行的网站加入“可信站点”区域后,可以用了,但是过了一段时间(安装了一些Windows更新后),又不能用了,也还是不能用网上银行,总提示“the "my" store could not be opened ”,到“可信站点”中看,工行的站点仍然在啊!不知道微软哪根筋抽了!不过现阶段,人家再抽筋,我们也必须跟着人家也抽筋,要不就别用网上银行!

这个问题困扰了好久,每次我都是使用管理员权限打开 IE 再重新粘贴网址来付款,有时候这种方法还不能用,比如在其他(非阿里巴巴旗下)网站使用支付宝付款时。

气愤之下,曾经到一个论坛大骂IE,大骂微软那帮傻.逼。但是骂也没用啊,那帮傻.逼也不会给你来解决这个问题。刚才一狠心,使用注册表监视器,终于发现了问题!也找到了解决方案,其实很简单:

删掉:HKEY_CURRENT_USER/Software/Microsoft/Windows/CurrentVersion/Internet Settings/ZoneMap/Domains

再重新在 IE 安全设置中加入你的站点。——直接在安全设置中删掉再重新加入是不行的,微软的那帮傻.逼不知道那根筋抽风了!

到此结束一切痛苦!

munmap 注意事项

阅读更多关于《munmap 注意事项》

linux/unix 下,或者说posix 的munmap,很简单,只有两个参数:

int munmap(void *start, size_t length);

其中 length 必须是 mmap 时的 length,如果小于当初 mmap 时的那个 length,并且正好少的部分跨越了一个page,那就麻烦了,我就犯了这个错误,非常严重的后果!内存泄漏,不是泄露了刚好少 unmap 的那个 page,而是整个 [start, length) 区域都不会成功被 unmap,也许内存中的更改已经写入文件,但是虚拟内存空间[start,length)未被释放!如此多次,会造成 ENOMEM!

感谢上帝,搞了半天,这个问题终于被发现了。

感觉吧,Windows 的很简单 UnmapViewOfFile 就一个参数,就是 MapViewOfFile 返回的那个地址,UnmapViewOfFile 时整个 map 区域都被释放,而 posix 的 munmap,从理论上讲,可以一次 mmap 一大块区域,然后多次 unmap 这个区域中的不同部分,这的确提高了一些灵活性,但是……。

 

cpu 的 cache 是很宝贵的——从互相平行的数组看

阅读更多关于《cpu 的 cache 是很宝贵的——从互相平行的数组看》

以前一直想不通,为什么在有些系统中,要把同一个数据结构的不同字段放入 多个互相平行的数组中,而不是放入一个结构中。 继续阅读

使用" 参数化基类" 和" 成员函数指针" 模拟实现虚函数--在实际中的应用

阅读更多关于《使用" 参数化基类" 和" 成员函数指针" 模拟实现虚函数--在实际中的应用》

// 使用" 参数化基类" " 成员函数指针" 模拟实现虚函数--在实际中的应用。

#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 ;

        this-> x2 = x2 ;

        context->printf("ConcreteClass1::Func1/n");

        context->printf("x1=%d, x2=%d/n/n", x1, x2);

        return 0;

    }

    int Func2(int x1, int x2 , int x3)

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        this-> x3 = x3 ;

        context->printf("ConcreteClass1::Func2/n");

        context->printf("x1=%d, x2=%d, x3=%d/n/n", x1, x2, x3);

        return 0;

    }

};

 

class ConcreteClass2

{

private :

    const Context* context;

    int x1, x2 , x3;

public :

    ConcreteClass2(const Context* context)

    {

        this->context = context;

    }

    int Func1(int x1, int x2 )

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        context->printf("ConcreteClass2::Func1/n");

        context->printf("x1=%d, x2=%d/n/n", x1, x2);

        return 0;

    }

    int Func2(int x1, int x2 , int x3)

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        this-> x3 = x3 ;

        context->printf("ConcreteClass2::Func2/n");

        context->printf("x1=%d, x2=%d, x3=%d/n/n", x1, x2, x3);

        return 0;

    }

};

 

template <class ConcreteClass>

class InstantialClass :

    // "BaseClass" must be first base class, otherwise,

    // function pointer convert in "BaseClass::assign()" may be not valid!

    public BaseClass, // interface inherit, multi inherit is not allowed!!

    protected ConcreteClass // implementation inherit, multi inherit is allowed

{

    // it is a guide line that do not hold any data member in this class!!

    //

    // if ‘BaseClass’ is not the first base class for ‘this’ class,

    // and data member is defined here,

    // and these data member will be modified,

    // it will error at runtime!

    // you can reverse the inherit order of

    // BaseClass and ConcreteClass, and try!!

    //

    int x1, x2 , x3;

public :

    // must delegate these member functions…

    int Func1(int x1, int x2 ) { return ConcreteClass::Func1 (x1, x2); }

    int Func2(int x1, int x2 , int x3)

    {

        this-> x1 = x1 ;

        this-> x2 = x2 ;

        this-> x3 = x3 ;

        return ConcreteClass::Func2 (x1, x2, x3 );

    }

 

    InstantialClass(const Context* context)

        : ConcreteClass(context)

    {

    // must assign these member function pointers…

    //  BaseClass::pFunc1 = (TFunc1)(Func1);

    //  int v = _MSC_VER;

#if _MSC_VER >= 1310 // vc2003

        assign(pFunc1, Func1);

        assign(pFunc2, Func2);

#else // in vc6, vc6 template support is not perfect!!

        pFunc1 = (TFunc1)Func1;

        pFunc2 = (TFunc2)Func2;

#endif

    // if use C Style cast in assign, follow line can be compiled,

    // but will error at runtime, because pointer to ConcreteClass

    // is different from to ‘this’!!

    // pointer to ‘BaseClass’ is equal to ‘this’..

    // so, do not write such code,

    // must delegate ‘ConcreteClass::Func2’ to ‘this->Func2’.

    // assign(pFunc2, ConcreteClass::Func2);

    }

};

 

template InstantialClass<ConcreteClass1>;

template InstantialClass<ConcreteClass2>;

 

int imp_entry(const Context* context)

{

    InstantialClass<ConcreteClass1> v1(context);

    InstantialClass<ConcreteClass2> v2(context);

    BaseClass* p1 = &v1;

    BaseClass* p2 = &v2;

 

    p1-> Func1(1111 , 2222);

    p2-> Func1(1111 , 2222);

    p1-> Func2(1111 , 2222, 3333);

    p2-> Func2(1111 , 2222, 3333);

 

    p1-> Func1(1111 , 2222);

    p2-> Func1(1111 , 2222);

    p1-> Func2(1111 , 2222, 3333);

    p2-> Func2(1111 , 2222, 3333);

 

    return 0;

}

 

// template instantiation generated functions were not

// lie in ‘entry()’ and ‘end_address()’.

// this is a problem, we must guess the actual codes size.

//

// it looks as if this is not a good solution for small shell codes.

//

// but in my shell code, I put all code in a PE file,

// and relocate the whole code section of the PE file.

// so, this is good idea for shell code.

// this technic is a good solution for virus,

// —- if you want write virus in C++ and use virtual function!

void end_address() {}

 

int main(int argc , char* argv[])

{

    Context context;

    context.printf = printf;

 

    typedef int (*T_entry)(const Context* context);

    unsigned char codeBuffer[16*1024];

    size_t codeSize = (unsigned char*)end_address – (unsigned char*)entry;

    size_t guessedCodeSize = sizeof(codeBuffer);

//  memcpy(codeBuffer, (void*)entry, codeSize); // run error!!

    memcpy(codeBuffer, (void*)entry, guessedCodeSize); // run ok!!

 

//  entry(&context);

    ((T_entry)(void*)codeBuffer)(&context);

 

    return 0;

}

 

 

 

自适应Lru(最近最少使用)算法

阅读更多关于《自适应Lru(最近最少使用)算法》

在缓存管理算法中,Lru 几乎是公认的最优的算法。然而它也有一些缺陷,主要是因为:它假定对实体的访问有局部特性。当访问模式没有局部特性的时候,它就会退化为FIFO(先进先出)算法。 继续阅读

高性能文件系统实现

阅读更多关于《高性能文件系统实现》
 

高性能文件系统-演示文档

PowerPoint下载

演示文档首页

Word Doc 文档下载

Fat 文件系统规格白皮书
文件系统的两种实现

标题

高性能文件系统 (该页文档描述)

最小实现

可扩展性

优良(基于虚拟文件系统构架)

时间性能

优良,接近硬件极限速度,
可用于驱动硬盘

差,仅可用于驱动存储卡片

空间性能

较大, Rom(Code)30K , Ram(RunTime) >= 32K

Rom(code) < 8KRam(RunTime) >=2K

支持

Fat12/Fat16/Fat32 ,长文件名

Fat12/Fat16 ,仅 8.3 文件名

可自定义路径解析

其它特点

对连续簇编组,不用 FatCache

FatCache

源码下载:

高性能文件系统( PowerPoint 文档描述)

最小实现
一个国外的Fat文件系统 (使用的是 FatCache ,不是对连续簇编组)

这些源码任何人可以自由下载,自由改动,
但我对此不提供技术支持,如果需要支持, 请联系我们!

软件加密技术及实现-续-01

阅读更多关于《软件加密技术及实现-续-01》

两年前,我曾在毕业设计:《软件加密技术及实现》中设想使用“代码转移”来实现更强大的反破解功能。

直到前不久,在朋友的鼓励下,我在多个方面增强了原先的软件SoftProtector,并改为图形界面,改名为《秦赢甲胄》(可在各搜索引擎搜索),开始尝试商业化。

为了实现更强大的反破解功能,前不久我开始思考实现“代码转移”,不想实现根设想完全两码事,太复杂了:需要对 x86 进行反汇编,代码分析,甚至虚拟执行(虚拟机),来完善《秦赢甲胄》。

在参考了很多资料之后,我终于深有体会,我需要更多的。

希望大家支持!

 

目前我的参考资料:

1.         《虚拟机设计与实现》,说实话,该书深度不够,不过它提到了不少好的参考资料。

2.         Java KVM 虚拟机源代码:http://www.sun.com

3.         IA-32 Intel® Architecture Software Developer’s Manual, http://www.intel.com

 

 

软件解密技术研究

阅读更多关于《软件解密技术研究》

软件解密技术研究

—-Windows PE 文件脱壳

通过设置Hook,动态跟踪堆栈,对加过壳的可执行文件进行解密还原。

 

当然,要解密,至少先要—-得到一个被加密过的“正版” 软件。

然后—-编写简单的Debugger

 

仅需要拦截LoadLibray/GetModuleHandle/GetProcAddress,在这三个Hook中执行记录Library文件名,Procedure(导入函数)名。自己按ImportTable结构伪造一个ImportTable,并存储额外的相关信息。

为每个导入函数生成一个Hook函数体,该函数(我们的Hook) 从堆栈中取得返回地址(即调用该函数的call指令的下一条指令的地址) ,对返回地址的前一条指令(即调用该函数的call指令)进行译码,一般是如下可能的形式:

   call   jump_thunk

   call   [thunk_fun]

   call   reg         ;为简单,先忽略此形式

   call   [reg]       ;为简单,先忽略此形式

   call   [reg + thunk_offset] ;为简单,先忽略此形式

其它奇奇怪怪的形式完全忽略不考虑,如

   push   offset ret_address

push   fun_address

ret

ret_address:

或:

   push   offset ret_address

jmp    fun_address

ret_address:

关键的难点在这里,很有可能在此处出现问题,因为反向译码有可能把一个地址错误的当成指令译码了(不过这种情况很少) 。如果忽略这些问题,则这一个难点就OK了。

称返回地址的前一条指令,即调用该函数的call指令,为caller_entry

   caller_entry指令的bin code为:op XXXXXXXX,其中XXXXXXXX为转向地址。我们的hook code都做些什幺工作呢?

1.      读出caller_entry及其附近一些bin code并写入我们的crack文件,为其后进一步分析用,当然该指令中XXXXXXXX会被记录下来。

2.      由于动态自动跟踪不可能跟踪到所有调用Import Function的地方,但几乎可以跟踪到对至少一个Import Function的一次调用。所以改动XXXXXXXX(jump_thunkfun_thunk的值)可能不太实际,于是只有—-

3.      jump jump_thunk,我们走到jump_thunk,这里一般是
”call [fun_thunk]” 的形式。

4.      fun_thunk写入我们的Crack文件,为进一步分析使用。

5.      在这样的过程中我们需要用户尽量遍历“该正版软件”所有的操作路径(如点文件>存储/另存,编辑>复制/粘贴

6.      用户点击Debugger的“遍历结束” 按钮,就可以把整个PE Image Dump出来。

然后,点击Debugger的“分析&破解” ,即可分析我们生成的Crack文件。

分析过程中的主要操作是:

1.      修改 Dump出来的内存,主要是PE HeaderSection Table

2.      走到fun_thunk,把[fun_thunk] 改为我们的hook地址。

该脱壳软件的特点(区别与其它脱壳软件)基本上只有一点:其它脱壳软件都是想办法取得残留的ImportAddressTableImportNameTable,从其中做文章。

而该软件是从程序的运行中获得实际的thunk地址,并自己构造ImportTable

其实一切都很简单!

后记:

本人一年前作“软件加密技术及实现” 为毕业论文,工作一年来,因专注于工作,几乎已经废弃了加密的研究。

不久前有朋友说:“你就会加密,你怎知你加密的不能被别人破解?” 于是又老毛病大发,连做梦都想:用什幺办法可以使别人不能破解?想来想去,总不能找到完全之策。最后终于想到了一个:“地址加密” 方法,即把ImportFunction的地址加密,调用ImportFunciton时,先解密地址再跳转到ImportFunciton,具体实现如下:

写一个Hook Code,把ImportAddressTable中的地址填为该Hook Code的地址,于是对应与每一个ImportAddressTableEntry,都有一个Hook Code的副本,该Hook Code对加密过的地址进行解密,然后再跳转过去。该Hook Code让它(cracker) 总不能从 PE Image中得到任何ImportFunction的地址。

我自以为此方法完美无缺,然而不久我又想到了破解方法,即此文所描述的。

于是,很快,我又找到了另外一种方法来对付这种破解—-

HookCode开始,把返回地址(即文中所说的call_entry) 加密,然后为被调函数(即该ImportFunction) 建立一个新的StackFrame,再把call_entry之前传来的参数拷贝到新的这个StackFrame中。然后调用ImportFuncion

然而此方法也有问题—-我实际上不知道被调函数有几个参数。

所以我为它创建StackFrame时,只能把该StackFrame建得足够大,可以容纳参数最多的函数—-如我假设它至少有100个参数,于是这会浪费较多的堆栈区,幸好这里不会有递归调用,否则堆栈有可能溢出。这个问题暂时得到了解决。

然而又出现了另外一个问题—-当被调函数返回,我不知道它到底跳过了几个参数(ImportFunction一般是stdcall,跳过参数区的责任由被调者完成) 。即被调函数返回后,ESP的值与调用前不同。

幸好,函数调用不会改变ESIEDIEBXEBP的值,我只要选用这其中的一个寄存器,如EBP,然后用他存储调用前的ESP(当然要先把它存入堆栈而后在恢复)。再调用ImportFunction,待它返回后,
ParamSize =(StackFrameSize – (EBP – ESP)) 就是被调者跳过的参数区的尺寸。

然而又有问题:此刻怎幺返回?我必须跳过参数区呀! 如果我可以生成一条指令ret ParamSize—-(ParamSize必须是立即数) ,就可以了。

但又有问题—-这样的代码是不可重入的!

没办法了吗?当然有,这样的代码可以完成ret ParamSize的功能:

    add    ESP, ParamSize

    jmp    [ESP – ParamSize] ;此刻,该返回地址已经解密.

一切OK!!

此加密方法,征求破解!!