마이크로소프트 사에서는 자주 사용하는 개발 IDE인 Visual Studio에서 scanf 사용을 권하지 않는다. 하위 버전에서는 경고를 띄우지만 최상위 버전에서는 SDL(security development lifecycle) 검사가 체킹 되어 있어 비주얼 스튜디오에서만 지원하는 scanf_s를 사용하지 않으면 오류가 뜨게 되어있다. scanf_s()는 문법은 scanf()와 다를게 거의 없다. 그러나 문자열을 입력받는 서식문자 %s를 사용할 땐, 저장할 문자열 뒤에 최대 문자열 입력 개수를 인자로 한 개 더 넣어주어야 한다. 1 2 char name[10]; scanf("%s", name); cs 이전 scanf 사용이 이랬었다면, 1 2 3 #define MAX_LEN 10 char name[MAX_LEN]; scanf_s("%s", name, MAX_LEN); cs scanf_s를 사용해야 할 때 이런 식으로 인자를 한 개 더 추가해 주어야 한다. 참고로 비주얼 스튜디오에서 scanf_s를 사용할 때 문자열 입력을 받는 때에 문자열 길이를 지정해 주지 않아도 문법 오류가 뜨지 않는데, 실행했을 때는 오류가 난다. 문법 오류가 나지 않아도 문법 오류이다. 이는 오묘한 문법때문인데, scanf_s를 이렇게 사용할 때의 케이스가 있기 때문이다. 1 2 3 4 5 #define MAX_LEN 10 char name[MAX_LEN]; int grade; int age; scanf_s("%s %d %d", name, MAX_LEN, &grade, &age); cs 문자열을 입력 받을 때 저장할 문자열 뒤에 최대 문자열 입력 개수를 적어주고 그 뒤에 입력받는 변수를 두면 된다. 이렇게 sca
리버싱 핵심원리 책을 읽으면서 실습했다. 크랙미란, 리버싱 연습을 위해 일부러 디버깅/리버싱으로 프로그램을 고의로 수정해서 문제를 풀어나가게 하는 프로그램들인데 유명한 입문? 크랙미 프로그램인 abex crackme 2를 리버싱 실습을 하려고 한다. abex2는 실행 시 이렇게 이름과 시리얼을 적는 곳과, Chcek, About, Quit 버튼이 세 개 있고 이름과 시리얼을 적고 check 버튼을 눌러서 이름에 대한 시리얼이 맞는 지 비교해 적절한 출력을 내 주는 프로그램이다. 이름에 1234를 적고 시리얼에 hello를 적어서 check 버튼을 눌렀더니 아니라고 뜬다. 그리고 이름이 4글자 미만이면 이름을 4글자 이상 적으라고 나온다. 이름은 최소 4글자는 적어야 한다. 올리디버거로 열어보았다. 이전에 보던 곳과는 다른 곳에서 시작한다. abex crackme 2는 비주얼 베이직으로 짜여있는 프로그램인데, 비주얼 베이직은 MSVBM이라는 비주얼 베이직 함수가 담겨있는 dll을 사용하고, 프로그램의 기본 main 함수가 아닌 버튼을 눌렀을 때 등의 버튼 이벤트 핸들러 함수 등에 사용자의 주요한 코드가 담겨있다고 한다. 실제로 ExeInfoPE로 살펴보았을 때 Visual Basic로 작성되어 있다는 것을 확인할 수 있었다. 버튼을 눌렀을 때의 이벤트 핸들러를 쉽게 찾기 위해 틀렸을 때 나오는 메시지박스의 문자열을 찾아보기로 했다. 올리디버거의 Search for - All referenced strings를 통해 프로그램에 있는 모든 문자열들을 찾아 볼 수 있다. 아래로 조금 내리니 틀렸을 때의 메시지와 맞췄을 때의 메시지 문자열을 다 찾아볼 수 있다. 더블클릭해서 주소를 찾아가 보았다. 문자열들을 집어넣어주고 CALL을 하는 모습이 보인다. 아래를 조금 내려보니 메시지박스를 띄우는 함수를 호출하는 것 같다. 이 부분에 브
abex crackme2를 풀어내는 방법중에 분기문이 있는 곳에 점프문을 수정해서 풀어 보았다. 다른 방법으로도 풀어내 보자. 틀렸을 때 나오는 메시지의 문자열을 바꾸는 방법 문자열 패치 문자열 수정하기도 귀찮아서 맞았을 때 나오는 문자열의 주소를 넣게 하였다. 그 다음 방법은 정석적인 이름에 따른 시리얼 값이 있는 주소에서 시리얼 값을 알아와서 맞게 입력해서 패치 없이 진행하기 테스트는 아래와 같이 하였다. 분기문이 있는 곳 위에 함수가 있는데 아마 이 함수에서 비교를 하는 것 같다. 함수 안에 들어갔을 때 local.17과 local.13의 주솟값을 매개변수로 넣은 arg.2와 arg.1의 주솟값을 또 push 하고 있는데 그 스택에 있는 주소를 아래 hex 덤프 창에서 보니 0019f18c 와 0019f19c로 서로 16바이트 차이나는 위치를 가지고 있으며 둘의 차이점은 빨간 네모를 친 곳밖에 차이가 나지 않는다. 책에서 본 것처럼 저것이 실제 문자열의 주소를 가리키게 하는 거라면 리틀 엔디언으로 표기된 주소를 다시 원래대로 바꾸고 주소를 따라가 보았다. 주소를 따라가 보니 9 5 9 6 9 7 9 8 이라는 문자가 나오고, 다음 주소를 따라가 보니 임시로 넣었던 시리얼 값인 a b c d가 나온다. 그럼 두 주소는 비교될 시리얼 값과 내가 넣은 시리얼 값일 것이다. 9 5 9 6 9 7 9 8 은 무엇을 의미하는 것인가. 아스키코드로도 95 96 97 98은 내가 넣은 시리얼 값과는 관련이 없다. 그럼 abcd와 95969798이라는 문자열을 그대로 비교한다는 것이니까 이름에 1234를 넣었을 때 시리얼 값은 95969798이라는 것을 알 수 있다. 다시 실행시켜 시리얼에 95969798을 넣었을 때 성공했다.
댓글
댓글 쓰기