ฉันจะตรวจสอบได้อย่างไรว่าแอพ iOS ทำงานบนโทรศัพท์ที่ถูกเจลเบรคแล้ว?


167

หากฉันต้องการให้แอปของฉันทำงานแตกต่างไปจาก iPhone ที่ถูกเจลเบรคแล้วฉันจะพิจารณาสิ่งนี้ได้อย่างไร


คุณกำลังจะติดตามเป้าหมายที่เคลื่อนไหวได้ แต่คุณอาจลองติดตามความคืบหน้าของแหล่งข้อมูลเหล่านี้เพื่อดูว่าเทคนิคของคุณมีประสิทธิภาพอย่างไร: - theiphonewiki.com/wiki/Bypassing_Jailbreak_Detection - theiphonewiki.com/wiki/XCon
Michael Bishop

คำตอบ:


90

มันขึ้นอยู่กับสิ่งที่คุณหมายถึงโดยการเจลเบรค ในกรณีง่าย ๆ คุณควรเห็นว่า Cydia ได้รับการติดตั้งแล้วหรือยัง

NSString *filePath = @"/Applications/Cydia.app";
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
   // do something useful
}

สำหรับเมล็ดที่ถูกแฮ็กมันมีส่วนเกี่ยวข้องมากขึ้น


17
มันจะไม่เพียงพอที่จะมองหาไฟล์ / dir ใด ๆนอกแซนด์บ็อกซ์ของคุณ? ชอบ / etc?
Fistman Rhythmic

58
โปรดทราบว่าผู้ใช้บางคนไม่ได้ติดตั้ง Cydia - นี่ไม่ใช่การตรวจสอบที่ดีและคุณควรตรวจสอบบางอย่างเช่น / bin / bash ที่ / all / users / will / have
สิทธิ์พอล

2
apt จัดเก็บข้อมูลที่ไหน หรือฉันจะเรียกคำสั่ง system () แล้วหาคำตอบ ฉันต้องการตรวจสอบว่าพวกเขามีแอพบางตัวหรือไม่และมีแอพให้ จำกัด แอพ
conradev

2
@RazorSharp ณ จุดนี้ผู้ใช้เกือบทั้งหมดมี Cydia อาจเพียงพอที่จะตรวจสอบในตอนนี้ อย่างไรก็ตามหากคุณต้องการการตรวจสอบที่เชื่อถือได้ 100% คุณจะต้องใช้การตรวจสอบเคอร์เนลตามด้านล่าง
สิทธิ์พอล

1
FWIW การตรวจสอบไฟล์มีความสำคัญต่อการเลี่ยงผ่าน หนึ่งสามารถใช้ mobilesubstrate เพื่อขอfileExistsAtPath:และทำให้มันกลับมาNOสำหรับเส้นทางเฉพาะที่คุณตรวจสอบ
toasted_flakes

55

นี่คือรหัสที่รวมคำตอบบางอย่างที่ฉันพบสำหรับความต้องการนี้และจะให้อัตราความสำเร็จที่สูงขึ้น:

BOOL isJailbroken()
{
#if !(TARGET_IPHONE_SIMULATOR)

   if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"] ||
       [[NSFileManager defaultManager] fileExistsAtPath:@"/Library/MobileSubstrate/MobileSubstrate.dylib"] ||
       [[NSFileManager defaultManager] fileExistsAtPath:@"/bin/bash"] ||
       [[NSFileManager defaultManager] fileExistsAtPath:@"/usr/sbin/sshd"] ||
       [[NSFileManager defaultManager] fileExistsAtPath:@"/etc/apt"] ||
       [[NSFileManager defaultManager] fileExistsAtPath:@"/private/var/lib/apt/"] ||
       [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://package/com.example.package"]])  {
         return YES;
   }

   FILE *f = NULL ;
   if ((f = fopen("/bin/bash", "r")) ||
      (f = fopen("/Applications/Cydia.app", "r")) ||
      (f = fopen("/Library/MobileSubstrate/MobileSubstrate.dylib", "r")) ||
      (f = fopen("/usr/sbin/sshd", "r")) ||
      (f = fopen("/etc/apt", "r")))  {
         fclose(f);
         return YES;
   }
   fclose(f);

   NSError *error;
   NSString *stringToBeWritten = @"This is a test.";
   [stringToBeWritten writeToFile:@"/private/jailbreak.txt" atomically:YES encoding:NSUTF8StringEncoding error:&error];
   [[NSFileManager defaultManager] removeItemAtPath:@"/private/jailbreak.txt" error:nil];
   if(error == nil)
   {
      return YES;
   }

#endif

   return NO;
}

