컴퓨터 프로그래밍/Autohotkey

[오토핫키 서버 연동] 5. 프로그램 서버 인증 / 차단

나노콛 2019. 8. 19. 18:30

일부 사용자에게만 프로그램을 사용하게 하기 위한 서버인증 로직입니다.

여기서 사용할 방법은 사용자마다 DriveGet 명령어로 하드 일련번호를 취득해서 서버에 업로드하고

서버에 등록된 사용자 일련번호가 있는 컴퓨터에서만 실행되도록 합니다.

DriveGet 명령어로 얻는 하드 일련번호는 포맷하면 변경이 되기 때문에 민감한 일련번호는 아닙니다.

DriveGet 명령어의 사용법은 다음과 같습니다.

// c:의 시리얼을 hdd변수에 담는다.
DriveGet, hdd, serial, c:\

변수를 hdd를 메시지 박스에 출력시켜보면 c:의 일련번호가 나옵니다.

c:의 일련번호를 클립보드에 저장하는 코드입니다.

DriveGet, hdd,serial,c:\
MsgBox, 일련번호 %hdd%가 클립보드에 저장되었습니다. 
Clipboard = %hdd%

위의 코드로 만든 프로그램을 실제 프로그램 사용을 원하는 사람들에게 배포하여 일련번호를 수집합니다.

서버에 일련번호를 저장한 텍스트를 업로드합니다

인증을 필요로 하는 프로그램의 코드입니다.

// 프로그램을 실행한 컴퓨터(사용자)의 c: 시리얼 획득
DriveGet, hdd, serial, c:\

// 서버에 업로드한 사용자 일련번호를 다운로드함
urldownloadtofile, https://******/cer1.txt, 나노콛.txt
urldownloadtofile, https://******/cer2.txt, 딸기.txt

fileread, cer1, 나노콛.txt
fileread, cer2, 딸기.txt
FileDelete, 나노콛.txt
FileDelete, 딸기.txt

// 현재 컴퓨터의 c: 시리얼과 등록된 사용자의 시리얼 비교
if (hdd=cer1)
{
      nick:="나노콛"
      MsgBox, %nick%님 어서오세요
      goto, MAIN
}

if (hdd=cer2)
{
     nick:="딸기"
     MsgBox, %nick%님 어서오세요
     goto, MAIN
}

// 시리얼이 맞는게 없다면 프로그램 종료
MsgBox, 인증되지 않으셨습니다.`n프로그램이 종료됩니다.
ExitApp

인증된 사용자의 c: 시리얼을 받아 서버에 업로드하고

각각의 시리얼을 받아 변수에 담은 후 if 문에서 비교를 합니다.

인증이 된 사용자라면 MAIN 레이블을 통해 MAIN 레이블이 있는 곳으로 점프하여 프로그램이 실행됩니다.

인증이 되지 않았다면 ExitApp 명령어를 만나서 프로그램이 종료됩니다.

인증 실패
인증 성공

인증된 사용자가 늘어날수록 일련번호를 다운로드할 코드와 다운로드한 텍스트를 처리할 코드, if 문도 늘어납니다.

사용자가 늘어나면 코드 수정을 해야 하는데

자동 업데이트를 이용해서 프로그램을 업데이트 하면됩니다.

업데이트가 되기 전에 인증코드로 인해 프로그램이 꺼지면 사용자 추가가 적용되지 않기 때문에

업데이트 코드가 인증코드보다 먼저 와야 합니다.


사용자 인증과 무관하게 프로그램 실행을 차단할 수 있는 방법을 알아보겠습니다.

check.txt 파일에 open을 쓰고 저장한 뒤 서버에 업로드합니다.

이 텍스트 파일을 읽어 open 이면 프로그램 실행 가능 close 면 실행 못하게 해보겠습니다.

urldownloadtofile, https://******/check.txt, check.txt
urldownloadtofile, https://******/notice.txt, notice.txt

fileread, serverState, check.txt
fileread, notice, notice.txt
filedelete, check.txt
filedelete, notice.txt

// check.txt 파일의 내용을 담은 serverState 변수의 내용이 'open'이면 프로그램 실행 
ifinstring, serverState, open
{
    if notice 
	{
		MsgBox, %notice%
	}
}

// check.txt 파일의 내용을 담은 serverState 변수의 내용이 'close'이면 프로그램 종료
Ifinstring, serverState, close
{
      Msgbox, 업데이트 중이거나 차단되었습니다.`n나중에 다시 시도 하세요
      ExitApp
}

서버 텍스트 파일 읽어오기는 앞서 했던 내용과 동일합니다.

Ifinstring 명령어는 해당 변수의 내용에 포함되어있는 문자열을 찾기 때문에 문자를 의미 없는 내용으로 작성해도 됩니다.

(ex. afvansvsavopendnfkjdvnmdv 이렇게 입력해도 중간에 open을 찾습니다.)

누구든지 프로그램을 실행 못하게 하려면 서버에 close라고 쓴 후 업로드하면 되고

실행 가능하게 하려면 open을 넣으면 됩니다.


이스터에그를 추가해서 모든 인증을 무마시키게 할 수도 있습니다.

실제 프로그램 구동에 필요한 부분에 핫키를 등록하면 됩니다.

+

Shift

^

Control

!

Alt

#

WinKey

^!Q:: 이렇게 핫키를 등록하면 차단이나 메시지 박스가 떴을 때 해당 키를 입력하면 됩니다.


