2012-10-05 2 views
2

형식화 된 I/O 함수가 제공된 인수보다 많은 인수를 예상 할 때 Format String Attack이 발생한다는 것을 알고 있습니다. C에서C에서 Format String Attack이 발생하는 이유는 무엇입니까?

, 메모리 위치를 읽기위한

한 예 :

printf("%x"); // this prints a memory address location in the stack 

메모리 위치에 덮어 쓰기에 대한 또 다른 예 :

printf("Overwritten%n"); //this prints the number of chars in "Overwritten" 

내 질문은 : 왜 이런 일이 일어날 않습니다를 두 경우 모두? 해당 값을 제공하지 않고 서식이 지정된 문자열에 % x 만 있으면 왜 메모리에 주소가 인쇄됩니까? 그 주소가 정확히 무엇입니까? 나는 그것이 일어난다는 것을 알고있다. 그러나 정말로 무엇이 계속하고 있냐?

덮어 쓰기와 동일합니다.

+0

전화 협약에 대해 읽어 보시기 바랍니다 : http://en.wikipedia.org/wiki/Calling_convention –

+0

[위키 피 디아 문서] (http://en.wikipedia.org/wiki/Uncontrolled_format_string)의 링크를 따라 검색 그 용어가 거기에서 사용되었습니다. YouTube에 관한 동영상도 있습니다. –

답변

4

발생하는 것은 정의되지 않은 동작입니다. Printf는 해당 값이 없다는 것을 모릅니다. 그것은 (당신이 제공하지 않은) 호출의 두 번째 매개 변수에 액세스하려고 시도하고 임의의 메모리 값에 액세스합니다.

"overwritten%n"의 경우 % n은 (는) % n을 (를) 호출 할 때까지 쓴 문자 수를 메모리에 저장합니다. 올바른 주소를 전달하지 않고 호출하면 무언가를 작성하여 메모리를 손상시킬 수 있습니다.

1

당신을 위해 도움이 될 수 있습니다 :
나는 당신이 Windows에서 작업하는 것 같아요. 엄격한 검사가 수행되지 않습니다.
리눅스에서 경고를 받았다.

int 주() {
printf ("% x");
printf ("덮어 쓰기 % n"); 기능에서 '주':
TEST.C : 4 : 경고 : 포맷에 너무 적은 인수
테스트
TEST.C
$의 GCC의 TEST.C :
}

는 다음과 같은 경고를 제공 .c : 5 : 경고 : 형식에 대한 인수가 너무 적음

1

이것은 printf이 프로그래머의 의도를 알지 못하기 때문입니다. 형식 문자열에 형식 식별자가 있으면 적절한 인수를 형식화합니다.

printf("%x"); 

은 (일반적으로 레지스터 또는 스택에 저장되는) 추가 인수가 필요합니다. 프로그래머는 컴파일러에게이 호출에서 추가 인수를 제공하라는 말을하지 않았기 때문에 그 때 인수가 발견 될 것으로 예상되는 곳에 printf이 저장되는 곳에 저장됩니다.

컴파일러는 일반적으로 다음 함수를 호출하기 전에 레지스터를 지우지 않습니다.

2

C가 "상위 레벨 어셈블러"라는 것을 감안할 때, 대답은 컴파일러 구조에 있습니다. printf은 모든 인수가 실제로 제공되었는지 여부를 확인하지 않고 변수 개수의 인수를 허용하는 함수입니다.따라서이 함수가 컴파일러 수준에서 인수를 허용하는 방법에 따라 다음 시나리오가 가능합니다.

먼저 printf에 전달 된 문자열이 구문 분석되어 결과적으로 문자열을 출력하는 내부 함수가 호출됩니다 두 번째 경우에는 '덮어 쓰기'됩니다 (첫 번째 경우 형식화 된 문자열의 첫 번째 기호는 매개 변수를 나타내는 '%'입니다). 그런 다음 매개 변수가 인쇄되도록 요청되면 해당하는 원시 데이터 인쇄 루틴이 호출되며 다음 스택에 놓아야 할 인수가 옵셋됩니다 (오프셋은 컴파일 타임에 계산 됨). %x의 경우 인수가 없으며 인쇄 할 변경되지 않은 문자열이 비어서 할당되지 않으므로 스택에있는 다음 32 비트 값은 현재 반환 주소이며 EXE에서 OS에 의해 생성 된 값입니다 로딩 시간은 실제로 call printf_hex_address 어셈블리 명령어를 통해 스택에 저장됩니다. 이 공격은 처리 프로그램이 실제로 메모리에 지속적이고 스왑되지 않을 경우이 주소는 프로그램의 주소 공간 내에서 쓰기 가능한 메모리 위치라는 사실을 기반으로합니다. "Overwritten"의 길이가 나타나는 이유는 문자열의 실제 길이가 전달되도록 내부 문자열 조작 루틴에 의해 설명 될 수 있습니다.

+0

여전히 printf ("% x") 호출에서 표시되는 주소를 가져올 수 없습니다. 이 주소가 무엇인지 설명하는 간단한 문장 하나가 필요합니까? –

+0

이것은 printf의 기본 구현에 따라 다릅니다. "내부 인쇄 루틴을 호출하는 printf의 코드 주소"일지라도 대략적인 추측은 "printf라는 코드 주소"입니다. – Vesper

관련 문제