특정 명령어의 메모리 내 주소 (악용 쓰기 용)는 어떻게 찾을 수 있습니까?DLL에서 특정 명령어의 메모리 내 주소를 찾는 방법
특히 을 가리킬 수있는 주소가없는 서비스 팩이없는 Windows XP의 user32.dll
에서 call ebp
명령어를 찾고 있습니다. 나는 Immunity Debugger과 OllyDBG을 대상에 설치했습니다.
특정 명령어의 메모리 내 주소 (악용 쓰기 용)는 어떻게 찾을 수 있습니까?DLL에서 특정 명령어의 메모리 내 주소를 찾는 방법
특히 을 가리킬 수있는 주소가없는 서비스 팩이없는 Windows XP의 user32.dll
에서 call ebp
명령어를 찾고 있습니다. 나는 Immunity Debugger과 OllyDBG을 대상에 설치했습니다.
명령어를 찾으려면 코드, .text 섹션이 시작하고 끝나는 위치를 파악한 다음 DLL을로드하고 지침을 찾을 때까지 라이너 검색을 수행해야합니다.
// test.c
// gcc -Wall -shared test.c -o test.dll
#include <stdio.h>
__declspec(dllexport) void test(void) {
asm("call *%ebp");
puts("test");
asm("call *%ebp");
}
를 컴파일하고 올리 디버그에서 DLL을로드하고 을 클릭 CTRL + F 및 CALL EBP
검색 :
6BEC125A |. FFD5 CALL EBP
6BEC125C |. C70424 6430EC6> MOV DWORD PTR SS:[ESP],test.6BEC3064 ; |ASCII "test"
6BEC1263 |. E8 74060000 CALL <JMP.&msvcrt.puts> ; \puts
6BEC1268 |. FFD5 CALL EBP
다음
우리는 두 call ebp
지침을 가지고 테스트 DLL을
첫 번째 지침의 주소는 0x6bec125a
이고 두 번째 주소는 0x6bec1268
입니다. call ebp
의 opcode는 0xff 0xd5
이므로이를 기억하십시오.
이제 우리는 당신이 -h
와 objdump를 사용할 수있는 코드의 경계를 찾을 필요가 :
> objdump --headers test.dll
test.dll: file format pei-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000984 6bec1000 6bec1000 00000600 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE, DATA
1 .data 00000008 6bec2000 6bec2000 00001000 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .rdata 0000011c 6bec3000 6bec3000 00001200 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
....
>
코드는 VMA, 가상 메모리 주소, 0x6bec1000
에서 시작하고 끝나는 때문에 그 크기는 0x984
입니다 0x6bec1000
+ 0x984
= 0x6bec1984
는 같이
0x6bec1000
....
what is between are the DLL instructions
....
0x6bec1984
나는 지금까지 분명 바랍니다.
우리는 우리의 call ebp
스캐너를 코딩 할 경우
.text
를 상대 주소와 가상 크기를 찾을 수 있습니다.0xff 0xd5
, call ebp
의 opcode, 간단한 라이너 검색을 찾을 준비가되었습니다. > gcc -Wall findopcode.c -o findopcode
> findopcode.exe test.dll
[*] Code section: `.text'
[*] Base address : 0x6bec0000
[*] Start address: 0x6bec1000
[*] End address : 0x6bec1984
[*] Found `call ebp` at: 0x6bec125a
[*] Found `call ebp` at: 0x6bec1268
>
그것은 꽤 잘,의는 user32.dll
을 해보자 작품 :
> findopcode.exe \Windows\System32\user32.dll
[*] Code section: `.text'
[*] Base address : 0x75680000
[*] Start address: 0x75681000
[*] End address : 0x756e86ef
[*] Found `call ebp` at: 0x756b49b5
>
// findopcode.c
// gcc -Wall findopcode.c -o findopcode
#include <windows.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
const char opcode[] = {0xff, 0xd5}; // The opcode of `call ebp'
FILE *dllFile;
HMODULE dllHandle;
IMAGE_DOS_HEADER dosHeader;
IMAGE_NT_HEADERS NtHeaders;
IMAGE_SECTION_HEADER sectionHeader;
unsigned int i;
unsigned char *starAddr;
unsigned char *endAddr;
if(argc < 2) {
printf("usage: %s [DLL]\n", argv[0]);
return -1;
}
if((dllFile = fopen(argv[1], "rb")) == NULL) {
perror("[!] Error");
return -1;
}
// Read the basic PE headers
fread(&dosHeader, sizeof(dosHeader), 1, dllFile);
fseek(dllFile, dosHeader.e_lfanew, SEEK_SET);
fread(&NtHeaders, sizeof(NtHeaders), 1, dllFile);
// Search for the executable section, .text section.
for(i = 0 ; i < NtHeaders.FileHeader.NumberOfSections ; i++) {
fread(§ionHeader, sizeof(sectionHeader), 1, dllFile);
// If we found a section that contains executable code,
// we found our code setion.
if((sectionHeader.Characteristics & IMAGE_SCN_CNT_CODE) != 0) {
printf("[*] Code section: `%s'\n", sectionHeader.Name);
break;
}
}
fclose(dllFile);
// Load the DLL to get it's base address
if((dllHandle = LoadLibraryA(argv[1])) == NULL) {
printf("[!] Error: loading the DLL, 0x%.8x\n", (unsigned int) GetLastError());
return -1;
}
// The code start at : base address + code virtual address
starAddr = (unsigned char *) dllHandle + sectionHeader.VirtualAddress;
// It ends at : base address + code virtual address + virtual size
endAddr = (unsigned char *) starAddr + sectionHeader.Misc.VirtualSize;
printf("[*] Base address : 0x%.8x\n", (unsigned int) dllHandle);
printf("[*] Start address: 0x%.8x\n", (unsigned int) starAddr);
printf("[*] End address : 0x%.8x\n", (unsigned int) endAddr);
// Simple liner search, when ever we find `0xff 0xd5' we print that address
for(endAddr -= sizeof(opcode) ; starAddr < endAddr ; starAddr++) {
if(memcmp(&opcode, (void *) starAddr, sizeof(opcode)) == 0) {
printf("[*] Found `call ebp` at: 0x%.8x\n", (unsigned int) starAddr);
}
}
FreeLibrary(dllHandle);
return 0;
}
를 컴파일하고 DLL로 테스트 : 여기
은 간단한 구현
난 하나만 찾았습니다 call ebp
a t 0x756b49b5
. 당신은 몇 가지 이상한 액세스 할 수있는 몇 가지 영역을 치면
if(IsBadReadPtr(starAddr, sizeof(opcode)) == 0 &&
memcmp(&opcode, (void *) starAddr, sizeof(opcode)) == 0) {
그래서 프로그램이 실패하지 않습니다 : 당신이 방법 당신은
memcmp
이
IsBadReadPtr를 사용하여 읽기 전에 읽기 액세스 권한이 있는지 확인하고자합니다.
와우! 우수 답변. 매우 유익하고 유익한 정보. 정말 고맙습니다! –
다른 방법은에서 msfpescan
을 사용하는 것입니다 metasploit framework :
msfpescan -j ebp user32.dll
음, DLL은 재배치 (그리고 _are 이전 being_) 그래서 당신은 단지 이제까지의 모듈의 기본 주소와 같은 주소 상대를 찾을 수 있습니다 신뢰할 수있는 방식으로. – Damon
@Damon은 모든 최신 OS에 해당하지만 Windows XP에서는 ASLR이 없기 때문에 DLL의 메모리 내 위치는 OS 버전과 SP 버전간에 매우 일치합니다. –
ASLR에 대해서도 생각조차하지 못했지만, 그것은 물론 다른 문제 일 것입니다. 일상적으로 발생하는 일반적인 DLL 리베이스를 생각하고있었습니다. 모든 DLL은 대개 동일한 기본 주소를가집니다 (링커에게 임의의 주소를 선택하도록 지시 할 수는 있지만 주소 공간을 더욱더 파편화합니다 ...).로드 될 때 리베이스됩니다. 첫 번째 DLL은 대개 원래 주소에로드 된 kernel32입니다. 그런 다음 일반적으로 NLS이고 다른 모든 DLL (user32 포함)은 모두 재배치됩니다. 부수적으로 그들은 매번 같은 주소로 끝날 수도 있지만 누가 알 수 있습니다. – Damon