macOS Firmware 패스워드 삭제 스크립트
지난번, 실수로 잘못 걸은 EFI 패스워드는 여전히 삭제하지 못하고 있는 상황이다.
이런 상황이긴 하지만.
과정에서 만든 스크립트 하나를 공개하기로 한다.
단순한 비밀번호나, 알 수 없는 오타를 쳐서 돌이킬 수 없는 상황에 빠졌을 때.
시간을 들여 EFI패스워드를 삭제할 수 있게 해 주는 스크립트다.
(약간 어렵게 느껴질 것이다, 모르면 커뮤니티에 들고가서 물어봐라)
이 스크립트는 인텔칩을 사용하며,
애플T2칩을 사용하지 않는 모든 맥킨토시에서 사용할 수 있다.
아래 스크립트의 사용순서는 다음과 같다.
- 스팟라잇 혹은 Applications > 유틸리티에서 터미널 (Terminal)을 켠다.
- 터미널에서 sudo su 라는 명령어를 친다.
- macOS 비밀번호를 입력한다.(맥 켜자마자 ID와 같이 입력하는 그 PW말이다.)
- 터미널 시작이 Sh-3.2#으로 바뀌었다면 성공이다.
- 스팟라잇 혹은 Applications > 유틸리티에서 스크립트 편집기 (Script Editor)을 켠다.
- 아래 박스 안의 코드를 복사해 붙여넣고 저장하라.
- 스크립트 편집기 위의 삼각형 버튼(플레이버튼 같은 거)을 눌러서 시작하라.
- 1회 49667번 반복한다. 한 차례 반복후, 아래 스크린샷을 참고하여 상태를 확인해라. (아래 다시 설명)
- 암호해제에 실패했다면 아래 스크립트에 써 있는대로 다음 순번을 설정후 저장하고 스크립트 편집기 (Script Editor)를 닫아라.
- 터미널도 종료하고 맥을 재부팅해라.
- 맥을 다시 켰다면 1번부터 다시 반복한다.
- 성공할때까지 한다.
아마도, 보통 아래 문자 이외에 사용하지 않을 것이다.
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
`1234567890-=[]\;',./
~!@#$%^&*()_+{}|:"<>?
-- 문자 Set 이른바 배열이다. (수학이나 컴퓨터공학의 그 배열 말이다.)
-- a_list라는 set 다음에 to가 있고, 거기서부터 {}(중괄호)로 하나의 꾸러미를 만들고 있다.
-- 이 꾸러미 안에 큰 따옴표 안에 한 글자부터, 한 문장까지 작성하고, 각 큰 따옴표 사이에 (,) 콤마로 다음 글자를 써 나간다.
-- 단, \ (역슬래시)와 " (큰 따옴표)는 프로그래밍 세계에서 특수문자로 취급해줘야 하는 글자들이다.
-- 따라서, 역슬래시를 하나 더 붙여 특수문자임을 표시한다. 역슬래시는 = \\ 큰 따옴표 = \" 이렇게 말이다.
-- 이 스크립트는 최대 13가지 패턴으로 나눌 수 있을 것을 상정하여 만든 것이다.
-- 이 스크립트를 사용할 유저는 각 리스트(list)의 꾸러미를 반드시 수정하라.
-- a부터 d 리스트는 글자 1개의 경우로 소문자, 대문자, 숫자, shift를 누른 상태에서의 숫자와 특수문자다.
set a_list to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ""}
set b_list to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", ""}
set c_list to {"`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "[", "]", "\\", ";", "'", ",", ".", "/", ""}
set d_list to {"~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", "|", ":", "\"", "<", ">", "?", ""}
-- e 리스트는 a부터 d를 모두 한줄에 담은 리스트이다.
-- 실제로 이렇게 쓸 일은 없을 것이며, 없어야 한다. (왜냐하면 시간이 많이 걸린다)
-- 그냥 이렇게 쓸 수 있다는 걸 보여주는 예제이다.
set e_list to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "[", "]", "\\", ";", "'", ",", ".", "/", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "{", "}", "|", ":", "\"", "<", ">", "?", " ", ""}
-- f부터 m리스트는 2개 이상의 글자를 담은 예제이다.
-- 예를 들어 비번이 q1w2e3r4이라고 가정하자.
-- qwer을 쓴 건 확실하거나 혹은 기억하는데. 숫자인지 특수문자인지 모를 경우가 있다.
-- 그렇다면 두 가지 방법이 있다.
-- a, c, e, g 리스트에 각각 "q" "w" "e" "r"을 넣는 거다.
-- 그리고 b리스트에 "1","!"을.
-- d 리스트에 "2","@"를 넣고.
-- f 리스트에 "3","#"을 넣고.
-- h 리스트에 "4","$"를 넣는거다.
-- 그리고 i, j, k, l, m은 모두 큰따옴표 2개만 넣어 "" <- 이렇게 빈칸으로 만들어 두고 돌리는 방법이다.
-- 또다른 방법은 이런 게 있다.
-- a리스트에 "q1w2e3r4","q!w@e#r$" 이렇게 2개의 문장만 넣고 b부터 m까지 모든 리스트를 빈칸으로 만드는 것이다.
-- 자신의 비밀번호 패턴을 기억해 내어 조합을 만들어 써라.
set f_list to {"aa", "bb", "cc", "dd", "ee", "ff", " ", ""}
set g_list to {"a1", "b2", "c3", "d4", "e5", "f6", "g7", ""}
set h_list to {"A!", "B@", "C#", "D$", "E\\", "F\"", ""}
set i_list to {"a-b c", "c\\d\"-e", "fat-32", ""}
set j_list to {"QhdldQhdld", "EhdldEhdld", "BlaBla", "MolooMoloo", ""}
set k_list to {"{a!", "]b%", "\\c(", "\"d_", ""}
set l_list to {" ", ""}
set m_list to {"zfs", "ntfs", "apfs", "ufs", "fat", "ex-fat", ""}
-- Set된 문자리스트에 몇개의 문자 혹은 단어의 묶음(큰따옴표로 묶은 것들)이 있는지는 자동으로 계산한다.
-- 계산된 값은 각 문자리스트의 count를 축약하여 의미하는 cnt안에 자동으로 담긴다.
-- 예를들면 아래 set된 a_cnt에는 a_list에 들어있는 큰따옴표 모음의 전체 갯수가 자동으로 담긴다.
-- 이 부분은 절대로 건들지 마라.
set a_cnt to length of a_list
set b_cnt to length of b_list
set c_cnt to length of c_list
set d_cnt to length of d_list
set e_cnt to length of e_list
set f_cnt to length of f_list
set g_cnt to length of g_list
set h_cnt to length of h_list
set i_cnt to length of i_list
set j_cnt to length of j_list
set k_cnt to length of k_list
set l_cnt to length of l_list
set m_cnt to length of m_list
-- 이것들은 출력할 문자의 중복을 검토하기 위한 것이다.
-- 이 부분은 절대로 건들지 마라.
set a_count to 0
set b_count to 0
set c_count to 0
set d_count to 0
set e_count to 0
set f_count to 0
set g_count to 0
set h_count to 0
set i_count to 0
set j_count to 0
set k_count to 0
set l_count to 0
-- 이 스크립트는 list의 큰따옴표안의 글자 혹은 문장을, a부터 m의 순서로 1세트씩 불러서 비밀번호를 조합한다.
-- 따라서 한번에 같은 글자가 2개만 나오도록 설정하고 있다. (아래에서 수정할 수 있다)
-- 스크립트가 시동하자마자 같은 글자 혹은 문장이 2개 이상 나올 가능성이 있다면, 아래 설정으로 회피할 수 있다.
-- m_id에 1을 쓴다.
-- l_id까지 1을 쓴다.
-- k_id는 2를 쓴다.
-- 이렇게 아래에서 2개의 리스트마다 +1 하는 것이다.
-- 처음부터 겹칠 일이 없다면 모두 1로 써도 된다.
-- 이 스크립트를 사용할 유저는 각 리스트(list)의 꾸러미 패턴에 맞춰 수정하라.
-- (물론 안 하고 그냥 모두 1로 두고 시작해도 된다. 단지 엄청나게 긴 시간이 걸릴 뿐이다)
-- 바로 아래 다시 설명하지만, 이 스크립트는 49667회만 반복한다.
-- 49667회중에 성공하면 좋겠지만, 실패하면 이어서 작업해야 할 것이다.
-- 이때, 여기 숫자를 재설정해주면 이어서 49667회 다시 반복작업을 해 준다.
-- 가장 마지막 줄의 결과를 여기에 반영하여 작업을 이어나간다.
set a_id to 6
set b_id to 6
set c_id to 5
set d_id to 5
set e_id to 4
set f_id to 4
set g_id to 3
set h_id to 3
set i_id to 2
set j_id to 2
set k_id to 1
set l_id to 1
set m_id to 1
-- 애플스크립트는 불행히도 사용할수록 RAM에 데이터가 쌓인다.
-- 따라서 루프(반복)문으로 만들어 긴 작업을 나눠서 하는 것이다.
-- 초기값은 당연히 0이고, 49667회 반복하고 종료된다.
-- 이 부분은 절대로 건들지 마라.
set loop_cnt to 0
set loop_limit to 49667
-- 비밀번호를 담기 위한 공간인데...
-- 사실 쓸모없다.
-- (사실, 이 스크립트에서는 더 심플하게 코드를 짜도 된다.)
-- (그러나, 이 스크립트는 계속 개량하여 쓰던 코드라 남아있게 되었다)
-- (따라서) 이 부분은 절대로 건들지 마라.
set efi_pw to ""
-- 이 부분은 절대로 건들지 마라.
repeat with m_lp from m_id to m_cnt
repeat with l_lp from l_id to l_cnt
repeat with k_lp from k_id to k_cnt
repeat with j_lp from j_id to j_cnt
repeat with i_lp from i_id to i_cnt
repeat with h_lp from h_id to h_cnt
repeat with g_lp from g_id to g_cnt
repeat with f_lp from f_id to f_cnt
repeat with e_lp from e_id to e_cnt
repeat with d_lp from d_id to d_cnt
repeat with c_lp from c_id to c_cnt
repeat with b_lp from b_id to b_cnt
repeat with a_lp from a_id to a_cnt
-- a 중복 검토.
-- 여기 a에서부터 m까지 절대로 건들지 마라.
if ((item a_lp of a_list) = (item b_lp of b_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item c_lp of c_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item d_lp of d_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item e_lp of e_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item f_lp of f_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item g_lp of g_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item h_lp of h_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item i_lp of i_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item j_lp of j_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item k_lp of k_list)) then
set a_count to a_count + 1
end if
if ((item a_lp of a_list) = (item l_lp of l_list)) then
set a_count to a_count + 1
end if
-- b
if ((item b_lp of b_list) = (item a_lp of a_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item c_lp of c_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item d_lp of d_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item e_lp of e_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item f_lp of f_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item g_lp of g_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item h_lp of h_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item i_lp of i_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item j_lp of j_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item k_lp of k_list)) then
set b_count to b_count + 1
end if
if ((item b_lp of b_list) = (item l_lp of l_list)) then
set b_count to b_count + 1
end if
-- c
if ((item c_lp of c_list) = (item b_lp of b_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item a_lp of a_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item d_lp of d_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item e_lp of e_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item f_lp of f_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item g_lp of g_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item h_lp of h_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item i_lp of i_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item j_lp of j_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item k_lp of k_list)) then
set c_count to c_count + 1
end if
if ((item c_lp of c_list) = (item l_lp of l_list)) then
set c_count to c_count + 1
end if
-- d
if ((item d_lp of d_list) = (item b_lp of b_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item c_lp of c_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item a_lp of a_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item e_lp of e_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item f_lp of f_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item g_lp of g_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item h_lp of h_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item i_lp of i_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item j_lp of j_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item k_lp of k_list)) then
set d_count to d_count + 1
end if
if ((item d_lp of d_list) = (item l_lp of l_list)) then
set d_count to d_count + 1
end if
-- e
if ((item e_lp of e_list) = (item b_lp of b_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item c_lp of c_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item d_lp of d_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item a_lp of a_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item f_lp of f_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item g_lp of g_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item h_lp of h_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item i_lp of i_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item j_lp of j_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item k_lp of k_list)) then
set e_count to e_count + 1
end if
if ((item e_lp of e_list) = (item l_lp of l_list)) then
set e_count to e_count + 1
end if
-- f
if ((item f_lp of f_list) = (item b_lp of b_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item c_lp of c_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item d_lp of d_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item e_lp of e_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item a_lp of a_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item g_lp of g_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item h_lp of h_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item i_lp of i_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item j_lp of j_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item k_lp of k_list)) then
set f_count to f_count + 1
end if
if ((item f_lp of f_list) = (item l_lp of l_list)) then
set f_count to f_count + 1
end if
-- g
if ((item g_lp of g_list) = (item b_lp of b_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item c_lp of c_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item d_lp of d_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item e_lp of e_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item f_lp of f_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item a_lp of a_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item h_lp of h_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item i_lp of i_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item j_lp of j_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item k_lp of k_list)) then
set g_count to g_count + 1
end if
if ((item g_lp of g_list) = (item l_lp of l_list)) then
set g_count to g_count + 1
end if
-- h
if ((item h_lp of h_list) = (item b_lp of b_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item c_lp of c_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item d_lp of d_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item e_lp of e_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item f_lp of f_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item g_lp of g_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item a_lp of a_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item i_lp of i_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item j_lp of j_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item k_lp of k_list)) then
set h_count to h_count + 1
end if
if ((item h_lp of h_list) = (item l_lp of l_list)) then
set h_count to h_count + 1
end if
-- i
if ((item i_lp of i_list) = (item b_lp of b_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item c_lp of c_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item d_lp of d_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item e_lp of e_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item f_lp of f_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item g_lp of g_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item h_lp of h_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item a_lp of a_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item j_lp of j_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item k_lp of k_list)) then
set i_count to i_count + 1
end if
if ((item i_lp of i_list) = (item l_lp of l_list)) then
set i_count to i_count + 1
end if
-- j
if ((item j_lp of j_list) = (item b_lp of b_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item c_lp of c_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item d_lp of d_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item e_lp of e_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item f_lp of f_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item g_lp of g_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item h_lp of h_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item i_lp of i_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item a_lp of a_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item k_lp of k_list)) then
set j_count to j_count + 1
end if
if ((item j_lp of j_list) = (item l_lp of l_list)) then
set j_count to j_count + 1
end if
-- k
if ((item k_lp of k_list) = (item b_lp of b_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item c_lp of c_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item d_lp of d_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item e_lp of e_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item f_lp of f_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item g_lp of g_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item h_lp of h_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item i_lp of i_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item j_lp of j_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item a_lp of a_list)) then
set k_count to k_count + 1
end if
if ((item k_lp of k_list) = (item l_lp of l_list)) then
set k_count to k_count + 1
end if
-- l
if ((item l_lp of l_list) = (item a_lp of a_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item b_lp of b_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item c_lp of c_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item d_lp of d_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item e_lp of e_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item f_lp of f_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item g_lp of g_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item h_lp of h_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item i_lp of i_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item j_lp of j_list)) then
set l_count to l_count + 1
end if
if ((item l_lp of l_list) = (item k_lp of k_list)) then
set l_count to l_count + 1
end if
-- 여기 if()라고 써 있는 부분은 엑셀의 if문과 같은 기능을 한다.
-- 이 스크립트에서는 위에서 쓴 것 처럼 모든 문자 혹은 문장을 1개씩 총 2개 중복하여 출력하는 걸 허락하고 있다.
-- 위에서 쓴것처럼 자신의 비밀번호 패턴에 따라서 어떤 문자 혹은 문장이 2회 이상 반복해야 한다면?
-- ≤ 1이 부분을 ≤ 2 혹은 ≤ 3 과 같이 바꿔줘라.
-- 자신의 비밀번호 및 위의 문자 리스트 패턴에 맞춰 이 부분을 반드시 수정하라.
if ((a_count ≤ 1) and (b_count ≤ 1) and (c_count ≤ 1) and (d_count ≤ 1) and (e_count ≤ 1) and (f_count ≤ 1) and (g_count ≤ 1) and (h_count ≤ 1) and (i_count ≤ 1) and (j_count ≤ 1) and (k_count ≤ 1) and (l_count ≤ 1)) then
-- tell 어쩌구 이 부분은 터미널에 비밀번호를 대입하는 기능을 담당한다.
-- 절대로 건들지 마라.
tell application "Terminal"
set W to (the first window whose tty of tab 1 contains "ttys000")
delay (random number from 0.27 to 0.43)
do script "firmwarepasswd -delete" in W
delay (random number from 0.01 to 0.1)
set efi_pw to ((item a_lp of a_list) & (item b_lp of b_list) & (item c_lp of c_list) & (item d_lp of d_list) & (item e_lp of e_list) & (item f_lp of f_list) & (item g_lp of g_list) & (item h_lp of h_list) & (item i_lp of i_list) & (item j_lp of j_list) & (item k_lp of k_list) & (item l_lp of l_list) & (item m_lp of m_list) & "\n")
do script efi_pw in W
end tell
set efi_pw to ""
set loop_cnt to loop_cnt + 1
end if
-- if문이 종료되는 구간이다.
-- if문이 끝나면 반드시 1회. 현재까지의 반복횟수가 49667회 이하인지 체크한다.
-- 만약 49667회라면 스크립트는 루프(반복)을 중단한다.
if (loop_cnt ≥ loop_limit) then exit repeat
-- 만약 루프(반복)이 계속된다면 중복체크를 0으로 리셋해준다.
-- 이 부분은 절대로 건들지 마라.
set a_count to 0
set b_count to 0
set c_count to 0
set d_count to 0
set e_count to 0
set f_count to 0
set g_count to 0
set h_count to 0
set i_count to 0
set j_count to 0
set k_count to 0
set l_count to 0
-- 여기부터 마지막 end repeat까지 절대로 건들지 마라.
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
if (loop_cnt ≥ loop_limit) then exit repeat
end repeat
-- 49667회 루프(반복)을 돌면, 종료 시점의 각 리스트의 현재 글자를 남겨준다.
-- 다음 루프(반복)에 이 글자에 해당하는 위치를 세어서 위의 a_id부터 m_id에 숫자를 갱신해라.
-- 이 코드는 절대로 건들지 마라.
set theDialogText to return & "a:" & (item a_lp of a_list) & ", b:" & (item b_lp of b_list) & ", c:" & (item c_lp of c_list) & ", d:" & (item d_lp of d_list) & ", e:" & (item e_lp of e_list) & ", f:" & (item f_lp of f_list) & ", g:" & (item g_lp of g_list) & ", h:" & (item h_lp of h_list) & ", i:" & (item i_lp of i_list) & ", j:" & (item j_lp of j_list) & ", k:" & (item k_lp of k_list) & ", l:" & (item l_lp of l_list) & ", m:" & (item m_lp of m_list) & "\n" & "loop count:" & loop_cnt & "."
이 스크립트는 보면 알 수 있듯이 초심자에게는 매우 어렵고 복잡해 보이며.
프로그램 유경험자에게도 애플스크립트가 익숙하지 않다면,
대충 뭔지는 알겠지만. 역시 어려울 수 있다.
그러나, 이 방식은 터미널을 이용해 EFI패스워드를 해제하는
소프트웨어 적으로 가장 안전하고 안정적인 방법이다.
(라는 게 내가 얻은 결론이다. 물론 시간도 많이 필요하다!)
스크립트를 더 세련되게 만들어, 터미널에서 나오는 문자를 파악해 성공-실패를 확인하고.
루프(반복)을 중단하게 할 수도 있겠지만.
애플스크립트를 이용한 방법은 현재 중단한 상태다.
딱히 수정할 이유도 없기도 한데. 그 이유는 아래 스크린샷을 통해 설명한다.
패스워드가 삭제되면, "Password Removed."가 뜨고,
그 이후로 루프(반복) 삭제 명령이 주입돼도,
가장 먼저 "No firmware password set"가 뜨면서 비밀번호를 먹지 않게 된다.
다음으로 패스워드가 삭제되거나,
삭제되지 않았어도 루프(반복)이 종료되면 보이는 변화를 살펴보자.
먼저 터미널을 통해 확인할 수 있는 명령어가 있다.
firmwarepasswd -check
그 아래 "Password Enabled: No" 가 반환된 모습이 보인다.
EFI에 설정된 패스워드가 없다는 뜻이다.
이어서 뒤에 있는 스크립트 에디터를 보자.
스크린샷 하단에 보면 Result라고 된 부분 아래에,
a부터 m까지 각 문자 리스트에서 추출되어 입력된 마지막 패스워드가 보인다.
이 스크린샷은 애초에 패스워드를 알고 있어서 5000회만에 비밀번호가 나왔지만.
실제 비밀번호를 잃어버린 경우 결코 단시간에 결과가 나오지 않는다.
이 비밀번호 체크가 CPU와 RAM과 SSD 사이에서 이뤄지는 게 아니라
통신이라는 방식으로 이뤄지다 보니. 터미널에 걸리는 부하도 무시할 수가 없다.
이것이 루프 카운트를 49667회로 한정한 이유다.
(49667회는 가장 안전하고 안정된 통신횟수라 정한 것이다)
터미널을 꺼도, 이 부하는 커널이라고 부르는
macOS의 핵심부에 남아있기 때문에
다음회 루프 (반복)은 반드시 재부팅후 진행하라는 것이다.
(잊어버릴 수 있으니 루프 종료 직후에 스크립트의 문자열 번호를 수정해 두라는 거다)
이 방법은 나중에 다듬어 Github에 재공개할지 그냥 이대로 둘지 하겠지만.
아무튼, EFI비번을 알 수 없어 고통받고 있는 사람들에게
비번의 전체 길이와 대략적인 문자열만 알고 있다면.
혼자서도 비번을 풀 수 있는 좋은 수단이 되어 줄 것이다.
그런 입장에 있는 사람은 극히 소수겠지만,
그런 이들에게 부디 유용하게 쓰이길 바라며 여기 우선 공개한다.