서버 인증 전체 소스 코드입니다.

curVer := 1.0

urldownloadtofile, https://******/ver.txt, ver.txt ;버전
fileread, UpdateVer, ver.txt
filedelete,ver.txt
FileDelete, Downloader*.exe


if(curVer!=UpdateVer)
{
      msgbox, 새버전 업데이트 합니다.`n프로그램이 재시작 됩니다.
      Url            = https://******/Downloader.exe
      DownloadAs     = Downloader%UpdateVer%.exe
      Overwrite      := True 
      UseProgressBar := True
      DownloadFile(Url, DownloadAs, Overwrite, UseProgressBar)
      run, Downloader%UpdateVer%.exe
      exitapp
}


DriveGet, hdd, serial, c:\

urldownloadtofile, https://******/cer1.txt, 나노콛.txt
urldownloadtofile, https://******/cer2.txt, 딸기.txt

fileread, cer1, 나노콛.txt
fileread, cer2, 딸기.txt
FileDelete, 나노콛.txt
FileDelete, 딸기.txt

if (hdd=cer1)
{
      nick:="나노콛"
      MsgBox, %nick%님 어서오세요
      goto, MAIN
}

if (hdd=cer2)
{
     nick:="딸기"
     MsgBox, %nick%님 어서오세요
     goto, MAIN
}
MsgBox, 인증되지 않으셨습니다.`n프로그램이 종료됩니다.
ExitApp


MAIN:
urldownloadtofile, https://******/check.txt, check.txt
urldownloadtofile, https://******/notice.txt, notice.txt

fileread, serverState, check.txt
fileread, notice, notice.txt
filedelete, check.txt
filedelete, notice.txt

ifinstring, serverState, open
{
    if notice 
	{
		MsgBox, %notice%
	}
}
Ifinstring, serverState, close
{
      Msgbox, 업데이트 중이거나 차단되었습니다.`n나중에 다시 시도 하세요
      ExitApp
}






^!Q::  ;; Ctrl + Alt + Q
iniread, dir,  dir.ini, dir, dir   

urldownloadtofile, https://******/first.txt, first.txt
urldownloadtofile, https://******/second.txt, second.txt
fileread, first, first.txt
fileread, second, second.txt
filedelete, first.txt
filedelete, second.txt




Gui, Add, CheckBox, x12 y10 w200 h30 vfirst, %first%
Gui, Add, CheckBox, x12 y+3 w200 h30 vsecond, %second%
Gui, Add, Edit, x12 y+3 w230 h20 vDirSelect, %dir%
Gui, Add, Button, x252 y9 w60 h60 ,체크받기
Gui, Add, Button, x252 y75 w60 h20 gDirSelectBt, 폴더선택
Gui, Add, Button, x252 y+5 w60 h20 gopenfolder,폴더열기
gui, add, statusbar, ,   Downloader ver%curVer%
Gui, Show, h145 w325, 다운로더
Return

GuiClose:
ExitApp

DirSelectBt:
  FileSelectFolder, dndir, , 3
  if dndir =
  {
     return
  }
  GuiControl,, DirSelect, %dndir%
  GUI, Submit, NoHide
IniWrite, %DirSelect%, dir.ini, dir, dir 
 Return

openfolder:
iniread, dir,  dir.ini, dir, dir
run, %dir%
return




	


button체크받기:
Gui, Submit, Nohide
iniread, dir,  dir.ini, dir, dir

if (first = 1)
{
	Url            = https://*****/img/333.gif
	DownloadAs     = %dir%/333.gif
	Overwrite      := True 
	UseProgressBar := True
	DownloadFile(Url, DownloadAs, Overwrite, UseProgressBar)
}


if (second = 1)
{
 Url            = https://*****/img/111.gif
	DownloadAs     = %dir%/111.gif
	Overwrite      := True 
	UseProgressBar := True
	DownloadFile(Url, DownloadAs, Overwrite, UseProgressBar)
}
Return


Delete::
ExitApp







; 다운로드 함수
DownloadFile(UrlToFile, SaveFileAs, Overwrite := True, UseProgressBar := True) {
      If (!Overwrite && FileExist(SaveFileAs))
          Return
      If (UseProgressBar) {
            WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
            WebRequest.Open("HEAD", UrlToFile)
            WebRequest.Send()
            FinalSize := WebRequest.GetResponseHeader("Content-Length")
            Progress, H80, , Downloading..., %UrlToFile%
            SetTimer, __UpdateProgressBar, 10
      }
      UrlDownloadToFile, %UrlToFile%, %SaveFileAs%
      If (UseProgressBar) {
          Progress, Off
          SetTimer, __UpdateProgressBar, Off
      }
    Return
    
      __UpdateProgressBar:
            CurrentSize := FileOpen(SaveFileAs, "r").Length
            CurrentSizeTick := A_TickCount
            Speed := Round((CurrentSize/1024-LastSize/1024)/((CurrentSizeTick-LastSizeTick)/1000)/1000) . " Mb/s"
            LastSizeTick := CurrentSizeTick
            LastSize := FileOpen(SaveFileAs, "r").Length
            PercentDone := Round(CurrentSize/FinalSize*100)
            Progress, %PercentDone%, %PercentDone%`% Done, Downloading...  (%Speed%), Downloading %SaveFileAs% (%PercentDone%`%)
      Return
}