1
@Porizm นี่เป็นเพียงการรวมกันของคำตอบที่ฉันพบ บางคนไม่ได้ผลสำหรับฉัน แต่ทำงานเพื่อคนอื่น .. ดังนั้นด้วยรหัสนี้คุณไม่ได้รับโอกาส .. ถ้าคุณใช้สิ่งนี้คุณสามารถมั่นใจได้ 99% เกี่ยวกับประสิทธิภาพคุณสามารถเรียกใช้งานได้เพียงครั้งเดียวในแต่ละรอบและบันทึกคำตอบที่ใดก็ได้คุณไม่จำเป็นต้องเรียกใช้ในแต่ละครั้ง ..
Yossi

3
@yossi และ porizm apple อนุมัติแอปของคุณที่มีรหัสข้างต้นหรือไม่ โปรดตอบ
karthikPrabhu Alagu

4
วิธีนี้ควรเป็นฟังก์ชัน C แบบอินไลน์ไม่ใช่ Objective-C มันง่ายเกินไปที่จะค้นพบและหลีกเลี่ยง Objective-C โดยเฉพาะอย่างยิ่งถ้าคุณเรียกมันว่าisJailbroken
progrmr

2
@Yossi อุปกรณ์นี้ใช้สำหรับ Jailbrobro หรือไม่ในการใช้ Taig?
Lakshay

3
@ Lakshay ฉันไม่รู้ .. คุณเป็นมากกว่าที่ได้รับเชิญให้ตรวจสอบและเพิ่มคำตอบได้ที่นี่ :)
Yossi

54
+(BOOL)isJailbroken {
    NSURL* url = [NSURL URLWithString:@"cydia://package/com.example.package"];
    return [[UIApplication sharedApplication] canOpenURL:url];
}

ตรวจสอบเส้นทางของไฟล์/Applications/Cydia.appไม่ได้รับอนุญาตในโทรศัพท์ปกติหรือไม่? ฉันไม่เคยได้ยินว่าแอปเปิ้ลตรวจพบสิ่งนี้และปฏิเสธแอปสำหรับแอปนี้ แต่แอปเปิ้ลคาดเดาไม่ได้ Cydia มีรูปแบบ URL cydia: // ซึ่งสามารถตรวจสอบได้อย่างถูกกฎหมายด้วย UIApplicationcanOpenURL:


1
นี่เป็นวิธีที่ดีในการตรวจสอบและไม่ไปนอกกล่องทรายของคุณ แน่นอนว่าถ้าผู้ฝ่าฝืนไม่ได้ติดตั้ง Cydia มันจะคืนค่า NO แต่ฉันคิดว่า Jailbreaks ส่วนใหญ่ติดตั้ง Cydia
Wim Haanstra

สามารถสตริงนี้ไม่สามารถเปลี่ยนแปลงได้เมื่อแอพแตก?
NSRover

8
สำหรับ iOS9.0 + คุณต้องเพิ่มคีย์ LSApplicationQueriesSchemes ในแอพพลิเคชั่น มิฉะนั้น canOpenURL จะส่งคืนค่าเท็จเสมอ
David V

1
สิ่งนี้จะให้ผลบวกที่ผิดพลาดหากผู้ใช้มีแอปที่ติดตั้งซึ่งสอดคล้องกับ cydia: // scheme เช่น InstantTV
thattyson

@thattyson ขอบคุณ! ฉันต้องการตรวจสอบว่าทำไมฉันถึงได้รับผลบวกปลอม
rickrvo

52

การตรวจสอบว่าเคอร์เนลเสียหรือไม่

การแหกคุกทำให้การตรวจสอบลายเซ็นของเคอร์เนลของรหัสที่เซ็นชื่อเสมอรายงานว่ารหัสถูกลงนามอย่างถูกต้องโทรศัพท์ที่ไม่เสียหายไม่สามารถเรียกใช้รหัสที่มีลายเซ็นไม่ดี

