IZH318 / Word-Apps-JLPT-JPT-Decryption-and-extraction-tools

Word Apps 어플 중 하나인 켜자마자 일본어 (강제로 일본어공부-JLPT, JPT) 어플의 단어 db를 복호화 및 추출하는 프로그램입니다.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

(Word Apps) 켜자마자 일본어 DB 복호화 및 추출

Word Apps App 중 하나인 켜자마자 일본어 (강제로 일본어공부-JLPT, JPT) App의 암호화된 데이터를 복호화하고, 정규 표현식을 사용하여 필요한 정보를 추출합니다.




🔍 주요 기능

_2024_07_21_06_50_09_973-ezgif com-video-to-gif-converter
(📌 켜자마자 일본어 DB 복호화 및 추출.py 전체 작업 과정 일부 편집본)

■ *.db 파일 내용 중 items 테이블의 content_data열 값을 복호화 하고 각 데이터의 유형별로 정리합니다.
켜자마자 일본어 DB 복호화 및 추출 (Raw).py Script를 사용하면 복호화 된 원본 코드 그대로 반환 됩니다.

■ 반환 된 결과를 *.txt 파일로 저장할 수 있습니다.




💾 다운로드

Program URL 필수여부 비고
Python Download 필수 ◼ Python Script 동작, 파이썬 3.9.0 버전 또는 그 이상 사용 가능
켜자마자 일본어 (강제로 일본어공부-JLPT, JPT) Download 필수 ◼ *.db 파일 추출 대상 Android App
반디집 (또는 다른 압축 프로그램 사용) Download 필수 ◼ *.apk 파일 내용 추출 프로그램
(* 다른 압축 프로그램 사용 가능)
CX 파일 탐색기 (또는 다른 *.apk 파일 추출 방법 사용) Download 필수 ◼ *.apk 파일 추출 App
(* 다른 App을 사용해서 *.apk 파일 추출, Android Emulator에서 *.apk 파일 추출, 다른 곳에서 *.apk 파일 다운 등 등 여러가지 방법 중 가장 마음에 드는 방법 택 1)

※ Script는 아래 표에서 다운 받거나, 본 Repositories Releases로 이동하여 다운로드 하십시오.

Script URL 비고
켜자마자 일본어 DB 복호화 및 추출 Download ◼ 복호화 된 데이터에서 각 유형별로 구분하여 Markdown 표로 반환
켜자마자 일본어 DB 복호화 및 추출 (Raw) Download ◼ 복호화 된 데이터 원본을 그대로 반환




❗ 주의 사항 ❗

※ 모든 내용은 2024-07-21 기준입니다.

※ App에서 지정 한 AES Key 값과 Iv 값은 언제 달라질 지 모릅니다.

(* 만약, AES Key 값과 Iv 값 변경으로 정상적으로 복호화가 안 되면 *.apk 파일을 직접 Decompile (또는 Reverse Engineering)해서 알아내야 함.)

※ 미처 발견하지 못한 오류가 있을 수 있습니다.




