Noniin, minulla on VB6-sovellus(piirustusohjelma), jota käytän suoraan usb-tikulta Windows pohjaisissa koneissa.
(Halusin aikoinaan sovelluksesta sellaisen, että se ei tarvitse erillistä asennusta vaan toimi itsenäisesti yhtenä .exe failina. Tämä mahdollista asiakkaan koneen käytön tarvittaessa. Ei ocx dll eikä mitään erikoista koodissa, vain ihan perusobjekteja, ei myöskään tietokantaa vaan failien käyttöä randomina.)
Ohjelma toimii ja olen tehnyt sillä sähkösuunnittelua koneisiin jo jonkin aikaa. Muutamalla asiakkaalla ja kolleegalla on ollut kiinnosstusta ohjelmasta, joten olen ajatellut kehittää siihen "käyttöoikeus"-ominaisuutta. Voisin sitten antaa/myydä käyttöoikeutta vaikka vuodeksi kerrallaan tms.??
Kehittelin kokeeksi systeemin, jossa käyttäjä antaa ohjelmalle kaksi tekstiriviä: "Käyttöaika & Nimi & Osoite & MuutYhteystiedot ..." sekä koodi "siansaksaaaaaaaa..." ja näiden tekstien pitää tietyllä algoritmillä pitää kutinsa keskenään. Tähän käytin n. 1MB kokoista siansksataulukkoa josta eka teksti hakee toisen tekstin kirjaimet.
Asiakkaan tiedot(teksti 1.) näkyyvät kaikissa tulostuksissa, joten tämä mahdollisesti ehkäisee luvatonta käyttöä - vai ehkäiseekö?
No, itsestänikin tämä vaikuttaa vähintäänkin ontuvalta ja koen osaamiseni tässä epävarmaksi (ja oletettavasti joku ammattilainen osaa murtaa tämän systeemin muutamassa sekunnissa)
Onko teillä suositusta miten lähtisin asiaa kehittämään? Onko mielestänne ylipäätään mahdollista suojata USB-tikulta suoritettavaa täysin itsenäistä ohjelmaa?
Mitään ohjelmaa, jota suoritetaan käyttäjän koneella, ei ole mahdollista suojata niin, että sitä ei voisi murtaa.
Itse käyttäisin asymmetristä salausta. Eli tekisin niin, että laittaisin lisenssitiedot selväkielisinä ja sitten omalla salaisella avaimellani allekirjoittaisin sen. Ohjelman mukana tulisi julkinen avain, jolla sitten allekirjoitus varmennettaisiin.
Tämänkin toki pystyy kiertämään muokkaamalla ohjelmaa. Mutta avaingeneraattoria ei pysty tekemään, joten muokkailu täytyy tehdä uudestaan jokaiselle uudelle versiolle.
Onkos tietoa voiko USB-muisteja yksilöidä, joten ohjelmaa olisi mahdollista käyttää vain tietyltä tikulta? Ohjelman levitys tapahtuisi siis tikun avulla.
(Yritin etsiä jotakin MAC-osoitteen tapaista yksilöivää tietoa ja joitakin arvoja löytyykin ominaisuus ikkunan kautta, mutta en tiedä mitä ne itseasiassa ovat.)
jtha kirjoitti:
Onkos tietoa voiko USB-muisteja yksilöidä, joten ohjelmaa olisi mahdollista käyttää vain tietyltä tikulta? Ohjelman levitys tapahtuisi siis tikun avulla.
Googlella löytyi ohjelma nimeltään AntiDuplicate, joka väittää osaavansa yksilöidä ohjelman tiettyyn USB-muistiin. Ohjeman sivuilla ei kylläkään sanota, millä tavoin se tarkistaa muistitikun alkuperäisyyden, mutta vastaavanlaisen virityksen saanee itsekin tehtyä.
Kiitos -tossu-! Ehdottomasti pitää tutkia tuo mahdollisuus.
itse tein yhteen sovellutukseen salauksen rijndaelilla, ja valmiita avainpareja parituhatta.
kun asiakas asensi sovellutuksen, ohjelmaan syötettiin avainparin asiakaspuolen koodi.
Tämän jälkeen softa otti yhteyden palvelimelle ja varmensi avaimen parin (ja poisti käyttölistalta).
Jos verkkoyhteyttä ei ollut, asiakas soitti firmaan ja pyysi salauksen avainparin (softa arpoi randomilla yhden avainparin listalta).
tämän jälkeen kyseinen pari poistettiin lisenssilistalta.
Me taas tehtiin jokunen vuosi sitten eräänlainen "suojaus" "multimediarompulle", jonka tarkoitus oli estää kyseisen yritysten myyjiä käyttämästä vanhentunutta versiota rompusta myyntitöissä.
Ajatus olikin kiva aluksi, kunnes huomasimme jok'ikinen vuosi olevamme päivittämässä romppua pahimman joulukiireen alla.
No olisiko ekalla kerralla kannattanut vaihtaa vanhenemispäivä vaikka heinäkuulle?
Sinänsä Leben tapauksessa ei tarvitse kovin monimutkaista "suojausta", kun voidaan olettaa että sitä ei lähde kukaan hakkeroimaan.
Tuosta groovyb:n viestistä tuli minulle enemmän kysymyksiä kuin vastauksia. Oliko siis koko systeemi kryptattuna ja se purettiin muistiin? Jos kerran ekan käyttökerran jälkeen avaimen toinen puolikas poistettiin käyttölistalta, niin oliko se sitten kertakäyttöinen sovellus. Vai menikö se niin, että ekan tarkistuksen yhteydessä avaimen toinen puolikas tallennettiin jemmaan käyttäjän koneelle vai peräti koko softa salaus purettuna?
Moi jtha!
tässä pikku esimerkki USB-tikun tsekkaamiseen...
Private Declare Function GetDriveType Lib "kernel32" _
Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Private Sub Form_Load()
Dim root As String
root = Left(App.Path, 3)
Dim msg As String
If GetDriveType(root) <> 2 Then
msg = "EI KÄYTTÖOIKEUTTA!" 'Esim.
End If
Dim driveletter As String
driveletter = UCase(Left(root, 1))
Select Case driveletter
Case "A", "B"
msg = "EI KÄYTTÖOIKEUTTA!"
End Select
Dim fullpath As String
fullpath = root & "mydrive.dat"
If Dir(fullpath) <> "" Then
Kill fullpath
End If
Shell "cmd /C dir root >" & fullpath, vbHide
JumpBack:
On Error Resume Next
flen& = FileLen(fullpath)
If Err <> 0 Then
Err.Clear
On Error GoTo 0
GoTo JumpBack
End If
Do While FileLen(fullpath) = 0
DoEvents: Loop
Dim rootdata As String
Open fullpath For Input As #1
rootdata = Input$(LOF(1), 1)
Close #1
Shell "cmd /C del " & fullpath, vbHide
'Huom! ko. tikun serial
If InStr(rootdata, "3B67-0B4F") = 0 Then
msg = "EI KÄYTTÖOIKEUTTA!"
End If
If msg <> "" Then
Dim msgresult As Long
msg = msg & vbCrLf & _
"Tahdotko siirtyä ohjelman toimittajan Internet sivustolle?"
msgresult = MsgBox(msg, vbYesNo, Me.Caption)
If msgresult = 6 Then
Shell "explorer http://www.sivusto.com", vbNormalFocus
End If
End
End If
'...
End SubTon käyttöoikeus-jutskan vois järjestää vaikkapa niin, että virittelis jokun ilmasen tahi huokean web-hotellin servulle PHP/MySql viritelmän jonne lähettelis WinInet API:n avulla sivun headereihin ao. tikun seriaalin ja responsena tulis sit tieto siitä onko lisenssi voimassa vaiko eikö...
täältä löytyy sample, jonka avulla tutustua WinInet API'n saloihin jos ei ole ennestään tuttua.
Grez,ohjelman järjestelmätiedot oli kryptattu, ja kryptaus purettiin aina käynnistyksen yhteydessä. Jos ohjelma asennettiin uudelleen,piti myös avaimet uusia. Listalta poisto sen takia ettei verkkovarmenteessa voinut käyttää samaa avainta kahdesti.
Minä tein tämän seuraavasti(toistaiseksi):
Etsin netistä vb6-koodin, jolla saadaan listattua usb-muistit, jotka ovat koneessa kiinni. Samalla saan muisteista luettua mm. valmistajan nimen ja muistin sarjanumeron. Muodostin tikun tiedoista ja lisenssinhaltijasta ym. tiedoista merkkijonon, jolle hain vastineen "siansakasaa" tietyllä algoritmilla. Nyt tallennan sovelluksen ja lisenssi ja siansksat ko. tikulle. Sovellus puolestaan lukee nämä tiedot faileista sekä usb-tikun sarjanumeron yms. ja hakee samalla algoritmillä "siansksa"-koodin, jonka on oltava sama kuin faileihin on upotettu. Nyt tämä softa siis toimii vain ja ainoastaan tällä yhdellä usb-tikulla. Brutaalia ehkä, mutta tuntuu toimivan.
Algoritmi, joka muodostaa siansaksan on mielestäni aika hankalasti arvattavissa, mutta olisi tietysti kiva testauttaa jollakin hakkerilla :-)
jtha kirjoitti:
Algoritmi, joka muodostaa siansaksan on mielestäni aika hankalasti arvattavissa, mutta olisi tietysti kiva testauttaa jollakin hakkerilla :-)
Murtuu 15 minuutissa. Mutta tuskin sillä on merkitystä koska ei varmaan ohjelman kohderyhmää kiinnosta alkaa hakkeroimaan. Tai jos joku niin tekee niin tuskin kovin moni.
neau33:n vinkkiin muuttaisin (todennäköisesti vitseiksi tarkoitetut) "fak juut" oikeasti joksikin vähääkään kuvaavimmiksi.
Muutenkin mm. Ohjelmointiputkan foorumilla näkee keskusteluissa paljon "virheilmoituksia", joista monet ovat oppineet käyttämään niitä väärin. Olen jokusen kerran myös eksynyt ihan vanhentuneesta linkistä sivulle, jossa minua tervehditään lämpimästi "Hacking attempt" -tervehdyksellä.
Eli jottei koskaan enää ikinä vahingossakaan mikään ohjelma ilmoittaisi noin vulgaaristi mistään, niin olisi hyvä, että kokemattomille koodareille annettaisiin vinkkejä, joissa ei heti haistatettaisi värkkejä ja haukuttaisi hakkereiksi, koske monille vinkit opettavat oikeasti koodaamaan virheilmoituksiin noita termejä.
Muutenkin omalla alalla olen saanut lukea paljon juttuja, joissa kolmen aikaan yöllä väliaikaisiksi tarkoitetut "vitsit" ovatkin jääneet kummittelemaan ihan asiakkaan versioihin.
Toteuttaisin Grezin neuvoa, ja en viitsisi nähdä vaivaa kovinkaan monimutkaisen suojauksen tekemiseen, vaan tyytyisin siihen, ettei softaa esim. vahingossa pääsisi levittämään eteenpäin.
Hyviä mielipiteitä.
Kuitenkin, jos joku viitsii vaikka murtaa tuon, niin ilmoittakaa kauanko meni, tarjoan kaljan vaikka sen peliprojektin julkistamistilaisuudessa.
Mitä tarkoitat murtamisella? Eikös tuo ole jo itsessään työkalu mikä tekee sen mitä voisin kuvitella murtamistyökalun tehtävän olevan.
Meinaan että ilman tuota pitäisi saada aikaiseksi selväkielisestä tekstistä sama koodi. Jos onnistuu helposti saamaan vastaavan koodin omin avuin niin sen voi liittää tiedostoihin keksittyjen käyttöoikeuksien kanssa ja alkuperäisen käyttöoikeuden voi helposti kiertää... äh, olenkohan suistumassa ojasta allikkoon tämän kanssa...
Täytyy sanoa että ei ole tullut harrastettua hakkerointia, mutta tiedän suurinpiirtein mitä tapoja kiertää kuvaamasi tyylisiä suojauksia on olemassa.
Ehkä nopein tapa on etsiä koodista kohta joka antaa esimerkiksi virheilmoituksen väärästä lisenssistä ja kelata siitä taaksepäin että missä se tarkistettiin ja sitten vaikka muuttaa koodia siten että tarkistuksen tulos on aina positiivinen.
Jos tarvitsee vaan yksi avain saada, niin voisi debuggerissa ajaa ohjelmaa ja kun ohjelma on laskenut oikean avaimen, jota alkaa vertaamaan käyttäjän syöttämään, niin kopioi sen lasketun oikean avaimen talteen.
Jos haluaa tehdä ihan koodigeneraattorin (mitä siis hait tässä), niin sen tekeminen on tietty hieman työläämpää kuin edellä mainitut suojauksen ohittamiset. Yksi tapa on tuktia mitä ohjelma tekee. Voisin sen tässä tehdä jos olisi ylimääräistä aikaa. (Tästä hassu offtopicci lopussa) Ja sitten kirjoittaa koodin joka tekee saman asian. Tai vielä yksinkertaisemmin, kopioi sen koodin laskevan koodinpätkän ohjelmasta ja upottaa sen omaan avaingeneraattoriin lähes sellaisenaan.
Offtopiccia:
Pitäis varmaan joskus leikkiä enemmän X86 assemblerin kanssa. Tullut puuhailtua lähinnä 68k prossujen kanssa aikanaan ja sitten mikrokontrollereilla.
Miksiköhän toi VB6 kääntäjä tekee tällaista. Siis selvästikin kutsumista varten lataillaan muuttujista arvoja, mutta jos ne kerran pusketaan pinoon lataamisen jälkeen, niin miksi jokainen vedetään eri rekisterin kautta?
Ja miksi tossa ei ole push aina heti lea:n jälkeen vaan se ennakoi yhden lea:n
Jos arvailla pitäisi niin liittyy jotenkin koodin optimointiin.
loc_00402081: lea edx, var_74 loc_00402084: lea eax, var_A4 loc_0040208A: push edx loc_0040208B: lea ecx, var_84 loc_00402091: push eax loc_00402092: push ecx loc_00402093: mov var_9C, 00401920h ; "\el_m_draw_varmuuskoodit.rnd" loc_0040209D: mov var_A4, 00000008h loc_004020A7: call [00401080h]
Hei, Grez.
Tuo esittämäsi koodinpätkä on VB6:ssa seuraava:
("TunnisteKoodi" unohtui siihen kun kopsasin sen piirustusohjelmasta)
Selventäneekö tämä tuon konekielisen?(assembler?)-koodin rakennetta..
Private Sub Command1_Click()
Dim Koodi As String
n = FreeFile
Open CurDir & "\el_m_draw_varmuuskoodit.rnd" For Random As n Len = 1
pit = LOF(n)
OtaKoodiTaulukosta n, pit, TunnisteKoodi & Text1.Text, Koodi
Close n
Text2.Text = Koodi
End SubNäyttää tosiaan siltä, että koodin tekevän algoritmin voi kopsata .exe failista kun homman osaa. Tämä kaikki selventää ajatuksiani, kiitoksia.
lainaus:
Selventäneekö tämä tuon konekielisen?(assembler?)-koodin rakennetta..
Ei siinä sinänsä mitään epäselvää ollut. En vaan ole itse hirveän harjaantunut x86-koodin lukija niin koko ohjelman toiminnan selvittämiseen mennisi minulta aika paljon aikaa.
Tuo kyseinen laittamani pätkä vastaa suunnilleen osaa:
& "\el_m_draw_varmuuskoodit.rnd"
Curdir oli aikaisemmin koodissa ja open on myöhemmin. Sinänsähän yhdestä VB6 -koodirivistä tulee helposti 20-50 riviä assemblyä, joten ei tuollaisen koodin toiminnan selvittäminen tietenkään hirveän nopeaa ole, varsinkaan jos ei ole harjaantunut assemblyn lukija. Itse piti ihan aluksi tarkistaa mitä tarkoittaa lea :D
Mutta tosiaan ohjelmien murtamiseen harjaantunut hakkeri murtaa tuollaisen suojauksen nopeasti. Kuten ihan alussa sanoin, niin mitään käyttäjän tietokoneella ajettavaa koodia ei ole mahdollista suojata niin, että sitä ei voisi murtaa. Tietenkin työmäärän kasvaessa hyöty pienenee. Ja kannattaa muistaa myös että ohjelmien luvaton käyttö on laitonta, joten asialliset firmat ei sitä tee vaikka ei mitään suojausta olisikaan. Tietty jos pääasiallinen asiakaskunta on pienet pajat ja ohjelman hinta on hirmuinen, niin suojaus voi olla tärkeää.
Heippa taas!
tässä vielä hieman aiheesta...
'Form1
(lisää vb-koodi ohjelmaasi, käännä ja tallenna .exe tikulle)
Private Declare Function GetDriveType Lib "kernel32" _
Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Dim xhttp As MyHttpClass
Private Sub Form_Load()
TsekkaaOikeudet
'...
End Sub
Private Sub TsekkaaOikeudet()
If Not Internet.Connected Then
MsgBox "Ei Internet-yhteyttä!"
End
End If
Dim root As String
root = Left(App.Path, 3)
Dim msg As String
If GetDriveType(root) <> 2 Then
msg = Space(30) & "EI KÄYTTÖOIKEUTTA!" 'Esim.
End If
Dim driveletter As String
driveletter = UCase(Left(root, 1))
Select Case driveletter
Case "A", "B"
msg = Space(30) & "EI KÄYTTÖOIKEUTTA!"
Case Else
End Select
Dim fullpath As String
fullpath = root & "mydrive.dat"
If Dir(fullpath) <> "" Then
Kill fullpath
End If
Shell "cmd /C dir root >" & fullpath, vbHide
JumpBack:
On Error Resume Next
flen& = FileLen(fullpath)
If Err <> 0 Then
Err.Clear
On Error GoTo 0
GoTo JumpBack
End If
Do While FileLen(fullpath) = 0
DoEvents: Loop
Dim rootdata As String
Open fullpath For Input As #1
Do While Not LOF(1)
Input #1, rootdata
If InStr(rootdata, "Aseman sarjanumero on") > 0 Then
rootdata = Trim(Replace(rootdata, _
"Aseman sarjanumero on", ""))
Exit Do
End If
Loop
Close #1
Shell "cmd /C del " & fullpath, vbHide
Set xhttp = New MyHttpClass
If xhttp.OpenHTTP("localhost") Then
Dim response As String
response = xhttp.SendRequest( _
"/ohjelmisto/tsekkaa.php?lisenssi=" & rootdata, "POST")
If Trim(response) = "nolicense" Then
msg = Space(30) & "EI KÄYTTÖOIKEUTTA!"
ElseIf Trim(response) = "expired" Then
msg = Space(25) & "KÄYTTÖOIKEUS PÄÄTTYNYT!"
ElseIf InStr(response, "daysleft") > 0 Then
Dim daysleft As String
daysleft = Trim(Replace(response, "daysleft", ""))
MsgBox "KÄYTTÖOIKEUS VANHENEE " & daysleft & " PÄIVÄN KULUTTUA!"
End If
End If
Set xhttp = Nothing
If msg <> "" Then
Dim msgresult As Long
msg = msg & vbCrLf & vbCrLf & _
"Tahdotko siirtyä ohjelman toimittajan Internet sivustolle?"
msgresult = MsgBox(msg, vbYesNo, Me.Caption)
If msgresult = 6 Then
Shell "explorer http://www.palvelimesi.com/sivustosi", vbNormalFocus
End If
End
End If
End Sub'Module1 Private Declare Function InternetGetConnectedState Lib _ "wininet.dll" (ByRef lpSFlags As Long, _ ByVal dwReserved As Long) As Long Public Type InternetConnection Connected As Boolean End Type Public Function Internet() As InternetConnection Dim cType As Long Internet.Connected = InternetGetConnectedState(cType, 0&) End Function
'MyHttpClass (Class Module)
Option Explicit
Public Enum ePort
INTERNET_DEFAULT_HTTP_PORT = 80
INTERNET_DEFAULT_HTTPS_PORT = 443
End Enum
Private Const INTERNET_OPEN_TYPE_DIRECT = 1
Private Const INTERNET_SERVICE_HTTP = 3
Private Const INTERNET_FLAG_PRAGMA_NOCACHE = &H100
Private Const INTERNET_FLAG_KEEP_CONNECTION = &H400000
Private Const INTERNET_FLAG_SECURE = &H800000
Private Const INTERNET_FLAG_FROM_CACHE = &H1000000
Private Const INTERNET_FLAG_NO_CACHE_WRITE = &H4000000
Private Const INTERNET_FLAG_RELOAD = &H80000000
Private Const BUFFER_LENGTH As Long = 1024
Private Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" _
(ByVal Agent As String, ByVal AccessType As Long, ByVal ProxyName As String, _
ByVal ProxyBypass As String, ByVal Flags As Long) As Long
Private Declare Function InternetConnect Lib "wininet.dll" Alias _
"InternetConnectA" (ByVal hInternetSession As Long, ByVal ServerName As String, _
ByVal ServerPort As Integer, ByVal UserName As String, ByVal Password As _
String, ByVal Service As Long, ByVal Flags As Long, ByVal Context As Long) As _
Long
Private Declare Function InternetCloseHandle Lib "wininet.dll" (ByVal hInet As _
Long) As Boolean
Private Declare Function InternetReadFile Lib "wininet.dll" (ByVal hConnect As _
Long, ByVal Buffer As String, ByVal NumberOfBytesToRead As Long, _
NumberOfBytesRead As Long) As Boolean
Private Declare Function HttpOpenRequest Lib "wininet.dll" Alias _
"HttpOpenRequestA" (ByVal hHttpSession As Long, ByVal Verb As String, ByVal _
ObjectName As String, ByVal Version As String, ByVal Referer As String, ByVal _
AcceptTypes As Long, ByVal Flags As Long, Context As Long) As Long
Private Declare Function HttpSendRequest Lib "wininet.dll" Alias _
"HttpSendRequestA" (ByVal hHttpRequest As Long, ByVal Headers As String, ByVal _
HeadersLength As Long, ByVal sOptional As String, ByVal OptionalLength As Long) _
As Boolean
Private hHTTP As Long
Private hConnection As Long
Private Const FIELDS_BUFFER_LENGTH As Long = 10
Private Const FIELDS_NAME_INDEX As Long = 0
Private Const FIELDS_VALUE_INDEX As Long = 1
Private DontEncode(255) As Boolean
Private FieldCount As Long
Private mFields() As String
Public Property Let Fields(Name As String, Value As String)
mFields(FIELDS_VALUE_INDEX, GetFieldIndex(Name, True)) = Value
End Property
Public Property Get Fields(Name As String) As String
Dim l As Long
l = GetFieldIndex(Name, False)
If l > -1 Then
Fields = mFields(FIELDS_VALUE_INDEX, l)
End If
End Property
Public Function OpenHTTP(Server As String, Optional Port As ePort = _
INTERNET_DEFAULT_HTTP_PORT, Optional UserName As String, Optional Password As _
String) As Boolean
CloseHTTP
hHTTP = InternetOpen("HTTP Client", INTERNET_OPEN_TYPE_DIRECT, UserName, _
Password, 0)
If hHTTP <> 0 Then
hConnection = InternetConnect(hHTTP, Server, INTERNET_DEFAULT_HTTP_PORT, _
UserName, Password, INTERNET_SERVICE_HTTP, 0, 0)
If hConnection <> 0 Then
OpenHTTP = True
Else
InternetCloseHandle hHTTP
hHTTP = 0
End If
End If
End Function
Public Sub CloseHTTP()
If hConnection <> 0 Then
InternetCloseHandle hConnection
End If
hConnection = 0
If hHTTP Then
InternetCloseHandle hHTTP
End If
hHTTP = 0
End Sub
Public Function SendRequest(ByVal File As String, Optional Method As String = _
"GET", Optional Referer As String, Optional Reload As Boolean = True) As String
Dim hRequest As Long
Dim r As Boolean
Dim Buffer As String
Dim Header As String
Dim Request As String
Dim POSTData As String
Dim response As String
Dim Read As Long
Dim Flags As Long
Method = UCase$(Method)
Request = BuildRequest
Buffer = Space$(BUFFER_LENGTH)
If Len(Request) > 0 Then
If Method = "POST" Then
Header = "Content-Type: application/x-www-form-urlencoded"
POSTData = Request
Else
File = File & "?" & Request
End If
End If
If Reload Then
Flags = Flags Or INTERNET_FLAG_PRAGMA_NOCACHE Or INTERNET_FLAG_RELOAD
End If
hRequest = HttpOpenRequest(hConnection, Method, File, "HTTP/1.1", "", 0, _
Flags, 0)
If hRequest <> 0 Then
If HttpSendRequest(hRequest, Header, Len(Header), POSTData, _
Len(POSTData)) Then
r = InternetReadFile(hRequest, Buffer, BUFFER_LENGTH, Read)
While r And (Read <> 0)
response = response & Left$(Buffer, Read)
r = InternetReadFile(hRequest, Buffer, BUFFER_LENGTH, Read)
Wend
End If
InternetCloseHandle hRequest
End If
SendRequest = response
End Function
Private Function GetFieldIndex(Name As String, Optional Add As Boolean) As Long
Dim l As Long
For l = 0 To FieldCount - 1
If StrComp(Name, mFields(FIELDS_NAME_INDEX, l), vbTextCompare) = 0 Then
GetFieldIndex = l
Exit Function
End If
Next
If Add Then
If FieldCount = UBound(mFields, 2) Then
ReDim Preserve mFields(1, UBound(mFields, 2) + FIELDS_BUFFER_LENGTH)
End If
mFields(FIELDS_NAME_INDEX, FieldCount) = Name
GetFieldIndex = FieldCount
FieldCount = FieldCount + 1
Else
GetFieldIndex = -1
End If
End Function
Private Function BuildRequest() As String
Dim l As Long
Dim s As String
For l = 0 To FieldCount - 1
s = s & URLEncode(mFields(FIELDS_NAME_INDEX, l)) & "=" & _
URLEncode(mFields(FIELDS_VALUE_INDEX, l)) & "&"
Next
If Len(s) > 0 Then
BuildRequest = Left$(s, Len(s) - 1)
End If
End Function
Public Function URLEncode(Data As String) As String
Dim l As Long
Dim b() As Byte
Dim s As String
Dim c As String
b = Data
For l = 0 To UBound(b) Step 2
If DontEncode(b(l)) Then
s = s & Chr(b(l))
Else
c = Hex(b(l))
While Len(c) < 2
c = "0" & c
Wend
s = s & "%" & c
End If
Next
URLEncode = s
End Function
Private Sub Class_Initialize()
Dim l As Long
ReDim mFields(1, FIELDS_BUFFER_LENGTH)
For l = Asc("0") To Asc("9")
DontEncode(l) = True
Next
For l = Asc("a") To Asc("z")
DontEncode(l) = True
Next
For l = Asc("A") To Asc("Z")
DontEncode(l) = True
Next
End Sub
Private Sub Class_Terminate()
Erase mFields
End Sub<?php //yksinkertainen malli (tsekkaa.php) //(lätki tämä web-hotellisi servulle) if(!isset($_POST["lisenssi"])) { $serial = $_GET["lisenssi"]; $mysql_host = "mysql_palvelimesi"; //(web-hotelleissa monesti: localhost) $mysql_user = "mysql_tunnuksesi"; $mysql_password = "mysql_salasanasi"; $mysql_database = "Tietokanta"; $conn = mysql_connect($mysql_host, $mysql_user, $mysql_password) or die(mysql_error()); mysql_select_db($mysql_database, $conn) or die(mysql_error()); $sql = "SELECT * FROM taulu WHERE serial='$serial'"; $result = mysql_query($sql, $conn) or die(mysql_error()); if (mysql_fetch_row($result)==null) { echo "nolicense"; } else { $today = date( "Y-m-d H:m:s"); if (mysql_result($result, 0, "started") == null || mysql_result($result, 0, "started") == "0000-00-00 00:00:00" ) { $datex = strtotime(date("Y-m-d H:m:s", strtotime($today)) . "+1 year"); $datex = date('Y-m-d', $datex); $sql = "UPDATE taulu SET started='$datex' WHERE serial='$serial'"; $result2 = mysql_query($sql, $conn) or die(mysql_error()); } else { $expiration = mysql_result($result, 0, "started"); $fullDays = date_diff($today, $expiration); if ((int)$fullDays <= 0) { echo "expired"; } elseif((int)$fullDays > 0 && (int)$fullDays < 11) { echo "daysleft" + $fullDays; } } } } function date_diff($start, $end="NOW") { $sdate = strtotime($start); $edate = strtotime($end); $time = $edate - $sdate; if($time>=86400) { $pday = ($edate - $sdate) / 86400; $preday = explode('.',$pday); $timeshift = $preday[0]; } return $timeshift; } ?>
jtha kirjoitti:
Hyviä mielipiteitä.
Kuitenkin, jos joku viitsii vaikka murtaa tuon, niin ilmoittakaa kauanko meni, tarjoan kaljan vaikka sen peliprojektin julkistamistilaisuudessa.
Selvitin käyttämäsi algoritmin. Sen muuttaminen käänteiseksi (jos tarvitsee) pitäisi olla triviaalia, enkä nyt kerkeä tehdä sitä. Joku tunti meni, ois menny paljon vähemmän jos toi olis ollut koodattu millä tahansa muulla kuin VB:llä (joka sylkee ihan käsittämätöntä binääriä)
http://fpaste.dy.fi/lF/dl binääri. oma "koodaajani", joka tekee saman kuin sinun ohjelmasi
Sorsa:
#include <stdio.h>
#include <stdlib.h>
#define RND_FILE "el_m_draw_varmuuskoodit.rnd"
#define MAGIC1 0x0c350
#define MAGIC2 0x0e7ef0
int main(int arcg, char *argv[])
{
FILE *rndf;
int sz;
unsigned char *rnd;
printf("OPtemp.exe keygen\n");
if(!(rndf = fopen(RND_FILE, "r"))) {
printf("%s ei aukee\n", RND_FILE);
return -1;
}
fseek(rndf, 0, SEEK_END);
sz = ftell(rndf);
/*if(sz != 0x0f4240) {
printf("väärän kokoinen %s\n", RND_FILE);
return -1;
}*/
rnd = malloc(sz);
fseek(rndf, 0, SEEK_SET);
fread(rnd, 1, sz, rndf);
fclose(rndf);
while(1) {
unsigned int i, idx, ebp18, edi;
unsigned char input[256];
printf("nimi kiitos: ");
scanf("%255s", input);
for(ebp18 = i = 0; i < strlen(input); i++)
ebp18 = input[i]%0x7b + ebp18;
for(i = 0; i < strlen(input); i++) {
idx = ((input[i]*(i+1) + ebp18) % sz);
edi = MAGIC1;
while(edi <= MAGIC2) {
idx = (edi - rnd[idx]*(i+1)) % sz;
idx = (edi + rnd[idx]*(i+1)) % sz;
edi += MAGIC1;
}
printf("%c", (rnd[idx] % 0x64) + 0x21);
}
printf("\n");
}
return 0;
}HUOM!! Jos koodattuun merkkijonoon tulee erikoismerkkejä (esimerkiksi ääkkösiä), niin jtha:n ohjelma ei näytä niitä oikein.
Kiitos, Deffi. Kaljalasku paisuu.
Nea, kiitos koodista ja vinkistä. Monesti tuolla teollisuudessa ei ole nettiä käytössä ja ohjelmaa käytetään mm. halleissa ja tuotantotiloissa, joten yritän vielä tsempata ja hankaloittaa kopiointia tikulta toiseen tai tikulta koneelle.
Tai sitten unohdat natseilun ja paat koko roskan avoimena lähdekoodina jakoon. "Teollisuuden hallit ja tuotantotilat" erityisesti kuulostaa siltä, että joku saattais tuohon jossain vaiheessa haluta jotain räätälöintiä, sitähän voit sitten myydä hyvään tuntihintaan.
"Teollisuuden hallit ja tuotantotilat" kuulostaa vähän siltä, ettei kukaan lähde kräkkäämään sellaista. Varsinkin jos ohjelma on suomenkielinen. Tulevaisuus näyttää kräkkerien kannalta muutenkin tosi tylsältä, koska kaikki softa on menossa vapaampaan ja ilmaiseen suuntaan! :(
[OHI AIHEEN]
En ole omalla alallani moista huomannut? Kaikesta joutuu maksamaan, niin suunnittelu- kuin ohjelmointisoftistakin(logiikkaohjelmointi).
En osaa kuvitella, että tässä markkinataloudessa kukaan tekisi töitä ilmaiseksi tai jakaisi tuotteita(softaa) ilmaiseksi, ellei siihen sisälly joku muuta kautta saavutettava hyöty.
PS:
En haluaisi viittauksia natsismista tai muuta arvostelua tämän vuoksi. Eikös Ohjelmointiputkan hieno idea ole tässä, että keskustelemme asioista ja opimmekin jotakin. Pysytään vaan asiassa ja jos jokin yksityiskohta ottaa aiheessa/keskustelijassa päähän niin ei tarvitse osallistua ko. keskusteluun - vai mitä?
[/OHI AIHEEN]
Avoimen lähdekoodin ohjelmaa voi aivan hyvin myös myydä, ja lisäksi voi veloittaa tuesta ja pyydettyjen muutosten toteuttamisesta.
jtha kirjoitti:
En haluaisi viittauksia natsismista tai muuta arvostelua tämän vuoksi.
Jep jep, natseilullahan toki ei voi viitata muuhun kuin natsismiin, siksi kielioppinatsikin on aina tällaisia http://www.youtube.com/watch?v=N4vf8N6GpdM
Itse en ainakaan tee open sourcea teollisuuteen (tai ylipäänsä ammattikayttöön). Niillä on varaa myös maksaa,ja vähentävät vielä verotuksessa. Sen päälle sitten vielä tuki,päivitykset ja räätälöinnit. Lahjoitan ennemmin vaikka spr:än tilille jos siltä tuntuu.
Aihe on jo aika vanha, joten et voi enää vastata siihen.