ดังนั้นให้รวมไฟล์ปฏิบัติการแยกต่างหากในแอปด้วยลายเซ็นที่ไม่ดี มันอาจเป็นโปรแกรม 3 บรรทัดที่มี main () และค่าส่งคืน รวบรวมการปฏิบัติการโดยไม่ต้องมีการเซ็นรหัส (ปิดใน Project Settings-> Build) และเซ็นชื่อด้วยคีย์อื่นโดยใช้ยูทิลิตี commandline "codesign"

ให้แอปของคุณเรียกใช้งานแยกจากกัน หากโปรแกรมของคุณไม่สามารถรับค่าส่งคืนได้เมื่อเรียกใช้โปรแกรมแยกต่างหากด้วย sig ที่ไม่ดีแสดงว่ามันถูกจำคุก หากปฏิบัติการแยกส่งกลับ A-OK โทรศัพท์จะถูกเจลเบรค


13
คุณจะได้รับ (ย่อย) ปฏิบัติการที่มีลายเซ็นไม่ถูกต้องเช่นนั้นผ่าน App Store หรือไม่?
fbrereto

34
บางทีสิ่งต่าง ๆ มีการเปลี่ยนแปลง แต่จะไม่ดำเนินการแยกปฏิบัติการป้องกันคุณจากการได้รับการอนุมัติไปยังที่ App Store?
Peter Zich

4
ใครบางคนสามารถตอบก่อนหน้านี้เพื่อแสดงความคิดเห็น? นี่เป็นคำถามที่สำคัญ
Petr

ไม่มีใครหยุดยั้งคุณไม่ให้เขียน Mach-O ลงดิสก์ด้วยลายเซ็นที่ไม่ถูกต้อง อย่างไรก็ตามฉันไม่เห็นด้วยกับคำตอบว่าการตรวจสอบว่าเคอร์เนลเสียหรือไม่เกี่ยวข้องหรือนี่เป็นการตรวจสอบขั้นสุดท้ายโดยวิธีการใด ๆ
saagarjha

20
BOOL isJailbroken()
{
#if TARGET_IPHONE_SIMULATOR
    return NO;
#else
    FILE *f = fopen("/bin/bash", "r");

    if (errno == ENOENT)
    {
        // device is NOT jailbroken
        fclose(f);
        return NO;
    }
    else {
        // device IS jailbroken
        fclose(f);
        return YES;
    }
#endif
}

นั่นเป็นทางออกที่ดี แต่ xCon และเครื่องมืออื่น ๆ เช่นสามารถข้ามการตรวจสอบนี้ได้อย่างง่ายดาย ดังนั้นฉันกำลังมองหาทางออกที่ดีกว่า
Alexei Robsky

7
@AlexeiRobsky ไม่มีทางออกที่สมบูรณ์แบบ จะมีใครบางคนที่จะหาวิธีหลีกเลี่ยงการป้องกันของคุณมันเป็นเรื่องจริง
Richard J. Ross III

14

คุณสามารถตรวจสอบว่าอุปกรณ์ JailBroken หรือไม่โดยตรวจสอบสิ่งต่อไปนี้:

  • ติดตั้ง Cydia แล้ว
  • ตรวจสอบบางส่วนของเส้นทางของระบบ
  • ทำการตรวจสอบความสมบูรณ์ของ Sandbox
  • ทำการตรวจสอบ symlink
  • ตรวจสอบว่าคุณสร้างและเขียนไฟล์นอก Sandbox ของคุณหรือไม่

มีห้องสมุดโอเพ่นซอร์สที่ฉันสร้างขึ้นจากบทความและหนังสือต่าง ๆ ลองใช้กับ GitHub !


14

ฉันทำใหม่ใน Swift 2.3 วิธีแก้ปัญหาที่ได้รับจาก @Yossi

public static func jailbroken(application: UIApplication) -> Bool {
    guard let cydiaUrlScheme = NSURL(string: "cydia://package/com.example.package") else { return isJailbroken() }
    return application.canOpenURL(cydiaUrlScheme) || isJailbroken()
}


