发新话题
打印

[原创]让VC++直接生成汇编代码

[原创]让VC++直接生成汇编代码

文章作者:独孤依人(cnsst)
信息来源:邪恶八进制信息安全团队(www.eviloctal.com

注:2007年10月27日星期六晚作于海南海口,首发脚本安全小组(www.cnsst.org),后由作者友情提交到邪恶八进制信息安全团队论坛。

看了李子明写的那篇《让汇编揭开死循环的神秘面纱》后,突然有个想法,那就是能不能把C++的代码直接翻译成ASM的,那样对于我们程序分析就更加清析了,也不用反汇编去分析了。在网上没看到相关类似的教程,于是,便有了此文。
首先,我们来看看子明兄原文中的小程序:
引用:
#include <stdio.h>

void main()
{
  int j, b[10];
  for ( j = 0; j <= 10; j++ )
  {
    b[j] = 0;
  }
}
请问这个程序是否有错?A.正常 B.越界 C.死循环

我想很多朋友会选择B,当然不排除有选择A和C的,其实正确答案是C,子明兄在文章中用逆向工程把原理已经说得很清楚了,这里就不再累述了。

从子明兄文章里我们可以总结出逆向工程具体的流程大概如下:
1、 高级语言程序(C、C++、...)-->编译-->生成可执行程序(机器码/汇编语言)
2、可执行程序-->反编译(IDA、OD、WIN32DASM等反编译软件)-->汇编代码
3、汇编代码-->分析、了解汇编代码程序流程-->进行逆向分析或者实现某个功能
4、逆向工程完毕

在我们没有程序源代码的情况下,做逆向分析也只有按照上述的流程(各位大大有什么更好的方法还希望分享下),然后我们在有源代码的情况,是不是可以直接来生成汇编代码而省去反编译那一步呢?答案是肯定的。
我们先把程序做如下改变(看汇编代码的时候更清楚):
引用:
/*
  Author : 独孤依人(CNSST)
  Date  : 2007-10-27
  Content: 代码演示让VC++直接生成汇编代码程序示例
*/
#include <stdio.h>

void main()
{
  int j=0, b[10]={1,2,3,4,5,6,7,8,9,10};
  for ( j = 0; j <= 10; j++ )
  {
    b[j] = 0;
  }
}
接下来,我们通过如下几步设置:
1)  选择菜单工程(Project)设置(Settings),出现如图1所示界面:
2)  选择C/C++标签,然后在分类(Category)中选择Listing Files,然后在列表文件类型(Listing file type)选择Assembly with Source code,如果图2所示: 这样设置之后就可以输出汇编代码了。
3)  编译构件执行后,我们看到Debug目录已生成了对应的汇编代码,如图3所示:

下面,我对生成的汇编代码做简单的解释(CNSST注://……为我加上的解释):
TITLE  C:\Documents and Settings\Administrator\桌面\test\test.cpp  //程序名
  .386P   //编译成386保护模式指令
include listing.inc
if @Version gt 510 //判断汇编语言编译器版本是否大于5.1
.model FLAT //以FLAT内存模式编译
Else   //以下声明一些段,之后对应C的相关代码,程序生成时都有相关注释。
_TEXT  SEGMENT PARA USE32 PUBLIC &#39;CODE&#39;
_TEXT  ENDS
_DATA  SEGMENT DWORD USE32 PUBLIC &#39;DATA&#39;
_DATA  ENDS
CONST  SEGMENT DWORD USE32 PUBLIC &#39;CONST&#39;
CONST  ENDS
_BSS  SEGMENT DWORD USE32 PUBLIC &#39;BSS&#39;
_BSS  ENDS
$$SYMBOLS  SEGMENT BYTE USE32 &#39;DEBSYM&#39;
$$SYMBOLS  ENDS
$$TYPES  SEGMENT BYTE USE32 &#39;DEBTYP&#39;
$$TYPES  ENDS
_TLS  SEGMENT DWORD USE32 PUBLIC &#39;TLS&#39;
_TLS  ENDS
;  COMDAT _main
_TEXT  SEGMENT PARA USE32 PUBLIC &#39;CODE&#39;
_TEXT  ENDS
FLAT  GROUP _DATA, CONST, _BSS //所有的段共享FLAT组
  ASSUME  CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC  _main
;  COMDAT _main
_TEXT  SEGMENT
_i$ = -4
_b$ = -44
_main  PROC NEAR          ; COMDAT

; 4  : {

  push  ebp
  mov  ebp, esp
  sub  esp, 108        ; 0000006cH
  push  ebx
  push  esi
  push  edi
  lea  edi, DWORD PTR [ebp-108]
  mov  ecx, 27          ; 0000001bH
  mov  eax, -858993460        ; ccccccccH
  rep stosd

; 5  :   int j=0, b[10]={1,2,3,4,5,6,7,8,9,10};

  mov  DWORD PTR _i$[ebp], 0
  mov  DWORD PTR _b$[ebp], 1
  mov  DWORD PTR _b$[ebp+4], 2
  mov  DWORD PTR _b$[ebp+8], 3
  mov  DWORD PTR _b$[ebp+12], 4
  mov  DWORD PTR _b$[ebp+16], 5
  mov  DWORD PTR _b$[ebp+20], 6
  mov  DWORD PTR _b$[ebp+24], 7
  mov  DWORD PTR _b$[ebp+28], 8
  mov  DWORD PTR _b$[ebp+32], 9
  mov  DWORD PTR _b$[ebp+36], 10    ; 0000000aH

; 6  :   for ( ij= 0; j <= 10; j++ )

  mov  DWORD PTR _i$[ebp], 0
  jmp  SHORT $L529
$L530:
  mov  eax, DWORD PTR _i$[ebp]
  add  eax, 1
  mov  DWORD PTR _i$[ebp], eax
$L529:
  cmp  DWORD PTR _i$[ebp], 10      ; 0000000aH
  jg  SHORT $L531

; 8  :     b[j] = 0;

  mov  ecx, DWORD PTR _i$[ebp]
  mov  DWORD PTR _b$[ebp+ecx*4], 0

; 9  :   }

  jmp  SHORT $L530
$L531:

; 10  : }

  pop  edi
  pop  esi
  pop  ebx
  mov  esp, ebp
  pop  ebp
  ret  0
