[Reversing2]

‍허진·2023년 3월 27일
0

hacking

목록 보기
5/7
post-thumbnail

Assignment1 - xor

IDA로 까봤다.


가장 중요한 부분은 for분 내부로 보인다.
a[i] 와 xor1[i] ^ v4[i] ^ xor2[i]가 같아야 한다!


a와 xor1, xor2에 저장된 값들을 확인할 수 있었다.

정리하면 다음과 같다.

xor에는 몇가지 성질이 있다. 자기 자신과 xor하면 0이 되고, 0과 xor하면 자기 자신이 되는 것이다. 그러므로 양변에 xor1과 xor2를 xor하여 a[i] ^ xor1[i] ^ xor2[i]로 v4의 값을 구할 수 있다.


다음과 같이 코드를 작성했다.


flag를 얻어냈다.

성공!

Assignment2 - bf

IDA로 까봤다.

역시나 for문 안을 살펴보자. v3는 a[i]와 v5[i]를 곱한 값이다.

그리고 HIBYTE(v3) + LOBYTE(a[i]) * v5[i]) - HIBYTE(HIDWORD(v3))가 b[i]와 다르면 안된다.

HI, LO가 있고, BYTE와 DWORD가 있는 것으로 보아, HIBYTE는 상위 1바이트, LOBYTE는 하위 1바이트, HIDWORD는 상위 4바이트를 뜻하는 것으로 보인다.


일단 a,b에는 다음 값들이 주어져있었다.

(unsiged __int8)(HIBYTE(v3) + LOBYTE(a[i]) * v5[i]) - HIBYTE(HIDWORD(v3)) != b[i]는 복잡해보이지만 정리해보면 간단하다.

먼저 HIBYTE(HIDWORD(v3))는 HIDWORD(v3)는 v3가 4byte 이상의 값이 될 수 없으므로 무조건 0이다.

또한, HIBYTE(v3) 역시 상위 1바이트를 뜻하는데, v3에 8바이트(__int64) 공간이 있지만 최댓값으로 가능한 것이 2바이트 이므로 HIBYTE(v3)도 0이다.

LOBYTE(a[i]) * v5[i])은 a[i]의 하위 1바이트는 a[i]이므로 v3에 해당한다. 따라서 위의 식은 v3의 하위 1바이트가 b[i]와 다른지를 판단하는 것으로 생각할 수 있다.


따라서 다음과 같이 함수를 선언하고, brute forcing으로 v5에 해당하는 문자열을 찾아냈다.

flag를 찾은 것 같다.

성공!

Assignment3 - maybe_easy

IDA로 까봤다.

str에 입력을 받는다. 입력은 26byte여야 한다! for문 안에서는 i가 1부터(++i이므로) 늘어나면서, two_xor과 Composite 함수를 호출하고, 그 값을 table과 비교하는 듯 하다. 먼저 table과 checktable을 확인해보자.


table은 위와 같다.


chektable은 길게 선언되어 있다.

둘을 정리하면 다음과 같다.

이제 two_xor 함수 내부를 보자.


매겨변수 a1과 a2에는 v6배열과 i가 전달되었다. 반환하는 값을 보면, a1 주소에서 a2번째 요소를 가리키는 주소를 참조하여 해당 주소의 4바이트 값(v6배열의 i번째 요소)과, 2의 a2승(1<<a2) mod 157을 xor연산한 값이다.
그렇게 복잡하지 않다!

이번엔 Composite 함수 내부를 보자.

매개변수 a1과 a2에는 각각 checktable과 v6 배열을 전달받았고, a3에는 i가 전달되었다.

먼저 v5에 a2 주소에서 a3번째 요소를 가리키는 주소를 참조하여 해당 주소의 4바이트 값(v6배열의 i번째 요소)를 저장한다.

그리고 반복문을 실행하는데, a1 주소에서 v5번째 요소를 가리키는 주소를 참조하여 해당 주소의 4바이트 값(checktable의 v5번째 요소)으로 v5을 업데이트한다. 이 반복문은 총 a3(i)번만큼 진행된다.

약간 복잡한듯하지만, i만큼 checktable에서 값을 찾고, 다시 그 찾은 값번째 값을 찾는 작업을 반복하는 것이다!

그리고 반복문을 마치면, 마지막으로 반환한 값을 table의 i번째 값과 비교한다.

해결한 코드는 다음과 같다. 역연산을 수행해야 하므로, 먼저 table의 i번째 값을 저장하고, checktable에서 몇번째 요소가 이와 같은지 찾는다.

