心寄笔端 附庸风雅

甘草的技术博客

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

这些都是我以前玩的,写到了Live Spaces上面了,以后把技术文章,都转过来。【玩,没有轻蔑的意思。按照那天在饼子堂的聊天说法,没有深入的研究,才叫玩。】

 

用机器码写Hello World (2006/1/24)
http://healerkx.spaces.live.com/blog/cns!9485ffc4816f2cad!267.entry

      为了做到这一点,我写了4个小程序。
      一个是Server。它实际上是我写出来具有缓冲区溢出漏洞的victim。所以我不用检测其中的漏洞在哪了。当然了,你要相信我,我也不会发现漏洞的技术。我看到WinDbg上千万行的白底黑字的输出就会头疼。
      还有一个Boft,它很简单,就是一个攻击程序。所以它简单,是因为它只含有发送的功能,而shellcode被我拿出来,写到了文件里了。
      一个简单的编译器,现在这个阶段叫它编译器太过了。其实他就是一个代码的转化器,它可以把我手工键入的机器码和注释,转换为Shellcode可用的机器码。
      最后一个是Shellcode,这个程序就是所有的关键了。当然了,这个可不是掌握了汇编就可以写出来的。关键在于,我前面提出的Server相当于Shellcode的运行环境。所以你的Shellcode里要包含指令外,还要有指令用到的数据。这样,你就不能用C/C++和一些汇编程序汇编出来的机器码了。因为它们非常容易包含绝对的地址。这个绝对地址在Shellcode工程里可以找到Hello World,但是被注入到Server后,就一定找不到Hello World了。

      所以,这个Shellcode里要含有数据。并且你的指令要进行相对寻址。所以我写好的Shellcode在前面加上NOP和JMP ESP的地址就可以了。而且Server是自己写的,所以很容易确定NOP的数量,使得JMP ESP的地址很容易覆盖栈上的原来EIP数据。更详细的说明,我在年后写出。提供给对这方面有兴趣的朋友参考。虽然这没有什么难度,而且baidu上也可以找到很多资料。但是很多细节足够难倒初学者了。

代码
_asm
 {
  
push -11
  
mov eax, 0x7c812ca9
  
call eax
  
mov edx, eax
  
jmp call_write_console
V1:
  _emit 
1
  _emit 
1
  _emit 
1
  _emit 
1
string:
  _emit 
'H'
  _emit 
'e'
  _emit 
'l'
  _emit 
'l'
  _emit 
'o'  
  _emit 
' '
  _emit 
'W'
  _emit 
'o'
  _emit 
'r'
  _emit 
'l'
  _emit 
'd'
  _emit 
'\n'
  _emit 
0   
call_write_console:
  
call nextline
  
nextline:
  
pop ebx
  
sub ebx, 22
  
push 0
  
push ebx
  
push 12
  
add ebx, 4
  
push ebx
  
push edx
  
mov eax, 0x7c81cbed
  
call eax
 }


 

关于缓冲区溢出攻击的一些研究说明 (2006/2/9)
http://healerkx.spaces.live.com/blog/cns!9485ffc4816f2cad!275.entry

      年前虽然说要写的,但是这种东西找资料,自己再下功夫看都能明白的,写得太直白了,就没有意思了,但是有朋友非要我写,而且我发现很多资料在某些地方说得很含糊,造成了阅读障碍。所以我还是写出来吧。
      还得声明先,我的水平还得的远了,写出来的东西,有些就是copy来的;而且我的重点在于道出一些资料上少见的东西。并且,说错的地方,请明白的朋友一定要指出来,也好让我再清楚些。
      首先说明的是,Win32的缓冲区溢出攻击比Linux的稍微难一些,但是是相似的。我们这里只说栈溢出攻击的情况,而且只说NNNNNRSSSSS格式。
      NNNNNNRSSSSSS,N就是Nop指令,R是Ret的意思,我们会将栈上保存EIP的内存覆盖为JMP ESP的地址,S就是Shellcode了。
      这里先说JMP ESP的地址,有人的疑问是“什么是机器码的地址?”。其实,机器码就是机器码,它们是没有所谓的地址的。这里所说的JMP ESP的地址,是指JMP ESP的机器码”FF E4”在进程中的某4 BYTES的内存上有这样的字符。实际上,很多黑客软件会在kernel32.dll,user32.dll里找JMP ESP的机器码字串。
