제2 장 - Win 32 프로그램 운행 원리 (부분 개념 및 코드 설명)

42122 단어
《 Windows 프로 그래 밍 》 기록 을 학습 하 다.
 
개념 팁:
1. 모든 프로 세 스 는 자신의 개인 주소 공간 을 부여 합 니 다.프로 세 스 내 스 레 드 가 실 행 될 때 이 스 레 드 는 프로 세 스 에 속 하 는 메모리 에 만 접근 할 수 있 고 다른 프로 세 스 에 속 하 는 메모리 가 차단 되 어 이 스 레 드 에 접근 할 수 없습니다.
PS: 프로 세 스 A 는 주소 공간의 0x 12345678 주소 에 데이터 구 조 를 가 질 수 있 고 프로 세 스 B 는 주소 공간의 0x 12345678 에 완전히 다른 데 이 터 를 저장 할 수 있 습 니 다.서로 방문 할 수 없다.
 
2. 대부분의 시스템 에서 윈도 우 는 주소 공간의 절반 (4GB 의 절반, 0x0000000 - 0x7FFFFF) 을 프로 세 스 에 개인 저장 소 로 남 겨 두 고 운영 체제 내부 에서 사용 하 는 데 이 터 를 저장 합 니 다.
 
3. 각 프로 세 스 의 주소 공간 은 사용자 공간 과 시스템 공간 두 부분 으로 나 뉜 다.사용자 공간 부분 은 프로 세 스 의 개인 주소 공간 입 니 다. 프로 세 스 는 다른 프로 세 스 의 이 부분 공간의 데 이 터 를 읽 거나 쓸 수 없습니다.시스템 공간 부분 에 운영 체제 의 코드 를 설치 하 는데 커 널 코드, 장치 구동 코드, 장치 I / O 버퍼 등 을 포함한다.시스템 공간 부분 은 모든 프로 세 스 에서 공 유 됩 니 다.일부 시스템 에서 이 데이터 구 조 는 보호 된다.접근 을 시도 할 때 접근 이상 이 발생 할 수 있 습 니 다.
 
4. 프로세서 가 여러 개의 특권 단 계 를 정의 합 니 다.예 를 들 어 80386 프로세서 가 모두 4 가지 (0 - 3) 특권 단 계 를 정의 하거나 링 이 라 고 합 니 다.이 중 0 레벨 은 최고급 (특권 레벨), 3 레벨 은 최저 레벨 (사용자 레벨) 이다.
 
5. 응용 프로그램의 접근 을 막 거나 관건 적 인 시스템 데이터 (즉 2GB 시스템 공간 내 데이터) 를 수정 하기 위해 윈도 는 두 가지 접근 모드 를 사용 했다. 커 널 모드 와 사용자 모드 는 각각 프로세서 의 0 과 3 이라는 두 가지 특권 단 계 를 사용 했다.사용자 프로그램의 코드 는 사용자 모드 에서 실행 되 고 시스템 프로그램 (예 를 들 어 시스템 서비스 프로그램 과 하드웨어 구동) 의 코드 는 커 널 모드 에서 실 행 됩 니 다.
 
6. 커 널 대상 은 시스템 이 제공 하 는 사용자 모드 에서 코드 와 커 널 모드 에서 코드 가 상호작용 을 하 는 기본 인터페이스 이다.커 널 인 터 랙 션 대상 을 사용 하 는 것 은 응용 프로그램 과 시스템 커 널 이 상호작용 을 하 는 중요 한 방식 중 하나 이다.
 
7. 커 널 대상 을 도입 하면 시스템 은 다음 과 같은 4 가지 임 무 를 편리 하 게 완성 할 수 있다.
1) 시스템 자원 에 식별 가능 한 이름 을 제공한다.
2) 프로 세 스 간 에 자원 과 데 이 터 를 공유 합 니 다.
3) 자원 이 허가 되 지 않 은 코드 에 접근 하지 않도록 보호 한다.
4) 대상 의 인용 상황 을 추적 하여 시스템 으로 하여 금 언제 한 대상 이 더 이상 사용 되 지 않 고 사용 하 는 공간 을 방출 할 수 있 는 지 알 게 한다.
 
