오랜만에 짬을 내서 문제를 계속해서 진행해보았다.

sub_20C의 가장 큰 블럭 중 하나를 분석했었는데 나머지 두 블럭도 추가적으로 분석하였다.
(1) 0x309 ~ 0x0310

이구간을 제외하면 이전글에서 분석했던 블럭과 크게 차이는 나지 않는다.
이구간에서 0xAD2에 저장된 값을 바꾸는데 내가 입력했던 문자열 8개를 레지스터에 계속 저장한다.
그 값을 0xAD2에 복사한다.
또 더하면서 carry flag가 set 되면 그 값을 r9 레지스터에 저장하는데 이 값은 나중에 사용된다.

(2) 0x32B ~ 0x3CB

이러한 코드가 계속해서 반복되고있다. 확인해보니 AVR reverse engineering (5) 에서 분석하였던 구간과 마찬가지로 
0xAE4 에서 값을 가져오고 이 값을 다른값과 and 연산을 한 후
sub_1E7의 인자값으로 이용한다
여기서 리턴된 값과 0x100을 더한 주소에 저장된 값을 불러온다.

이러한 과정을 AD2~ADB까지 모두 적용한뒤 0xAE4를 가지고 있는 레지스터는 1 증가 0x100를 가지는 레지스터에는 4씩 증가시키고
이를 총 8회 반복한다.


 (3)0x3D4 ~

이전 포스트에서 이 구간에서도 값을 변경했었던 것을 확인하였는데 

여기서 아까 언급하였던 r9 레지스터에 저장되었던 값이 Y+2 에 복사되었는데, 이 값을 Z+9 즉 0xADB 번지에 복사한다.


그 아래를 보면 Z (0xAD3 으로 초기화되어있음)에 r16레지스터 값을 저장하는게 있는데 r16과 r22는 각각 Z번지에 저장된 값으로 조건이 맞다면  rotate 연산과 shift연산을 수행한 후 or 연산한다.
따라서 shift와 rotate 연산 진입 조건을 만족시키지 않는다면 해당값은 변경이 없다.

비교대상값이 이 구간에서 변형이 없었다면 좋겠지만, 보장할 수 없기 때문에 이 구간에서 얼마나 변형되는지를 확인할 필요가 있었는데
(1)에서 구한 r8과 r9 레지스터의 저장된 값이 영향을 준다는 것을 확인하였다. 또 정말 운좋게도 우연히 입력했던 테스트 값이 비교 대상의 첫번째 바이트와 동일하였다.
첫번쨰 바이트는 (2)에서 r8 레지스터의 값(문자들의 합)이 xor 연산을 거듭하면서 변형된것이기 때문에 거꾸로 비교대상의 문자들의 총합을 유추 할 수 있었다.
해서 문자들의 총합을 유지하면서 값을 변경시켜봤을 때 계속 고정된 위치만 덮어씌워지는것을 확인하였다.

해서 변경된 바이트를 제외하고 브루트포싱으로 구할 수 있는지 확인해보고자 한다.

연산하는 코드를 위와 같이 c로 작성하였다.

작성한 코드로 기준문자와 비교하여 한문자씩 변화하였을 때 어떻게 영향을 주는지 확인하였다. 하지만 예상했던것과 다르게 결과가 나오는것을 확인하였다. 
아마 결과값 바이트 Y 와 결과를 만드는 바이트 X가 서로 같은 위치가 아니라 다른 위치이기 때문이라고 본다.

 
가장 윗줄은 처음에 입력된 바이트이고 화살표가 가리키는 것은 이 입력값이 어떤위치의 바이트라고 보면
그 밑에 있는 결과 값 중 노란색 원은 네번째 바이트에 의해서 만들어졌지만, 그 다음 줄의 결과값을 보면 두번째 줄의 초록색 원이 영향을 줬지만
그 초록색원은 첫번째 줄의 가장 왼쪽에 있는 초록색원에 의해서 생성된 값이다. 즉, 단계가 진행되면서 입력했던 네번째 바이트 뿐만아니라 다른 바이트에 의해서도 변할 수 있는 것이다.

따라서 그냥 연산으로 한문자씩 변화시켜가면서 구할 수는 없다는 것을 확인하였고 결국 역연산 코드를 짜야 되는 것으로 결론이 났다.

