이 질문을 여기에 두어야 할지 아니면 여기에 두어야 할지 잘 모르겠습니다.reverseengineering.stackexchange.com
에서 인용위키피디아:
8086 프로세서에서는 인터럽트 테이블을 IVT(Interrupt Vector Table)라고 합니다. IVT는 항상 0x0000에서 0x03ff 범위의 메모리에서 동일한 위치에 상주하며 256개의 4바이트 실제 모드 원거리 포인터(256 × 4 = 1024바이트 메모리)로 구성됩니다.
qemu 모니터에서 찾은 내용은 다음과 같습니다.
(qemu) xp/128xw 0
0000000000000000: 0xf000ff53 0xf000ff53 0xf000e2c3 0xf000ff53
0000000000000010: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000020: 0xf000fea5 0xf000e987 0xf000d62c 0xf000d62c
0000000000000030: 0xf000d62c 0xf000d62c 0xf000ef57 0xf000d62c
0000000000000040: 0xc0005526 0xf000f84d 0xf000f841 0xf000e3fe
0000000000000050: 0xf000e739 0xf000f859 0xf000e82e 0xf000efd2
0000000000000060: 0xf000d648 0xf000e6f2 0xf000fe6e 0xf000ff53
0000000000000070: 0xf000ff53 0xf000ff53 0xf0006aa4 0xc0008930
0000000000000080: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000090: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000c0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000d0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000e0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000100: 0xf000ec59 0xf000ff53 0xf000ff53 0xc0006730
0000000000000110: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000120: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000130: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000140: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000150: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000160: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000170: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000180: 0x00000000 0x00000000 0x00000000 0x00000000
0000000000000190: 0x00000000 0x00000000 0x00000000 0xf000ff53
00000000000001a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001c0: 0xf000d611 0xf000ec4e 0xf000ec4e 0xf000ec4e
00000000000001d0: 0xf000d61a 0xf000d623 0xf000d608 0xf000ec4e
00000000000001e0: 0xf000ff53 0x00000000 0xf000ff53 0xf000ff53
00000000000001f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
이러한 가치를 어떻게 이해해야 할지 모르겠습니다. 인터럽트 설명자 테이블처럼 보이지 않습니다(값을 역참조하면 모든 null 값이 제공됨). 그렇다면 나는 정확히 무엇을 보고 있는 걸까요?
답변1
펌웨어가 무엇이든 남겨두십시오.
SU Q&A에서 설명했듯이 이상적인 최신 시스템에서는 프로세서가 리얼 모드로 전혀 들어가지 않습니다.최신 64비트 Intel 칩 PC는 어떤 모드에서 부트 섹터를 실행합니까?, Johan Myréen이 다른 답변에서 지적했듯이 물리적 메모리의 첫 번째 KiB는 중요하지 않습니다. 그러나 많은 최신 펌웨어에는 (여전히)호환성 지원, 의미는
- 그들은 물러설 수 있습니다(예,뒤쪽에, MBR 및 VBR의 레거시 PC/AT 부트로더와 같이 리얼 모드용으로 작성된 시스템 소프트웨어를 실행하기 위해 가상 모드에서 보호 모드로 직접 이동한다는 점을 고려합니다.
- 이들은 이전 리얼 모드 펌웨어 API를 제공하고 이러한 API에 대해 위의 시스템 소프트웨어가 의존하는 모든 데이터 구조를 설정합니다.
이러한 데이터 구조 중 하나는 리얼 모드 IVT입니다. 이전 리얼 모드 펌웨어 API는 int
명령어를 기반으로 했으며, 리얼 모드 IVT는 초기화의 일부로 해당 명령어에 대한 다양한 펌웨어 처리 루틴에 대한 포인터와 함께 펌웨어로 채워졌습니다.
보호 모드 시스템 소프트웨어에는 이전 리얼 모드 펌웨어 API가 필요하지 않으며 리얼 모드에서 프로세서를 실행하지 않으므로 물리적 메모리의 첫 번째 1KiB에 있는 리얼 모드 IVT는 사용되지 않습니다. (v8086 보호 모드는 주소를 지정하지 않습니다.물리적주소는 00000000 이상이니 꼭 기억해주세요. 해결됐어논리적00000000 이상의 주소는 페이지 테이블에 의해 변환됩니다. ) 최신 EFI 시스템에서 펌웨어는 물리적 메모리의 메모리 맵을 운영 체제 부트로더에 전달하여 펌웨어가 자체 보호 모드 API 목적으로 사용하도록 예약된 부분을 알려주고 운영 체제는 계속해서 자유롭게 사용할 수 있습니다. 물리적 메모리 풀의 어느 부분인가요? 이론적으로 물리적 메모리의 첫 번째 페이지는 후자 범주에 속할 수 있습니다.
실제로, 먼저 펌웨어는 일반적으로 물리적 메모리의 첫 번째 페이지를 "부팅 서비스 코드"로 표시합니다. 이는 운영 체제가할 수 있는이를 선언하고 계속해서 물리적 메모리 풀의 일부로 사용합니다.하지만 그 후에야EFI 펌웨어의 부팅 시간 서비스는 운영 체제에 의해 꺼지고 펌웨어는 런타임 서비스만 제공하도록 축소됩니다. add_efi_memmap
이에 대한 예는 Finnbarr P. Murphy가 보여준 Linux 커널 로그(옵션 포함)에서 볼 수 있습니다.
[0.000000] efi: mem00: 유형=3, attr=0xf, 범위=[0x0000000000000000-0x0000000000001000) (0MB)xe는 다른 프로그램을 사용하여 보다 이해하기 쉬운 형식으로 디코딩되어 다음을 수행합니다.
[#00] 유형: EfiBootServicesCode 속성: 0xF 물리학: 0000000000000000-0000000000001000 가상: 0000000000000000-0000000000001000
둘째, 실제로 Linux는 이러한 물리적 메모리 범위를 명시적으로 무시합니다.~ 일지라도펌웨어에는 계속 사용할 수 있다고 나와 있습니다. EFI 및 비 EFI 펌웨어 모두에서 Linux는 물리적 메모리 맵이 있으면 이를 패치합니다(라는 함수에서trim_bios_range
), 다음과 같은 커널 로그 메시지를 생성합니다.
[0.000000] e820: 업데이트 [mem 0x00000000-0x00000fff] 사용 가능 ==> 예약됨
이는 리얼 모드 IVT가 펌웨어 API의 일부가 아닌 최신 EFI 펌웨어를 처리하는 것이 아니라 펌웨어 API의 일부이지만 펌웨어가 이를 보고하는 이전 PC98 펌웨어를 처리하기 위한 것입니다(다음과 동일한 API를 통해). 물리적 메모리) 운영 체제에서 쉽게 재정의할 수 있습니다.
따라서 물리적 메모리의 이론적 범위는할 수 있다커널 메모리 할당자 및 요구 페이징 가상 메모리의 일시적인 요구에 따라 임의의 코드 또는 데이터가 포함되어 있습니다. 실제로 Linux는 펌웨어가 초기에 설정하기 때문에 이를 변경하지 않습니다.
시스템의 펌웨어는 시스템을 리얼 모드 IVT 항목으로 채웠습니다. 물론, 리얼 모드 IVT 항목은 단지 16:16 원거리 포인터입니다. 2바이트 16진수 덤프를 사용하여 메모리를 보면 실제로 이를 매우 명확하게 볼 수 있습니다. 몇 가지 예:
- 대부분의 IVT 항목은 리얼 모드 펌웨어 ROM 영역의 주소인 F000:FF53을 가리킵니다. 실행만 하는 가상 루틴일 수도 있습니다
iret
. - IVT 시작하기 1E동일한 ROM 영역에 있는 테이블인 F000:6AA4를 가리킵니다.
- IVT 입구 1층리얼 모드 비디오 ROM 펌웨어 영역의 테이블인 C000:8930을 가리킵니다.
- IVT 항목 43리얼 모드 비디오 ROM 펌웨어 영역의 또 다른 테이블인 C000:6730을 가리킵니다.
추가 읽기
- 핀바 머피(2012-08-18).UEFI 메모리 V E820 메모리. fpmurphy.com.
- 최신 64비트 Intel 칩 PC는 어떤 모드에서 부트 섹터를 실행합니까?
답변2
원래의 8086 프로세서 아키텍처(80286+ 프로세서에서 리얼 모드로 구현됨)는 보호 모드에서 실행되는 Linux와 아무 관련이 없습니다. 물리적 주소 0에는 인터럽트 벡터 테이블이 없으며 대신 인터럽트 설명자를 포함하는 인터럽트 설명자 테이블이 사용됩니다. IDT는 메모리의 어느 위치에나 위치할 수 있습니다.
Linux 커널은 펌웨어(BIOS 또는 EFI)에서 물리적 메모리 맵을 가져옵니다. 이를 통해 사용 가능한 물리적 메모리 페이지 프레임과 예약되거나 없는 프레임을 알 수 있습니다. 사용 가능한 페이지 프레임의 범위는 연속적이지 않지만 종종 큰 구멍이 있습니다. 전통적으로 x86 Linux 커널은 물리적 메모리가 사용 가능한 것으로 표시되어 있어도 부팅을 건너뜁니다. 따라서 Linux 커널은 물리적 주소 0을 사용하지 않습니다.
답변3
덤프 메모리
다음은 외부에서 수행하지 않고 시스템 내부에 메모리 내용을 덤프하는 또 다른 방법입니다.
$ head /dev/mem | hexdump -C
00000000 53 ff 00 f0 53 ff 00 f0 53 ff 00 f0 53 ff 00 f0 |S...S...S...S...|
00000010 53 ff 00 f0 53 ff 00 f0 cc e9 00 f0 53 ff 00 f0 |S...S.......S...|
00000020 a5 fe 00 f0 87 e9 00 f0 53 ff 00 f0 46 e7 00 f0 |........S...F...|
00000030 46 e7 00 f0 46 e7 00 f0 57 ef 00 f0 53 ff 00 f0 |F...F...W...S...|
00000040 22 00 00 c0 4d f8 00 f0 41 f8 00 f0 fe e3 00 f0 |"...M...A.......|
00000050 39 e7 00 f0 59 f8 00 f0 2e e8 00 f0 d4 ef 00 f0 |9...Y...........|
00000060 a4 f0 00 f0 f2 e6 00 f0 6e fe 00 f0 53 ff 00 f0 |........n...S...|
00000070 ed ef 00 f0 53 ff 00 f0 c7 ef 00 f0 ed 57 00 c0 |....S........W..|
00000080 53 ff 00 f0 53 ff 00 f0 53 ff 00 f0 53 ff 00 f0 |S...S...S...S...|
...
...
000afea0 00 00 00 00 00 00 00 00 aa aa aa 00 aa aa aa 00 |................|
000afeb0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000b0000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
000c0000 55 aa 40 e9 62 0a 00 00 00 00 00 00 00 00 00 00 |[email protected]...........|
000c0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 42 |..............IB|
분석하다
000c0000 위의 윗부분은 부트로더와 관련이 있을 수 있습니다. 내가 왜 이것을 의심하겠습니까? 55aah 위치의 코드는 000c0000
일반적으로 보조 부트 로더를 실행하기 위해 BIOS를 트리거하는 것과 같은 작업에 사용되는 메모리의 표시일 수 있습니다.
그러나 이 55aah가 c0000h-effffh 범위에 나타나는 것을 고려하면 이 부분은 PNP 확장 헤더일 가능성이 더 높습니다.
인용하다:BIOS 부팅 사양3.3 PnP 확장 커넥터가 있는 장치
옵션 ROM이 있는 모든 IPL 장치에는 시스템 메모리 주소 C0000h와 EFFFFh 사이(55AAh부터 시작) 사이의 2k 경계에 있는 유효한 옵션 ROM 헤더가 포함되어야 합니다. PnP 확장 헤더가 있는 장치만 시작을 제어할 수 있습니다. 확장 헤더는 표준 옵션 ROM 헤더의 오프셋 +1Ah에 위치하며 장치 구성에 대한 중요한 정보를 포함합니다. 또한 BIOS가 장치에서 부팅하기 위해 호출하는 장치 옵션 ROM(BCV 또는 BEV)의 코드에 대한 포인터도 포함되어 있습니다. PnP 확장 헤더의 구조는 부록 A를 참조하세요. PnP 확장 헤더를 사용하여 IPL 장치를 시작하는 방법에는 두 가지가 있습니다. BCV 또는 BEV를 포함해야 합니다.
53 이후..
처음에는 53ffh 데이터에 관해서. 나는 그것이 무엇인지 정확히 모른다. 추가 조사에 따르면 BIOS의 MBR 부트 로더가 부팅을 위해 Linux 커널로 넘겨진 후 Linux 커널에 무언가 기록되었을 가능성이 있습니다.
일반적으로 부트로더는 커널을 메모리에 로드한 다음 커널로 점프합니다. 그러면 커널은 부트로더가 사용하는 메모리를 회수할 수 있습니다(이미 작업을 수행했기 때문입니다). 그러나 부팅 섹터에 운영 체제 코드를 포함하고 운영 체제가 부팅된 후에도 그대로 유지하는 것은 가능합니다.
더 자세히 살펴보면 다음과 같은 연구 논문에서 이 단락을 발견했습니다./dev/mem을 통해 악성코드 삽입:
메모리 장치 1개
/dev/mem은 물리적으로 주소를 지정할 수 있는 메모리용 드라이버 인터페이스입니다. mem과 kmem의 원래 목적은 커널 디버깅을 지원하는 것이었습니다. 주소 오프셋을 선택하기 위해 lseek()를 사용하여 일반 문자 장치처럼 장치를 사용할 수 있습니다. kmem 장치는 유사하지만 가상 주소 지정 컨텍스트에서 커널 메모리 이미지를 제공합니다. Xorg 서버는 mem 장치를 사용하여 VESA 비디오 메모리와 물리적 주소 0x00000000에 있는 BIOS ROM 인터럽트 벡터 테이블(IVT)에 액세스하여 VM86 모드에서 비디오 모드를 작동합니다. DOSEMU는 또한 이를 사용하여 BIOS IVT에 액세스하여 다양한 작업(디스크 읽기, 콘솔에 인쇄 등)에 대한 BIOS 인터럽트를 실행할 수 있습니다.