2026-10-18 · Android 정적 분석 · 제품 구현 전 조사
19개 은행 중 17개 APK 확보·매니페스트 해독·서명 검증. REA/JADX로 진입점과 관련 코드를 추적했다. 실기기 실행 검증은 0개다. 17/19는 조사 APK 확보율 89.5%이며 앱 실행 성공률이나 이용자 점유율이 아니다.
하나의 매장 QR로 공통 웹페이지를 열고, 사용자가 선택한 송금 앱에서 가능한 가장 깊은 단계로 연결한다. 계좌 복사·앱 실행은 최소 기능이며, 은행별로 이체 화면·수취 계좌·금액 입력까지 조사했다. 은행 버튼은 보낼 앱을 선택하는 것이며, 전달하는 수취은행과 계좌는 매장의 값으로 유지한다. 토스·부산에는 수취 계좌와 금액을 처리하는 코드, KB·IBK·신한에는 수취 계좌·금액 전달 후보, 경남에는 수취 계좌 전달 후보가 있다. 카카오뱅크·농협·우리·산업·수협·전북·SC에서도 구체적인 이체 화면 연결 근거를 확보했다. 카카오페이는 은행 19개와 별도로 공식 계좌·금액 앱링크 규약을 확인했다. 나머지도 단순 스킴 목록이 아니라 실제 수신 처리부/화면 전달부 또는 보호 코드 경계까지 기록했다.
19개 중 외부 앱 진입 근거는 APK 17개와 하나 공식 웹을 합쳐 18개다. 특정 이체 대상까지 조합한 경로는 13개, 이 중 수취계좌 직접 전달 후보는 6개(토스·부산·KB·IBK·신한·경남)다. 코드의 완성도는 표에 따로 구분했다. 산업은행의 구형 화면 클립보드 입력 경로는 별도 대안이며 직접 쿼리 전달 6개에 넣지 않았다. 실기기 성공은 모든 단계에서 0개다. 80% 기준은 최소 16개 은행이 실제로 해당 동작에 성공해야 충족한다.
Android Chrome은 사용자 클릭으로 BROWSABLE 앱 진입점을 여는 intent 링크와 설치되지 않았을 때의 대체 URL을 지원한다. HTTPS 웹에서 계좌 복사도 가능하다. 따라서 QR→공통 HTTPS 페이지→은행 선택→가장 깊은 확인 경로, 그리고 계좌 복사 기능이라는 구조를 위해 별도 사용자용 앱이 반드시 필요하지는 않다. 그러나 앱 내부에서 받지 않는 수취 인자를 웹이나 별도 앱이 임의로 채울 수 있다는 뜻은 아니다. iOS는 은행별 별도 검증 범위다.
Chrome 공식 Intent 문서 · Clipboard writeText 문서
supertoss://send?amount=0&bank=신한은행&accountNo=[마스킹]&origin=qr
macOS Vision으로 사용자 첨부 PNG를 해독했다. 토스 앱에서 신한은행 수취 계좌로 보내는 링크다. 원문은 프로젝트 evidence/qr에 보관했고 이 보고서에는 실제 계좌번호를 넣지 않았다. APK 수취 화면에서 accountNo, bank 또는 bankCode, 양수 amount 처리 코드를 확인했다. 금액 0을 양수 금액으로 취급하지 않는 분기도 확인했다.
카카오페이 공식 계좌송금 앱링크 가이드에는 계좌+금액, 계좌만, 빈 이체 화면의 세 동작이 명시되어 있다. 알림톡 문서의 alimtalk= 접두어를 일반 브라우저 링크에 그대로 붙이지 않는다. 공식 웹 브리지의 /t/ 경로는 카카오톡 내 카카오페이로 연결한다. 카카오뱅크는 별도 APK에서 widget 및 multiple_transfer 명령을 확인했다.
‘전달’은 코드상 데이터 흐름을 뜻한다. 서버가 수락하고 실제 화면에 채워지는지는 실행 검증이 필요하다. ‘미확정’은 기능이 없다는 뜻이 아니다.
| 은행/앱 | 근거 | 확인 깊이 | 진입점/후보 | 남은 경계 |
|---|---|---|---|---|
| KB국민 | APK | 이체 화면 + 수취계좌/금액 전달 후보 | kbbank://call?id=qr&cmd=move_to&url={encoded /mquics?page=D001474}&urlparam={encoded fields} | 외부 urlparam→Bundle와 클립보드→D001474 공통 경로. 입금계좌번호/입금은행코드/입금은행명/이체금액/pReceiveAmtYn=1 확인. 실제 화면 수락 미검증 |
| 신한 | APK+공식 웹 | 이체 화면 + 수취계좌/금액 전달 후보 | shinhansol://SM0101S0010T01?receiverNumber={계좌}&receiverBankCode={코드}&receiverBankName={은행명}&receiverName={예금주}&amount={금액} | 공식 link.html→외부 URI→EntryViewModel JSON까지 확인. 공식 내부 JS의 동일 이체 화면 인자와 조합. startMainActivityWithUri 보호 opcode로 로그인 이후 값 보존 미확정 |
| 우리 | APK+공식 웹 | 이체 화면 후보 NWTSW00001_001M | wooribank://call?JSON_DATA={encoded JSON} | ACTION_URL/ACTION_PARAM/ROUTE_DATA 전달; 수취 필드 소비 화면은 추가 검증 필요 |
| 하나 | 공식 웹 | 화면 주소 전달 | hanabank-oqf:// | 신규 com.hanabank.oqf APK 미확보; 공식 oneqplus.jsp에서 앱 연결 확인 |
| NH농협 | APK | 이체 serviceId NSFTP0101R + 클립보드 파싱 | newnhsmartbanking://sbbank?DATA={encoded JSON} | DATA 저장→NHMain→JS serviceId/params 전달. 실제 이체 화면은 인증 세션 필요; 직접 계좌 인자 미확정 |
| IBK기업 | APK+공식 웹 | 이체 화면 + 수취은행/계좌/금액 전달 후보 | ionebank://openmenu?menuid=trn_trn_000100_1&mnrc_bncd={코드}&mnrc_acno={계좌}&tran_amt={금액} | 공식 openmenu 생성자 + APK 내장 goLogin 예제 + 공통 MenuData.param 경로. param으로 감싸지 않고 최상위 query로 전달. 현재 서버 메뉴·필수 필드·실제 화면 미검증 |
| SC제일 | APK+공식 웹 | 계좌이체 경로 + 클립보드 읽기/파서 | accom.scbank.ma30://ma30sso?t=redirect&goTo=%2Ftransfer%2FMA3TRNSTR001.mnu | 공식 HTML의 이체 경로와 앱 링크 생성자 결합. 공개 GET은 메뉴 ID 보존 후 로그인/앱 전용 안내. 수취 인자 및 클립보드→이체 필드 연결 미확정 |
| 씨티 | APK | 외부 URI와 쿼리 5개 파싱 | citimobileapp://sms 또는 citimobileapp://smartpay | 키 문자열 보호. smartpay를 일반 계좌이체로 간주하지 않음 |
| KDB산업 | APK+공식 웹 | 현재 건별이체 화면 + 별도 구형 화면의 클립보드 선입력 후보 | smartkdb://go_page?COM_ID=MPTFQT04N10 | 현재 화면의 계좌 필드는 PAGE_DATA_MAIN에서 소비되나 외부 쿼리 연결 미확정. 별도 MPTFCO04N10은 비밀번호/계좌 검사와 사용자 확인 후 클립보드 계좌·금액을 입력하는 코드 존재. 구형 경로 실행 가능성은 미검증 |
| Sh수협 | APK+공식 웹 | 계좌이체 메뉴 PSM00162 | suhyuppsmb://suhyuplink?menuId=PSM00162 | 공식 전체메뉴에서 계좌이체 ID 확인. linkParam JSON 추가 전달 가능. 공개 GET은 로그인으로 이동; 수취 계좌 필드 미확정 |
| iM | APK | 외부 진입 | mbanking://openservice 등 등록 host 필요 | 매니페스트의 진입 클래스 본문을 현재 DEX에서 찾지 못함; 보호 코드 경계 |
| 부산 | APK+공식 웹 | 수취은행/계좌/금액의 이체 화면 소비 코드 | bslink://call?mnu=MBPTWD1000TWD10&DEPS_BNKCD={코드}&DEPS_ACNO={계좌}&TRNF_AMT={금액} | ServiceMenu.parameter→parameter2→LOGIN_MENU_PARAM2→TransferFragment 변수 연결. smali 분기 대조. 로그인·현재 메뉴표·확인 상태 XF1.w() 및 실행 미검증 |
| 경남 | APK+공식 웹 | 이체 화면 + 수취은행/계좌 전달 후보 | alopex://psb?url={encoded URL} | 경로 knsb/sbp/trn/SBPTRNS10IPTV00M.html; RCV_BK_CD/RCPE_RCV_ACT_NO. 정적 경로 조합이며 실기기/서버 수락 미검증; 금액 키 미확정 |
| 광주 | APK+공식 웹 | 공식 웹의 화면ID+JSON 전달 | kjbank://asb?u={encoded path and JSON} | APK 진입점은 등록되어 있으나 본문은 패킹 경계. 수취 필드 미확정 |
| 전북 | APK+공식 웹 | 계좌이체 화면 P_M_TRN219001_91 | jbprivatebank://jbprivate?byPassData={encoded JSON action/data} | 공식 생성자가 {action,data} 평문 JSON을 인코딩. APK→JS JSON.parse→로그인 검사→form.move. 공개 화면은 SVC_LOGIN_CHECK; 수취 계좌 필드 미확정 |
| 제주 | APK 미확보 | 미확정 | 미확정 | com.jejubank.smartnew 공개 다운로드 경로 확보 실패; 불가능 판정 아님 |
| 카카오뱅크 | APK | 로그인 후 계좌이체 화면 | kakaobank://widget?type=transfer_open | widget/transfer_open 문자열 정적 복호화→ACCOUNT 모드→CanI 접근 검사. 다른 type=transfer 경로도 있으나 raw 계좌번호 전달 확인 못 함; seqNo 의미 미확정 |
| 케이뱅크 | APK+공식 웹 | 메뉴ID와 쿼리를 앱 WebView 주소로 전달 | ukbanksmartbankweb://?{JSON} | DeepLinkViewModel.makeSchemeUrl; 이체 메뉴 및 일부 보호된 JSON 키 미확정 |
| 토스 | 사용자 QR+APK | 수취은행/계좌/금액 소비 코드 | supertoss://send?bank={은행명}&accountNo={계좌}&amount={금액}&origin=qr | 사용자 QR 해독. bankCode도 처리. 양수 amount를 처리하는 수취 화면 코드, SendActivity→TransferSendActivity 연결. registry의 SendActivity 연결은 확인했으나 암호화된 send 키 평문 연결은 미완료. 실제 실행 미검증 |
| 카카오페이 (별도) | 공식 가이드+공식 웹 JS | 수취은행/계좌/금액 선입력 규약 | https://link.kakaopay.com/t/money/to/bank?bank_code={코드}&bank_account_number={계좌}&amount={금액} | 공식 문서는 알림톡 범위. 현재 웹 브리지는 kakaotalk://kakaopay/...로 경로/쿼리 유지. 외부 브라우저 실기기 검증 필요 |
LinkTo 공개 데모와 공개 transfer-apps 응답·클라이언트 생성자를 확인했다. 토스·카카오페이에는 계좌와 금액 템플릿이 있으나, 다른 항목 상당수는 앱 스킴만 있고 일부는 enabled=true여도 스킴 값이 없다. 표시된 은행 수를 실제 이체 화면 또는 계좌 자동입력 지원 수로 세면 안 된다. 이 조사는 별도로 현재 APK의 host 조건과 실제 소비 코드를 대조했다.
REA 6.5.0 + 고정된 JADX headless 0.7.1 JAR + JDK17을 사용했다. 보존된 REA package 결과 13개 중 8개는 성공 Evidence, 5개는 오류 기록이며, 실패 또는 미실행 건은 직접 JADX/AXML 조사와 구분했다. 따라서 17개를 모두 REA로 완전 복원했다는 의미가 아니다. 큰 토스 APK에서 REA 시간 제한과 4GB 메모리 한계를 만났고, 같은 JADX 엔진의 직접 API를 8GB로 사용해 관련 Java와 smali를 추출했다. 직접 추출 결과를 REA Evidence로 표시하지 않았다. 난독화/Java 복원 오류는 원본 smali와 함께 남겼다. 문자열 복호화는 상수와 알고리즘을 별도 코드로 재현했으며 대상 앱 초기화 코드는 실행하지 않았다.
일부 화면은 서버에서 로그인 후 내려오거나 앱이 실행될 때 보호된 코드를 풀어 사용한다. 농협의 정확한 이체 화면 공개 GET은 인증 세션 오류를 반환했다. 해당 화면의 필드 소비 여부는 추측하지 않았다. 하나·제주는 추가 공개 경로 약 30개까지 조사했으나 APK를 확보하지 못했다. 하나의 현재 앱 실행 스킴은 공식 웹에서 별도 확인했다. 제주의 현재 패키지는 확인했으나 실행 스킴은 미확정이다. 사용자 기기 로그인·송금·은행 앱 설치는 수행하지 않았다.
구현 시작 전 남은 항목은 bank-matrix.json과 은행별 findings의 remaining/limitations에 기록했다.