(3)에서 나오는 명령어들이 무엇을 수행하는지 코드를 보니 잘 몰랐는데 전체적인 기능은 레지스터를 대상으로 로테이트 명령어를 수행하는 녀석이었다.
그리고 첫번째 바이트가 (2)에서 첫번째 바이트를 바꾸는것을 확인하여 첫번째 바이트외에 다른 바이트가 연산에 포함되지 않았다고 판단하여
제일 첫번째 바이트가 동일하다면 역연산에 끝 바이트도 동일할 것이다.
역연산 끝에 나타나는 바이트는 입력한 문자를 모두 합한것이었기 때문에,  (3)에서 발생하는 스왑도 동일할 것이라 가정하였다. 

그래서, 비교대상 10 바이트 9A 7D 72 57 D5 78 49 E6 F2 02 는 9A 7D 72 75 EA 78 a4 E6 F2 02 가 된다고 생각하고 역연산 코드에 넣어보기로 했다.

중간에 반복횟수와 초기 입력값에 혼동이 있어 시간이 걸렸지만
.
.
.
.



비밀번호를 구했다!




성공적으로 로그인 되는것을 확인하였다. 그리고 리드미를 읽으니 플래그가 출력되었다 감동 ㅠㅠ
아쉽게도 비밀번호 문자열과 리드미가 읽는것과 어떤영향을 주는지 정확하게 파악하진 못했지만, 플래그를 얻었으니 여기서 마무리 지어야겠다.



끄읏

 

'reversing.kr' 카테고리의 다른 글

AVR reverse engineering (5) CustomShell  (0) 2018.08.06
reversing.kr CRC1  (0) 2018.02.07
AVR reverse engineering (4) CustomShell  (0) 2018.02.05
AVR reverse engineering (3) CustomShell  (0) 2018.02.05
AVR reverse engineering (2) AVR ATmega128  (0) 2018.01.30
sub_20c 를 본격적으로 분석하기 시작했다.


0x23A 까지 실행하였을 때, 0xAD3(AD4가 아니였음)으로 입력한 패스워드 문자열 8개를 복사했다.



그 아래에 있는 베이직블록에서 진행한것은 r19,r18,r03,r21,r20 에 AD3에 복사한 1,2,3,4,7 번째 문자 이다.
Y+5,Y+4,Y+3 에 5,6,8 번째 문자를 복사 했다.


loc_24C 에 진입하기 직전 r24 = 0xFF , r30 = 0x76 , r31 = 1 이었는데
loc_251 로 진입하면서 모두 0으로 되었다.

한줄 한줄 분석하고 있는데, 넘나 피곤하다. Hex ray의 위대함을 실감하고 있다.
대략 알 수 있는 것은
(1) 0x23B ~ 0x302 까지의 코드가 8번 반복이 될 것이라는 점과
(2) and를 하고 있는 친구는 0xAE4 부터 하나씩 가져오는 문자인데, 매 루프 마다 증가할 예정이다. 0xAE4 ~ ... 의 값이 매번 고정이었던거같은데 확실하지는 않음.
(3)sub_1DC에 의해서 가져오는 값은 0x00, 0x02, 0x03 세 종류이다. 따라서 XOR 하게되는 r24 친구는 0x100, 0x102, 0x103 셋 중 하나로 결정된다. 
(4)일련의 반복과정으로 0xAD2 ~ 0xADB 번지에 차곡차곡 갱신된다. 

이런식으로 끝까지 블럭을 분석하였다.

얼핏보면 길지만 결국에는 입력한 여덟문자를 토대로 어떤문자열과 연산하여 열개의 문자열을 생성해내는 것이었다.

나머지 아랫부분의 긴 블럭 또한 위쪽처럼 열문자에 대해 어떤 변화를 줄 것이다.
그래프뷰의 아랫쪽에 긴 블럭 이후에도 AD2~ ADB가 영향을 받는지 확인하고 싶었다. 정확히는 0x3D4 까지 코드가 실행 된 이후에도 영향을 받는지 확인하고싶었다. 영향을 안 받는다면 그 이후 것은 해석할 필요가 없기 때문
(1) 0x3D4 까지 실행된 직 후

(2)0x3F7 까지 실행된 직 후



AD2~ ADB 전체는 아니지만 일부는 영향을 받는다.

'reversing.kr' 카테고리의 다른 글

