x86 Linux의 물리적 주소 0에는 무엇이 포함됩니까? 4 =

이 질문이 여기 또는 reverseengineering.stackexchange.com에 있는지 확실하지 않습니다.

Wikipedia 에서 인용 :

8086 프로세서에서 인터럽트 테이블을 IVT (인터럽트 벡터 테이블)라고합니다. 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

그 값으로 무엇을 만들어야할지 모르겠습니다. 인터럽트 디스크립터 테이블처럼 보이지 않습니다 (해당 값을 역 참조하면 모든 널이 제공됨). 그래서 내가 실제로 무엇을보고 있습니까?



답변

펌웨어에 포함 된 내용

이상적인 현대 시스템에서이 SU Q & A에서 설명했듯이 프로세서는 절대 실제 모드로 들어 가지 않습니다. 현대 64 비트 인텔 칩 PC는 어떤 모드에서 부팅 섹터를 실행합니까? , 물리적 메모리의 첫 KiB는 Johan Myréen이 다른 대답을하기 위해 만든 것처럼 관련이 없습니다. 그러나 많은 최신 펌웨어 (여전히)는 호환성을 지원 합니다.

  • 그들은 (예, 다시 놓을 수 에서 부팅, 프로그램 / 같은 오래된 스타일의 PC로 실시간 모드로 기록되는 시스템 소프트웨어를 실행하기 위해 리얼 모드로 보호 모드에서, 그들은 보호 모드로 비현실적인 모드에서 직접 갔다 제공) MBR 및 VBR; 과
  • 이전 리얼 모드 펌웨어 API를 제공하고 위에서 언급 한 시스템 소프트웨어가 사용하는 API에 대한 모든 데이터 구조를 설정합니다.

이러한 데이터 구조 중 하나는 리얼 모드 IVT입니다. 이전 리얼 모드 펌웨어 API는 int명령어를 기반으로 하며, 리얼 모드 IVT는 해당 명령어에 대한 다양한 펌웨어 처리 루틴에 대한 포인터로 초기화의 일부로 펌웨어에 의해 채워집니다.

보호 모드 시스템 소프트웨어는 이전 리얼 모드 펌웨어 API가 필요하지 않으며 프로세서를 리얼 모드로 실행하지 않으므로 첫 번째 1KiB 물리적 메모리의 리얼 모드 IVT는 사용되지 않습니다. (v8086 보호 모드는 물리적 주소 00000000 이상을 다루지 않습니다 . 기억해야합니다. 논리적 주소 00000000 이상을 처리하며 페이지 테이블로 변환됩니다.) 최신 EFI 시스템에서 펌웨어는 물리적 메모리의 메모리 맵을 운영 체제로 넘깁니다. 부트 스트랩, 자체 보호 모드 API 목적으로 펌웨어에 예약 된 부분과 운영 체제가 물리적 메모리 풀에 사용할 수있는 부분을 알려줍니다. 이론적으로 실제 메모리의 첫 페이지는 후자의 범주에 속할 수 있습니다.

실제로, 첫째, 펌웨어는 종종 운영 체제는 것을 의미한다 “부팅 서비스 코드”와 같은 물리적 메모리의 첫 페이지를 표시 할 수 있습니다 , 그것을 주장하고 그냥 가서 물리적 메모리 풀의 일부로 사용 하지만 이후 부팅이 EFI 펌웨어의 시간 서비스는 운영 체제에 의해 종료되었으며 펌웨어는 런타임 서비스 만 제공하도록 축소되었습니다. 이에 대한 예는 add_efi_memmapFinnbarr P. Murphy가 표시 한 Linux 커널 로그 ( 옵션 포함) 에서 확인할 수 있습니다 .

[0.000000] efi : mem00 : 유형 = 3, attr = 0xf, 범위 = [0x0000000000000000-0x0000000000001000) (0MB)

xe는 다음과 같이 사람이 읽을 수있는 형태로 다른 프로그램으로 디코딩합니다.

[# 00] 유형 : EfiBootServicesCode 속성 : 0xF
      물리 : 0000000000000000-0000000000001000
      덕 : 0000000000000000-0000000000001000

실제로, 둘째, 리눅스는 명시 적으로 물리적 메모리의 범위를 무시 하는 경우에도 펌웨어가 가서 사용할 수 있다고 말한다. EFI 및 비 EFI 펌웨어 모두에서 Linux에 물리적 메모리 맵이 있으면이를 패치하고 ( 이름이 지정된 함수trim_bios_range 로) 다음과 같은 커널 로그 메시지가 생성됩니다.

[0.000000] e820 : 업데이트 [mem 0x00000000-0x00000fff] 사용 가능 ==> 예약 됨

이것은 최신 EFI 펌웨어에는 그다지 적합하지 않습니다. 실제 모드 IVT는 펌웨어 API의 일부이지만 펌웨어 API의 일부이지만 펌웨어는 펌웨어 API의 일부인 오래된 PC98 펌웨어에 대처하기 때문에 펌웨어 API의 일부가 아닙니다. 운영 체제에서 덮어 쓸 수있는 물리적 메모리와 같은 자체 동일한 API).

이론적으로 물리적 메모리의 범위 는 커널 메모리 할당 자와 수요 페이징 된 가상 메모리의 순간적인 요구에 따라 임의의 코드 또는 데이터를 포함 할 수 있습니다. 실제로 리눅스는 펌웨어가 원래 설정 한대로 그대로 유지합니다.