原因是这样的:

      当EIP指向Ret指令的时候,而Ret相当于POP EIP,执行后就会把原来PUSH到栈上的EIP恢复到EIP内。
      这里还要打断一下,因为很多朋友看不到PUSH EIP的指令,那是因为CALL指令的缘故,CALL一个函数的时候,相当于PUSH EIP【似乎这里有问题,应该是EIP + CALL指令长度】,然后在JMP到那个函数的地址。所以栈上会有原EIP的值,然后接下来就会执行PUSH EBP了。
      所以,栈的情况是,内存地址由高到低:原EIP,原EBP,其他的一些寄存器的值,然后就是函数栈的参数,变量了。我们用NNNNNNRSSSSS格式的 Shellcode覆盖这段栈,使得JMP ESP的地址覆盖到存放原EIP的内存地址。这样,Ret后,就会执行JMP ESP,而ESP往后移动,这样就跳到我们的Shellcode上了。
      至于NNNRSSSS中N的个数是由栈的情况来定的,通常可以通过试验或者调试计算出来。这里需要说明的是,如果Shellcode比较短,那么NNNNN的部分可以写入Shellcode,只要在S的部分往前跳转就可以了。
      还有,Shellcode如果被strcpy这样的函数处理。还要避免含有’\0’,这个我还没有研究。只是听说有这个问题需要注意。
      另一个重要的问题是Shellcode的相对地址问题。比如说我们的Shellcode里需要字符串,我们要把这些字符串信息发送过去。而实际的C和汇编 编译器会把这些字符串常量编译为绝对的地址。那么这个地址就不能被Shellcode所采用了。所以我们要把一个可以进行相对寻址的字符串常量写入 Shellcode。

      这里,饼子堂的“支书”教了我一招,用_emit指令来腾出指令空间存放字符串常量。我在前面的回复里给出了这样的代码,可以参考一下。
      那么在这里问题里面就有一个获得EIP的问题了,Win32汇编语言是不能显式操作EIP寄存器的(我目前所知的),所以要通过一个小技巧来获得EIP的 值。这个就是CALL NEXTLINE,这个在那段代码里也有。其中的POP EBX,就可以将EIP的值存入EBX中。其中的原理,前面也说过了。

      今天就说这么多吧,欢迎拍砖。


本进程内Hook API的简单做法 (2006/6/29)
http://healerkx.spaces.live.com/blog/cns!9485ffc4816f2cad!398.entry


本文提供一种超级简单的Hook进程内API的方法。
主要使用到的Win32 API有以下这么多,不熟悉的朋友可以先看看它们的文档。
GetCurrentProcess(...)
WriteProcessMemory(...)
 
所以说他简单,是因为在这个程序里没有太多的计算相对地址的东西。
而且这个例子还有一个算是幸运的地方。那就是当我得到一个函数的地址的时候,然后去调用它的机器码恰好是5个字节。
8B 45 F8
FF D0
这个与
E8 20 15 FF FF, call addr地址等长度。
 
我们这里以Hook 本进程内的WriteFile为例子。我们声明一个和它同型的函数:

BOOL
WINAPI
MyWriteFile(HANDLE hFile, LPCVOID lpBuffer, 

DWORD nNumberOfBytesToWrite, 

LPDWORD lpNumberOfBytesWritten, 

LPOVERLAPPED lpOverlapped);

 
我们将要所有的WriteFile都先走我们的函数MyWriteFile,然后再执行真正的WriteFile实现部分。
于是我们首先要跟踪WriteFile的调用位置。改写那里的机器码。
 
void* m = MyWriteFile;
__asm {
    mov eax, m
    call eax
}

 

