반응형

구조체를 선언할때 보통 아래와 같은식으로 한다.


#pragma pack(push, 1)

  구조체 정의

#pragma pack(pop)



왜냐하면 Win32에서는 기본형이 4Byte이므로 4Byte씩 처리하는것이 가장 빠르다.

그래서 win32에서는 데이타 정렬((Data alignment))을 기본적으로 4Byte씩 하도록 되어있다.


struct A

{

    char a;

    short b;

};

위와 같이 struct가 정의된경우 struct A를 sizeof(A) 하면 얼마일까?


char a  =  1Byte  , short b = 2Byte 이므로 sizeof(A) = 3Byte가 나올까?

그냥하면 3Byte가 아닌 8Byte가 나온다.


위 구조체의 데이타를 같은 구조체에 copy하는데는 문제없겠지만

socket이나 serial로 전송하거나 한다면 문제가 발생할 것이다.


이럴때 데이타정렬을 원하는 size로 하게 하려면

#pragma pack( 1)을 하면 된다.


#pragma pack(push, 1) 

struct A

{

    char a;

    short b;

};

#pragma pack(pop)



#pragma pack(push)  //이전 데이타 정렬 보관

#pragma pack(1)       // 1Byte씩 데이타정렬 설정

...

#pragma pack(pop)   //이전 데이타 정렬 복구



어쩌다 한번씩 깜빡하고 이문제로 해맬때 있다.

혹 모르는 분을 위해..

그리고 스스로 기억을위해 정리해본다.


델파이에서는 packed 키워드를 이용하여 정렬한다.


type
  // Declare an unpacked record
  TDefaultRecord = Record
    name1   : string[4];
    floater : single;
    name2   : char;
    int     : Integer;
  end;

  // Declare a packed record
  TPackedRecord = Packed Record
    name1   : string[4];
    floater : single;
    name2   : char;
    int     : Integer;
  end;

 

참조

http://www.delphibasics.co.uk/RTL.asp?Name=Packed

반응형
 

컴파일러는 사용자가 작성한 코드를 컴파일하기에 앞서 전처리문에서 정의해 놓은 문장들을 먼저 처리한다.

종류로는 #include, #define, #if, #error, #line, #pragma 등이 있다.
이것은 방대한 소스 코드를 지우지 않고 활성화와 비활성화하는 데에 가장 많이 이용된다.
즉, 기존에 있는 소스 코드를 건드리지 않고 부분적인 컴파일을 하는 것이다.

어떤 C 컴파일러는 전처리문의 첫 문자 #이 항상 그 라인의 첫 문자이어야 한다.

ANSI 표준에 따른 C의 전처리문의 종류
- 파일 처리를 위한 전처리문 : #include
- 형태 정의를 위한 전처리문 : #define, #undef
- 조건 처리를 위한 전처리문 : #if, #elif, #ifdef, #elif defined(), #ifndef, #else, #endif
- 에러 처리를 위한 전처리문 : #error
- 디버깅을 위한 전처리문 : #line
- 컴파일 옵션 처리를 위한 전처리문 : #pragma

조건 처리를 위한 전처리문은 어떤 조건에 대해 검사를 하고 그 결과를 참(0이 아닌 값) 또는 거짓(0)으로 돌려준다.
#if : ...이 참이라면
#ifdef : ...이 정의되어 있다면
#else : #if나 #ifdef에 대응된다.
#elif : else + if의 의미
#elif defined() : else + ifdef의 의미
#endif : #if, #ifdef, #ifndef이 끝났음을 알린다.

#include
헤더 파일과 같은 외부 파일을 읽어서 포함시키고자 할 때 사용된다. 이때의 파일은 이진 파일(Binary file)이 아닌 C의 소스 파일과 같은 형태의 일반 문서 파일을 말한다:
#include <stdio.h>        /* 이 위치에 stdio.h라는 파일을 포함시킨다. */
#include "text.h"           /* 이 위치에 text.h라는 파일을 포함시킨다. */

<...>을 사용할 때와 ...을 사용할 때의 차이점은 <...>은 컴파일러의 표준 포함 파일 디렉토리(또는 사용자가 별도로 지정해 준)에서 파일을 찾는 것을 기본으로 한다. 그리고 ...을 사용했을 때는 현재의 디렉토리를 기본으로 파일을 찾게 된다. 아예 디렉토리를 같이 지정할 수도 있다:
#include <C:\MYDIR\MYHEAD.H>
#include "C:\MYDIR\MYHEAD.H"

#define
상수 값을 지정하기 위한 예약어로 구문의 상수로 치환한다. 또한 #define은 함수 역활과 비슷하게 아래와 같이 쓰일 수 있다:
#define SUM(x) ((x) = (x) + (x))

#define으로 정의할 수 있는 것은 숫자만이 아니다:
#define MYNAME "Young Hee"