static func isJailbroken() -> Bool {

    if isSimulator {
        return false
    }

    let fileManager = NSFileManager.defaultManager()
    if fileManager.fileExistsAtPath("/Applications/Cydia.app") ||
        fileManager.fileExistsAtPath("/Library/MobileSubstrate/MobileSubstrate.dylib") ||
        fileManager.fileExistsAtPath("/bin/bash") ||
        fileManager.fileExistsAtPath("/usr/sbin/sshd") ||
        fileManager.fileExistsAtPath("/etc/apt") ||
        fileManager.fileExistsAtPath("/usr/bin/ssh") {
        return true
    }

    if canOpen("/Applications/Cydia.app") ||
        canOpen("/Library/MobileSubstrate/MobileSubstrate.dylib") ||
        canOpen("/bin/bash") ||
        canOpen("/usr/sbin/sshd") ||
        canOpen("/etc/apt") ||
        canOpen("/usr/bin/ssh") {
        return true
    }

    let path = "/private/" + NSUUID().UUIDString
    do {
        try "anyString".writeToFile(path, atomically: true, encoding: NSUTF8StringEncoding)
        try fileManager.removeItemAtPath(path)
        return true
    } catch {
        return false
    }
}

static func canOpen(path: String) -> Bool {
    let file = fopen(path, "r")
    guard file != nil else { return false }
    fclose(file)
    return true
}

6

วิธีที่ซับซ้อนที่สุดที่ฉันรู้คือใช้objc_copyImageNames()ฟังก์ชั่น มันส่งคืนรายการของไลบรารีที่โหลดอยู่ในปัจจุบันและเนื่องจากคนส่วนใหญ่มี MobileSubstrate บนอุปกรณ์ที่ถูกเจลเบรคและเครื่องมือ crack iAP ส่วนใหญ่ขึ้นอยู่กับมันอย่างน้อยไลบรารี MobileSubstrate บางอันจะปรากฏขึ้น


คุณมีลิงค์ใด ๆ เกี่ยวกับห้องสมุด MobileSubstrate / CydiaSubstrate หรือไม่? ฉันไม่มีโทรศัพท์ที่ถูกเจลเบรคให้เล่นด้วยดังนั้นฉันจึงขับ "คนตาบอด" และการค้นหาโดยทั่วไปของ Google จะมาพร้อมกับความคิดเห็นของคุณด้านบน
chadbag

@chadbag ฉันไม่มีอย่างใดอย่างหนึ่ง แต่คุณสามารถค้นหาdebไฟล์ของ MobileSubstrate, แกะมันออกและบัญชีดำ (เกือบ) ทั้งหมด.dylibมันบรรจุอยู่
Maxthon Chan

ขอบคุณฉันได้รับรหัสการคิดและฉันอาจเพิ่มบางสิ่งเพิ่มเติมตามความคิดเห็นของคุณ ขอบคุณมาก!
chadbag

4

ฉันไม่ทราบ "APIs" ใด ๆ ที่มีอยู่สำหรับสิ่งนี้ หากมีอยู่แล้วผลิตภัณฑ์ปิดบังแหกคุกจะปิดบังพวกเขาอย่างรวดเร็ว

เมื่อผู้คนจำนวนมากชี้ให้เห็นว่ามันเป็นเกมแมวและเมาส์ และหลังจากผู้เล่นทั้งสองกลายเป็นผู้เชี่ยวชาญมันก็ขึ้นอยู่กับว่าใครจะได้รับการเคลื่อนไหวครั้งแรก (ผู้ที่ถืออุปกรณ์)

ฉันพบคำแนะนำที่ดีมากมายสำหรับการตรวจจับการแหกคุกในหนังสือเล่มใหม่ของ Zdziarski "การแฮ็กและการรักษาความปลอดภัยแอป iOS" (โดยส่วนตัวแล้วฉันจ่ายมากขึ้นสำหรับ eReilly เพราะพวกเขาอนุญาตให้คัดลอกและวาง)

ไม่ฉันไม่ได้มีส่วนเกี่ยวข้องกับผู้เผยแพร่ แต่ฉันพบว่ามันเป็นหนังสือที่ดี ฉันไม่ชอบเพียงแค่เผยแพร่ความผิดพลาดของแฮ็กเกอร์เพื่อให้พวกเขาสามารถแก้ไขได้ดังนั้นฉันคิดว่าฉันจะชี้ไปที่หนังสือ