AVR reverse engineering (6) CustomShell  (0) 2018.08.06
reversing.kr CRC1  (0) 2018.02.07
AVR reverse engineering (4) CustomShell  (0) 2018.02.05
AVR reverse engineering (3) CustomShell  (0) 2018.02.05
AVR reverse engineering (2) AVR ATmega128  (0) 2018.01.30
CRC 알고리즘 연산방법이 왜 그런건가 끙끙 거리다가 그냥 받아드리니 마음이 편해졌다.

CRC 테이블을 생성했을 때, CRC-32 알고리즘 기준으로 설명을 해보자면 CRC-32 초기값은 0xFFFFFFFF 이다.

이 때, 내가 입력한 문자열이 "abcd1234" 라면

첫번째 문자를 CRC-32 값(현재 0xFFFFFFFF)의 최하위 바이트와 xor 을 한다. 

그럼 0x61 ^ 0xFF = 0x61 이고 이 값이 CRC-32 의 테이블 인덱스 값이 된다.

해당 값이 0xAABBCCDD 라고 가정한다면,

새로운 CRC-32 값은 (기존의 CRC-32 값 ( 현재는 0xFFFFFFFF ) <<  8) ^ ( 직전에 구한 테이블 값 (0xAABBCCDD)) 가 된다. 

즉 0x554433DD 

이제 그 다음은 b 에 대해서

CRC-32 값 최하위 바이트 DD 와 b(0x62) 를 연산하면 0xBF 이다

0xBF의 테이블 값이 0x11223344 라고 가정한다면,

새로운 CRC-32 값은 0x4433DD00( 0x554433DD << 8 을 한 값이다.) ^ 0x11223344

0x5511EE44

이것을 문자열 끝까지 반복하는 알고리즘이다.

이제 문제를 IDA를 사용하여 확인해보면


GUI 윈도우 프로그램인데, WinMain을 보면 sub_401070을 호출하고 있다. 이 함수를 분석을 해야한다.

해당 함수를 HexRay 기능을 사용하여 보면 아래와 같다.


이 코드가 전부이고 문자를 여덟개만 받는다. 그 문자열을 256바이트짜리 문자에 0 , 8 , 16 ... 간격으로 넣는데 난 처음에 테이블에다가 넣는다고 착각했는데 사실 이 친구는 CRC 검사를 할 대상 문자열이다.

이 문자열을 대상으로 CRC 값을 생성해내고, 기준값과 검사해서 아니면 Wrong 맞으면 Correct 인데 우리는 CRC 값을 조작해내는게 아니라 기준 CRC 값을 생성해내는 문자열을 알아내는게 문제이다.

이 과정에서 역연산과 연산을 사용하여 문자열을 찾아내면 된다. 문제를 해결하는 키포인트는 결국에는 브루트 포싱이라는 것 그렇다면 n^8 인데 어마어마한 연산량이기 때문에 쉽지 않다.

그렇기 때문에 역연산과 연산을 사용하여 저 시간복잡도를 줄일 수가 있다. 대충 (n^4) * (n^4) 으로 줄일 수 있고 여기에 각종알고리즘을 적절히 사용하면 속도를 더 끌어 올릴 수 있다.


참조한 글

 CRC 알고리즘과 취약점 - anch0vy : http://anch0vy.tistory.com/60

그리고 문제해결에 결정적인 단서를 받은 

브루트포싱 해야된다고 쐐기를 박아주셔서 삽질할 시간을 줄여주셨다.

이것보다 CRC2는 훠얼씬 어렵다는데 무서워서 못 풀겠다.
어제 길다고 넘어간 sub_20C를 결국 분석해야겠다는 결론에 이르렀다. 

그리고 문자열을 입력하다가 (3)에서 적은내용이 잘못되었다는 것을 알았는데
r29:r28 이 가리키는 곳에 문자열은 (어떤문자, 입력한 문자열) 로 내가 입력한 문자가 아니었다.



위의 그래프를 보면 노란색으로 칠한 부분에서 함수호출이 각각 9번,10번이 발생하고 있다.
저 함수에서 생성된 값이 10바이트 10바이트 인 것과 연관이 있어보인다.

sub_20C를 호출 후 변화가 생기는 데이터는
(r29+0x1):(r28+0x1) 과 (r29+0x1):(r28+0xA) 인데


입력 문자열 : 4321dcbb

sub_20C 진입전 (r29+0x1):(r28+0x1) = 9A 7D 72 57 D5 78 49 E6 F2 02
sub_20C 진입전 (r29+0x1):(r28+0xA) = A6 93 C4 DD 1D 71 DE C4 A0 02