이렇게 #define으로 정의된 것은 일반적인 변수와는 다르다. 그 차이는 명백하다:
#define MYNAME "Turbo"
char my_name[] = "Turbo"

MYNAME은 전처리문으로 my_name은 문자형 배열 변수로 정의되었다:
printf(MYNAME);
printf(MYNAME);
printf(my_name);
printf(my_name);

이것을 전처리한 상태는 다음과 같이 될 것이다:
printf("Turbo");
printf("Turbo");
printf(my_name);
printf(my_name);

이런 결과에서 우리가 유추해 볼 수 있는 것은 전처리 명령을 사용했을 경우 "Turbo"라는 동일한 동작에 대해서 두개의 똑같은 문자열이 사용됐고, 변수를 사용했을 경우에는 하나의 문자열을 가지고 두번을 사용하고 있다는 것이다. 결과적으로 이런 경우에는 전처리문을 사용했을 경우 메모리 낭비를 가져 온다는 것을 알 수 있다.

#undef
#define으로 이미 정의된 매크로를 무효화한다:
#define ADD(a, b) (a + b)
#undef ADD(a, b)

앞으로 사용되는 ADD(...)는 undefined symbol이 되어 에러 처리된다.

#if ~ #endif
#if 구문은 if랑 아주 비슷하다. 이것은 어떠한 구문을 컴파일 할지 안할지를 지정할 수 있다:
#define A 1

#if A
source code ...
#endif

위 source code 부분은 컴파일이 된다. if문에서와 같이 참, 거짓을 구분하여 컴파일이 된다. 위에서 A값은 1 즉 0보다 큰 수이기 때문에 참인 것이다. 직접 아래와 같이 하면 거짓이기 때문에 source code 부분은 컴파일이 되지 않는다:
#if 0
source code ...
#endif

#if A == 2
source code 2 ...
#elif A == 3
source code 3 ...
#else
source code 1 ...
#endif

#ifdef ~ #endif
컴파일 할 때
#define MYDEF                /* MYDEF는 값은 가지지 않았지만 어쨋든 정의는 되었다 */

#ifdef YOURDEF              /* 만약 YOURDEF가 정의되어 있다면... */
#define BASE 10             /* BASE == 10 */
#elif defined MYDEF                    /* 그외에 MYDEF가 정의되었다면... */
#define BASE 2               /* BASE == 2 */
#endif

BASE는 상수 2로 치환되어 전처리기가 컴파일러에게 넘겨준다.

#ifndef __헤더명_H__ ~ #endif
헤더 파일이 겹치는 것을 막기 위한 일종의 매크로이다. 예를 들어, 헤더 파일에 어떤 클래스의 인터페이스 선언을 넣었다고 하자. 이 클래스 인터페이스에서 다른 파일의 프로토타입이 필요해서 다른 A 파일을 include 하고 있는데 이 헤더 파일을 include 하는 파일에서 A라는 헤더 파일을 이미 include 하고 있다면 두번 define한 것이 된다. 그러면 SYNTEX 에러가 난다. 그래서 그런 것을 막는 방법의 하나로 #ifndef을 사용한다. 이전에 include되어 있으면 #endif 쪽으로 점프해 버려 결국 한번 선언되는 것이다:
#include  <stdio.h>    ------ (a)
#include  <stdio.h>    ------ (b)

이렇게 두번 썼다고 하자. 그런데 앞에서 이미 include 했는데 밑에 또 한다면 문제가 된다. 컴파일러가 검사해야할 코드량도 많아진다. 그래서 stdio.h에는
#ifndef __STDIO_H__
#define __STDIO_H__
...
#endif
가 선언되어 있다. 만약 __STDIO_H__가 선언되어 있지 않다면 선언한다는 뜻이다. 그 뒤 (b)에서는 이미 (a)쪽에서 __STDIO_H__ 을 선언한 상태이기 때문에 전처리기 쪽에서 무시해버린다. 그러므로 컴파일러는 (a)만 검사한다.

#defined
define이 여러 개 되어 있는지를 검사할 때 쓴다. 이것은 여러 개를 동시에 검사 할 수 있다:
#if defined A || defined B
#if (defined A) || (defined B)
#if defined(A) || defined(B)


#ifdef와 #if defined의 차이
#ifdef은 정의가 되어 있는지를 테스트 하기 때문에 한번에 여러 개를 사용할 수 없다:
#ifdef name

여러 개가 정의되어 있는지를 테스트하기 위해서 #if defined를 사용할 수 있다:
#if defined(MACRO1) || defined(MACRO2)

#if는 ||로 중첩해서 사용할 수 있다(형식이 #if expression이므로 C 표현이 올 수 있다):
#if (MACRO1) || (MACRO2)