4

ลองเรียกใช้งานโค้ดที่ไม่ได้ลงชื่อผ่านแอปพลิเคชันของคุณ

อุปกรณ์ที่ถูกเจลเบรคจะมีคุณสมบัติดังต่อไปนี้:

  • เรียกใช้รหัสที่ไม่ได้ลงนาม
  • ติดตั้ง Cydia แล้ว
  • มีไฟล์แหกคุก
  • เต็ม r / w การเข้าถึงระบบไฟล์ทั้งหมด
  • ไฟล์ระบบบางไฟล์จะได้รับการแก้ไข (เนื้อหาดังนั้น sha1 จึงไม่ตรงกับไฟล์ต้นฉบับ)
  • ติดอยู่กับรุ่นที่ระบุ (รุ่นที่แหกคุก)

เพียงแค่ตรวจสอบการมีอยู่ของไฟล์สำหรับการตรวจจับการแหกคุกก็ล้มเหลว การตรวจสอบเหล่านี้ง่ายต่อการข้าม


3
การพยายามรันโค้ดที่ไม่ได้ลงชื่อจะทำให้แอปของคุณถูกปฏิเสธจาก appstore
Frederic Yesid PeñaSánchez

4

ไฟล์ทั่วไปบางไฟล์ที่ต้องตรวจสอบ: /Library/MobileSubstrate/MobileSubstrate.dylib

/Applications/Cydia.app

/var/cache/apt

/var/lib/apt

/var/lib/cydia

/var/log/syslog

/var/tmp/cydia.log

/bin/bash

/bin/sh

/usr/sbin/sshd

/usr/libexec/ssh-keysign

/etc/ssh/sshd_config

/etc/apt

ตรวจสอบไฟล์ส่วนใหญ่ที่เกี่ยวข้องกับ Cydia


3

ฉันขอแนะนำให้ค้นหาไฟล์ที่ไม่มีใน iPhone "vanilla" ชุดแหกคุกทั้งหมดที่ฉันเคยเห็นติดตั้ง ssh นั่นอาจเป็นตัวบ่งชี้ที่ดีสำหรับโทรศัพท์ที่ถูกเจลเบรค


18
ssh ไม่เคยติดตั้งโดยอัตโนมัติผู้ใช้จะต้องติดตั้งเอง
สิทธิ์พอล

1
ฉันไม่ได้ติดตามฉากแหกคุกจริงๆ แต่อย่างที่ฉันจำได้เมื่อฉันเขียนสิ่งนี้ (ม.ค. '09) Ziphone และคนอื่น ๆ ติดตั้งระบบย่อย ssh และ bsd ตามค่าเริ่มต้น บางทีนั่นอาจไม่ใช่ความจริงอีกต่อไป
Gordon Wilson

12
เชื่อใจฉันเมื่อฉันพูดว่า chpwn ติดตามฉากแหกคุก
Winfield Trail

3

สิ่งที่เราทำคือเรามีฟีด RSS เพื่อสื่อสารกับผู้ใช้ของเรา ( Stocks Live ) เราใส่รายการข่าวที่ระบุสิ่งนี้:

อุปกรณ์ที่ถูกเจลเบรคบางตัวมีปัญหา bla bla bla เราทำการแฮกเพื่อแก้ไขปัญหาเหล่านั้น แต่เราจำเป็นต้องรู้ว่านี่เป็นอุปกรณ์ที่เจลเบรคหรือไม่กดที่นี่เพื่อที่แอพจะแก้ไขปัญหา หากคุณกลับสู่ภาวะปกติเช่นลบการเจลเบรคออกให้กดที่นี่

จากนั้นคุณประมวลผลการโต้ตอบของผู้ใช้และทำสิ่งที่เหมาะสมเช่นทำพฤติกรรมต่าง ๆ


3

ลองค้นหาไฟล์ที่อุปกรณ์ cydia หรือ jailbroken สร้าง หรือลองเขียนไฟล์นอก Blackbox ของแอพ หากคุณประสบความสำเร็จในการทำเช่นนั้นอุปกรณ์จะถูกโจมตี / เจลเบรคที่ :)