그리고 시스템에서 펌웨어가 실제 모드 IVT 항목으로 채워졌습니다. 리얼 모드 IVT 항목은 물론 16:16 멀리 포인터이며, 2 바이트 16 진 덤프를 사용하여 메모리를 보면 실제로이를 명확하게 볼 수 있습니다. 몇 가지 예 :

  • 대부분의 IVT 항목은 리얼 모드 펌웨어 ROM 영역의 주소 인 F000 : FF53을 가리 킵니다. 아마도 아무것도하지 않는 더미 루틴 일 것입니다 iret.
  • IVT 항목 1E 는 동일한 ROM 영역에있는 테이블 인 F000 : 6AA4를 가리 킵니다.
  • IVT 항목 1F 는 리얼 모드 비디오 ROM 펌웨어 영역의 테이블 인 C000 : 8930을 가리 킵니다.
  • IVT 항목 43 은 실제 모드 비디오 ROM 펌웨어 영역의 다른 테이블 인 C000 : 6730을 가리 킵니다.

추가 자료


답변

원래 8086 프로세서 아키텍처 (80286+ 프로세서에서 실제 모드로 구현 됨)는 보호 모드에서 작동하는 Linux와 관련이 없습니다. 물리적 주소 0에는 인터럽트 벡터 테이블이 없으며 대신 인터럽트 설명자를 포함하는 인터럽트 설명자 테이블이 사용됩니다. IDT는 메모리의 어느 곳에 나 위치 할 수 있습니다.

Linux 커널은 펌웨어 (BIOS 또는 EFI)에서 실제 메모리 맵을 가져와 사용 가능한 물리적 메모리 페이지 프레임과 예약 또는 존재하지 않는 프레임을 알려줍니다. 사용 가능한 페이지 프레임의 범위는 연속적이지 않지만 일반적으로 큰 구멍이 있습니다. 전통적으로 x86 Linux 커널은 사용 가능한 것으로 표시되어 있어도 물리적 메모리의 시작을 건너 뛰었습니다. 따라서 물리적 주소 0은 Linux 커널에서 사용되지 않습니다.


답변

덤핑 메모리

다음은 시스템 내부의 메모리 내용을 덤프하고 외부에서 수행해야하는 대체 방법입니다.

$ 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  |U.@.b...........|
000c0010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 49 42  |..............IB|

분석

000c0000보다 높은 부분은 부트 로더와 관련이있을 수 있습니다. 왜 이것을 의심할까요? 위치에있는 코드 55aah 000c0000는 일반적으로 BIOS가 보조 부트 로더를 실행하기위한 트리거와 같은 것들에 대한 메모리의 표시 일 수 있습니다.

참조 : 부팅 서명-BIOS

  ss # 1

그러나이 55aah가 c0000h-effffh 범위에서 발생하면이 부분이 PNP 확장 헤더 일 가능성이 큽니다.

참조 : BIOS 부팅 사양

3.3 PnP 확장 헤더가있는 장치

옵션 ROM이있는 모든 IPL 장치에는 2k 경계에서 시스템 메모리 주소 C0000h와 EFFFFh 사이에 상주하며 55AAh로 시작하는 유효한 옵션 ROM 헤더가 포함되어야합니다. 장치의 부팅은 PnP 확장 헤더가있는 경우에만 제어 할 수 있습니다. 오프셋 + 1Ah의 표준 옵션 ROM 헤더 내에 주소가있는 확장 헤더에는 장치를 구성하는 데 사용되는 중요한 정보가 포함되어 있습니다. 또한 BIOS가 장치에서 부팅하기 위해 호출 할 장치의 옵션 ROM (BCV 또는 BEV)에 코드를 가리키는 포인터도 포함되어 있습니다. PnP 확장 헤더의 구조는 부록 A를 참조하십시오. PnP 확장 헤더가있는 IPL 장치를 부팅하는 방법에는 두 가지가 있습니다. BCV 또는 BEV를 포함해야합니다.

53ff …

처음에있는 53ffh 데이터에 관해서. 그것이 실제로 무엇인지는 분명하지 않습니다. 추가 조사를 통해 BIOS의 MBR 부트로드가 Linux 커널로 전달되어 부팅 된 후 Linux 커널이 작성한 것 같습니다.

일반적으로 부트 로더는 커널을 메모리에로드 한 다음 커널로 이동합니다. 그러면 커널은 부트 로더가 사용한 작업을 이미 회수 할 수 있습니다 (이미 작업을 수행했기 때문에). 그러나 부트 섹터에 OS 코드를 포함시키고 OS가 시작된 후에도 상주 상태를 유지할 수 있습니다

더 파고 나는 / dev / mem을 통한 악성 코드 삽입 이라는 제목의 연구 논문 에서이 단락을 찾을 수있었습니다 .

1 멤 장치

/ dev / mem은 물리적으로 주소 지정 가능한 메모리에 대한 드라이버 인터페이스입니다. mem과 kmem의 원래 의도는 커널 디버깅을 돕는 것이 었습니다. lseek ()를 사용하여 주소 오프셋을 선택하는 일반 문자 장치처럼 장치를 사용할 수 있습니다. kmem 장치는 비슷하지만 가상 주소 지정과 관련하여 커널 메모리 이미지를 제공합니다. Xorg 서버는 mem 장치를 사용하여 VESA 비디오 메모리와 물리적 주소 0x00000000에있는 BIOS ROM IVT (Interrupt Vector Table)에 액세스하여 VM86 모드에서 비디오 모드를 조작합니다. 또한 DOSEMU는이를 사용하여 BIOS IVT에 액세스하여 다양한 작업 (디스크 읽기, 콘솔 인쇄 등)에 대해 BIOS 인터럽트를 수행 할 수 있습니다.

참고 문헌


답변