#error
소스 라인에 직접 에러 메세지를 출력한다. 전처리기가 #error 문을 만나면 그 즉시 컴파일을 중단하고 다음과 같은 에러 메시지를 출력한다:
ERROR : XXXXX.c ########: Error directive: 내용
- XXXXX.c --> 현재 컴파일 중인 파일 명
- ####### --> 전처리기가 #error 문을 만난 시점에서의 행 번호(헤더 포함)

#ifdef __LARGE__
#error This program must be compiled in LARGE memory model!
#endif

이 내용은 만일 프로그램이 LARGE 모델이 아니라면 "#error" 뒤에 표시된 메세지를 출력하고 컴파일을 중지하게 된다.

#line
이 명령은 소스 코드의 행 번호를 지정하기 위한 것으로 주로 컴파일러에 의해 미리 정의된 __LINE__과 함께 사용된다.
__LINE__과 __FILE__을 각각 행 번호와 파일 명으로 변경한다:
#include <stdio.h>
#define DEBUG

void main(void)
{
        int count = 100;

        #line 100               /* 다음 줄번호를 100으로 설정한다 */
                                   /* <-- 이 줄의 번호가 100이다 */
        #ifdef DEBUG        /* <-- 이 줄의 번호가 101이다 */
        printf("line:%d, count = %d\n", __LINE__, count);
        #endif

        count = count * count - 56;
        #ifdef DEBUG
        printf("line:%d, count = %d\n", __LINE__, count);
        #endif
        count = count / 2 + 48;
        #ifdef DEBUG
        printf("line:%d, count = %d\n", __LINE__, count);
        #endif
}

#pragma
컴파일 옵션의 지정. 컴파일러 작성자에 의해서 정의된 다양한 명령을 컴파일러에게 제공하기 위해 사용되는 지시어이다. 컴파일러의 여러 가지 옵션을 명령행에서가 아닌 코드에서 직접 설정한다. #pragma는 함수의 바로 앞에 오며 그 함수에만 영향을 준다.
Turbo C는 9개의 #pragma 문(warn, inline, saveregs, exit, argsused, hdrfile, hdrstop, option, startup)을 지원하고 있다:

#pragma inline
컴파일할 때 어셈블러를 통해서 하도록 지시한다. 즉, 인라인 어셈블리 코드가 프로그램에 있음을 알려준다(명령행 상에서 '-B' 옵션).

#pragma saveregs
이 홉션은 휴즈 메모리 모델에 대해 컴파일된 함수에게 모든 레지스터를 저장하도록 한다.

#pragma warn
이 지시어는 Turbo C에게 경고 메시지 옵션을 무시하도록 한다.

#pragma warn -par
이는 매개 변수(parAMETER)가 사용되지 않았다고 경고(warnING)를 내지 못하도록 한다. 이와 반대되는 표현은
#pragma warn +par

경고의 내용 앞에 (+)를 사용하면 경고를 낼 수 있도록 설정하고 (-)를 사용하면 경고를 내지 못하도록 하는 것은 모든 경고에 대해 동일하다. 명령 행에서는 "-wxxx"로 경고를 설정하고 "-w-xxx"로 경고를 해제한다. 경고의 종류는 무척 많은데 자주 사용되는 것을 아래에 나타냈다. 모든 것을 알고 싶다면 컴파일러 User's Guide의 명령행 컴파일러 부분을 참고하기 바란다:
par : 전해진 파라미터가 사용되지 않음
rvl : void 형이 아닌 함수에서 리턴 값이 없음
aus : 변수에 값을 할당했으나 사용하지 않았음
voi : void 형 함수에서 리턴 값이 사용되었음
sig : 부호 비트(MSB)가 고려되지 않은 형 변환(type-castion)에서 부호 비트를 소실할 수 있음

Standard C pre-defined symbols

__FILE__ a string that holds the path/name of the compiled file
__LINE__ an integer that holds the number of the current line number
__DATE__ a string(Mmm dd yyyy) that holds the current system date
__TIME__ a string(hh:mm:ss) that holds the current system time
__STDC__ defined as the value '1' if the compiler conforms with the ANSI C standard
__cplusplus determines if your compiler is in C or C++ mode. Usually used in headers


#include <stdio.h>