그리고 Composite 함수에서 i만큼 반복문을 수행했으므로 checktable에서 값을 찾고 업데이트해서 다시 찾는 과정을 i만큼 수행한다.

마지막으로 그렇게해서 나온 값을 2의 i승 mod 157과 xor하면 str의 각 자리 요소를 얻을 수 있다!


i가 1일때부터 진행하여 0번째 요소는 상관없긴 하다 ^^;;


성공!

Assignment4 - chall6

IDA로 따봤다.

아주 간단해보인다. 함수이름은 chall6으로 바꿔주었다. 입력받은 v4 배열을 매겨변수로 전달하는 함수이다.

chall6함수를 보았다.


쉽다. 매겨변수로 받은 a1의 i번째 요소를 가리키는 주소값에서 1바이트 값을 읽어와서, arr1 배열의 해당 값번째 요소와 arr2의 i번째 요소를 비교하는 것이다.

arr1배열과 arr2배열은 다음과 같다.

정리해보았다.


이전 문제에서 했던 것과 마찬가지로, arr2의 i번째 값을 key로 저장해놓고, arr1에서 key와 같은 값이 몇번째 요소에 위치하는지 파악하여 그 수를 flag에 저장한다.
이와 같은 과정을 거치면 우리가 입력해야 하는 flag를 얻게 된다.

코드는 다음과 같다.

flag를 얻어냈다.

그대로 복붙하면,

성공!

Assignment5 - chall7

IDA로 따봤다.


scanf로 문자열을 입력받고, 이를 chall7함수의 매개변수로 전달한다.

chall7함수를 보도록 하자.


if문을 해석해보면,
a1 배열의 i번째 요소를 i & 7만큼 rol한 값이 arr 배열의 i번째 값과 i를 xor한 값과 같아야 한다.

먼저 arr을 보자.

정리하면 다음과 같다.

rol과 ror은 일반적인 쉬프트연산과 다르므로 함수로 따로 구현해주었다.
참고

위의 코드는 ror함수를 따로 구현하고, 역연산을 취해서 값을 flag에 저장하고 이를 출력하는 코드이다.


코드 실행 결과는 위와 같았다.


성공!

Assignment6 - chall8

IDA로 까봤다.


scanf로 문자열을 입력받고, 이를 chall8함수의 매개변수로 전달한다.

chall8함수를 보도록 하자.

-5에 a1의 i번째 값을 곱하고 1byte로 자른 뒤, 이를 arr의 i번째 값과 비교한다.

먼저 arr은 다음과 같다.

정리해보았다.

1byte로 자르는 과정이 포함되기에 역으로 구하는 것은 힘들어보이고, brute force로 구해보았다.

코드는 간단하다. k를 증가시켜가면서 arr의 i번째 값과 같다면 이를 flag에 저장하고 출력하는 것이다.


실행결과과 위와 같았다. 브루트 포싱한 거 딱 걸렸다. ^^;;


성공!

Assignment7 - chall9

IDA로 까봤다.

메인 함수는 이전과 비슷하다.

chall9 함수를 살펴보자.


인자로 전달받은 문자열의 길이를 확인한다. 길이가 8의 배수이면 안된다.

그 다음 key 함수에 인자로 문자열을 다시 보내는데, 8바이트 단위로 끊어서 전달한다.

마지막으로 다시 문자열과 checktable을 0x19만큼 비교하고 값을 반환한다.

key 함수를 살펴보자.


for문 내부를 살펴보자. 함수의 인자로 전달받은 배열을 한 바이트씩 수정해나간다. 이때 uint8로 자르고, ROR 하는 과정도 존재한다.

먼저 arr을 살펴보자.


정리하면 다음과 같다.

checktable 또한 살펴보자.

정리하면 다음과 같다.

역연산을 수행해야 한다.

for문에서 1씩 증가시키면서 수행한 부분은 1씩 감소하면서 진행한다.

ROR은 ROL로 대체하고, unit8로 자르는 것도 잊지 않으면서 이항을 통해 checktable의 값을 다시 되돌려야 한다.


구현한 함수는 다음과 같다. for문 내부에서는 역연산을 수행하고 있으며, a1이라는 임시 리스트를 바탕으로 b1(checktable의 값을 가짐)을 8바이트씩 나누어서 진행하고 있다.

flag를 얻었다!


성공!

profile
매일 공부하기 목표 👨‍💻 

0개의 댓글