저번 rev-basic-3 풀이에 이어 rev-basic-4도 풀어보려고 한다.
파일을 실행해보았을 때, Input으로 입력을 받고 입력받은 값에 대해 Wrong 혹은 Correct를 출력하는 것 같다.
파일을 실행해보았을 때 보였던 Wrong
라는 문자열이 있는 부분으로 가보았다.
함수가 몇개 보이는데, Wrong과 Correct를 가르는데에는 uVar1가 0인지, 0이 아닌지만 중요하므로 FUN_140001000
함수만 분석하면 될 것 같았다.
FUN_140001000
함수 들어가보기들어가면 아래와 같은 코드가 보인다.
가장 중요한 부분은 아래의 부분같다.
if (((int)(uint)*(byte *)(param_1_local_118 + (int)local_18) >> 4 |
(*(byte *)(param_1_local_118 + (int)local_18) & 15) << 4) !=
(uint)(byte)(&DAT_140003000)[(int)local_18])
break
문제를 풀면서 쉬프트, 비트 or, 비트 and 연산에 대해 공부할 수 있었다.
예를들어 16진수 F5(이진수 : 1111 0101)에 대하여 위의 연산을 수행한다고 해보자.
// dec : 0xF5를 10진수로 변환
const dec = parseInt('F5', 16);
// bin : 2진수로 변환
const bin = dec.toString(2);
console.log('dec: ', dec); // 245
console.log('binary: ', bin); // 1111 0101
// 상위 4비트 추출 후 오른쪽 시프트
// &0xF0을 하는 이유 : 0xF0는 1111 0000이고 비트 & 연산을 하면 상위 4비트만 유지, 하위 4비트 0으로 제거
// 상위 4비트를 오른쪽으로 이동하여 하위 4비트 위치로
console.log(((dec & 0xf0) >> 4).toString(2)); // 0000 1111
// 하위 4비트 추출 후 왼쪽 시프트
// &0x0F를 하는 이유 : 0x0F는 0000 1111이고 비트 & 연산을 하면 하위 4비트만 유지, 상위 4비트 0으로 제거
// 하위 4비트를 왼쪽으로 이동하여 상위 4비트 위치로
console.log(((dec & 0x0f) << 4).toString(2)); // 0101 0000
// 추출한 상위 4비트와 하위 4비트를 OR 연산(합치기)
const res = ((dec & 0xf0) >> 4) | ((dec & 0x0f) << 4);
console.log(res.toString(16)); // 0101 1111 (0x5F)
// 즉 연산을 수행하면 앞부분과 뒷부분이 바뀜. 0xF5 => 0x5F
const rawData = ['24', '27', '13', 'C6', 'C6', '13', '16', 'E6', '47', 'F5', '26', '96', '47', 'F5', '46', '27', '13', '26', '26', 'C6', '56', 'F5', 'C3', 'C3', 'F5', 'E3', 'E3'];
let result = [];
for (let i = 0; i < rawData.length; i++) {
// 배열의 문자열을 16진수로 변환
array_dec = parseInt(rawData[i], 16);
// 연산 후 빈 배열에 넣기
let converted = ((array_dec & 0xf0) >> 4) | ((array_dec & 0x0f) << 4);
result.push(String.fromCharCode(converted));
}
// Br1ll1ant_bit_dr1bble_<<_>>
// 배열에서 문자들을 모아서 하나의 문자열로 출력하기
console.log(result.join(''));
Correct가 출력되었다!