void main(void)
{  
        printf("The path/name of this file is %s\n", __FILE__);  
        printf("The current line is %d\n", __LINE__);  
        printf("The current system date is %s\n", __DATE__);  
        printf("The current system time is %s\n", __TIME__);  

        #ifdef __STDC__  
        printf("The compiler conforms with the ANSI C standard\n");  
        #else  
        printf("The compiler doesn't conform with the ANSI C standard\n");  
        #endif  

        #ifdef __cplusplus  
        printf("The compiler is working with C++\n");  
        #else  
        printf("The compiler is working with C\n");  
        #endif 


프로그래머들 마다 코딩 스타일(암시적 약속)이 있다. 보통 매크로, const 변수는 대문자로 적는 것이 원칙이다. 매크로 함수와 일반 함수, 매크로 대상체(object-like macro)와 일반 변수를 구분하기 쉽게 해주는 것이기 때문이다.

#define STDIO_H_
왜 뒤에 _를 붙였을까? 이것도 하나의 암시적 약속이다. 컴파일러 제작 회사는 매크로를 정의할 때 사용자들과 이름이 충돌이 나지 않게 하기 위해서 대부분 _를 뒤어 덧붙인다. 또한 _를 하나 혹은 두 개 연속으로 시작하는 것은 컴파일러 내부에서 사용하는 매크로라는 성격이 강하다. 물론 강제적인 뜻은 없으며 단지 관습상 그렇다. 왜 이것이 관습이 되었나 하면 보통 매크로 변수 이름이나 함수 이름을 지을 때 뒤에 _를 붙이지 않기 때문이다. 그래서 함수 제작자들이 _를 단골로 붙였다.

<출처 : http://cafe.naver.com/devctrl.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=468 >

반응형

사용자 삽입 이미지

단순히 필요한 자료를 정리하기 위해 블로그를 시작했었다.

그리고 무차별적으로 출처도 표시하지 않고 스크랩해서 올렸었다.

자신의 블로그의 순위까지 알려주는 서비스도 등장한걸 보니 개인 블로그에 대한 관심이

높아졌구나 하는 생각이 들었다.

정작 내가 출처도 밝히지 않고 스크랩했던 글의 저작자(?)들은 나로 인한 피해를 입었다는 생각이 든다.

남의 글을 퍼갈때는 출처를 꼭 밝히도록 해야겠다.. 그리고 블로그에 시간과 노력을 들여

내가 정리한 자료를 올리도록 해야겠다는 생각이 들었다.

정작 내 블로그에 내가 작성한 글들은 몇개 되지 않고 순위검색을 해보니

어느 정도의 순위에 기쁘기도 하지만 내가 스크랩해온 분들의 자료들이 대부분이라 생각하니 부끄럽기도 하다.
반응형
  설명                                                                             스택 프레임                   SP 위치

1. 스택은 현재 초기값(sp) 상태

   이 상태에서 함수호출(CALL nnnn)이 들어오면

 

 ←SP(한칸위를 가리켜야되는데 그림이..)

들어온곳을 가리킴

 

 

 


2. 함수의 인자(두개라고 가정한다.)와 다음 명령어 주소를 차례로 PUSH 한다. 이때 인자의 푸시 순서는는 오른쪽에서 왼쪽으로(FIFO 이므로) 하며 다음 명령어 주소(이것이 복귀 주소이다.)는 IP 에 들어있다.

   그리고 IP를 호출 함수의 시작주소로 변경한다

argument 1

←SP

argument 2

IP(복귀 주소)

 

 

 

 

 


3. IP가 피호출함수의 시작주소로 변경되었으므로 함수가 시작된다. 함수에 진입하면 일단 BP레지스터를 스택에 PUSH한다.(이전 BP를 유지하지 위함. 아래에서 BP 레지스터를 SP를 저장하는 용도로 사용하기 때문에 함수를 여러번 호출할 경우를 대비해 BP를 스택에 넣어두는 것이 필요하다.)

argument 1

←SP

argument 2

IP(복귀 주소)

BP

 

 

 

 


4. 그 뒤 SP를 BP에 옮긴다.(BP=SP). 이것은 함수내에서의 SP 사용으로 SP가 계속 내려가기 때문에 BP를 SP의 저장용도로 사용하기 위함이다.

(이제 PUSH된 BP와 레지스터 BP의 값은 다르다)

 

argument 1

←SP,BP

argument 2

IP(복귀 주소)

BP

 

 

 

 


5. 함수내부에서 스택 사용으로 SP가 증가한다(사용하지 않더라도 상관없다.) 

winapi같은 __stdcall 호출규약을 따르는 프로시저는

사용할 내부변수의 크기를 계산해서

enter x,x 명령어로 sp의 값을 감소시켜준다

(여기선 enter 4,3)

c, c++ 의 __cdecl 호츌규약 프로시저는 수동으로..

argument 1

←BP

←SP

 

argument 2

IP(복귀 주소)

BP

내부변수

내부변수

내부변수

 

 

 


6. 함수에서 복귀를 위해(return) SP를 BP로 되돌린다(SP=BP) 

argument 1

←SP,BP

argument 2

IP(복귀 주소)

BP

내부변수

내부변수

내부변수

 

 

 


7. SP를 되돌렸으면 POP BP를 하여 스택에 저장되어있던 BP를 다시 BP 레지스터에 저장한다.(이로써 함수 호출 이전의 BP 로 돌아온것) 

POP을 했기 때문에 SP가 하나 증가하여 이제 복귀 주소를 가리키고 있다.

argument 1

 

←SP

 

argument 2

IP(복귀 주소)

BP

내부변수

내부변수

내부변수

 

 

 


                                                                                                                     ←SP

8. ret 명령어는 다시 POP IP를 수행한다. 이로써 IP는 저장되어있던 복귀주소 즉 함수호출 CALL nnnn 다음 명령어로 변경된다.

이때 __stdcall을 사용하는 윈도우 프로그램은 ret 뒤의 피연산자로 붙은 4(인자크기 × 인자수)가 SP+4를 수행하여 SP를 4만큼 증가시킨다. (이부분 전체명령어는 ret 4이다. 피호출측에서 스택을 복구 시킨다.)

cdecl을 사용하는 c,c++프로시저는 복귀한뒤에 add, sp+4 를 할 수 있다.(호출측에서 스택을 복구시킨다)

argument 1

 

argument 2

IP(복귀 주소)

BP

내부변수

내부변수

내부변수

 

 

 


                                                                                                                      ←SP

9. 최종적으로 IP는 CALL nnnn의 다음 명령어로 변경되었고 SP또한 함수 호출 이전의 상태로 되돌아 왔다.(스택의 내용을 delete 한 것은 아니지만 스택포인터가 증가되어 앞으로 덮어쓰게 될것이므로 지워진것이나 마찬가지이다.)

argument 1

 

argument 2

IP(복귀 주소)

BP

내부변수

내부변수

내부변수

 

 

 

 32bit 이상 프로세서 에서는 확장 EBP,ESP 등등으로 바뀐다..


winapi 함수는 __stdcall을 쓰며 피호출 함수안에서 스택을 복구 시켜주고 복귀하며

c, c++ 함수는 __cdecl을 쓰며 호출하는 함수에서 피호출함수가 리턴되면 스택을 복구 시킨다.


enter 명령은 (enter n,0)

    push ebp

    mov ebp,esp

    sub esp,n

세개의 명령과 같고


leave명령은

    mov esp,ebp

    pop ebp

명령과 같다.


함수에서 리턴하려면

enter

leave

ret 명령으로 짝을 이루어야 한다.(스택을 피호출 측에서 복구해야 한다면  'ret 매개변수의 총크기')

반응형

[발췌:Windows 시스템 실행파일의 구조와 원리 중]

 

비주얼 스튜디오 제공 DumpBin.exe

Viual Studio.NET 2003 명령 프롬프트 > BumpBin

- COFF 형태의 이전 PE 포맷을 비롯한 모든 실행 파일을 비롯하여 임포트 라이브러리 파일(.lib), 익스포트 라이브러리 파일(.exp), 그리고 .obj 등의 가능한 모든 형태의 PE 포맷을 다 지원함.

DumpBin.exe 옵션 들

 옵션  설명
 /ALL  PE 이미지를 위 리스트에 기술된 모든 옵션을 통해서 상세히 그 정보를 보여준다.
 /CLRHEADER  해당 PE가 관리 PE(.NET 기반 PE)인 경우 CLR  헤더의 내용을 출력한다.  
 /DISASM[:{BYTES|NOBYTES}]  텍스트 섹션의 코드 덤프를 역어셈블링해서 어셈블리어로 보여준다.
 /EXPORTS  DLL일 경우 이 DLL이 익스포트한 함수나 변수의 정보를 출력한다.
 /HEADERS  PE 파일의 헤더 정보를 출력한다.
 /IMPORTS[:filename]  임포트한 함수들이나 변수에 대한 정보를 출력한다.
 /RELOCATIONS  기준 재배치 섹션을 통해 재배치 정보를 출력한다.
 /SECTION:name  name 속성에 지정된 이름을 가진 섹션의 정보를 출력한다.


Smidgeonsoft 제공 PEBrowse Professional Interactive(freeware)

[관련사이트:smidgeonsoft]

- GUI를 가지며 비주얼하게 PE의 내용을 볼 수 있는 것이 장점.

  해당 PE를 로드시켜 디버깅도 가능하기 때문에 해당 PE가 실제 가상 주소 공간에 매핑된 상태를 눈으로 직접 확인할 수 있는 유용한 툴.


참고 : PE 이미지를 대상으로 하는 라이브러리인 ImageHelp 라이브러리가 있다

         디폴트로 제공되는 이 라이브러리는 PE 파일을 대상으로 작업 가능한 많은 기능들을 제공한다.

         자세한 설명은 MSDN 을 참고.

반응형

1. PE Format 완전 분석

http://hdp.null2root.org/reversing/PE_analysis_anesra.pdf


2.  Once Upon A Time In PE (번역) - 충실하게 역자주를 달아서 설명이 더 쉽게 되어 있다.(어셈블리어를 좀 알면 더 좋다)

http://web.kaist.ac.kr/~taekwonv/pe_icezlion.htm


원문: (윗글의 링크가 깨어져서 필요할 경우 참조.)

http://win32assembly.online.fr/


http://win32assembly.online.fr/pe-tut1.html (1. Overview Of PE File Format)

http://win32assembly.online.fr/pe-tut2.html (2. Detecting a Valid PE File)

http://win32assembly.online.fr/pe-tut3.html (3. File Header)

http://win32assembly.online.fr/pe-tut4.html (4. Optional Header)

http://win32assembly.online.fr/pe-tut6.html (5. Section Table)

http://win32assembly.online.fr/pe-tut7.html (6. Import Table)

http://win32assembly.online.fr/pe-tut7.html (7. Export Table )


Import Table에 대해 자세히 설명.

http://web.kaist.ac.kr/~taekwonv/pe_iat.htm


3. PE 파일 분석 - 쉬운 설명과 함께 C++ 예제로 어떻게 구현할수 있는지도 알수 있다.

http://kkamagui.springnote.com/pages/407001


4. Peering Inside the PE: A Tour of the Win32 Portable Executable File Format (by Matt Pietrek) - 1994년 (오래되었지만, 고전같이 한번 볼만한 글)

http://msdn.microsoft.com/en-us/magazine/ms809762.aspx


번역:http://blog.naver.com/gekigang/140016674843 


5. An In-Depth Look into the Win32 Portable Executable File Format (by Matt Pietrek) - 2002년

An In-Depth Look into the Win32 Portable Executable File Format, Part 2

(위의 글을 Win32의 변화에 맞추어 같은 저자가 다시 쓴 글)

http://msdn.microsoft.com/en-us/magazine/bb985992.aspx

http://msdn.microsoft.com/en-us/magazine/cc301805.aspx


http://msdn.microsoft.com/en-us/magazine/cc301808.aspx


6. Physical Layout of a .NET Assembly

http://www.informit.com/articles/article.aspx?p=25350


7. PE 레퍼런스(The PE file format by LUEVELSMEYER)

http://webster.cs.ucr.edu/Page_TechDocs/pe.txt


http://win32assembly.online.fr/files/pe1.zip


8. PE 파일 구조 다이어그램

(그림으로 PE 파일이 어떻게 구성되어 있는지 한눈에 볼수 있게 되어 있다)

http://www.openrce.org/reference_library/files/reference/PE%20Format.pdf


9. Wikipedia

http://ko.wikipedia.org/wiki/PE_%ED%8F%AC%EB%A7%B7


* PE 파일을 수정하는 여러 가지 방법들 소개

http://web.kaist.ac.kr/~taekwonv/


* 무료 PE 에디터 - Explorer Suite

http://www.ntcore.com/exsuite.php


* Visual Studio 안에 있는 툴 (...\vc\bin 폴더) - dumpbin


i.e. dumpbin /header "실행 파일"


그 파일안의 파일 헤더, Optional 헤더 등의 내용을 보여준다.

반응형
고통을 받는것은 그에게 죄가 있어서 때문만은 아냐.

그리고 고통을 받는다고 그 죄가 사라지는것은 아니고,

단지 중요한 것은 그 고통을 통해 어떤 것이라도 느끼고

깨달을 수만 있다면 그 고통의 시간이 가치를 갖는다는 것 뿐일거야.

모든것을 포기한 자에게 고통은 찾아오지 않아

하지만 고통이 찾아오지 않는곳엔 행복도 오지 않아

###################################################

소유욕은 번뇌로 이른다..

가지고자 함은 곧 잃음이요..

만남이 있으면 헤어짐이 있기 마련이다......

모든 일에는 순리가 있으며 그대로 흐른다...

모든 삼라만상이 자연의 순리로 흐른다...

동전의 양면과 같이 세상은 존재한다....

그곳에 내가 존재한다... 아픔이 있는 자의 모습으로

아픔 없는 자의 모습으로... 그렇게 존재한다....


이렇게 존재하고 싶었구나 했다.. ㅎㅎ
반응형
HANDLE WINAPI CreateFile(
            LPCTSTR lpFileName, -1
            DWORD dwDesiredAccess, -2
            DWORD dwShareMode, -3
            LPSECURITY_ATTRIBUTES lpSecurityAttributes, -4
            DWORD dwCreationDisposition, -5
            DWORD dwFlagsAndAttributes, -6
            HANDLE hTemplateFile -7
);

1. 개방할 파일 이름을 지정
2. 일기/쓰기 모드를 지정, or(|) 연산으로 결합 가능
   - GENERIC_READ 읽기 모드 지정
   - GENERIC_WRITE 쓰기 모드 지정
3. 파일 공유방식 지정
   - 0 다른 프로세스에 절대 공유 불가, 이미 개방된 파일은 중복 개방 불가
   - FILE_SHARE_READ 다른 프로세스에서 이 파일에 동신 읽기 접근 가능
   - FILE_SHARE_WRITE 다른 프로세스에서 이 파일에 도시 쓰기 접근 가능. 단 동시에 같은 영여에 데이터를 쓰는 문제를 피해야 함.
4. 보안 속성을 지정
5. 파일이 생성되는 방법을 지정
   - CREATE_ALWAYA 항상 새파일을 생성
   - CREATE_NEW 새 파일 생성(같은 이름 존재->실패)
   - OPEN_ALWAYS 기존 파일 개방, 없으면 생성
   - OPEN_EXISTING 기존 파일 개방, 없으면 실패
   - TRUNCATE_EXISTING 기존 파일의 내용 지우고 개방
6. 파일의 특성 정보를 설정, or(|)연산 가능, 기본설정(FILE_ATTRIBUTE_NORMAL)
7. 기존에 존재하는 파일과 동일한 특성을 가지는 새 파일을 만들 때 사용
8. 함수 호출이 성공하면 파일의 핸들 반환.
반응형
HGLOBAL hRe;
char* pText;

hRe=LoadResource(hInst,FindResource(hInst,MAKEINTRESOURCE(IDR_GG2),TEXT("GG")));

pText=(char*)LockResource(hRe);
MessageBox(NULL,pText,"dfd",MB_OK);

FreeResource(hRe);

사용자 리소스를 사용하기 위해서는 리소스 타입를 Custom...에서 이름을 지정해주어야 한다

본인은 위체서 처럼 "GG"라는 이름으로 타입을 지정했다.

리소스를 사용하기 위해서는 일단 해당 리소스를 찾고 로딩하고.. 사용하게 된다.

HRSRC hResc=FindResource(hInst,MAKEINTRESOURCE(IDR_GG2),TEXT("GG"));

는 리소스를 찾는 과정으로 반환값은 HRSRC라는 이름의 핸들러다. 이때 필요한 정보는 인스턴스, 리소스 ID와 소속 타입...(실제론 모든 리소스를 접근하는 표준 방법임)

찾는후에 로딩하는 과정은

HGLOBAL hRe=LoadResource(hInst,hResc);

위와 같이 로딩을 한후에 실제로 사용하기 위해서는 LockResource와 FreeResource를 사용해서 메모리에 실제적으로 적재하거나 해제하는 작업을 시행한다.

char* pText=(char*)LockResource(hRe);
MessageBox(NULL,pText,"dfd",MB_OK);

FreeResource(hRe);

결국 LockResource를 호출하게 되면 해당 데이타에 대한 포인터를 반환하면 적당히 원하는 타입으로 변경하면 된다. 위의 경우엔 char* 로 했다.

사용후에는 hRe를  FreeResource해주면 된다.


OS에서는 메모리가 부족하면 자동으로 리소스 부분을 메모리에서 제거한다. 즉 필요할때 로딩을 언제든지 할수 있으며, 리소스는 메모리 문제로 인해서 제거될수 있는 유동적인 존재다.


따라서 실제 로딩을 하는 것은 LockResource이며 없다면 다시 로딩을 시행할 것이다. 있다면 존재하는 녀석을 반환하게 될 것이다.


FreeResource는 메모리에서 완벽한 제거가 아니라, 메모리가 부족하면 언제든지 메모리에서 제거될수 있다는 것을 부여한다고 보면 되겠다.
-----------------------------------------------------------------------------------------------------

HRSRC FindResource( HMODULE hModule,LPCTSTR lpName,LPCTSTR lpType)


hModule:리소스를 가진 모듈 핸들

lpName:리소스 이름

lpType:리소스 타입


리턴:리소스 핸들 리턴 

ex)FindResource( g_hInstance,MAKEINTRESOURCE(IDR_SPR_TML),"TML" );



