2007年4月6日星期五

如何获得物理内存大小

The GlobalMemoryStatus function obtains information about the system's current usage of both physical and virtual memory.

 

张志强
2007-04-06

2007年4月5日星期四

建行用户网上银行16万巨款被盗案告破

 
网上银行账户内16万余元莫名"流失",原来是被害人网上购物浏览图片时"顺道"将病毒也引进了电脑。日前,本市警方在云南警方的大力协助下,一举侦破"3・10"特大网上盗窃案,犯罪嫌疑人白某和葛某在昆明落入法网。据了解,这是迄今为止本市警方破获的最大一起网上盗窃案。昨天,警方向外界进行了情况通报。

3月10日中午,市民蔡先生像往常一样,上网查看自己银证通账户情况。意想不到的事情发生了,蔡先生发现账户下显示资金余额只有36.62元,而不是本应该有的16万余元。蔡先生马上联系建行,客服小姐说,钱都通过网上银行转账转走了。

卢湾警方接报后,迅速成立专案组。在分析案情和银行反馈信息并向被害人了解了上网情况后,侦查员进行了综合判断,认为被害人的电脑极有可能被黑客侵入并安装木马程序,从而导致银行账号、密码和认证证书被盗,导致账号内存款"流失"。侦查员通过查询银行转账记录,查明被害人的两张信用卡被犯罪嫌疑人通过网上银行分11次转出人民币共计163014元(不包括转账手续费),被盗资金全部转入一个开户在云南昆明的建设银行活期账户内并已被人取走。

据此,警方迅速派员赴云南昆明开展侦查工作。在当地警方的大力协助下,侦查员很快查明犯罪嫌疑人实施网上盗划的行为地在昆明市金沙小区金春苑某室内,并进一步查明该室实际居住人是青年男子白某和青年女子葛某。经与银行监控录像比对,确定白某即为取款人。

2007年3月28日晚,侦查员通过守候伏击顺利抓获了白某和葛某,并查获了作案用的电脑和部分赃物。

经查,犯罪嫌疑人白某今年31岁,葛某今年27岁。其中白某是某公司的软件开发人员。两人到案后,如实供述了经事先预谋,在网上利用发送照片之际,将携带木马程序的病毒植入被害人的电脑,进而获取了被害人的银行账号、密码和认证证书,同时修改了被害人的密码,盗取被害人银行账户内人民币的犯罪事实。

目前,两人已被依法刑事拘留,案件在进一步侦查中。
 
 
 
呵呵,我关心使用了什么取证方法,调查结果在法庭上的认可程度!!
 
 

张志强
2007-04-05

2007年4月3日星期二

上网偶遇

歹徒闯入民宅强 J妇女遭到誓死反抗,丈夫下地回来见老婆被歹徒压住,抡起铁铲怒拍,就听老婆骂道:「该死的,反抗了半天,被你一铲子给拍进去了.
 
 

张志强
2007-04-03

new的三中使用方法

new有三种使用方式:plain new,nothrow new和placement new。
(1)plain new顾名思义就是普通的new,就是我们惯常使用的new。在C++中是这样定义的:
    void* operator new(std::size_t) throw(std::bad_alloc);
    void operator delete(void *) throw();
提示:plain new在分配失败的情况下,抛出异常std::bad_alloc而不是返回NULL,因此通过判断返回值是否为NULL是徒劳的。
(2)nothrow new是不抛出异常的运算符new的形式。nothrow new在失败时,返回NULL。定义如下:
    void * operator new(std::size_t,const std::nothrow_t&) throw();
    void operator delete(void*) throw();
(3)placement new意即"放置",这种new允许在一块已经分配成功的内存上重新构造对象或对象数组。placement new不用担心内存分配失败,因为它根本不分配内存,它做的唯一一件事情就是调用对象的构造函数。定义如下:
    void* operator new(size_t,void*);
    void operator delete(void*,void*);
