-
CodeEngn Basic RCE 14$ 리버싱 $/CodeEngn Basic RCE 2019. 5. 7. 16:06
해당 문제에서 Name과 Serial을 입력하는 폼이 있는것 같습니다.
한번 파일을 확인해 보겠습니다.
UPX로 Packing 되어 있는 파일입니다.
해당 파일을 UPX.exe 파일로 Unpacking을 해보겠습니다.
Unpacking 한 후의 파일을 확인해 보면 다음과 같습니다.
올리디버거로 열어 보겠습니다.
이런 모습의 코드가 나옵니다.
일단 함수를 확인해서 입력받는 함수를 찾아 보겠습니다.
GetDlgItem 관련 함수를 전부 BP걸어 보았습니다.
F9를 이용해서 이동해 보겠습니다.
4번정도 누르니까 입력을 받기 위해서 대기를 합니다.
Name에 CodeEngn , Serial에 1234를 입력해 보겠습니다.
그러면 004012BD에서 멈춰 있습니다.
4012C2부터 코드를 해석해 보도록 하겠습니다.
004012B1
PUSH 40
Count 40
004012B3
PUSH 14.00403038
Buffer (사용자가 입력한 값을 403038에 저장)
004012B8
PUSH 6A
Control ID
004012BA
PUSH DWORD PTR SS:[EBP+8]
hWnd
004012BD
CALL <JMP.&USER32.GetDlgItemTextA>
GetDlgItemTextA 함수 호출 (Name 입력 Form)
004012C2
CMP EAX, 0
EAX (Name 의 글자수) 와 0 비교
004012C5
JE SHORT 14.004012DF
EAX 가 0 (Name Form에 아무것도 적지 않았을때) 이면 4012DF로 이동
004012C7
PUSH 40
Count 40
004012C9
PUSH 14.00403138
Buffer (사용자가 입력한 값을 403138에 저장)
004012CE
PUSH 6B
Control ID
004012D0
PUSH DWORD PTR SS:[EBP+8]
hWnd
004012D3
CALL <JMP.&USER32.GetDlgItemTextA>
GetDlgItemTextA 함수 호출 (Serial 입력 Form)
004012D8
CMP EAX, 0
EAX (Serial 의 글자수) 와 0 비교
004012DB
JE SHORT 14.004012DF
EAX 가 0 (Serial Form에 아무것도 적지 않았을때) 이면 4012DF로 이동
004012DD
JMP SHORT 14.004012F6
4012F6으로 점프
004012DF
PUSH 0
Style
004012E1
PUSH 14.00403462
Title
004012E6
PUSH 14.00403000
Text
004012EB
PUSH 0
hOwner
004012ED
CALL <JMP.&USER32.MessageBoxA>
MessageBoxA 함수 (입력값이 없으면 출력하는 메시지)
이를 지나면 엄청나게 중요한 알고리즘이 나타납니다.
해당 알고리즘에 대해서 설명을 해보겠습니다.
간략하게 설명하자면 name의 길이를 구하기 -> 길이 만큼 알고리즘을 반복시키기 -> 해강 결과를 ESI에 저장 ->serial 값을 16진수로 변환후 EAX에 저장 -> EAX와 ESI를 비교 -> 분기 의 형식이 됩니다.
004012F6
PUSH 14.00403038
name 값 (CodeEngn)
004012F8
CALL <JMP.&KERNEL32.lstrlenA>
lstrlen 함수 호출 길이 값 EAX에 저장
00401300
XOR ESI, ESI
ESI 0 으로 초기화 00401302
MOV ECX, EAX
ECX에 EAX 값 저장
00401304
MOV EAX, 1
EAX 값에 1 저장
00401309
MOV EDX, DWORD PTR DS:[403038]
EDX에 첫번째 부터 4번째 문자열 저장
0040130F
MOV DL, BYTE PTR DS:[EAX+403037]
DL에 첫 문자열 저장
00401315
AND EDX, 0FF
EDX에 0FF를 AND연산 해서 EDX에 DL이 남도록 함
0040131B
MOV EBX, EDX
EDX값을 EBX에 저장
0040131D
IMUL EBX, EDX
EBX와 EDX 값을 곱한다. 그리고 다시 EBX에 저장.
00401320
ADD ESI, EBX
ESI값에 EBX(제 곱값)를 더한다.
00401322
MOV EBX, EDX
EDX의 값을 EBX에 저장
00401324
SAR EBX, 1
쉬프트 연산자 진행 (S: 쉬프트 , A:산술 , R:우측)
00401326
ADD ESI, EBX
ESI에 EBX값을 더하기
00401328
SUB ESI, EDX
ESI에 EDX값 빼기
0040132A
INC EAX
EAX에 1 증가
0040132B
DEC ECX
ECX에 1 감소
0040132C
JNZ SHORT 14.00401309
ECX값이 0 이면 점프
0040132E
PUSH ESI
ESI값 PUSH
0040132F
PUSH 14.00403138
입력한 Serial 값 PUSH
00401334
CALL 14.00401383
16진수로 변환하는 코드 호출
00401339
POP ESI
ESI값을 POP
0040133A
CMP EAX, ESI
EAX와 ESI 비교
0040133C
JNZ SHORT 14.00401353
같으면 분기
위처럼 알고리즘이 반복합니다.
그렇게 하고 40133A 주소에 도착하면 다음과 같은 문자열을 확인 할 수 있습니다.
EAX는 제가 입력한 1234가 16진수로 들어간 것이므로
진짜 Serial은 129A1 입니다 이를 10진수로 변환 하면 다음과 같습니다.
129A1 = 76193
Serial 값은 76193입니다.
'$ 리버싱 $ > CodeEngn Basic RCE' 카테고리의 다른 글
CodeEngn Basic RCE 16 (0) 2019.05.07 CodeEngn Basic RCE 15 (0) 2019.05.07 CodeEngn Basic RCE 13 (0) 2019.05.06 CodeEngn Basic RCE 12 (0) 2019.05.06 CodeEngn Basic RCE 11 (0) 2019.05.06