숫자로 정의된 리소스 이름을 문자열 형태로 바꿔주는 매크로 ex)MAKEINTRESOURCE(IDR_SPR_TML)  

-------------------------------------------------------------------------------------
SizeofResource 함수는 지정된 리소스의 바이트 단위 크기를 반환한다.

DWORD SizeofResource(
  HMODULE hModule, // resource-module handle
HRSRC hResInfo // resource handle );

Parameters

hModule
그 리소스를 포함하고 있는 실행가능한 파일의 모듈에 대한 핸들
hResInfo
리소스의 핸들. 이 핸들은 FindResource 나 FindResourceEx 함수를 사용해서 생성되어야만 한다.

Return Values

만약 함수가 성공하면 반환값은 리소스의 바이트 숫자 크기이다.

만약 실패하면 반환값은 0이다. 확장된 에러 정보를 원하면 GetLastError을 호출하라.

QuickInfo

  Windows NT: Requires version 3.1 or later.
  Windows: Requires Windows 95 or later.
  Windows CE: Requires version 1.0 or later.
  Header: Declared in winbase.h.
  Import Library: Use kernel32.lib.
-------------------------------------------------------------------------------------

HGLOBAL LoadResource(HMODULE hModule, HRSRC hResInfo);
hModule: 해당 모듈 핸들
hResInfo : 잀을 리소스 핸들
리턴: 16비트 호환성을 위해 HCLOBAL핸들을 리턴하자민 이 핸들은 
실제로 전역 메모리
핸들이 아닌 단순한 핸들이다,
이렇게 읽은 리소스의 포인터를 얻으려면 LockResource()함수를
써야함...

-------------------------------------------------------------------------------------

LockResource 함수는 지정된 리소스를 메모리에서 잠근다

LPVOID LockResource(
  HGLOBAL hResData   // handle to resource to lock
);
 

Parameters

hResData
잠겨질 리소스의 핸들. LoadResource 함수는 이 핸들을 리턴한다

Return Values

만약 로드된 리소스가 잠기면, 반환값은 리소스의 첫번째 바이트의 포인터이다.
그렇지 않으면 NULL

Remarks

FindeResource 나 FindResourceEX 함수에 의해 반환된 핸들을 사용함으로써
리소스를 잠그려고 시도하면 동작하지 않을 것이다.
당신은 정확하지 않거나 불규칙한 데이터를 가리키는 값을 얻게 될 것이다.

accelerator table, bitmap, cursor, icon, menu 등의 사용을 끝내고
다음 표에 있는 함수 중 하나를 호출해 관련 메모리를 해제할 수 있다.

ResourceRelease function
Accelerator tableDestroyAcceleratorTable
BitmapDeleteObject
CursorDestroyCursor
IconDestroyIcon
MenuDestroyMenu

그것들을 생성한 프로세스가 종료 될 때 시스템은 이들
리소스를 자동으로 제거하지만, 적절한 함수를 호출하는 것은
메모리를 보호하고, 프로세스의 작업량을 줄여준다.

QuickInfo

  Windows NT: Requires version 3.1 or later.
  Windows: Requires Windows 95 or later.
  Windows CE: Requires version 1.0 or later.
  Header: Declared in winbase.h.
  Import Library: Use kernel32.lib.

반응형

특정 디렉토리 아래에 있는 모든 파일과 디렉토리 혹은 특정 조건의 파일과 디렉토리를 얻고자 한다면, 다음 API 함수를 이용한다.

HANDLE FindFirstFile(LPCSTR lpFileName, LPWIN32_FIND_DATA finddata);
BOOL FindNextFile(HANDLE hFind, LPWIN32_FIND_DATA finddata);
BOOL FindClose(HANDLE hFind);


FindFirstFile : 파일 검색을 시작한다.
파일 검색 문자열이 잘못되었거나 다른 이유로 함수 실행이 실패했을 경우 INVALID_HANDLE_VALUE로 Define된 상수값을 반환한다. 성공했을 경우 파일 검색 핸들을 반환하고 두 번째로 전달되는 구조체에 첫 번째로 발견되는 파일의 정보를 넣어준다.

LPCSTR lpFileName
파일 검색 문자열을 넘겨준다.
예) "c:\*.*" 혹은 "c:\*.txt"