提示1:palcement new的主要用途就是反复使用一块较大的动态分配的内存来构造不同类型的对象或者他们的数组。
提示2:placement new构造起来的对象或其数组,要显示的调用他们的析构函数来销毁,千万不要使用delete。
char* p = new(nothrow) char[100];
long *q1 = new(p) long(100);
int *q2 = new(p) int[100/sizeof(int)];
 

张志强
2007-04-03

关于C结构体的bit field

C语言的STRUCT提供了一种叫bit field的语法,可以根据需要决定成员占用某字节的从X位到Y位,例如,下面一个结构:
struct tagtest
{
   char a:4;
   char b:2;
   char c:2;
};

这个定义的含义是整个结构是一个字节长度,成员a占4位,b占2位,c占2位。这样定义以后,我们可以方便的通过设置成员的值来设置结构,而不需要进行位操作了。例如:
tagtest myTest;
myTest.a = 10;
myTest.b = 2;
myTest.c = 1;
 

张志强
2007-04-03

Dump 调用堆栈的原理以及异常信息的反馈

动机:

在游戏开发过程中,我们利用 QA 部门来做产品的质量保证,尽可能将绝大部分错误消化在内部,保证游戏的版本质量,但是 QA 部门毕竟有他的局限性,尽管经过严格的测试也很难保证将所有的问题一网打尽.

 

通过在 Log 中转储的错误信息,我们可以进一步找出问题,但是 Log 文件产生在终端,我们拿到的也仅仅是公司内部测试部门产生的 Log 文件,显然公司内部得到的信息是很有限的,如果能从玩家那里拿到异常信息,我们才能最快的去解决问题,尽可能在错误产生重大影响之前将其解决,所以我们有必要从被动的获取异常信息,转为主动去获取.

 

可行性 :

       在错误发生时 Dump 调用堆栈,可以让我们知道错误发生的位置,这比已往普通的 LOG 更加有效的多.我们可以将出错的堆栈地址反馈回来.这一切在终端出现异常的时候自动进行. Windows 操作系统提供的 SEH 结构化异常机制可能让我们在程序崩溃的瞬间处理这些事情.

 

效率问题 :

       SHE windows 的异常机制,除非在编译时候特别指定不使用,否则总有默认的 SEH 处理机制, kernel32.dll 中有默认的 SEH 处理接口,当我们需要自己处理异常的时候,我们的处理点会挂接在异常处理链的最前端,这种链类似 Hook 的链.链的头部放在 fs[0] 的位置.也就是说效率的问题是可以不必考虑,

 

 

具体实现 :

       通过阅读反汇编代码可以了解函数调用过程中堆栈的结构 :

      

       1 函数调用时 CALL 将下一行指令地址压入堆栈

       2 函数运行第一行会将 EBP 压入堆栈

       3 保存当前堆栈地址到 EBP (mov ebp,esp)

      

       再遇到 call 时从第一步执行,所以每次第二步压入堆栈的都是上一层函数调用的 ESP 地址,而这个地址 +4 字节偏移则是当前调用函数返回后的下一条指令,也就是上一层函数的地址,所以我们只要知道当前函数的 EBP ( 也就是当前函数的栈顶 ) 就能够遍历得到所有调用堆栈层次.

       dumpebp.jpg

我们将windows SEH 结构化异常引入后,可以在异常发生的时候得到当前的EBP值,从而通过这个值得到整个调用堆栈的地址.

 

在发布工程的时候,我们只需要生成map文件,就可以通过这个地址得到崩溃位置.使用HTTP GET 或POST方式可以将我们所需要的崩溃信息提交到我们指定的网站.这种方式只是通过URL参数来提交数据,只需要使用API InternetOpenUrl就可以很方便的将信息提交.此外如果不使用HTTP方式,我们也可以在这个时候创建新的socket 对指定的服务器进行连接来传输数据.

    
    static TCHAR hdrs[] 
= _T("Content-Type: application/x-www-form-urlencoded"
); 
    static 