sub_20C진입후 (r28+0x1)):(r28+0x1) = 9A 7D 72 57 D5 78 49 E6 F2 02 (변동없음)
sub_20C 진입후 (r29+0x1):(r28+0xA) = A7 27 89 BB 3A E2 B7 89 A3 02 (전부변함)  


입력 문자열 : reverse1

sub_20C 진입전 (r29+0x1):(r28+0x1) = 9A 7D 72 57 D5 78 49 E6 F2 02
sub_20C 진입전 (r29+0x1):(r28+0xA) = A6 93 C4 DD 1D 71 DE C4 A0 02  


sub_20C 진입후 (r29+0x1):(r28+0x1) = 9A 7D 72 57 D5 78 49 E6 F2 02 (변동없음)
sub_20C 진입후 (r29+0x1):(r28+0xA) = DF ED 6C 99 46 CE A7 87 F0 03 (전부변함)  



(r29+0x1):(r28+0x1) 은 문자열에 관계없이 변화가 없고
(r29+0x1):(r28+0xA) 은 문자열에 따라 변화가 다름을 확인할 수 있었다.

하지만 연산내부를 살펴보니 역연산으로 복원이 불가능한 연산들이 몇 가지 있어서

동일한 10byte로 덮어씌운뒤 쉘에 진입하니 readme 의 내용이 변하였다. 하지만 이전에 있던 내용이 바뀐게 아니라 가리키는 장소가 변한 것으로 보인다.

그럼 여기서 영향을 주는게 저 10byte 인지 아니면 입력한 문자열 그 자체인지를 확인하였다.

입력 문자열 : bungbung 이고 10byte 를 9A 7D 72 57 D5 78 49 E6 F2 02 로 맞췄을 때


입력 문자열 : bungbung 이고 10byte 를 수정하지 않았을 때


다르다! 올ㅋ 혹시나 하는 마음에 다시해보았다.

... 똑같다..

그렇다면 어쨌든 readme 의 데이터는 고정된 위치를 가리키는게 아니라 문자열에 따라 어딘가를 가리키는 것이 아닌가 라는 생각이 들었다.
10byte는 사실상 중요하지않고 입력하는 8개 문자가 중요한것으로 보인다.

어쨌든 cat 명령을 수행 할 때 어떻게 동작되는지 확인하려고 하는데 우연히 data memory 에서 오른쪽 버튼으로 클릭하니 아래와 같은게 보였다.

그렇다. 메모리영역에 접근할 때 브레이크포인트를 거는것이 가능했다!
이걸 왜 어제는 못 봤는지 모르겠지만 있어서 다행이다. 이로써 한결 분석하기 편해졌다.

cat을 입력할 때 점프하는 곳은 0x1B5 였다. 


좀 더 진행하니 sub_661 로 진입한다는 것을 알았다.


ㅎ... 또 멋지고 아름다운 그래프 오버뷰가 나를 맞이해줬다.

sub_20c 를 역연산 하는게 맞을지도 모르겠다..

sub_661 함수 에서 0x6b5 를 대상으로 뭔가를 열심히 읽고있다. 보니 입력한 패스워드문자열이 복사된 곳이다.


여기서 문자를 출력하고 있는데 이것으로는 readme의 내용을 알 수 없을거 같다.
따라서 sub_20c를 다시 분석해야 할꺼 같다.

'reversing.kr' 카테고리의 다른 글

AVR reverse engineering (5) CustomShell  (0) 2018.08.06
reversing.kr CRC1  (0) 2018.02.07
AVR reverse engineering (3) CustomShell  (0) 2018.02.05
AVR reverse engineering (2) AVR ATmega128  (0) 2018.01.30
AVR reverse engineering(1) - 환경구축  (0) 2018.01.29
환경구축과 타겟 머신(ATmega128/L) 에 대략적인 정보를 확인하였으니 본격적으로 문제를 접근해보고자 한다.

먼저 IDA 를 이용해 문자열이 뭐가 있는지 확인해보았다.

이름답게 passwd, shadow 등의 명령어와 readme가 있다.

일단 readme를 읽으면 끝나는게 아닐까? 라는 의심을 가지고 문제에 접근하기로했다.

하지만 우선은 Login 과 Password 에서 입력하는 값을 맞추지 않으면 넘어가지 못할것이다.