LPWIN32_FIND_DATA finddata
파일 검색 데이터 구조체의 포인터를 넘겨준다.


FindNextFile : 다음 파일의 정보를 얻는다.
함수 실행이 성공하였을 경우 TRUE를, 실패하였을 경우 FALSE를 반환한다. 함수 성공시 두 번째 인자로 전해지는 구조체에 파일의 정보를 넣어준다.

HANDLE hFind
FindFirstFile이 반환한 파일 검색 핸들을 넘겨준다.

LPWIN32_FIND_DATA finddata
파일 검색 데이터 구조체의 포인터를 넘겨준다.

FileClose
: 파일 핸들을 닫는다.
FindFirstFile에 의해 열린 파일 핸들을 닫는다. 성공하였을 경우 TRUE를, 실패하였을 경우 FALSE를 반환한다.
HANDLE hFind
FindFirstFile이 반환한 파일 검색 핸들을 넘겨준다.


 실제 사용 예는 다음과 같다.

Windows 디렉토리의 모든 파일 및 폴더 출력 (Language : c)
  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4.  
  5. int main()
  6. {
  7.     WIN32_FIND_DATA FindData;
  8.     HANDLE hFind;
  9.     char path[255];
  10.  
  11.     strcpy(path, "c:\\windows\\*");
  12.    
  13.     hFind = FindFirstFile((LPCSTR)path, &FindData);
  14.     if(hFind==INVALID_HANDLE_VALUE)
  15.         return 0;
  16.    
  17.     do
  18.     {
  19.         printf ("%s\n", FindData.cFileName);
  20.     }while(FindNextFile(hFind, &FindData));
  21.  
  22.     FindClose(hFind);
  23.  
  24.     return 0;
  25. }


(2003/2005)LPCSTR 캐스팅에 문제가 있는 경우 Project -> Properties -> Configuration Properties -> General -> Character Set을 Not Set으로 설정하기 바랍니다.

+ Recent posts