8. 커 널 대상 의 데이터 구 조 는 커 널 모드 에서 만 접근 할 수 있 기 때문에 메모리 에서 이러한 데이터 구 조 를 직접 찾 는 것 은 응용 프로그램 에 있어 불가능 합 니 다.응용 프로그램 은 커 널 대상 에 API 함 수 를 사용 해 야 합 니 다.
 
9. 함 수 를 호출 하여 커 널 대상 을 만 들 때 함 수 는 이 커 널 대상 을 표시 하 는 핸들 을 되 돌려 줍 니 다.핸들 은 프로 세 스 와 관련 된 것 으로 커 널 대상 을 만 드 는 프로 세 스 에 만 유효 합 니 다.물론 여러 프로 세 스 가 하나의 커 널 대상 을 공유 하 는 것 도 가능 합 니 다. Duplicate Handle 함 수 를 사용 하여 프로 세 스 핸들 을 다른 프로 세 스 에 복사 하면 됩 니 다.
 
10. 커 널 대상 중 가장 간단 하고 자주 사용 하 는 속성 - 사용 계수.계수 속성 을 사용 하여 프로 세 스 가 특정 커 널 대상 에 대한 응용 횟수 를 가리 키 며, 시스템 에서 인용 횟수 가 0 인 것 을 발견 하면 자원 을 자동 으로 닫 습 니 다.(생 성 시 1 로 초기 화 되 었 습 니 다. 이 커 널 대상 을 열 때마다 1 을 더 하고 닫 으 면 1 을 줄 입 니 다. 0 으로 줄 였 을 때 프로 세 스 가 이 커 널 대상 에 대한 모든 인용 이 닫 혔 음 을 설명 합 니 다. 시스템 은 이 커 널 대상 자원 을 방출 해 야 합 니 다.)
 
11. 프로 세 스 (Process) 는 실행 중인 프로그램 으로 자신의 가상 주소 공간 을 가지 고 있 으 며, 프로 세 스 가 만 든 파일, 파이프, 동기 화 대상 등 자신의 코드, 데이터 와 다른 시스템 자원 을 가지 고 있다.하나의 프로 세 스 도 이 프로 세 스 를 실행 하 는 스 레 드 (Thread) 를 하나 이상 포함 합 니 다.
 
12. 프로그램 과 프로 세 스 가 표면 에서 매우 비슷 하 다.그러나 프로그램 은 일련의 정적 명령 이 고 프로 세 스 는 용기 입 니 다. 프로그램 인 스 턴 스 상하 문 에서 실행 되 는 일련의 스 레 드 에 사용 되 는 자원 을 포함 합 니 다.
 
13. 스 레 드 는 프로 세 스 내 실행 코드 의 독립 된 실체 입 니 다.운영 체제 가 프로 세 스 를 만 든 후에 스 레 드 실행 프로 세 스 의 코드 를 만 들 것 입 니 다.보통 이 스 레 드 를 주 스 레 드 라 고 부른다.주 스 레 드 는 실행 과정 에서 다른 스 레 드 를 만 들 수 있 습 니 다 (보조 스 레 드 라 고 함).
 
14. Win 프로 세 스 의 두 구성 부분:
1) 프로 세 스 커 널 대상.운영 체 제 는 이 커 널 대상 을 사용 하여 프로 세 스 를 관리 합 니 다.이 커 널 대상 도 운영 체제 가 프로 세 스 통계 정 보 를 저장 하 는 곳 이다.
2) 개인 적 인 가상 주소 공간.이 주소 공간 은 실행 가능 하거나 DLL 모듈 의 코드 와 데 이 터 를 포함 하고 프로그램 이 동적 으로 메모 리 를 신청 하 는 곳 입 니 다. 예 를 들 어 스 레 드 스 택 과 프로 세 스 더미 등 입 니 다.
 
15. 응용 프로그램 은 프로그램 이 실 행 될 때 호출 되 는 입구 함수 가 있어 야 합 니 다.콘 솔 프로그램 을 만 들 었 다 면 이 입구 함 수 는 main 입 니 다.
    PS:int main(int argc,char *argv[]);
 
16. 사실상 운영 체 제 는 실제 main 함 수 를 호출 하 는 것 이 아니 라 C / C + + 운행 기 시작 함 수 를 호출 합 니 다. 이 함 수 는 C / C + 운행 기 라 이브 러 리 를 초기 화 합 니 다.따라서 프로그램 에서 malloc 와 free 같은 함 수 를 호출 할 수 있 습 니 다.
 
