래퍼런스도 준다
분석을 굉장히 하게 싫게 생겼다
__int64 __fastcall sub_174A(unsigned int a1)
{
return (unsigned int)__ROL4__(
(((16
* ((4 * ((2 * a1) & 0xAAAAAAAA | (a1 >> 1) & 0x55555555)) & 0xCCCCCCCC | (((2 * a1) & 0xAAAAAAAA | (a1 >> 1) & 0x55555555) >> 2) & 0x33333333)) & 0xF0F0F0F0 | (((4 * ((2 * a1) & 0xAAAAAAAA | (a1 >> 1) & 0x55555555)) & 0xCCCCCCCC | (((2 * a1) & 0xAAAAAAAA | (a1 >> 1) & 0x55555555) >> 2) & 0x33333333) >> 4) & 0xF0F0F0F) << 8) & 0xFF00FF00 | (((16 * ((4 * ((2 * a1) & 0xAAAAAAAA | (a1 >> 1) & 0x55555555)) & 0xCCCCCCCC | (((2 * a1) & 0xAAAAAAAA | (a1 >> 1) & 0x55555555) >> 2) & 0x33333333)) & 0xF0F0F0F0 | (((4 * ((2 * a1) & 0xAAAAAAAA | (a1 >> 1) & 0x55555555)) & 0xCCCCCCCC | (((2 * a1) & 0xAAAAAAAA | (a1 >> 1) & 0x55555555) >> 2) & 0x33333333) >> 4) & 0xF0F0F0F) >> 8) & 0xFF00FF,
16);
}
무서운 함수도 있다
일단 실행시키면 시간이 안된다
컴퓨터 시간을 2030년
으로 바꾸고 하면 실행은 되다? 안되나 하는데 플래그는 안나온다
cf. 이 문제에는
낚시
가 많다
Fishing 0x01. Reference
ptrace
에 대한 레퍼런스가 주어진다
영어로 된 어려워보이는 문헌이지만, 쓸모 없다
읽느라 시간 낭비할 필요가 없다
Fishing 0x02. ptrace
왜일까? 일단 ptrace
는 동적 분석을 하지 못하도록 해주는 함수?이다
동적분석을 막아놓았다는 소리이다
그러면 어떻게 할까?
동적분석을 안하고 정적분석을 하면 된다
Fishing 0x03. rand() and XOR
여기서 랜덤값 2개를 구하고 xor
을 해준다
뭔가 구조적으로는 비슷한데, random
의 값만 바뀌는 것이다
xor
의 중요한 특징 중에는
xor
을두번
하면원래 값
이 나온다
그럼 다시 보면 여기서 차이점은 random
값의 차이이다
random
값은 time
을 기준으로 seed
를 생성하고, 동일한 seed
에는 동일한 random
값이 나온다
비슷한 pwnable
문제도 많다 ()cat jump, randerer, Rock Paper Scissors등등
의문점은
"여기서
seed
가 바뀔까?"
이다
seed
가 바뀌려면 프로그램 코드 실행 후 1초
의 시간이 흘러야 되는데 아무리 오래 걸려도 그렇지 않다
정리하면
동일한
random
값으로두번
xor
연산을 하기에
"XOR 연산들은 쓸모가 없다"
이다
이 부분만 확인해주면 된다
sub_174A
가 무섭게 생긴 함수이고
unk_4020
의 값은
[0x66, 0x0C, 0x4C, 0x86, 0xA6, 0x2C, 0x1C, 0x9C, 0x1C, 0x66,
0x1C, 0x2C, 0x9C, 0x6C, 0xA6, 0xCC, 0xA6, 0x6C, 0x6C, 0xAC,
0xA6, 0xA6, 0x86, 0x4C, 0x2C, 0x46, 0xEC, 0x8C, 0xEC, 0x46,
0x8C, 0x9C, 0x4C, 0xEC, 0xC6, 0x66, 0x4C, 0x46, 0x86, 0x4C]
이다
sub_174A
를 이쁘게 python
으로 바꾸면 (with. GPT)
def sub_174A(a1):
t1 = (2*a1) & 0xAAAAAAAA | (a1>>1) & 0x55555555
t2 = (4 * t1) & 0xCCCCCCCC | (t1 >> 2) & 0x33333333
t3 = (16 * t2) & 0xF0F0F0F0 | (t2 >> 4) & 0x0F0F0F0F
t4 = ((t3 << 8) & 0xFF00FF00) | ((t3 >> 8) & 0x00FF00FF)
result = rol(t4, 16)
return result
이렇게 된다
참고로 python
에서 ror
, rol
연산이 정의가 안되어 있기에,
def rol(data, shift, size=32):
shift %= size
remains = data >> (size - shift)
body = (data << shift) - (remains << size )
return (body + remains)
def ror(data, shift, size=32):
shift %= size
body = data >> shift
remains = (data << (size - shift)) - (body << size)
return (body + remains)
정의를 해줘야 한다
거꾸로 역연산 하는 코드는 GPT와 함께 써보면
def inverse_sub_174A(result):
t4 = ror(result, 16)
t3 = ((t4 & 0xFF00FF00) >> 8) | ((t4 & 0x00FF00FF) << 8)
t2 = ((t3 & 0xF0F0F0F0) >> 4) | ((t3 & 0x0F0F0F0F) << 4)
t1 = ((t2 & 0xCCCCCCCC) >> 2) | ((t2 & 0x33333333) << 2)
a1 = ((t1 & 0xAAAAAAAA) >> 1) | ((t1 & 0x55555555) << 1)
return a1
이렇게 된다
그러면 unk_4020
을 inverse_sub_174A
에 돌려보면
0x66303261
0x65343839
0x38663834
0x39366533
0x65363635
0x65656132
0x34623731
0x37623139
0x32376366
0x32626132
이렇게 나온다
이걸 두개씩 끊어서 list
로 만들면
arr = [0x66, 0x30, 0x32, 0x61, 0x65, 0x34, 0x38, 0x39, 0x38, 0x66, 0x38, 0x34, 0x39, 0x36, 0x65, 0x33, 0x65, 0x36, 0x36, 0x35, 0x65, 0x65, 0x61, 0x32, 0x34, 0x62, 0x37, 0x31, 0x37, 0x62, 0x31, 0x39, 0x32, 0x37, 0x63, 0x66, 0x32, 0x62, 0x61, 0x32]
이렇게 되고, 이를 문자열로 바꾸면
for i in arr:
print(chr(i), end='')
이렇게 나온다
DH{f02ae4898f8496e3e665eea24b717b1927cf2ba2}
로 제출하면
안된다
이유는
여기에 있다
끊어서 넣어준다
그래서 답을 4글자씩 그룹을 만들고, 그 그룹을 뒤집어서 합쳐주면 된다
txt = "f02ae4898f8496e3e665eea24b717b1927cf2ba2"
# f02a
# e489
# 8f84
# 96e3
# e665
# eea2
# 4b71
# 7b19
# 27cf
# 2ba2
# a20f 984e 48f8 3e69 566e 2aee 17b4 91b7 fc72 2ab2
마지막은 손으로 했다
def rol(data, shift, size=32):
shift %= size
remains = data >> (size - shift)
body = (data << shift) - (remains << size )
return (body + remains)
def ror(data, shift, size=32):
shift %= size
body = data >> shift
remains = (data << (size - shift)) - (body << size)
return (body + remains)
def sub_174A(a1):
t1 = (2*a1) & 0xAAAAAAAA | (a1>>1) & 0x55555555
t2 = (4 * t1) & 0xCCCCCCCC | (t1 >> 2) & 0x33333333
t3 = (16 * t2) & 0xF0F0F0F0 | (t2 >> 4) & 0x0F0F0F0F
t4 = ((t3 << 8) & 0xFF00FF00) | ((t3 >> 8) & 0x00FF00FF)
result = rol(t4, 16)
return result
def inverse_sub_174A(result):
t4 = ror(result, 16)
t3 = ((t4 & 0xFF00FF00) >> 8) | ((t4 & 0x00FF00FF) << 8)
t2 = ((t3 & 0xF0F0F0F0) >> 4) | ((t3 & 0x0F0F0F0F) << 4)
t1 = ((t2 & 0xCCCCCCCC) >> 2) | ((t2 & 0x33333333) << 2)
a1 = ((t1 & 0xAAAAAAAA) >> 1) | ((t1 & 0x55555555) << 1)
return a1
arr = [0x66, 0x30, 0x32, 0x61, 0x65, 0x34, 0x38, 0x39, 0x38, 0x66, 0x38, 0x34, 0x39, 0x36, 0x65, 0x33, 0x65, 0x36, 0x36, 0x35, 0x65, 0x65, 0x61, 0x32, 0x34, 0x62, 0x37, 0x31, 0x37, 0x62, 0x31, 0x39, 0x32, 0x37, 0x63, 0x66, 0x32, 0x62, 0x61, 0x32]
for i in arr:
print(chr(i), end='')
txt = "f02ae4898f8496e3e665eea24b717b1927cf2ba2"
# cnt = 0
# temp = ""
# for i in txt:
# if cnt % 5 ==0:
# #print(temp, end=' ')
# print("".join(reversed(temp)), end=' ')
# temp = ""
# else:
# temp += i
# cnt+=1
# f02a
# e489
# 8f84
# 96e3
# e665
# eea2
# 4b71
# 7b19
# 27cf
# 2ba2
# a20f 984e 48f8 3e69 566e 2aee 17b4 91b7 fc72 2ab2
ptrace
를 별생각 안하고 늘 정적분석만해서 그런지 낚시에 안 낚였다
xor
이 필요없는건 신박한 구현이였다
sub_174A
함수가 이해하기 어려웠고, GPT없이는 못 풀었을 것 같다
리버싱에서 역연산이나 &
연산, >>, <<
비트 쉬프트 연산과 ror, rol
연산을 잘 안써보다보니 어려웠고, 많이 배운 문제였다
삽질을 했다면 오히려 안티 리버싱
에 대해서 배울 수 있었을텐데,, 많은것을 배운 문제이다
inverse_sub_174A 함수에서 나온 결과를 2개씩 끊지 마시고 .to_bytes(4, "little")을 이용하여 출력하면 좋아요~