어디서 입력값을 뱉는가 Atmel Studio와 IDA를 이용해 찾아보니


sub_729를 호출했을 때 login, password 에 대한 입력값을 받고 r24 레지스터에 리턴값을 저장했다.
설마해서 r24를 1로 넣었더니


오우야 안찾아도 쉘로 들어갈 수 있다!

다행히도 명령어에는


ls와 cat을 지원해준다 사용해본결과 ls -al 도 가능하다

readme 는 tmp 에 있었고, 대망의 cat readme를 입력해보았다.

왓 더.. 안된다 절대 저 사진처럼 문자가 두개씩 들어갔기때문은 아니다!
에러 메시지를 보면 알겠지만 (입력한 문자열) : No such file or directory 로 출력되기때문에 문자열은 제대로 들어갔다고 판단했다.

혹시나 하는 마음에 IDA에서 readme 문자열을 클릭해보았다.


... 띄어쓰기가 있었다 readme(공백문자) 였던 것이다!
공백문자를 쓰고 입력해도 아마 파싱하는 과정에서 공백문자가 제거되기 때문인지 찾을수 없다고 나오기 때문에 직접 저 부분을 00 으로 수정한 뒤 다시 해보았다.

위와 같이 개박살난 문자열이 나온다. 해당 메모리  분석이 필요하다.

IDA로 조회 해봤을 때 zZbN????28?qG 로 처음부터 이 값이 들어가 있음을 알 수 있다.
7A 5A 62 4E 0F 1F 12 03  32 38 1D 71 47 13바이트인데 해시값은 아닌거 같다. 

메모리 브레이크 포인트를 걸고 싶은데 어떻게 거는지 모르겠다.

혹시나 해서 위의 13바이트를 토대로 0~255 xor 연산을 수행했으나 문자열처럼 보이는게 없다.

Login : 에서 받은 문자열과 Password : 에서 받은 문자열을 체크하는 루틴에서 Login에서 일치하지 않은 경우 r24에 0을 넣고 리턴한다.
이 때 거치지 않은 루틴에 Password : 에서 받은 문자열을 가지고 장난질을 하는 sub_205 라는 함수가 있는데 내부를 보면

오우야.. 길고 아름답다.

여기서 하나 가정을 세웠다. 비밀번호도 아이디도 틀린상태에서 r24를 바꿨을 때 readme 값이 변하지 않은거라면,
아이디를 맞춘상태에서 r24를 변경하고 진행했을 때 readme의 내용이 영향이 있을까? 라는 것이었다. 그리고 이 영향을 주는 함수가 sub_20C라고 가정하고 확인해보았다.

sub_20C 수행 전

sub_20C  수행 후


...변화가 없다.

sub_8F5를 수행하고 나서는 변화가 있을지 확인해보았다.

...변화가 없다. ㅠㅠ

로그인 검증루틴 끝날때 까지 없다.

'reversing.kr' 카테고리의 다른 글

AVR reverse engineering (5) CustomShell  (0) 2018.08.06
reversing.kr CRC1  (0) 2018.02.07
AVR reverse engineering (4) CustomShell  (0) 2018.02.05
AVR reverse engineering (2) AVR ATmega128  (0) 2018.01.30
AVR reverse engineering(1) - 환경구축  (0) 2018.01.29
구글에서 검색하다 나온 자료인
Practical Firmware Reversing and Exploit Developmetn for AVR-based Embedded Devices
에서 나온 ATmega128에 대한 정보를 정리하였다.

AVR = Alf and Vegard's RISC processor 

(1) 구조
Modifed Harvard architecture 8-bit RISC single-chip microcontroller 
Haravrd architecture ?
간단히 말하자면 명령어 버스와 데이터 버스를 물리적으로 분할한 컴퓨터 구조

(2) 용도
Industrial PLCs and gateways
IoT
HID devices
Automotive applications
Radio applications
Arduino platform
...

(3)Core


보면 code 와 data가 분리되어있음을 확인 할 수 있다.

(4) Memory Map
-A 유형
0000 ~ FFFF 번지 까지 있음
0000 ~ 001F 는 레지스터 (32)
0020 ~ 005F 는 I/O 레지스터(64)
0060 ~ 00FF 는 External I/O 레지스터(160)
0100 ~ 10FF 는 Internal SRAM
1100 ~         는 External SRAM 
-B 유형
0000 ~ FFFF 번지 까지 있음
0000 ~ 001F 는 레지스터 (32)
0020 ~ 005F 는 I/O 레지스터(64)
0060 ~ 0FFF 는 Internal SRAM
1000 ~         는 External SRAM