17. 콘 솔 프로그램 에서 C / C + + 실행 기 시작 함 수 는 프로그램 입구 함수 main 을 호출 합 니 다.없 으 면 'unsolved external symbol' 오 류 를 되 돌려 줍 니 다.
 
18. Win 32 프로그램의 시작 과정 은 프로 세 스 의 생 성 과정 입 니 다. 운영 체 제 는 CreateProcess 함수 (코드 설명 에서 이 함수 에 대한 구체 적 인 설명 이 있 을 것 입 니 다) 를 호출 하여 새로운 프로 세 스 를 만 듭 니 다.하나의 스 레 드 가 CreateProcess 함 수 를 호출 할 때 시스템 은 프로 세 스 커 널 대상 을 만 듭 니 다. 사용 계 수 는 1 로 초기 화 됩 니 다. 이 프로 세 스 커 널 대상 은 프로 세 스 자체 가 아니 라 시스템 이 이 프로 세 스 를 관리 하 는 작은 데이터 구조 일 뿐 입 니 다.시스템 은 다음 에 새로운 프로 세 스 를 위해 가상 주소 공간 을 만 들 고 프로그램 이 실 행 될 때 필요 한 코드 와 데 이 터 를 불 러 옵 니 다.시스템 은 이 어 새 프로 세 스 를 위 한 메 인 스 레 드 를 만 들 것 입 니 다. 이 메 인 스 레 드 는 C / C + 실행 기 시작 코드 를 실행 하여 실 행 됩 니 다. C / C + 실행 기 시작 코드 는 main 함 수 를 호출 합 니 다.시스템 이 새 프로 세 스 와 프로 세 스 의 주 스 레 드 를 성공 적 으로 만 들 수 있다 면 CreateProcess 함 수 는 TRUE 로 돌아 갑 니 다. 그렇지 않 으 면 FALSE 로 돌아 갑 니 다.
 
