에이전트에게 질문하기
앱에 표시되는 로그인 코드는 계속 바뀝니다. 무엇 때문에 바뀌는지 찾아 그 동작을 재현하려고 합니다.
REA로 aegis-v3.4.3.apk을 분석해 주세요. 6자리 로그인 코드가 어떻게 생성되고 왜 30초마다 바뀌는지 설명한 뒤, 시간을 바꿔 볼 수 있는 작은 데모를 만들어 주세요.
다운로드한 APK를 분석하는 예시 프롬프트입니다. 먼저 REA의 Android 분석 환경을 설정하세요. APK와 분석 설정 받기 ↓
코드 생성기 사용해보기
앱은 시간을 30초 단위로 나눕니다. 시간 구간 번호와 계정 키를 결합해 코드를 생성합니다. 같은 키와 같은 시간 구간이면 같은 코드가 나옵니다.
60초 구간에서 시간 바꾸기
- 시간 초시간을 조절할 수 있는 예제 시계
-
30초 구간구간
floor(59 / 30)
30~59초 - 생성된 코드계정 키 + 시간 구간 → 여섯 자리 숫자
59초: 287082. 60초: 359152. 같은 구간 안에서는 시간을 바꿔도 코드가 유지됩니다.
REA로 코드 찾기
-
APK에서 클래스 3개로 좁히기
에이전트 → REAinspect_android_package {"path": "aegis-v3.4.3.apk"} search_android_classes {"path": "aegis-v3.4.3.apk", "query": "Totp"}REA → 에이전트 · 결과 발췌Package: com.beemdevelopment.aegis Version: 3.4.3 Classes: 3,077 Three matches: otp.TotpInfo ui.views.TotpProgressBar importers.TotpAuthenticatorImporterTotpInfo은 계산 코드의 후보이며, 나머지 둘은 진행률 표시줄과 가져온 계정에 관련됩니다. TOTP는 시간 기반 일회용 비밀번호입니다. -
코드 생성기와 앱 화면 연결
에이전트 → REAinspect_android_class {"path": "aegis-v3.4.3.apk", "class_name": "com.beemdevelopment.aegis.otp.TotpInfo"} trace_android_references {"path": "aegis-v3.4.3.apk", "class_name": "com.beemdevelopment.aegis.otp.OtpInfo", "method_name": "getOtp"}REA → 에이전트 · 메서드와 호출 함수TotpInfo methods: getOtp() · overload 0 getOtp(long) · overload 1 OtpInfo.getOtp callers: ui.views.EntryHolder.getOtp ui.MainActivity.copyEntryCodeREA가 타임스탬프 오버로드를 식별하고 기본 메서드의 호출자를 찾습니다. 이어서
EntryHolder.getOtp을 살펴보면 화면에서TotpInfo.getOtp(timestamp)을 호출하는 것을 확인할 수 있습니다.
요청의 입력 경로는 줄여 표시했습니다. 결과의 클래스 이름에서는 공통 접두사 com.beemdevelopment.aegis을 생략했습니다.
계산 읽기
REA는 시간 변환, 기본 설정, 생성 메서드를 반환합니다. 생성자는 간격을 30초, 자릿수를 6으로 정합니다. 타임스탬프 메서드는 초를 시간 구간 번호로 바꿉니다.
// TotpInfo defaults and clock
setPeriod(30);
getOtp(System.currentTimeMillis() / 1000);
// OtpInfo default algorithm and digits
this(bArr, "SHA1", 6);
// Block passed to the generator
(long) Math.floor(j / ((double) this._period))
// generateOTP → getHash
byte[] hash = getHash(bArr, str, j);
// getHash: account key + encoded block
Mac mac = Mac.getInstance(str);
mac.init(secretKeySpec);
return mac.doFinal(bArrArray);
// OTP.toString, case 0
this._code % ((int) Math.pow(10.0d, i))
// Keep leading zeroes
while (sb.length() < i) {
sb.insert(0, "0");
}
// Group time into 30-second blocks
seconds = current_time_ms / 1000
block = floor(seconds / 30)
// Generate a number from the key and block
hash = HMAC_SHA1(account_key,
big_endian_8_bytes(block))
number = select_31_bits(hash)
// Format the default six-digit code
code = number % 1_000_000
code = pad_with_zeroes(code, 6)
시간으로 구간을 정합니다. 30~59초는 모두 구간 1이며, 60초가 되면 구간 2로 바뀝니다.
키도 중요합니다. 생성기는 계정 키와 시간 구간을 결합합니다. 키가 다른 계정은 같은 시점에도 다른 코드를 표시할 수 있습니다.
6자리를 유지합니다. 1,000,000으로 나눈 나머지의 앞자리를 필요에 따라 0으로 채우므로, 코드는 0으로 시작할 수도 있습니다.
분석한 여러 메서드에서 발췌했으며, 표시를 위해 줄바꿈을 적용했습니다. 오른쪽 패널은 설명을 위한 요약입니다. Aegis 코드의 라이선스는 GPL-3.0입니다.
생성기 내부
배포된 APK에서는 generateOTP가 kotlin.ExceptionsKt에 들어 있습니다. REA는 TotpInfo에서의 호출을 추적해 이 함수 본문을 반환합니다. 원본 소스에서는 이 도우미 함수를 HOTP라고 부릅니다.
public static OTP generateOTP(byte[] bArr, String str,
int i, long j)
throws NoSuchAlgorithmException, InvalidKeyException {
byte[] hash = getHash(bArr, str, j);
int i2 = hash[hash.length - 1] & 15;
return new OTP(
(hash[i2 + 3] & 255)
| ((hash[i2] & 127) << 24)
| ((hash[i2 + 1] & 255) << 16)
| ((hash[i2 + 2] & 255) << 8), i, 0);
}
해시의 마지막 바이트로 위치를 고릅니다. 그 위치의 4바이트로 양의 31비트 수를 얻고, 요청한 자릿수로 줄여 표시합니다. 생성자의 마지막 인수는 컴파일 과정에서 생긴 코드 서식 분기를 선택합니다.
재구성 결과 검증
REA가 반환한 Java 메서드 일부를 작은 테스트 프로그램으로 묶었습니다. 시간 구간 경계와 0으로 시작하는 코드를 포함한 133개 테스트 사례에서 독립적으로 재구현한 결과와 출력이 일치했습니다.
| 예제 시간 | 구간 | 6자리 코드 |
|---|---|---|
| 30초 | 1 | 287082 |
| 59초 | 1 | 287082 |
| 60초 | 2 | 359152 |
| 1,111,111,109초 | 37,037,036 | 081804 |
생성기는 RFC 6238에 공개된 SHA-1 기준 사례 6개와도 일치합니다. 브라우저 구현을 이 사례들과 비교해 보세요:
기준 사례는 8자리를 사용합니다. 검사에서는 이에 대응하는 6자리 결과도 검증합니다.
검증에서는 추출한 Java 메서드와 새 데모를 실행합니다. Android APK 자체는 정적 분석으로 검사했습니다.
직접 APK 분석하기
macOS나 Linux에서 REA를 설정한 뒤, 이 두 파일을 같은 폴더에 다운로드하세요. Windows에서는 WSL 같은 Linux 환경을 사용하세요.
Android 분석에는 전체 JDK 17 이상이 필요합니다. JAVA_HOME 또는 PATH로 사용할 JDK를 선택하세요. 이 사례에서는 JDK 21을 사용했습니다.
REA에 분석 도구 파일을 지정하고 APK를 분석하세요:
REA_JADX_MCP_JAR="$PWD/jadx-headless-mcp-0.7.1-all.jar" \
npx rea-agents@latest inspect-android-package \
./aegis-v3.4.3.apk --format json --full-output
에이전트는 위 프롬프트로 REA CLI를 통해 분석을 이어갈 수 있습니다. MCP를 사용하려면 REA 서버 환경에 REA_JADX_MCP_JAR을 추가하고 다시 연결하세요.
다음 질문: 계정이 8자리 코드나 다른 시간 간격을 사용하면 어떻게 될까요?
출처
2026년 10월 9일 REA 6.1.0으로 분석했습니다. 디컴파일 발췌문의 출처는 Aegis이며, 그림과 요약, 브라우저 재구현은 새로 만든 교육 자료입니다.