(5) Registers
R1~R25 - GPR
X,Y,Z      - pair "working" registers e.g memory addressing operations <- 메모리맵에 26~32번에 해당
I/O registers - 다른 하드웨어에 접근하기 위한 용도

(6) special registers
PC - program counter , 16 bit register
SP - stack pointer, 16 bit register
SREG - status register 8 bit register

(7) Memory addressing
SRAM/EEPROM - 16-bit addressing, 8-bit element 단위는 8bit지만 16bit 간격으로 하나의 번지임
Flash - 16(8)-bit addressing, 16-bit element

'reversing.kr' 카테고리의 다른 글

AVR reverse engineering (5) CustomShell  (0) 2018.08.06
reversing.kr CRC1  (0) 2018.02.07
AVR reverse engineering (4) CustomShell  (0) 2018.02.05
AVR reverse engineering (3) CustomShell  (0) 2018.02.05
AVR reverse engineering(1) - 환경구축  (0) 2018.01.29
아래와 같은 목표를 달성하고자 한다.
  1. QEMU로 해당 펌웨어를 실행시키는 환경 구축해보기
  2. Firmware 를 변경하여 공유기에 올려보기
  3. NAND FLASH의 내용을 추출해보기

Reversing.Kr 에 CustomShell 이라고 AVR revese engineering 문제가 있어서 풀어보려고 한다.


우선 Atmel AVR 8 bit 이기 때문에 이에 맞는 실행 환경을 구축해야한다.

다양한 방법이 있지만,

Atmel Studio 4.19와 HAPSIM을 사용하여 구축하려고 한다.


사실 Linux의 simavr, simulavr 을 사용하려고 했는데, 동작이 내가 예상했던대로 안되는데..

ATmega128L에서 USART를 사용하여 입,출력을 하는데 내가 simavr,simulavr의 USART 입출력을 제대로 다루지 못해 안되는 것이라고 생각되지만 

정확하게 원인을 잘 모르겠다. ㅠㅠ


ATmel Studio 4.19 - https://www.microchip.com/avr-support/avr-and-sam-downloads-archive (스크롤을 내려서 하단에 보면 Atmel studio 4를 다운받을 수 있다.)


HAPSIM - http://www.helmix.at/hapsim/#hapsimdownload 


아무래도 윈도우 10 이전에 나온거다 보니 구동환경은  윈도우 7 32bit 가 적절하다고 생각한다.


이하 환경 구축은


https://blukat29.github.io/2015/09/debugging-avr/ 이 분의 글을 보면서 구축하였다.


(1)초기화면에서 Open을 누르고 기존에 있는 ELF 파일을 누르고 나면 해당화면과 같이 Device를 고를 수 있다. 나는 ATmega128을 선택하였다.

(2)hapsim을 실행시키고 File -> New -> Terminal을 선택하고, Options -> Terminal Settings 에 들어간 후 아래의 화면처럼 Local Echo에 체크하고 USART0을 선택한 후 OK를 눌렀다.



(3) AVR studio 에서 Run 을 누르면 아래와 같이 출력된다. 근데 처음 Run을 눌렀을 때 화면도 안나오고 했었는데, 

AVR studio 에서 start debugging 을 누른 상태에서 hapsim을 실행하고 그 후 (2)을 거친 후 Run 눌러야 잘 동작했다.


'reversing.kr' 카테고리의 다른 글

AVR reverse engineering (5) CustomShell  (0) 2018.08.06
reversing.kr CRC1  (0) 2018.02.07
AVR reverse engineering (4) CustomShell  (0) 2018.02.05
AVR reverse engineering (3) CustomShell  (0) 2018.02.05
AVR reverse engineering (2) AVR ATmega128  (0) 2018.01.30

IDA로 해당파일을 열면 아래와 같은 그래프가 우리를 맞이해준다.

 

 

 

오우야

 

 

어셈블리어로 보면 위와 같은 사진으로 1이 쭉 들어가고 있다.


 

이 부분을 대충보고 넘어갔는데, 뻘짓하다가 다시 돌아와서 보니 4byte 배열로 1이 들어간게 아 니라 듬성듬성 띄워져 있었다.

 

 

 

 