- (BOOL)jailbroken
{
    NSFileManager * fileManager = [NSFileManager defaultManager];
    return [fileManager fileExistsAtPath:@"/private/var/lib/apt/"];
}

2
Apple อนุมัติแอปของคุณที่มีรหัสข้างต้นหรือไม่
karthikPrabhu Alagu

3

โปรดใช้รหัสต่อไปนี้สำหรับ Swift 4 ขึ้นไป: เพิ่มรหัสต่อไปนี้ใน appdelegate:

private func getJailbrokenStatus() -> Bool {
    if TARGET_IPHONE_SIMULATOR != 1 {
        // Check 1 : existence of files that are common for jailbroken devices
        if FileManager.default.fileExists(atPath: "/Applications/Cydia.app")
            || FileManager.default.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib")
            || FileManager.default.fileExists(atPath: "/bin/bash")
            || FileManager.default.fileExists(atPath: "/usr/sbin/sshd")
            || FileManager.default.fileExists(atPath: "/etc/apt")
            || FileManager.default.fileExists(atPath: "/private/var/lib/apt/")
            || UIApplication.shared.canOpenURL(URL(string:"cydia://package/com.example.package")!) {
            return true
        }
        // Check 2 : Reading and writing in system directories (sandbox violation)
        let stringToWrite = "Jailbreak Test"
        do {
            try stringToWrite.write(toFile:"/private/JailbreakTest.txt", atomically:true, encoding:String.Encoding.utf8)
            //Device is jailbroken
            return true
        } catch {
            return false
        }
    }
    else {
        return false
    }
}

func applicationDidBecomeActive (_ application: UIApplication) {

    if getJailbrokenStatus() {
        let alert = UIAlertController(title: LocalizedKeys.Errors.jailbreakError, message: LocalizedKeys.Errors.jailbreakErrorMessage, preferredStyle: UIAlertController.Style.alert)
        let jailBrokenView = UIViewController()

        jailBrokenView.view.frame = UIScreen.main.bounds
        jailBrokenView.view.backgroundColor = .white
        self.window?.rootViewController = jailBrokenView
        jailBrokenView.present(alert, animated: true, completion: nil)
    }

    if #available(iOS 11.0, *) {
        if !UIScreen.main.isCaptured {
            DispatchQueue.main.async {
                self.blockImageView.removeFromSuperview()
            }
        }
    }
}

1

นี่คือโซลูชันของฉัน: ขั้นตอนที่ 1

extension UIDevice {
    func isJailBroken() -> Bool {
        let cydiaPath = "/Applications/Cydia.app"
        let aptPath = "/private/var/lib/apt/"
        if FileManager.default.fileExists(atPath: cydiaPath) || FileManager.default.fileExists(atPath: aptPath) {
            return true
        }
        return false
    }
}

ขั้นตอนที่ 2: เรียกใช้ภายในviewDidLoad()ตัวควบคุมมุมมองหน้าจอเรียกใช้งานของคุณ (หรือ VC ที่คุณใช้เป็นครั้งแรก):

       // show a blank screen or some other view controller
       let viewController = UIDevice.current.isJailBroken() ? JailBrokenViewController() : NextViewController()
       self.navigationController?.present(viewController, animated: true, completion:nil)

-2

ลองเข้าถึง /Application/Preferences.app/General.plist คุณควรจะสามารถทำได้บน iPhone ที่เจลเบรคในโทรศัพท์ที่ไม่ใช่ Jb คุณจะไม่สามารถเข้าถึงได้


3
คำตอบนี้น่าสนใจยิ่งขึ้นด้วยรหัสแหล่งที่มา IMHO: สิ่งนี้จะทำให้คุณได้รับการโหวต
Johan Karlsson

5
-1 = อุปกรณ์ Unjailbroken ยังสามารถเปิดและอ่านไฟล์นี้ได้ (ทดสอบ)
ส่ง

@JohanKarlsson ฉันคิดว่าผู้อ่านที่นี่สามารถเขียนซอร์สโค้ดของตัวเองได้ หากพวกเขาทำไม่ได้ - พวกเขามาทำอะไรที่นี่?
gnasher729
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.