_main  ENDP
_TEXT  ENDS
END

直接生成的汇编代码看起来比反汇编的直观多了,再来分析其中的原理,挑出其中的一段代码如下:

; 5  :   int j=0, b[10]={1,2,3,4,5,6,7,8,9,10};

  mov  DWORD PTR _i$[ebp], 0
  mov  DWORD PTR _b$[ebp], 1
  mov  DWORD PTR _b$[ebp+4], 2
  mov  DWORD PTR _b$[ebp+8], 3
  mov  DWORD PTR _b$[ebp+12], 4
  mov  DWORD PTR _b$[ebp+16], 5
  mov  DWORD PTR _b$[ebp+20], 6
  mov  DWORD PTR _b$[ebp+24], 7
  mov  DWORD PTR _b$[ebp+28], 8
  mov  DWORD PTR _b$[ebp+32], 9
  mov  DWORD PTR _b$[ebp+36], 10    ; 0000000aH

; 6  :   for ( j = 0; j <= 10; j++ )

  mov  DWORD PTR _i$[ebp], 0
  jmp  SHORT $L529
这段代码让迷团浮出水面,具体分析见子明兄原文,这里也不再累述。此文到此算是结束了,对逆向工程也许没有什么用,但对于学习逆向工程的朋友或许有些帮助。本文方法只是一个小技巧而已,除此之外,还可以通过命令行程序CL.exe来做到,这里也不再累述。最后,祝愿小组所有的兄弟学业、爱情、事业有成,同时欢迎大家来我们脚本安全小组(Www.cnsst.org)做客。
脚本安全小组:Www.Cnsst.Org MSN:cn557@hotmail.com  我们这帮兄弟,永远的兄弟——We are not the only ones,but we will try to be the best!——All In Script 脚本渗透自用利器开发中……

TOP

这个程序编译不能通过 怎么转换成汇编代码?

TOP

呵呵,地址覆盖问题!

TOP

引用:
引用第1楼mmzz321于2007-10-28 10:35发表的 :
这个程序编译不能通过 怎么转换成汇编代码?
是b [ i ] 吧,被过滤掉了

TOP

文章作者:匿名
我想说下我的菜菜的想法啊,别笑我,  楼猪所说的可以把C++代码转换成汇编,那么也就是说用C++写个下载者的代码可以直接转换成汇编了,..这里面有个文章讨论在程序中用汇编的方法加个下载者了.哪个楼猪最后都没有给个可行的方法我也测试了,不能用,我想用你的这样的方法可以么?可以参照最小的下载者的代码转换,我想空间应该够的 .不然加个区段也可以把,这是我的一点的想法.....这成感染了,..反正我的想法就是这样的,不知道可行不可行,晚上我先测试把,希望有说的不对的地方指教下 ...

TOP

数组越界后刚好把堆栈中的变量j覆盖成0了,导致死循环……

TOP

话虽如此,但是真正编译起来,问题会很多耶。。
游戏吧  http://www.game8.cc/MyBlog    http://www.asm32.cn

TOP

.386
.model flat,stdcall
option casemap:none
include Windows.inc
include user32.inc
include kernel32.inc
includelib kernel32.lib
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
.DATA
ClassName db "SimpleWinClass",0
AppName db"Our First Window",0
.DATA?
hInstance HINSTANCE ?
CommandLine LPSTR ?
.CODE
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND

mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style,CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc,OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor ,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx,addr wc
invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,hInst,NULL
mov hwnd,eax
invoke ShowWindow,hwnd,CmdShow
invoke UpdateWindow,hwnd
   .WHILE TRUE
      invoke GetMessage,ADDR msg,NULL,0,0
      .BREAK .IF(!eax)
      invoke TranslateMessage,ADDR msg
      invoke DispatchMessage,ADDR msg
    .ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.IF uMsg==WM_DESTROY
    invoke PostQuitMessage,NULL
.ELSE
   invoke DefWindowProc,hWnd,uMsg,wParam,lParam
   ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start
   
帮我看看这段代码怎么通不过呀

TOP

LS就是创建一个窗口,对比一下罗云彬的代码就知道错哪里了
游戏吧  http://www.game8.cc/MyBlog    http://www.asm32.cn

TOP

引用:
引用第7楼leyuxin于2007-10-30 11:16发表的 :
.386
.model flat,stdcall
option casemap:none
include Windows.inc
include user32.inc
.......
代码没问题,可能是你没有注意被包含的.inc类型文件的地址,加上完整路径就可以了。
编译的时候应该可以发现的。

TOP

清0,WNDCLASSEX结构,试试。。。。

TOP

cl /AF *.c
linux下gcc加-s
楼主的方法麻烦了点

TOP

发新话题