⏩ 사용 방법

  1. Python과 반디집(또는 다른 압축 프로그램)을 설치합니다.

    2024-07-21 06 43 56
    [ ※ 주의 ] Python 설치 시 Add python.exe to PATH 에 반드시 체크 후 Install Now 클릭
    (📌 미처 누르지 못했다면 설치 파일 다시 실행 또는 제거 후 재 설치)

    2024-07-21 06 44 08
    [ ※ 주의 ] 설치 후 Disable path length limit 기능을 사용할 수 있도록 반드시 클릭
    (📌 필수는 아니나, 해당 기능을 사용하는 것을 권장)



  2. 필수 Package 설치

    2024-07-21 08 45 41

    Python 설치 후 키보드 Win + R 또는 시작 -> 검색란에 cmd를 입력하여 cmd를 실행하고 아래 코드를 입력하여 필수 Package를 설치합니다.



    (필수) Package 설치

    pip install pycryptodome
    or
    python -m pip install pycryptodome



    [ ※ 주의 ] 만약 위 명령어 사용 중 ERROR: Could not install packages due to an EnvironmentError: [WinError 5] 액세스가 거부되었습니다: (생략) Consider using the --user option or check the permissions. 과 같은 오류가 나왔다면 끝에 --user를 붙여서 입력

    (* 권한 오류 발생시 두 코드 중 하나 선택)
    pip install pycryptodome --user
    or
    python -m pip install pycryptodome --user



  3. 켜자마자 일본어 (강제로 일본어공부-JLPT, JPT) App의 *.apk 파일을 추출하여 작업 할 PC로 복사 또는 이동 후 *.apk 파일을 압축 프로그램으로 실행합니다.

    2024-07-21 06 44 18



  4. *.db 파일을 찾아 원하는 경로에 끌어다 놓습니다.

    2024-07-21 06 44 30
    (📌 2024-07-21 기준 \assets\jpkr_20200219.db파일 위치)



  5. Python Script에 *.db 파일 이름을 입력하고 저장합니다.

    2024-07-21 09 15 34
    만약, db 파일 이름이 jpkr_20200219.db 이면 db_filename = 'jpkr_20200219.db'과 같이 입력
    (📌 [ ※ 주의 ] 반드시 파일 이름을 따옴표(') 안에 입력해야 함.)



  6. Python Script 파일과 *.apk 파일에서 추출 한 *.db 파일을 동일한 위치에 두고 Python Script 파일을 실행합니다.

    _2024_07_21_09_42_01_620-ezgif com-optimize
    (📌 켜자마자 일본어 DB 복호화 및 추출.py 전체 작업 과정 무편집본)



🛠 App 파일 및 AES Key, Iv 값 분석

※ 이 작업은 Android App과 DB의 구조를 이해하고 응용할 수 있는 분들께 추천드리는 작업입니다.

Program URL 필수여부 비고
DB Browser for SQLite Download 필수 ◼ *.db 내용 보는거
다른 프로그램 써도 됨
Bytecode Viewer Download 필수 ◼ *.apk 내용 분석(* 필자는 2.9.22 버전 사용)
다른 버전 써도 되고 다른 프로그램 써도 됨
Java (또는 다른 압축 프로그램 사용) Download 필수 ◼ Windows 사용자는 가급적 x64 MSI Installer 설치 파일 받아서 설치
반디집 (또는 다른 압축 프로그램 사용) Download 필수 ◼ *.apk 파일에서 *.db 파일 추출 용
다른 압축 프로그램 써도 됨




  1. *.apk 파일에서 db 파일 빼내기

    01-01. 작업 할 PC에 *.apk 파일 옮기고 반디집으로 열기

    2024-07-21 20 42 00



    01-02. 내부 파일들 중 Data가 들어 있을 법 한 *.db 파일 찾아서 압축 해제

    2024-07-21 20 42 10
    (📌 2024-07-21 기준 \assets\jpkr_20200219.db파일 위치)



  2. *.db 파일 분석

    02-01. DB Browser for SQLite 실행 후 조금 전 빼낸 *.db 파일 불러오고 데이터 보기 클릭

    2024-07-21 20 39 26



    02-02. 테이블(T)에서 모든 테이블 데이터 확인 후 단어가 저장되어 있을 법 한 테이블 이름과 해당 테이블의 열 이름 종류 기억

    2024-07-21 20 39 41
    (📌 2024-07-21 기준 items 테이블)



  3. App 구조 분석

    03-01. 화면 좌측 상단에 보이는 Drag class/jar/zip/APK/DEX here에 *.apk 파일 드래그 또는 File - Add... 로 불러오기

    2024-07-21 21 02 48

    2024-07-21 21 05 57
    (📌 *.apk 파일이 정상적으로 불러와진 모습)



    03-02. items 테이블과 어떤식으로 연결되어 있는지 확인하기 위해 여러개의 열 값 중 content_data으로 우선 검색

    2024-07-21 21 07 47
    (📌 Search 창에 있는 Search_String 칸에 content_data 입력 후 Search 버튼 클릭 후 반환 된 코드 모두 확인)



    03-03.alib/word/model/Item.class 라는 파일에서 content_data 검색 후 해당 글자가 있는 근처를 우선으로 분석

    2024-07-21 21 10 47
    (📌 57번째 줄 et1 var10 = new et1()코드 내용을 바탕으로 et1 Class 확인)



    03-04. Files 창에 et1 입력 후 Enter

    켜자마자 일본어 DB 복호화 및 추출 et1 설명



    03-05. 코드 분석

    2024-07-21 21 19 45
    (📌 위 스크린 샷 기준 133번째 줄 decrypt, 149번째 줄 encrypt라는 내용을 봐서 복호화 하거나 암호화하는 코드일 가능성이 높은 것을 확인)

    켜자마자 일본어 DB 복호화 및 추출 et1 각 변수 설명

    코드 처음 부분부터 각 변수별 값 분석

    public String a 값 : Iv 값(* 블록 암호화에서 사용되는 추가적인 입력 값으로, 암호화 과정에서 사용되는 초기 상태를 설정하는 데 사용)

    public String e 값 : AES 암호화에서 사용할 키

    this.d = Cipher.getInstance("AES/CBC/NoPadding"); 코드 : AES 알고리즘을 CBC(Cipher Block Chaining) 모드로 사용하며, 패딩 없이 데이터를 암호화 및 복호화하기 위해 Cipher 객체를 생성하는 부분



  4. 테스트

    켜자마자 일본어 DB 복호화 및 추출 AES 복호화 테스트 설명
    (📌 위 사이트는 여기를 클릭하여 이동)



⚙ 고급 설정 (선택)

※ 이 작업은 Python 언어로 작성 된 Script의 내용을 이해하고 응용할 수 있는 분들께 추천드리는 작업입니다.

❔ 파일이 정상적으로 복호화 되지 않는 경우
원인 1 : *.db 내용 중 items테이블 변경(* Ex. 열 이름, 기록 된 데이터가 다른 테이블로 이동 등)
원인 2 : *.db 내용 중 지정 된 item_type 값을 참고하여 올바르지 않은 규칙으로 처리(* Ex. 데이터 구조 변경 등)



해결 방법
원인 1
*.db 파일 분석 후 78번째 줄 cursor.execute("SELECT id, content_data, item_type FROM items") 코드에서 테이블과 열 이름 수정
(📌 추가로 수정해야 하는 부분이 있다면 Python Script에 기록 된 주석 내용 참고하여 수정)



원인 2
켜자마자 일본어 DB 복호화 및 추출 (Raw).py 파일 실행
(📌 추가로 수정해야 하는 부분이 있다면 해결 방법 - 원인 1 내용과 Python Script에 기록 된 주석 내용 참고하여 수정)


복호화 된 원본 데이터 구조 분석

각 `item_type`별 구조 예시
# item_type 1
{"word":"あいさつ","grammer":"명사,동사","display":"あいさつ","concise":"① 인사","content":null,"voice_usa":"挨拶","example":"あいさつの言葉<ことば>\n인사말\nあいさつを交<か>わす\n인사를 나누다\n","url":null}

# item_type 5
{"word":"油<あぶら>を売<う>る","explanation":"あぶらをうる","pronunciation":"기름을 팔다","korean_display":"수다를 떨거나 딴짓을 하며 해야할 일을 미루는 것. 에도시대에 머릿기름 장사를 하던 사람이 자연스럽게 대화를 하면서 구매를 유도했던 모습에 비유","vowel":"","example":"油<あぶら>を売<う>る"}

# item_type 6
{"korean_display":"아","word":"あ","grammer":"히히라가나에서 가장 먼저 배우게 되는 5글자 あいうえお(아이우에오)는 일본어에서 유일한 모음이다.\n \n ※히라가나란? 일본어의 기본 문자로 기초 공부를 하기 위해 필수로 익혀야 하는 글자들이다.\n \n 청음 : 부가적인 부호없이 글자 하나 만으로 사용할 수 있으며, 가장 기본 문자이다. 탁음,반탁음,요음을 제외한 글자를 전부 청음이라고 보면 된다.","display":"あ","concise":"a","voice":""}

(📌 기본 형식이 언제 변경될지 모르기 떄문에 반드시 수정 작업 할 때는 켜자마자 일본어 DB 복호화 및 추출 (Raw).py 파일로 원본 데이터 분석 후 작업해야 됨.)


(* 아래 코드는 임의로 줄 바꿈하여 알아보기 쉽게 정리한 것)

# item_type 1
"word": "あいさつ",
"grammer": "명사,동사",
"display": "あいさつ",
"concise": "① 인사",
"content": null,
"voice_usa": "挨拶",
"example": "あいさつの言葉<ことば>\n인사말\nあいさつを交<か>わす\n인사를 나누다\n",
"url": null

# item_type 5
"word": "油<あぶら>を売<う>る",
"explanation": "あぶらをうる",
"pronunciation": "기름을 팔다",
"korean_display": "수다를 떨거나 딴짓을 하며 해야할 일을 미루는 것. 에도시대에 머릿기름 장사를 하던 사람이 자연스럽게 대화를 하면서 구매를 유도했던 모습에 비유",
"vowel": "",
"example": "油<あぶら>を売<う>る"

# item_type 6
"korean_display": "아",
"word": "あ",
"grammer": "히라가나에서 가장 먼저 배우게 되는 5글자 あいうえお(아이우에오)는 일본어에서 유일한 모음이다.\n \n ※히라가나란? 일본어의 기본 문자로 기초 공부를 하기 위해 필수로 익혀야 하는 글자들이다.\n \n 청음 : 부가적인 부호없이 글자 하나 만으로 사용할 수 있으며, 가장 기본 문자이다. 탁음,반탁음,요음을 제외한 글자를 전부 청음이라고 보면 된다.",
"display": "あ",
"concise": "a",
"voice": ""




켜자마자 일본어 DB 복호화 및 추출.py 파일 코드 중 정규 표현식 관련 코드 수정

수정해야 하는 부분
01. 49번째 줄 ~ 75번째 줄
patterns = {
    # item_type이 1일 때 사용하는 정규 표현식 패턴
    'word_1': re.compile(r'"word":"(.*?)","grammer"'),  # 'word' 항목 추출
    'grammar_1': re.compile(r'"grammer":"(.*?)","display"'),  # 'grammer' 항목 추출
    (...생략...)
    'url_1': re.compile(r'"solve":"(.*?)"'),  # 'solve' 항목 추출
    
    # item_type이 5일 때 사용하는 정규 표현식 패턴
    'word_5': re.compile(r'"word":"(.*?)","explanation"'),  # 'word' 항목 추출
    'explanation_5': re.compile(r'"explanation":"(.*?)","pronunciation"'),  # 'explanation' 항목 추출
    (...생략...)
    'example_5': re.compile(r'"example":"(.*?)"'),  # 'example' 항목 추출
    
    # item_type이 6일 때 사용하는 정규 표현식 패턴
    'korean_display_6': re.compile(r'"korean_display":"(.*?)","word"'),  # 'korean_display' 항목 추출
    'word_6': re.compile(r'"word":"(.*?)","grammar"'),  # 'word' 항목 추출
    (...생략...)
    'voice_6': re.compile(r'"voice":"(.*?)"')  # 'voice' 항목 추출
}
위 정규 표현식 설명

예시

복호화 된 원본
{"word":"あいさつ","grammer":"명사,동사","display":"あいさつ","concise":"① 인사","content":null,"voice_usa":"挨拶","example":"あいさつの言葉<ことば>\n인사말\nあいさつを交<か>わす\n인사를 나누다\n","url":null}

Python Script
re.compile(r'"word":"(.*?)","grammer"')




re.compile(...) : 정규 표현식을 컴파일하여 패턴 객체를 생성하는 Python의 re 모듈 함수
(* 정규 표현식을 컴파일하여 패턴 객체를 만들면, 나중에 이 패턴을 사용해 문자열에서 원하는 부분을 추출하거나 검색할 수 있음.)

r'"word":"(.*?)","grammer"' : 컴파일할 정규 표현식 패턴

" : 큰따옴표 문자 그 자체를 의미. 문자열에서 "word"와 "grammer"이라는 문자열을 직접 매칭하기 위해 사용

"word":" : "word":" 문자열을 정확히 매칭.
(* 이 부분은 탐색하려는 패턴의 시작 부분)

(.*?) : 이 부분은 실제로 추출하려는 값을 포함하는 그룹

. : 어떤 문자 하나를 의미

*? : 0번 이상의 반복을 의미하며, 가능한 한 적게 일치하도록 함.
(* 비탐욕적(non-greedy) 방식(가능한 가장 짧은 문자열을 일치)으로 문자열 일치 시도 )

","grammer" : ","grammer" 문자열을 정확히 매칭하기 위해 사용
(* 이 부분은 추출하려는 값 뒤에 오는 부분을 매칭.)




이 정규 표현식은 "word":"와 ","grammer" 사이의 문자열을 추출하는 것을 목적으로 함.
(* Ex. "word":"あいさつ","grammer"에서 "あいさつ" 값 추출)


(📌 반드시 *.db 파일에서 item_id분석 후 분리하여 변수 명을 지정해야 됨.)
(📌 새로 추가 된 형식이 있다면 반드시 위 코드 설명을 참고하여 추가로 작성해야 됨.)



02. 107번째 줄 ~ 119번째 줄
    word_match = None
    grammar_match = None
    display_match = None
    concise_match = None
    content_match = None
    voice_usa_match = None
    example_match = None
    url_match = None
    explanation_match = None
    pronunciation_match = None
    korean_display_match = None
    vowel_match = None
    voice_match = None

(📌 새로 추가 된 형식이 있다면 반드시 추가로 작성해야 됨.)



03. 122번째 줄 ~ 144번째 줄
    if item_type == 1:
        word_match = patterns['word_1'].search(decrypted_content)
        grammar_match = patterns['grammar_1'].search(decrypted_content)
        (...생략...)
        url_match = patterns['url_1'].search(decrypted_content)
    elif item_type == 5:
        word_match = patterns['word_5'].search(decrypted_content)
        explanation_match = patterns['explanation_5'].search(decrypted_content)
        (...생략...)
        example_match = patterns['example_5'].search(decrypted_content)
    elif item_type == 6:
        korean_display_match = patterns['korean_display_6'].search(decrypted_content)
        word_match = patterns['word_6'].search(decrypted_content)
        (...생략...)
        voice_match = patterns['voice_6'].search(decrypted_content)

(📌 정규 표현식 패턴에 추가 한 변수 명을 item_type에 맞게 새로 추가 또는 수정)



04. 147번째 줄 ~ 164번째 줄
    result = {
        'id': item_id,
        'item_type': item_type,
        'category_id': category_id if category_id is not None else 'N/A',  # category_id가 None이면 'N/A'로 설정
        'category_title': category_title if category_title is not None else 'N/A',  # category_title이 None이면 'N/A'로 설정
        (...생략...)
        'voice': voice_match.group(1) if voice_match else 'N/A'  # voice_match가 존재하면 첫 번째 그룹의 값을 사용하고, 없으면 'N/A'로 설정
    }

(📌 정규 표현식 패턴에 추가 한 유형 추가 또는 수정)
(📌 새로운 유형을 추가 할 경우 코드 복사 후 맨 앞 ''사이 글자는 새로 추가된 유형으로, ifelse 사이 값은 정규 표현식 패턴에 추가 한 변수 명으로 지정하면 됨)



05. 171번째 줄 ~ 179번째 줄
markdown_output = "| ID | Item Type | Category ID | Category Title | Word | Grammar | Display | Concise | Voice USA | Example | URL | Explanation | Pronunciation | Korean Display | Vowel | Voice |\n"
markdown_output += "|----|-----------|-------------|----------------|------|---------|---------|---------|-----------|---------|-----|-------------|---------------|----------------|-------|-------|\n"

# results 리스트의 각 결과를 반복하여 Markdown 표의 각 행을 생성
for result in results:
    markdown_output += (f"| {result['id']} | {result['item_type']} | {result['category_id']} | {result['category_title']} | "
                        f"{result['word']} | {result['grammar']} | {result['display']} | {result['concise']} | "
                        f"{result['voice_usa']} | {result['example']} | {result['url']} | {result['explanation']} | "
                        f"{result['pronunciation']} | {result['korean_display']} | {result['vowel']} | {result['voice']} |\n")

(📌 result(* 147번째 줄 ~ 164번째 줄)에 추가 한 변수 명 추가)





About

Word Apps 어플 중 하나인 켜자마자 일본어 (강제로 일본어공부-JLPT, JPT) 어플의 단어 db를 복호화 및 추출하는 프로그램입니다.

License:MIT License


Languages

Language:Python 100.0%