끝없는 1의 나열 끝에 다음과 같이 분기문과 루프문이 보인다. 입력한 문자열로 무언가 하고 있 었는데 이 부분에서 멀쩡한 Hex Ray 기능을 안쓰고 이것만 보고있다가 시간을 까먹었다.

 

Hex Ray 기능을 쓰면 아래와 같이 간결하게 나온다.

 

 

278~285 라인에서 받은 문자열을 4byte 배열에 0 1로 바꿔서 넣는다.


 

그리고 286~296라인에서 01로 표현 4byte 배열을 가지고 이리저리 비트를 뒤집는다.

 

나머지 297~304라인에서 무언가와 비교를 해서 모두다 일치하면 1 아니면 0을 리턴 한다.

 

그 무언가는 앞서 말했던 1이 쭈욱 들어가던 녀석들이다. , 초기에 들어가던 1값을 역산하면 무 언가가 나온다고 생각하였다.

 

Sub_104C에서는 무엇을 하는가 살펴보았는데 아래와 같았다.

 

 

 

 

파라미터 a2 는 문자열길이*8 이었고, a1은 입력한 문자열을 01로 바꾼 배열의 포인터이다. 따라서 해당 함수는 a2배열의 v4번째 원소와 i번째 원소에 대해 if 문 내의 과정을 거치는데 저것을 계산해보면 아래와 같다.

 

A1[i] 의 값을 x a1[v4]의 값을 y라고 한다면

 

14번째라인 a1[i] = x^y

 

15번째라인 a1[v4] = y^(x^y)

 

16번째라인 result a1[i]를 가리키게 한다.

 

17번째라인 result = (x^y)^(y^x^y) = a1[i]

 

XOR 연산에서는 교환법칙 결합법칙이 모두 성립하므로 A1[v4] = y^y^x, y^y = 0 이므로 A[v4] = x

 

 

Result = (x^y)^(y^x^y) = x^(y^y)^x^y = x^x^y = y = a[i] 이다


 

즉 결과적으로 해당 함수의 행동은

 

0~(a2-1) 사이의 인덱스를 rand()%a2 로 구한 후

 

a1[i] a1[v4]를 교환하는 것이다.

 

다시 sub_104c를 호출하는 함수로 돌아가면

 

 

이 곳을 거꾸로 하면 플래그가 출력되겠다는 생각이 들었다.

 

따라서 아래와 같은 과정으로 역산 하는 코드를 작성하였다.

 

1.     gdb에서 비교대상이 되는 배열에서 값을 가져온다.

 

2.     Rand() 함수가 srand()를 사용하여 시드를 바꾸지 않으므로 항상 일정한 패턴의 난수가 출력 출력된다. 따라서 미리 rand()함수를 여러 번 호출하여 rand()값이 들어있는 16*비교대상 배 열 길이의 배열을 생성한다.

 

3.     이 후 295 -> 287순으로 16번 반복하는 코드를 작성한다

 

이렇게 진행하였으나 3에서 문제가 생겨서 안되었다. 저것을 거꾸로 해도 원래의 값이 안 나왔 기 때문 ㅠㅠ

 

뭔가 그레이코드 처럼 보이기도 해서 그레이코드인가 유심히 살펴봤으나 그레이코드도 아니라는 생각이 들었고 어떻게 저 부분을 역연산 할까 고민하다가 생각난 것이

 

v3 값을 처음에 주기 때문에 v3 값을 알고 있고 결과값을 안다면 연산하기 전 값이 출력되지 않을까? 라는 가정을 세우고 다시 역연산을 해보았다.

 

예를들어 v3=1 이고 결과값이 1 일 때, 연산 전 값이 0 라면 결과값이 1이 나오므로 맞다.

 

하지만 v3=1 이고 결과값이 1 일 때, 연산 전 값이 1 이라면 v3 0이 되므로 결과값이 0이 나와야 하므로 모순이다.

 

이런 식으로 v3와 결과값에 대한 테이블을 작성하니 아래와 같이 나왔다.

v3 가 0 일 때

v3 가 1 일 때 

 연산결과 가 0 일 때

 0

 1

 연산결과 가 1 일 때

 1 

 0


따라서 위와 같은 테이블을 참조하여 역연산 하도록 하였다.

 

  

결과가 아래와 같이 출력되었다.

+ Recent posts