19. 일반적으로 생 성 프로 세 스 를 부모 프로 세 스 라 고 부 르 며, 생 성 된 프로 세 스 를 하위 프로 세 스 라 고 부른다.시스템 은 새 프로 세 스 를 만 들 때 새 프로 세 스 에 STARTUPINFO 형식의 변 수 를 지정 합 니 다. 이 구 조 는 부모 프로 세 스 가 하위 프로 세 스에 전달 하 는 디 스 플레이 정 보 를 포함 합 니 다.(그래 픽 인터페이스 응용 프로그램 에 있어 서 이 정 보 는 새로운 프로 세 스 의 메 인 스 레 드 의 메 인 창 표시 등에 영향 을 줄 수 있 습 니 다.)
 
 
코드 설명:
1.CreateProcess(create process)
PS: 완전한 프로 세 스 를 만 드 는 프로그램 입 니 다. Windows 자체 명령 행 프로그램 cmd. exe 를 열 었 습 니 다. (하지만 저 는 보통 Win + R 입 니 다. 직접 cmd 로 들 어 갑 니 다.)
 1 #include "stdafx.h"
 2 #include 
 3 #include 
 4 
 5 int main(int argc, char* argv[])
 6 {
 7     char szCommandLine[] = "cmd";
 8     STARTUPINFO si = { sizeof(si) };
 9     PROCESS_INFORMATION pi;
10 
11     si.dwFlags = STARTF_USESHOWWINDOW;    //   wShowWindow    
12     si.wShowWindow = TRUE;            //      TRUE             ,
13                         //  FALSE      
14     BOOL bRet = ::CreateProcess (
15         NULL,            //               
16         szCommandLine,        //      
17         NULL,            //        
18         NULL,            //        
19         FALSE,            //                    
20         CREATE_NEW_CONSOLE,    //                
21         NULL,            //           
22         NULL,            //             
23         &si,
24         &pi);
25 
26     if(bRet)
27     {
28         //
29         ::CloseHandle (pi.hThread);
30         ::CloseHandle (pi.hProcess);
31 
32         printf("       ID :%d 
", pi.dwProcessId); 33 printf(" ID :%d
", pi.dwThreadId); 34 } 35 return 0; 36 }

 
2.ProcessList(process list)
PS: ToolHelp 함수 의 CreateToolhelp32Snapshop 함 수 를 사용 하여 현재 시스템 에서 실행 중인 프로 세 스에 스냅 샷 (Snapshot) 을 찍 어 프로 세 스 목록 을 가 져 옵 니 다. 그리고 Process32First 함수 와 Process32Next 함 수 를 이용 하여 스냅 샷 에 기 록 된 목록 을 옮 겨 다 닙 니 다.
 1 #include "stdafx.h"
 2 #include 
 3 #include  //           
 4 
 5 int main(int argc, char* argv[])
 6 {
 7     PROCESSENTRY32 pe32;
 8     //
 9     pe32.dwSize = sizeof(pe32); 
10     
11     //               
12     HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
13     if(hProcessSnap == INVALID_HANDLE_VALUE)
14     {
15         printf(" CreateToolhelp32Snapshot    ! 
"); 16 return -1; 17 } 18 19 // 20 BOOL bMore = ::Process32First(hProcessSnap, &pe32); 21 while(bMore) 22 { 23 printf(" :%s
", pe32.szExeFile); 24 printf(" ID :%u

", pe32.th32ProcessID); 25 26 bMore = ::Process32Next(hProcessSnap, &pe32); 27 } 28 29 // snapshot 30 ::CloseHandle(hProcessSnap); 31 return 0; 32 }

 
3.TerminateProcess(terminate process)
PS: 이 프로그램 은 프로 세 스 만 의 ID 번 호 를 입력 하여 이 프로 세 스 를 끝 냅 니 다. 병 사 는 작업 결 과 를 되 돌려 줍 니 다. (작업 관리자 에서 프로 세 스 ID 를 찾 아 보 세 요. QQ 같은 것 을 가 져 오 는 것 을 권장 합 니 다. Windows 같은 것 은 절대 찾 지 마 세 요)
 1 #include "stdafx.h"
 2 #include 
 3 
 4 BOOL TerminateProcessFromId(DWORD dwId)
 5 {
 6     BOOL bRet = FALSE;
 7     //
 8     HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwId);
 9     if(hProcess != NULL)
10     {
11         //     
12         bRet = ::TerminateProcess(hProcess, 0);
13     }
14     CloseHandle(hProcess);
15     return bRet;
16 }
17 
18 int main(int argc, char* argv[])
19 {
20     DWORD dwId;
21     printf("            ID : 
"); 22 scanf("%u", &dwId); 23 if(TerminateProcessFromId(dwId)) 24 { 25 printf("
"); 26 } 27 else 28 { 29 printf("
"); 30 } 31 32 return 0; 33 }

 
4.Testor
PS: 이것 은 이 장의 마지막 프로그램 인 메모리 수정 기 서 비 스 를 위 한 테스트 프로그램 입 니 다. 그 다음 에는 메모리 수정 기 를 통 해 g nNum 과 i 의 값 을 수정 합 니 다.
 1 #include "stdafx.h"
 2 #include 
 3 //       
 4 int g_nNum;    
 5 int main(int argc, char* argv[])
 6 {
 7     int i = 198;    //       
 8     g_nNum = 1003;
 9 
10     while(1)
11     {
12         //           
13         printf(" i = %d, addr = %08lX;   g_nNum = %d, addr = %08lX 
", 14 ++i, &i, --g_nNum, &g_nNum); 15 getchar(); 16 } 17 18 return 0; 19 }

 
5.MemRepair(memory repair)
PS: 이 장의 마지막 프로그램 인 메모리 수정 기 입 니 다. 프로그램 설명 이 적 혀 있 습 니 다.
  1 #include "stdafx.h"
  2 #include "windows.h"
  3 #include "stdio.h"
  4 #include 
  5 
  6 
  7 BOOL FindFirst(DWORD dwValue);    //               
  8 BOOL FindNext(DWORD dwValue);    //             2、3、4……   
  9 
 10 DWORD g_arList[1024];        //     
 11 int g_nListCnt;            //        
 12 HANDLE g_hProcess;        //       
 13 
 14 
 15 //////////////////////
 16 
 17 BOOL WriteMemory(DWORD dwAddr, DWORD dwValue);
 18 void ShowList();
 19 
 20 
 21 int main(int argc, char* argv[])
 22 {
 23     //   02testor  
 24     char szFileName[] = "..\\02testor\\debug\\02testor.exe";
 25     STARTUPINFO si = { sizeof(si) };
 26     PROCESS_INFORMATION pi;
 27     ::CreateProcess(NULL, szFileName, NULL, NULL, FALSE, 
 28                             CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
 29     //
 30     ::CloseHandle(pi.hThread);
 31     g_hProcess = pi.hProcess;
 32 
 33     //        
 34     int    iVal;
 35     printf(" Input val = ");
 36     scanf("%d", &iVal);
 37 
 38     //        
 39     FindFirst(iVal);
 40     
 41     //         
 42     ShowList();
 43 
 44 
 45     while(g_nListCnt > 1)
 46     {
 47         printf(" Input val = ");
 48         scanf("%d", &iVal);
 49 
 50         //       
 51         FindNext(iVal);
 52 
 53         //       
 54         ShowList();
 55     }
 56 
 57 
 58     //     
 59     printf(" New value = ");
 60     scanf("%d", &iVal);         
 61 
 62     //     
 63     if(WriteMemory(g_arList[0], iVal))
 64         printf(" Write data success 
"); 65 66 67 ::CloseHandle(g_hProcess); 68 return 0; 69 } 70 71 BOOL CompareAPage(DWORD dwBaseAddr, DWORD dwValue) 72 { 73 // 1 74 BYTE arBytes[4096]; 75 if(!::ReadProcessMemory(g_hProcess, (LPVOID)dwBaseAddr, arBytes, 4096, NULL)) 76 return FALSE; // 77 78 // 1 79 DWORD* pdw; 80 for(int i=0; iint
)4*1024-3; i++) 81 { 82 pdw = (DWORD*)&arBytes[i]; 83 if(pdw[0] == dwValue) // 84 { 85 if(g_nListCnt >= 1024) 86 return FALSE; 87 // 88 g_arList[g_nListCnt++] = dwBaseAddr + i; 89 } 90 } 91 92 return TRUE; 93 } 94 95 BOOL FindFirst(DWORD dwValue) 96 { 97 const DWORD dwOneGB = 1024*1024*1024; // 1GB 98 const DWORD dwOnePage = 4*1024; // 4KB 99 100 if(g_hProcess == NULL) 101 return FALSE; 102 103 // 104 DWORD dwBase; 105 OSVERSIONINFO vi = { sizeof(vi) }; 106 ::GetVersionEx(&vi); 107 if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) 108 dwBase = 4*1024*1024; // Windows 98 ,4MB 109 else 110 dwBase = 640*1024; // Windows NT ,64KB 111 112 // 2GB 113 for(; dwBase < 2*dwOneGB; dwBase += dwOnePage) 114 { 115 // 1 116 CompareAPage(dwBase, dwValue); 117 } 118 119 return TRUE; 120 } 121 122 BOOL FindNext(DWORD dwValue) 123 { 124 // m_arList , m_nListCnt 125 int nOrgCnt = g_nListCnt; 126 g_nListCnt = 0; 127 128 // m_arList 129 BOOL bRet = FALSE; // 130 DWORD dwReadValue; 131 for(int i=0; i) 132 { 133 if(::ReadProcessMemory(g_hProcess, (LPVOID)g_arList[i], &dwReadValue, sizeof(DWORD), NULL)) 134 { 135 if(dwReadValue == dwValue) 136 { 137 g_arList[g_nListCnt++] = g_arList[i]; 138 bRet = TRUE; 139 } 140 } 141 } 142 143 return bRet; 144 } 145 146 // 147 void ShowList() 148 { 149 for(int i=0; i< g_nListCnt; i++) 150 { 151 printf("%08lX
", g_arList[i]); 152 } 153 } 154 155 BOOL WriteMemory(DWORD dwAddr, DWORD dwValue) 156 { 157 return ::WriteProcessMemory(g_hProcess, (LPVOID)dwAddr, &dwValue, sizeof(DWORD), NULL); 158 }

 
 
요약: 중요 한 개념, 지식, 코드 설명 이 모두 표시 되 었 습 니 다. 이 장 을 통 해 Win 32 프로그램 실행 등 원리 에 대해 명확 하 게 이해 할 수 있 습 니 다. 프로그램 이 실행 되 는 전체 과정 을 진정 으로 이해 하고 메모리 의 실제 상황 을 이해 할 수 있 습 니 다. 예전 에 Win 32 프로그램 에 대한 인식 이 명확 하지 않 았 던 것 을 바 꾸 었 습 니 다.

좋은 웹페이지 즐겨찾기