我们先得到以上代码的Shellcode,就是8B 45 F8 FF D0;
我们写它到一个我们找到的固定地址,
 CHAR szBuffer[5= { 0x8B0x450xF80xFF0xD0 };
 DWORD d 
= 0;
 WriteProcessMemory(GetCurrentProcess(), (VOID
*)0x7C810FA6, szBuffer, 5&d);
 
这样,调用WriteFile的时候,就会跳转到MyWriteFile上了。
当然了,我们还要能够调用真正的WriteFile,我们只要在MyWriteFile的开始把那段机器码改回来就可以了。
这个和上面的方法是一样的。
BOOL WINAPI
MyWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
 CHAR szBuffer[
5= { 0xe80x200x150xff0xff };
 DWORD d 
= 0;
 BOOL b 
= WriteProcessMemory(GetCurrentProcess(), (VOID*)0x7C810FA6, szBuffer, 5&d);
 
return WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
}

 


这样就可以了,简单吧? 这么改来改去的好处是,你不用自己出来太多的栈指针的问题。否则自己弄汇编来处理这些事情,既要写很多代码,又容易出现错误。
OK,全篇结束,这么做的价值不是很大,要是Hook 其他进程的API了,那就做屏幕取词好了。呵呵。但是原理都是相同的啊。

另外值得加的还有很多Comments,特别是李西西(印象里,当时他是金山毒霸的一员),他的回复是:帅哥, hook了之后你又把代码copy回去了? 这个算是一次性hook? 考虑多线程了吗? 永久hook怎么办? 难道再重新hook一次?

嗯,我想我在这里考虑得太简单了,实际应用中确实会有问题罢。但是做人不能太像《0 Bug》一书的作者肖舸了。于是也一并转过来。

世界很大,技术很多,再发点技术文章,来结束这篇汇总:

押键和指令存储
http://healerkx.spaces.live.com/blog/cns!9485FFC4816F2CAD!1245.entry

      押键...,指令存储...,对于那些熟悉我的朋友来说,乍一看这标题,以为是讲编程呢。不是,KOF相关的。
      所谓押键,就是Press a Key and Hold On
      以KOF97,八神的“白光”为例。【所谓白光,是因为梦弹一段的时候,八神划出的血痕很亮,而超必杀的瞬间,又因为时间瞬间的暂停,使得那一道光非常亮白。】
      近身C + 6A + 八稚女。【用统一的数字键来表示方向吧,玩家都明白。】
      可以用押键的方法,简化为如此这般:近身C(押住) + 26A + 624A。这样,就不会变成C接暗勾手了。
      理论简而言之,C + 26A,你看到的将会是重拳->暗勾手。而如果你押住C,那么26A将不会出必杀技。系统就是如此设计的,当你押住ABCD中某键的时候,你是不会 再打出必杀技的。这样押住C,八神就只能在C后打出梦弹了,而不会出错招。并且将指令26存储起来。【指令存储稍后再说】。
      再说些比较有用的押键连续技。
      草薙的近身B + 2B + A + 无式(最终决战奥义),可以演变成如此输入法:
      近身B + 2B(押住B) + 26A + 26A。【注意,必须是26A,草薙的两个大招就是这样,无式用A出,大蛇薙用C出,否则接不上。】
      还有就是Robert的极限流连舞脚接龙虎乱舞,很典型的取消技。
      C + 极限流连舞脚 + 2A(取消) + 龙虎乱舞,可以演变成:
      C + 极限流连舞脚 + 2A(押住) + 26 + 松开A + 524A。否则很容易出26A,或者来不及出超必杀。
      再有就是二阶堂的2B * 3 >> 雷光拳:
      可以2B (2押住)>> 6B >> 6B >> (2松开)6A。... ...
      指令存储就简单了,
      做一个简单的实验,八神离近对手,但不是近身。【也别太远了,大概不到一个人的身位吧,不过某些角色的指令投太过分了,居然能抓到一个身为远】
      先输入426,然后不要松开6,那么八神会往前走吧?! 然后近身的时候输出C,那么一个屑风就出来了。
      OK,讲点实际的,比如大门,克拉克,夏尔米都有的624624A超必杀,也可以使用此理论进行实战出招,近敌的时候先624,然后跑至近身,再624A or C即可。这样避免了你到对手近身再输入两个反半圆的窘迫。
      先说这么多吧,以后再说跑动蓄力。

【难道这个就不技术了?】


 

 

 

 

 

posted on 2010-02-24 14:27  甘草  阅读(671)  评论(1编辑  收藏  举报
Baidu
Google
心寄笔端
TEST
以后我会加上Power By的,先别介意