const TCHAR* accept= _T("Accept: */*"
); 
        static TCHAR action[]=_T("datecomit.aspx"
);//预提交的页面
        static TCHAR server[]=_T("192.168.9.119");//提交的server地址

    static TCHAR frmdata[
1024={0}; 
    _tcscpy(frmdata,_T("message=this is a test message");  //提交数据, message为提交名字   
    
    
// for clarity, error-
checking has been removed 
    HINTERNET hSession 
= InternetOpen("MyAgent"

    INTERNET_OPEN_TYPE_PRECONFIG, 
NULLNULL0
); 
    HINTERNET hConnect 
= InternetConnect(hSession, server

    INTERNET_DEFAULT_HTTP_PORT, 
NULLNULL, INTERNET_SERVICE_HTTP, 01
); 
    HINTERNET hRequest 
= HttpOpenRequest(hConnect, "POST", actionNULLNULL&accept, 01
); 
    HttpSendRequest(hRequest, hdrs, strlen(hdrs), frmdata, strlen(frmdata)); 

 

此后我们只需要定期观察所提交的内容,便可以立即得知是否有异常出现.根据同一异常出现的几率可以得知是否是致命的错误,是否需要紧急更新.


张志强
2007-04-03

2007年4月2日星期一

C++的编程模型

网上看见一篇文章,觉得很有道理!

原文:http://www.cppblog.com/netnchen/archive/2007/03/28/20764.html

 

 

一种语言代表了一种思维,而思维决定了问题的解决方式。

 

从程序设计语言出现到现在已经经历了四代。大多数高级语言都对应到第三代或四代程序设计语言。按其主要支持的编程模型(思维模式)分类,大致可以分为如下类型

1 过程型:这类语言把应用抽象为序列化的操作步骤,其典型代表如PASCALC等。

2 函数型:这类语言把应用抽象为函数(按定义,函数是从一个域到另一个域的映射);它们试图把问题分解为集合和集合间的函数关系。典型代表是LISP

3 逻辑型:这类语言把问题抽象为事实与规则的结合,试图通过逻辑演算解决实际问题。典型代表是PROLOG

4 面向对象型:这类语言从上世纪80年代后迅速发展,这类语言试图将实际问题抽象为独立的对象以及对象间的交互,典型代表是早期的SmallTalkEiffel

5 面向数据结构型:这类语言将问题抽象为对结构化数据的操作,例如现在常用的SQL

 

作为一个诞生与上世纪80年代初期的编程语言,C++被广泛的认为是一种支持面向对象的语言;但是,我认为C++的伟大之处却更多的在于(除了所提供完备的面向对象支持)它同样提供了C的面向过程的编程模型以及只有少数高级语言能支持的范型编程(我更喜欢叫它面向算法的编程)。在实际的应用过程中,我们往往需要不同层次的抽象,C++所支持的广泛的编程模型为我们提供了强大和灵活的工具,使得我们在设计和实现时能自如的选择不同的模型,以最合理的(组合)方式解决问题。

 

不可否认,在当今的程序设计中,面向对象已经基本上是一统江湖,但它往往并不是最合理的选择;例如在针对协议栈的开发中,使用面向过程的模型往往优于使用面向对象的模型(或许这也是为什么主流的电信设备供应商坚持使用C的原因?);而在针对算法进行抽象时,使用面向对象的思维模式几乎完全是不可行的(算法和对象间的不同之处是显而易见的);如果机械的运用面向对象思维,只能使最终产品的质量、可维护性、可读性下降。

 

或许有人会问,那么应该如何选择抽象方式呢?我觉得这个应该是因人和问题的不同而不同的,关键是在使用C++的过程中,多从这些方面进行思考、总结,以体会采用不同模式解决问题的优缺点,努力使用最合理的方式(或组合)对问题进行抽象并加以解决。我也常常为这些种种选择而迷惑,因此在这儿也希望那些已经到了"不惑"层次的哥们多多指教。

 

当然,从另一方面来说,越多的选择往往意味着越难的选择,这或许也是为什么现在这么多人趋骛与更单纯、更简单的JAVAC#的原因吧;但是当我们真正理解并掌握C++提供的这些编程模型时,我想我们会更加坚定当初选择C++的信念;

 

张志强
2007-04-02