visualc源碼
① 如何在Visual Studio2005中直接編譯c源代碼
新建=>項目=>Visual C++項目=>Win32控制台應用程序=>(輸入名字)=>應用程序設置=>空項目=>源文件=>添加(不是菜單欄里的,是右邊的解決方案視圖里的)=>現有項=>添加已經有了的以C為擴展名的C文件=>(菜單欄)調試=>啟動調試就行了(直接按F5也行)
為了看到程序運行結果,請包含頭文件#include <stdlib.h>,請在程序末加一句system("pause");
② 怎樣用Microsoft visual c++把c源代碼編譯成exe 可執行文件
調試
-->
生成解決方案.
如果沒有建立工程的話,
那麼先-
新建-
控制台項目
-
空的項目.
然後給項目
-
添加文件.
然後
調試
-->
生成解決方案.
基本步驟就是這樣,
具體VC版本不同文字會略有差別,
基本上一樣.
③ 如何在Visual C++ 6.0調試多源代碼C程序!
裝上c語言考試系統,抽一道題,打開考生文件夾,會看到裡面有三個
.c
文件。。tk.c
error.c
和program.c,那分別是填空題,改錯題,和編程題地源程序,把他們用vc++6.0程序打開,就能看到源代碼,然後修改代碼,編譯,連接,運行
c++6.0隻是用來調試程序的~
④ 怎樣用Microsoft visual c++把c源代碼編譯成exe 可執行文件
以VC6舉例:
1、打開電腦上安裝的vc6.0,進入如圖界面
⑤ C 語言源代碼在Microsoft Visual C++ 6.0 中運行怎麼操作
哪來這么麻煩,直接用創建一個文本文件,把代碼放進去保存,然後把這個文本文件的擴展名「.txt」改為「.cpp」,然後用vc打開。(打開方法也很多:1如果你的系統.cpp格式的文件關聯了vc,直接雙擊就能打開;2.打開vc界面,上面有個「open」,然後找到這個文件打開它),接下來就可以編譯和調試
⑥ VC 6.0的C語言庫函數的源代碼可以在哪找到
深入printf
/***
*printf.c - print formatted
*
* Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* defines printf() - print formatted data
*
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
/***
*int printf(format, ...) - print formatted data
*
*Purpose:
* Prints formatted data on stdout using the format string to
* format data and getting as many arguments as called for
* Uses temporary buffering to improve efficiency.
* _output does the real work here
*
*Entry:
* char *format - format string to control data format/number of arguments
* followed by list of arguments, number and type controlled by
* format string
*
*Exit:
* returns number of characters printed
*
*Exceptions:
*
*******************************************************************************/
int __cdecl printf (
const char *format,
...
)
/*
* stdout ''PRINT'', ''F''ormatted
*/
{
va_list arglist;
int buffing;
int retval;
va_start(arglist, format);
_ASSERTE(format != NULL);//斷言宏。如果輸出格式字元串指針為空,則在DEBUG版下斷言,報告錯誤。
_lock_str2(1, stdout);
buffing = _stbuf(stdout);//stdout:指定輸出到屏幕
retval = _output(stdout,format,arglist);
_ftbuf(buffing, stdout);
_unlock_str2(1, stdout);
return(retval);
}
以上為printf()的源代碼
1、從含有可選參數函數中獲得可選參數,以及操作這些參數
typedef char *va_list;
void va_start( va_list arg_ptr, prev_param );
type va_arg( va_list arg_ptr, type );
void va_end( va_list arg_ptr );
假定函數含有一個必選參數和多個可選參數,必選參數聲明為普通數據類型,且能通過參數名來獲得該變數的值。可選參數通過宏va_start、va_arg和va_end(定義在stdarg.h或varargs.h中)來進行操作,即通過設置指向第一個可選參數指針、返回當前參數、在返回參數後重新設置指針來操作所有的可選參數。
va_start:為獲取可變數目參數的函數的參數提供一種便捷手段。設置arg_ptr為指向傳給函數參數列表中的第一個可選參數的指針,且該參數必須是va_list類型。prev_param是在參數列表中第一個可選參數前的必選參數。
va_arg:返回由arg_ptr所指向的參數的值,且自增指向下一個參數的地址。type為當前參數的類型,用來計算該參數的長度,確定下一個參數的起始位置。它可以在函數中應用多次,直到得到函數的所有參數為止,但必須在宏va_start後面調用。
va_end:在獲取所有的參數後,設置指針arg_ptr為NULL。
下面舉例說明:
#include
#include
int average( int first, ... );
void main( void )
{
/* Call with 3 integers (-1 is used as terminator). */
printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );
/* Call with 4 integers. */
printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );
/* Call with just -1 terminator. */
printf( "Average is: %d\n", average( -1 ) );
}
int average( int first, ... )
{
int count = 0, sum = 0, i = first;
va_list marker;
va_start( marker, first ); /* Initialize variable arguments. */
while( i != -1 )
{
sum += i;
count++;
i = va_arg( marker, int);
}
va_end( marker ); /* Reset variable arguments. */
return( sum ? (sum / count) : 0 );
}
返回值為:
Average is: 3
Average is: 8
Average is: 0
綜上所述,在printf()函數中,可以只輸出一個字元串,也可按照一定的形式輸出含有多個可選參數的字元串信息。因此,首先就要通過這些宏來獲取所有的可選參數。在上面的源碼可以看出printf()中,只使用了宏at_start,將可選參數的首地址賦給了arglist。
2、鎖定字元串及輸出字元串到屏幕
#define _lock_str2(i,s) _lock_file2(i,s)
void __cdecl _lock_file2(int, void *);
#define _unlock_str2(i,s) _unlock_file2(i,s)
void __cdecl _unlock_file2(int, void *);
int __cdecl _stbuf(FILE *);
void __cdecl _ftbuf(int, FILE *);
int __cdecl _output(FILE *, const char *, va_list);
在output函數中,讀取格式字元串中的每一個字元,然後對其進行處理,處理方式根據每一個字元所代表的意義來進行,如:普通字元直接利用函數WRITE_CHAR(ch, &charsout);輸出到控制台。
其中的主要部分是對轉換說明符(d,c,s,f)的處理,現在將對其中的部分代碼進行詳細說明,這里只說明最基本的轉換說明符,對這些須基本的轉換說明符進行修飾的修飾符,程序中單獨進行處理。下面是函數output()(output.c)部分源代碼:
case ST_TYPE:
//表示當前處理的字元的類型為轉換說明符。
...
switch (ch) {
//下面對參數的獲取都是利用宏va_arg( va_list arg_ptr, type );來進行的。
case ''c'': {
//從參數表中獲取單個字元,輸出到緩沖字元串中,此時,type=int
buffer[0] = (char) get_int_arg(&argptr); /* get char to print */
text = buffer;
textlen = 1; /* print just a single character */
}
break;
case ''s'': {
//從參數表中獲取字元串,輸出到緩沖字元串中,此時,type=char*
int i;
char *p; /* temps */
text = get_ptr_arg(&argptr);
...
}
break;
case ''w'': {
//對寬字元進行處理
...
} /* case ''w'' */
break;
...
case ''e'':
case ''f'':
case ''g'': {
//對浮點數進行操作
...
#if !LONGDOUBLE_IS_DOUBLE
/* do the conversion */
if (flags & FL_LONGDOUBLE) {
_cldcvt((LONGDOUBLE*)argptr, text, ch, precision, capexp);
va_arg(argptr, LONGDOUBLE);
//對長雙精度型進行處理,此時,type=long double
}
else
#endif /* !LONGDOUBLE_IS_DOUBLE */
{
//對雙精度型進行處理,此時,type=double
_cfltcvt((DOUBLE*)argptr, text, ch, precision, capexp);
va_arg(argptr, DOUBLE);
}
...
break;
//對整型變數處理
case ''d'':
case ''i'':
...
goto COMMON_INT;
case ''u'':
radix = 10;
goto COMMON_INT;
case ''p'':
...
goto COMMON_INT;
case ''o'':
...
註:對於浮點型double和long double,有相應的轉換說明符(%f表示雙精度型,%lf表示長雙精度型),而float卻沒有。其中的原因是,在K&RC下,float值用於表達式或用作參數前,會自動轉換成double類型。而ANSI C一般不會自動把float轉換成double。有些程序已假定其中的float參數會被轉換成double,為了保護大量這樣的程序,所有printf()函數的float參數還是被自動轉換成double型。因此,在K&RC或ANSI C下,都無需用特定的轉換說明符來顯示float型。
綜上所述,轉換說明符必須與待列印字元的類型。通常,用戶有種選擇。例如,如要列印一個int類型的值。則只可以使用%d,%x或%o。所有這些說明符都表示要列印一個int類型的值;它們只不過提供了一個數值的幾種不同表示。類似一,可以用%f、%g和%e來表示double類型的值。但如果轉換說明與類型不匹配,將會出現意想不到的結果。為什麼呢?問題就在於C向函數傳遞信息的方式。
這個失敗的根本細節與具體實現相關。它決定了系統中的參數以何方式傳遞。函數調用如下:
float n1;
double n2;
long n3;
long n4;
...
printf("%ld,%ld,%ld,%ld",n1,n2,n3,n4);
這個調用告訴計算機,要把變數n1,n2,n3和n4的值交給計算機,它把這些變數放進稱作棧(stack)的內存區域中,來完成這一任務。計算機把這些值放進棧中,其根據是變數的類型而不是轉換說明符,比如n1,把8個位元組放入棧中(float被轉換成double),類似地,為n2放了8位元組,其後給n3和n4各放了4個位元組。接著,控制的對象轉移到printf();此函數從棧中讀數,不過在這一過程中,它是在轉換說明符的指導下,讀取數值的。說明符%ld指定printf()應讀4個位元組(va_arg( va_list arg_ptr, type )中type=long),因此printf()讀入棧中的4個位元組,作為它的第一個值。但是這只是n1的前半部分,這個值被看成一個long整數。下一個說明符%ld讀入4個位元組,這正是n1的後半部分,這個值被看成第二個long整數。類似地,第三、第四次又讀入n2的前後兩部分。因此,盡管我們對n3和n4使用了正確的說明符,printf()仍然會產生錯誤。
這里也可以下載
http://mirrors.kernel.org/gnu/glibc/glibc-2.7.tar.gz
⑦ 怎樣在visual C++中建立一個C源程序
1、首選先打開c++編程軟體,打開之後會有提示,不用管它,關閉就可以了。
⑧ Visual Studio 2019怎麼編譯C語言源程序
1、首先,打開C語言編輯器工具,然後在該工具中編寫程序的源代碼,如下圖所示,然後進入下一步。
⑨ 如何看c語言標准庫函數的源代碼
1、首先標准只是規定了這些函數的介面和具體的運行效率的要求,這些函數具體是怎麼寫得要看各個編譯器的實現和平台。
2、例如使用的編譯器是visual studio,微軟提供了一部分C運行時(CRT)的源碼,裡面會有memcpy,strcpy之類的函數的實現,在visual studio 2005下的路徑是C:Program FilesMicrosoft Visual Studio 8VCcrtsrc。
⑩ 用什麼軟體來查看一個用Microsoft Visual C++ 6.0 編寫的程序的源代碼
標 題: MFC逆向初級研究(1)
作 者: 北斗之搖光
時 間: 2007-03-15 17:14
鏈 接: http://bbs.pediy.com/showthread.php?t=41087
詳細信息:
【文章標題】: MFC逆向初級研究(1)
【文章作者】: 北斗之搖光
【作者郵箱】: [email protected]
【下載地址】: 自己搜索下載
【作者聲明】: 只是感興趣,沒有其他目的。失誤之處敬請諸位大俠賜教!
--------------------------------------------------------------------------------
【詳細過程】
引言
本文主要針對微軟的VC++6.0中使用MFC產生的EXE文件的逆向研究,我曾經使用微軟的Visual Studio 2005編譯了一
個EXE文件,通過IDA反匯編以後發現該文件與VC++6.0產生的文件還是有所區別,因此特別在此聲明一下。文中主要使用了I
DA pro 5.0和在看雪(www.pediy.com)下載的OllyICE作為工具對目標文件進行反匯編。在此也感謝看雪論壇的各位的無私奉
獻,在研究過程的中的困難多通過各位的帖子得到了幫助。
逆向的關鍵
我認為逆向的關鍵主要是要弄明白目標文件的演算法和實現過程,在Window操作系統下,軟體的實現過程就體現在其
對Window消息的處理,而軟體的演算法則包含在處理的具體過程中。對於通過SDK編寫的"傳統"的Windows應用程序基本都具備
幾個共同的特徵:WinMain函數、WinProc函數、窗口注冊、消息循環。對於這類目標文件的分析主要集中的WinProc的分析上
,WinProc的函數地址獲得一般是通過窗口注冊函數中的參數獲得。(由於我對於這類文件沒有具體逆向過,所以只是大概的
說說,有不對的地方請各位不要客氣,盡管拍磚)
而使用MFC(Microsoft Function Class)顧名思義,該類庫主要封裝了大部分的Windows API函數所以在代碼中看
不到原本的SDK編程中的消息循環、窗口過程函數等等東西,所有這些封裝在相應的mfcxx.dll中,讓程序員能夠專著與處理
過程與演算法。這種做法於逆向而言有好處也有壞處:
壞處就是加大了對於MFC產生的EXE文件的逆向難度,讓許多的和我一樣的菜鳥迷失在匯編代碼中找不找北了,基本主要就靠
猜測實現過程中用到了那些函數,然後對文件導入表的函數下斷點來尋找我們所需要的處理過程;
好處就是這樣的做法使得EXE文件中主要都是目標程序的Window消息處理流程以及演算法,而且dll中的大部分函數的功能都能
在MSDN中查到。如果能夠通過對目標文件的分析得到這個Window消息處理流程和演算法架構,基本上我們就可以重寫整個軟體;
要做到上面的目標,首先我們要對MFC有所了解,推薦沒有基礎的兄弟們讀讀候俊傑的《深入淺出MFC》。該書在逆向過
程中完全可以作為一本參考書,讓你能通過源代碼了解實現過程,網上有很多該書的電子版下載。
一個逆向MFC產生的EXE文件的例子
下面我們就通過一個具體的例子來學習一下如何從目標文件中挖到我們需要的東西。首先我們來產生一個需要的EXE文件。
在此我假定各位對MFC有過一定的使用經驗,畢竟逆向分析才是本文的重點。
1.產生例子所需要的目標文件:
我們通過VC++6.0的向導來產生一個名為ReverseMFC的工程,這個工程的設置情況如下:
Application type of fff:
Dialog-Based Application targeting:
Win32
Classes to be created:
Application: CFffApp in ReverseMFC.h and ReverseMFC.cpp
Dialog: CFffDlg in ReverseMFCDlg.h and ReverseMFCDlg.cpp
Features:
+ Uses shared DLL implementation (MFC42.DLL)
+ Localizable text in:
中文[中國]
直接編譯以後就能夠運行,為了確定我們是否正確的分析的整個目標文件,在該對話框中加入一個我們自定義的按鈕如
下,對於該按鈕的處理函數如下設定為:
AfxMessageBox("I find it!",MB_OK);編譯後就得到了我們需要的目標文件。
現在我們得到了所需要的目標文件,在IDA中載入該文件。在此我們最好是產生Release版本的EXE文件,畢竟所有的發
布軟體都是Release版本的。
2.具體分析
在IDA中按Ctrl+S找到.rdata段,該段主要存儲了目標文件的類運行時創建信息、MessageMap信息、MessageEntry信息、
虛函數表、RTTI數據(如果編譯選項中選擇了支持RTTI的話)。
在到達.rdata段後我們可以看到這樣的代碼,對數據進行格式轉換後可以得到如下圖所示的數據。
.rdata:004021C0 ; 屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯?
.rdata:004021C0
.rdata:004021C0 ; Segment type: Pure data
.rdata:004021C0 ; Segment permissions: Read
.rdata:004021C0 _rdata segment para public 'DATA' use32
.rdata:004021C0 assume cs:_rdata
.rdata:004021C0 ;org 4021C0h
.rdata:004021C0 off_4021C0 dd offset sub_401000 ; DATA XREF: sub_401010o
.rdata:004021C4 dd offset dword_4021C8
.rdata:004021C8 dword_4021C8 dd 111h ; DATA XREF: .rdata:004021C4o
.rdata:004021CC dd 0
.rdata:004021D0 dd 0E146h
.rdata:004021D4 dd 0E146h
.rdata:004021D8 dd 0Ch
.rdata:004021DC dd offset CWinApp::OnHelp(void)
.rdata:004021E0 dd 0
.rdata:004021E4 dd 0
.rdata:004021E8 dd 0
.rdata:004021EC dd 0
.rdata:004021F0 dd 0
.rdata:004021F4 dd 0
.rdata:004021F8 off_4021F8 dd offset CWinApp::GetRuntimeClass(void)
.rdata:004021F8 ; DATA XREF: unknown_libname_1-56o
.rdata:004021FC dd offset sub_401040
.rdata:00402200 dd offset nullsub_2
.rdata:00402204 dd offset nullsub_3
.rdata:00402208 dd offset nullsub_2
.rdata:0040220C dd offset CCmdTarget::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *)
其中的off_4021C0就是一個MessageMap數據;dword_4021C8就是MessageMap所指的MessageEntry數據;off_4021F8就是一個
類的虛函數表的開始位置。那麼具體這些數據時那個類的相關數據呢?如此判斷的依據是什麼?
首先我們知道MessageEntry是的數據結構定義如下,而且以6個0表示整個數組的結束。
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
因此我們有理由假設"dword_4021C8就是MessageMap所指的MessageEntry數據"。
而MessageMap數據結構定義如下:
struct AFX_MSGMAP
{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
off_4021C0的兩個數據中第二個數據恰恰就是我們前面假設為MessageEntry的指針,跟入其第一個數據,我們看到如下的代
碼:
.text:00401000 ; *************** S U B R O U T I N E ***************************************
.text:00401000
.text:00401000
.text:00401000 sub_401000 proc near ; DATA XREF: .rdata:off_4021C0o
.text:00401000 mov eax, ds:AFX_MSGMAP const CWinApp::messageMap
.text:00401005 retn
.text:00401005
.text:00401005 sub_401000 endp
恰恰是一個返回基類的MessageMap的函數。因此我們也同樣有理由假設"off_4021C0就是一個MessageMap數據"。
對於虛函數表的假設是如何被證明呢?首先我們要知道關於虛函數表的一點知識:虛函數表由虛函數的地址組成,表中函數
地址的順序和它們第一次出現的順序(即在類定義的順序)一致。若有重載的函數,則替換掉基類函數的地址。通過這個我
們可以知道MFC中虛函數表中的函數順序必然是先按照CObject->CCmdtarget->。。。。這個類繼承順序中的虛函數順序來處
理虛函數表中的函數順序的。只要證明這個我們"假設的虛函數"中的函數順序與上面提到的知識相符合則有理由說明我們的
假設成立。
首先來看CObject中虛函數的順序,在查看CObject的聲明文件後得到了這個類的虛函數順序:
virtual CRuntimeClass* GetRuntimeClass() const;
virtual ~CObject(); // virtual destructors are necessary
virtual void Serialize(CArchive& ar);
#if defined(_DEBUG) || defined(_AFXDLL)
// Diagnostic Support
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
再來查看CCmdtarget的虛函數順序,在查看CObject的聲明文件後得到了這個類的虛函數順序:
DECLARE_DYNAMIC(CCmdTarget);
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo);
#ifndef _AFX_NO_OLE_SUPPORT
// called when last OLE reference is released
virtual void OnFinalRelease();
#endif
#ifndef _AFX_NO_OLE_SUPPORT
// called before dispatching to an automation handler function
virtual BOOL IsInvokeAllowed(DISPID dispid);
virtual BOOL GetDispatchIID(IID* pIID);
virtual UINT GetTypeInfoCount();
virtual CTypeLibCache* GetTypeLibCache();
virtual HRESULT GetTypeLib(LCID lcid, LPTYPELIB* ppTypeLib);
之所以還要列出"DECLARE_DYNAMIC(CCmdTarget);"是因為這個宏的定義如下:
#define DECLARE_DYNAMIC(class_name) \
protected: \
static CRuntimeClass* PASCAL _GetBaseClass(); \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
這個virtual CRuntimeClass* GetRuntimeClass() const; 覆蓋掉了一開始的CObject的相對應函數。依次按照類的順序對
照下來,就可以知道該表確實是虛函數表。同時,對應的GetMessageMap虛函數的位置上跟入後,可以得到如下代碼:
.text:00401010 ; *************** S U B R O U T I N E ***************************************
.text:00401010
.text:00401010
.text:00401010 sub_401010 proc near ; DATA XREF: .rdata:00402228o
.text:00401010 mov eax, offset off_4021C0
.text:00401015 retn
.text:00401015
.text:00401015 sub_401010 endp
恰恰是返回了我們之前假設的MessageMap的地址。
--------------------------------------------------------------------------------
【版權聲明】: 本文原創於看雪技術論壇, 轉載請註明作者並保持文章的完整, 謝謝!