কোনও শিকড় ডিভাইসে চলছে কিনা তা নির্ধারণ করুন


292

আমার অ্যাপ্লিকেশনটির কার্যকারিতার একটি নির্দিষ্ট অংশ রয়েছে যা কেবলমাত্র এমন ডিভাইসে কাজ করবে যেখানে রুট উপলব্ধ। এই বৈশিষ্ট্যটি ব্যবহার করার পরে ব্যর্থ হওয়ার পরিবর্তে (এবং তারপরে ব্যবহারকারীর জন্য উপযুক্ত ত্রুটি বার্তা প্রদর্শন করুন), আমি প্রথমে রুট উপলব্ধ কিনা চুপচাপ পরীক্ষা করার দক্ষতাটি পছন্দ করব এবং যদি তা না হয় তবে প্রথমে সম্পর্কিত বিকল্পগুলি লুকিয়ে রাখি ।

এই কাজ করতে একটি উপায় আছে কি?


11
এটি করার কোনও নির্ভরযোগ্য উপায় নেই; নীচের উত্তরগুলি সাধারণ বৈশিষ্ট্যগুলি পরীক্ষা করে তবে প্রদত্ত ডিভাইসটি একটি সাধারণ উপায়ে রুট করা যায় না। যদি রুটের জন্য অনুসন্ধান করা প্রচলিত হয়, মূল সমাধানগুলি সম্ভবত তাদের আড়াল করার প্রয়াসে যেতে শুরু করবে। যেহেতু তারা অপারেটিং সিস্টেমের আচরণটি পরিবর্তন করতে পারে তাদের এগুলি করার জন্য প্রচুর বিকল্প রয়েছে।
ক্রিস স্ট্রাটন

আপনার অ্যাপ্লিকেশনটির সক্ষমতা গোপন করার পরিবর্তে সামগ্রিক অভিজ্ঞতার সাথে অস্পষ্টতা যুক্ত করার পরিবর্তে ব্যবহারকারীকে আরও বেশি তথ্য সরবরাহ করার মূল শুরুর অভাবের কারণে ফাংশনটি উপলভ্য নয় এটি ইঙ্গিত করা ভাল।
নিক শিয়াল

নীচের উত্তরগুলি কি সিস্টেমহীন রুটের জন্য কাজ করে ?
পীযূষ কুকাদিয়া

উত্তর:


259

এখানে একটি শ্রেণি যা রুটের জন্য তিনটি উপায়ের জন্য পরীক্ষা করবে।

/** @author Kevin Kowalewski */
public class RootUtil {
    public static boolean isDeviceRooted() {
        return checkRootMethod1() || checkRootMethod2() || checkRootMethod3();
    }

    private static boolean checkRootMethod1() {
        String buildTags = android.os.Build.TAGS;
        return buildTags != null && buildTags.contains("test-keys");
    }

    private static boolean checkRootMethod2() {
        String[] paths = { "/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
                "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su"};
        for (String path : paths) {
            if (new File(path).exists()) return true;
        }
        return false;
    }

    private static boolean checkRootMethod3() {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(new String[] { "/system/xbin/which", "su" });
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            if (in.readLine() != null) return true;
            return false;
        } catch (Throwable t) {
            return false;
        } finally {
            if (process != null) process.destroy();
        }
    }
}

8
যদি দুটি প্রশ্নের অনুরূপ উত্তরের ওয়ারেন্ট হয় তবে সেগুলি সময় নকলের 99% হয়, সুতরাং উভয়টিতে একই উত্তর পোস্ট করার পরিবর্তে দ্বিখ হিসাবে পতাকাঙ্কিত করুন। ধন্যবাদ।
কেভ

2
তাই হতে পারে, তা আমি শুধু লেট করছি আপনি কি জানেন যে সঠিক ডুপ্লিকেট উত্তর পতাকাঙ্কিত সম্প্রদায় দ্বারা। আপনার নিজের উত্তরগুলি তৈরি করতে হবে এবং ওপি'র সমস্যার সুনির্দিষ্ট ক্ষেত্রগুলিকে সম্বোধন করা উচিত। অনুলিপিগুলি আকর্ষণ করে ঝুঁকির জবাব কপি এবং পেস্ট করুন।
কেভ

9
-1, এই পদ্ধতিটি ব্যবহার্য নয়, কারণ কিছু ফোনে suবাইনারি অন্তর্ভুক্ত থাকে যখন মূল না থাকে।
neevek

12
কেবল আপনাকে জানাতে চেয়েছিলাম, ফক্স ডিজিটাল কপি (বিটা) অ্যাপ্লিকেশনটি আপনার কোডটি প্রায় ভার্বাটিম ব্যবহার করে, যার মধ্যে রুট এবং এক্সেকশেল ক্লাস, পাশাপাশি চেকরুটমেথোড 1/2/3 পদ্ধতি রয়েছে। এটি অত্যন্ত কৌতুকপূর্ণ খুঁজে পেয়েছি।
ম্যাট জোসেফ

8
ফক্স যেমন অগনিত অন্যদের বিরুদ্ধে মামলা করে?
কেভিন পার্কার

58

আপনি যদি ইতিমধ্যে ফ্যাব্রিক / ফায়ারবেস ক্র্যাশলিটিক্স ব্যবহার করে থাকেন তবে কল করতে পারেন

CommonUtils.isRooted(context)

এটি সেই পদ্ধতির বর্তমান বাস্তবায়ন:

public static boolean isRooted(Context context) {
    boolean isEmulator = isEmulator(context);
    String buildTags = Build.TAGS;
    if(!isEmulator && buildTags != null && buildTags.contains("test-keys")) {
        return true;
    } else {
        File file = new File("/system/app/Superuser.apk");
        if(file.exists()) {
            return true;
        } else {
            file = new File("/system/xbin/su");
            return !isEmulator && file.exists();
        }
    }
}

সর্বকালের সেরা উত্তর। দয়া করে যেকোন লাইব্রেরিতে এটি ব্যবহার করুন, চীনা ডিভাইসে প্রচুর মিথ্যা ইতিবাচক চলমান রয়েছে।
পেড্রো পাওলো আমোরিম

এই পদ্ধতিতে কি কোনও মিথ্যা ইতিবাচক আছে?
এহসান মাশহাদি

আমি এই সাথে নেক্সাস 5 উপর পরীক্ষা download.chainfire.eu/363/CF-Root/CF-Auto-Root/... , এই এক সঠিক নয়।
জেফ্রি লিউ

54

রুটটুলস লাইব্রেরিতে রুটটি পরীক্ষা করার জন্য সহজ পদ্ধতি সরবরাহ করা হয়:

RootTools.isRootAvailable()

উল্লেখ


10
isRootAv উপলভ্য () কেবলমাত্র পথের মধ্যে su এর অস্তিত্ব এবং কিছু অন্যান্য হার্ড-কোডেড ডিরেক্টরি পরীক্ষা করে। আমি শুনেছি কিছু অনারোটিং সরঞ্জামগুলি সেখানে ছুটি দেবে, সুতরাং এটি একটি মিথ্যা ইতিবাচক দেবে।
বব হোয়াইটম্যান

13
রুটটুলস.আইস্যাকসিজিভেন () কেবলমাত্র রুটের জন্য যাচাই করবে না, তবে রুটের অনুমতিও অনুরোধ করবে; সুতরাং একটি অরক্ষিত ডিভাইস সর্বদা এই পদ্ধতিতে মিথ্যা ফিরে আসবে।
সামগ্রিক

2
@ সমষ্টি 1166877, আপনি ঠিক বলেছেন, তবে এটি যথেষ্ট ভাল নয়, আমি যখন জিজ্ঞাসা করব তখন আমাকে রুট অনুমতির প্রয়োজন হয় না? আমি এটি জানতে চাই যে এটি মূলযুক্ত কিনা, তবে এই মুহুর্তে আমার রুট অনুমতি দরকার নেই।
neevek

4
ডিভাইসটি রুট হওয়া সত্ত্বেও যখন ব্যবহারকারী অনুমতি অস্বীকার করে তখন ইস্যাকসিজিভেন () মিথ্যা ফিরিয়ে দেয়।
subair_a

এটিই একমাত্র উত্তর যা আমি আপ-ভোটিংয়ের পক্ষে খুঁজে পাই। যদি আপনি অনুরূপ কিছু মাত্র পেস্ট অনুলিপি করতে চান নীচের আমার উত্তর পরীক্ষা করে দেখুন, অথবা আরো কিছু বিবরণ চাই
rsimp

52

আমার অ্যাপ্লিকেশনটিতে আমি "su" কমান্ড প্রয়োগ করে ডিভাইসটি মূলযুক্ত কিনা তা পরীক্ষা করে দেখছিলাম। তবে আজ আমি আমার কোডের এই অংশটি সরিয়েছি। কেন?

কারণ আমার অ্যাপ্লিকেশনটি একটি স্মৃতি ঘাতক হয়ে গেছে। কিভাবে? আমাকে আমার গল্প বলা যাক।

কিছু অভিযোগ ছিল যে আমার অ্যাপ্লিকেশনটি ডিভাইসগুলি কমিয়ে দিচ্ছে (অবশ্যই আমি ভেবেছিলাম এটি সত্য হতে পারে না)। আমি চেষ্টা করার চেষ্টা করলাম কেন। সুতরাং আমি হ্যাপ ডাম্পগুলি এবং বিশ্লেষণ করতে এমএটি ব্যবহার করেছি এবং সবকিছুই নিখুঁত বলে মনে হয়েছিল। তবে আমার অ্যাপ্লিকেশনটিকে অনেকবার পুনরায় চালু করার পরে আমি বুঝতে পেরেছিলাম যে ডিভাইসটি আসলেই ধীর হয়ে যাচ্ছে এবং আমার অ্যাপ্লিকেশনটি থামানো দ্রুততর হয়নি (আমি ডিভাইসটি পুনরায় চালু না করা পর্যন্ত)। আমি আবার ডাম্প ফাইল বিশ্লেষণ করেছি যখন ডিভাইসটি খুব ধীর হয়। তবে ডাম্প ফাইলের জন্য সবকিছুই নিখুঁত ছিল। তারপরে আমি প্রথমে যা করতে হবে তা করেছি। আমি প্রক্রিয়া তালিকাভুক্ত।

$ adb shell ps

surprize; আমার অ্যাপ্লিকেশনটির জন্য অনেকগুলি প্রক্রিয়া ছিল (ম্যানিফেস্টে আমার অ্যাপ্লিকেশনটির প্রক্রিয়া ট্যাগ সহ)। তাদের মধ্যে কিছু জম্বি ছিল তাদের মধ্যে কিছু না।

একটি নমুনা অ্যাপ্লিকেশন যার একটি একক ক্রিয়াকলাপ রয়েছে এবং কেবল "su" কমান্ড কার্যকর করে, আমি বুঝতে পেরেছি যে অ্যাপ্লিকেশনটির প্রতিটি প্রবর্তনে একটি জম্বি প্রক্রিয়া তৈরি করা হচ্ছে। প্রথমে এই জম্বিগুলি 0 কেবি বরাদ্দ করে তবে কিছু ঘটে তার চেয়ে বেশি এবং জুম্বি প্রক্রিয়াগুলি আমার অ্যাপ্লিকেশনটির মূল প্রক্রিয়া হিসাবে প্রায় একই কেবিগুলি ধারণ করে এবং তারা স্ট্যান্ডআর্ট প্রক্রিয়াতে পরিণত হয়।

Bugs.sun.com- তে একই ইস্যুটির জন্য একটি বাগ রিপোর্ট রয়েছে: http://bugs.sun.com/view_bug.do?bug_id=6474073 এটি ব্যাখ্যা করে যদি কমান্ড না পাওয়া যায় তবে এক্সিকিউটিভ () পদ্ধতিতে জম্বিগুলি তৈরি হতে চলেছে । তবে আমি এখনও বুঝতে পারি না কেন এবং কীভাবে তারা স্ট্যান্ডআর্ট প্রক্রিয়াতে পরিণত হতে পারে এবং উল্লেখযোগ্য কেবিএস ধরে রাখতে পারে। (এটি সব সময় হয় না)

আপনি নীচের কোড নমুনা চাইলে চেষ্টা করতে পারেন;

String commandToExecute = "su";
executeShellCommand(commandToExecute);

সাধারণ কমান্ড কার্যকর করার পদ্ধতি;

private boolean executeShellCommand(String command){
    Process process = null;            
    try{
        process = Runtime.getRuntime().exec(command);
        return true;
    } catch (Exception e) {
        return false;
    } finally{
        if(process != null){
            try{
                process.destroy();
            }catch (Exception e) {
            }
        }
    }
}

সংক্ষেপে; ডিভাইসটি মূলযুক্ত কিনা তা নির্ধারণ করার জন্য আমার কাছে আপনার কোনও পরামর্শ নেই। তবে আমি যদি আপনি থাকতাম আমি রানটাইম.জেটআরটাইম ()। এক্সিকিউট () ব্যবহার করতাম না।

যাইহোক; RootTools.isRootAv উপলভ্য () একই সমস্যা সৃষ্টি করে।


5
এটা খুব উদ্বেগজনক। আমার কাছে একটি শিকড় ডিভাইস সনাক্তকরণ ক্লাস ছিল যা একই কাজ করেছিল - এটি পড়ার পরে আমি নিশ্চিত করেছিলাম যে উপরে এজেনীয় কী কী বিশদ বর্ণনা করেছেন। মাঝেমধ্যে জম্বি প্রক্রিয়াগুলি পিছনে ফেলে রাখা, ডিভাইসটির মন্দা ইত্যাদি ...
এডাব্লুটি

1
আমি জিটি-এস5830 আই অ্যান্ড্রয়েড 2.3.6 এ রুটটুলস 3.4 এর সাথে সমস্যাটি নিশ্চিত করেছি confirm বেশিরভাগ জম্বি বরাদ্দ মেমরি পেয়েছে এবং সমস্যাটি নিয়মতান্ত্রিক। আমার 3-4 ডিগ্রি পরীক্ষার পরে ডিভাইসটি পুনরায় চালু করতে হবে। আমি পরীক্ষার ফলাফল ভাগ করে নেওয়া পছন্দ হিসাবে সংরক্ষণ করার পরামর্শ দিই।
খ্রিস্ট

2
গুগল এখন প্রসেসবিল্ডার () এবং স্টার্ট () কমান্ড ব্যবহার করার পরামর্শ দেয়।
EntangledLoops

1
@ নিকস আকর্ষণীয়, তবে আপনি কোন আদেশটি চালু করেছিলেন? 23 - আমি একই সমস্যা এখানে 9 থেকে আলাদা এপিআই স্তরের অসংখ্য অ্যান্ড্রয়েড ফোনে কমান্ড ব্যবহারের হবে না
EntangledLoops

1
@EntangledLoops। ধন্যবাদ. আমি আমার নিজস্ব বাইনারি চালু করি এবং স্টিডিন / স্টাডাউটের মাধ্যমে এটির সাথে ইন্টারঅ্যাক্ট করি। আমি কীভাবে এটি থামিয়েছি তা আবার যাচাই করেছিলাম এবং জানতে পেরেছি যে কোনও একটিতে আমি প্রসেস.ডেস্ট্রয় () মিস করেছি। সুতরাং, কোন জম্বি নেই।
নিক এস

36

এখানে তালিকাবদ্ধ উত্তরগুলির মধ্যে অনেকের অন্তর্নিহিত সমস্যা রয়েছে:

  • পরীক্ষা-কীগুলির জন্য চেক করা মূল অ্যাক্সেসের সাথে সম্পর্কিত হয় তবে অগত্যা এটির গ্যারান্টি দেয় না
  • "PATH" ডিরেক্টরিগুলি হার্ড কোডিংয়ের পরিবর্তে প্রকৃত "PATH" পরিবেশের পরিবর্তনশীল থেকে নেওয়া উচিত
  • "Su" এক্সিকিউটেবলের অস্তিত্বের অর্থ এই নয় যে ডিভাইসটি মূলী হয়েছে
  • "যা" এক্সিকিউটেবলটি ইনস্টল হতে পারে এবং নাও হতে পারে এবং সম্ভব হলে আপনার সিস্টেমটিকে তার পথটি সমাধান করতে দেওয়া উচিত
  • কেবলমাত্র ডিভাইসে সুপার ইউজার অ্যাপ্লিকেশন ইনস্টল থাকা মানে এই নয় যে ডিভাইসটিতে এখনও রুট অ্যাক্সেস রয়েছে

RootTools Stericson লাইব্রেরি থেকে আরো বৈধভাবে রুট চেক বলে মনে হয়। এটিতে প্রচুর অতিরিক্ত সরঞ্জাম এবং ইউটিলিটি রয়েছে তাই আমি এটির সুপারিশ করছি। তবে এটি কীভাবে মূলের জন্য বিশেষভাবে পরীক্ষা করে তার কোনও ব্যাখ্যা নেই এবং বেশিরভাগ অ্যাপ্লিকেশন সত্যই এটি প্রয়োজনের চেয়ে কিছুটা ভারীও হতে পারে।

আমি বেশ কয়েকটি ইউটিলিটি পদ্ধতি তৈরি করেছি যা রুটটুলস লাইব্রেরির উপর ভিত্তি করে আলগা। যদি আপনি কেবল "su" এক্সিকিউটেবল ডিভাইসে থাকে কিনা তা পরীক্ষা করতে চান তবে আপনি নিম্নলিখিত পদ্ধতিটি ব্যবহার করতে পারেন:

public static boolean isRootAvailable(){
    for(String pathDir : System.getenv("PATH").split(":")){
        if(new File(pathDir, "su").exists()) {
            return true;
        }
    }
    return false;
}

এই পদ্ধতিটি "PATH" এনভায়রনমেন্ট ভেরিয়েবলের তালিকাভুক্ত ডিরেক্টরিগুলির মধ্যে কেবল লুপ করে এবং যদি তার মধ্যে একটি "su" ফাইল উপস্থিত থাকে তবে তা পরীক্ষা করে।

মূল অ্যাক্সেসের সত্যতা যাচাই করার জন্য "su" কমান্ডটি আসলে চালানো উচিত। যদি সুপার ইউজারের মতো কোনও অ্যাপ্লিকেশন ইনস্টল করা থাকে, তবে এই মুহুর্তে এটি রুট অ্যাক্সেসের জন্য জিজ্ঞাসা করতে পারে, বা এটি ইতিমধ্যে কোনও টোস্টকে মঞ্জুর / অস্বীকৃত থাকলে অ্যাক্সেস মঞ্জুর / অস্বীকৃত কিনা তা নির্দেশ করে দেখানো যেতে পারে। চালানোর জন্য একটি ভাল কমান্ড হ'ল "আইডি" যাতে আপনি যাচাই করতে পারেন যে ব্যবহারকারীর আইডি আসলে 0 (মূল)।

মূল অ্যাক্সেস দেওয়া হয়েছে কিনা তা নির্ধারণের জন্য এখানে একটি নমুনা পদ্ধতি রয়েছে:

public static boolean isRootGiven(){
    if (isRootAvailable()) {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(new String[]{"su", "-c", "id"});
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String output = in.readLine();
            if (output != null && output.toLowerCase().contains("uid=0"))
                return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (process != null)
                process.destroy();
        }
    }

    return false;
}

আসলে "su" কমান্ডটি চালানো পরীক্ষা করা গুরুত্বপূর্ণ কারণ কিছু ইমুলেটরগুলির "সু" এক্সিকিউটেবল প্রাক-ইনস্টলড থাকে তবে কেবলমাত্র নির্দিষ্ট ব্যবহারকারীদেরই এটি অ্যাডিবি শেলের মতো অ্যাক্সেস করার অনুমতি দেয়।

এটি চালানোর চেষ্টা করার আগে "su" এক্সিকিউটেবলের অস্তিত্বের জন্য এটি পরীক্ষা করাও গুরুত্বপূর্ণ, কারণ অ্যান্ড্রয়েড অনুপস্থিত কমান্ডগুলি চালানোর চেষ্টা করে এমন প্রক্রিয়াগুলি সঠিকভাবে নিষ্পত্তি না করার জন্য পরিচিত। এই ভূত প্রক্রিয়াগুলি সময়ের সাথে সাথে মেমরির খরচ চালিয়ে যেতে পারে।


IsRootAv উপলভ্য () পদ্ধতিটি দুর্দান্ত কাজ করে, আপনাকে ধন্যবাদ। আমি এএনআর এড়ানোর জন্য মূল থ্রেড এ না চালানোর পরামর্শ দিচ্ছি, যেমন এসিঙ্কটাস্কের কল
থান্ডারস্টিক

1
আমি মনে করি যে শিকড় উপলব্ধ নয় এবং তা নিশ্চিত করার জন্য এটির মধ্যে পার্থক্য রয়েছে। আপনি যদি নিশ্চিত করতে চান যে কোনও ডিভাইস রুট নয়, প্রস্তাবিত চেকগুলি ভাল। আপনি মিথ্যা ইতিবাচক পাবেন তবে এটি ঠিক আছে যখন কোনও আপোসযুক্ত ডিভাইসে আপনার কোডটি চালনা না করা আপনার প্রধান উদ্বেগ।
জেফ্রি ব্লাটম্যান

1
@ DAC84 আমি নিশ্চিত না যে আমি আপনার প্রশ্নটি বুঝতে পেরেছি। আপনি যদি ইজ রুটজিভেন চালনা করেন এবং আপনার মূল অ্যাপ্লিকেশনটিকে অস্বীকার করেন তবে এটি মিথ্যা ফিরতে হবে। এটা কি হচ্ছে না? আপনি যদি সতর্কতা এড়াতে চান তবে আপনি কেবল 'রুটঅভ্যালেবল' ব্যবহার করতে পারেন যার নামটিও এসইউএসজিস্ট থাকতে পারে। আপনি নিখরচায় রুট দিতে এবং এটি পরিচালনা না করার জন্য আপনার মূল অ্যাপ্লিকেশনটি কনফিগার করার চেষ্টা করতে পারেন।
আরএসম্পি

1
@ বিয়িংজেইকে আসলেই নয়, যদিও এটিই সবচেয়ে বেশি আপনি যা চালাতে চান না এটি পরীক্ষা করতে পারেন যা আসল পরীক্ষা। যদিও এটি কার্যকর করার চেষ্টা করার আগে আপনার PATH তে su পরীক্ষা করা দরকার। তবে প্রকৃতপক্ষে কার্যকর করা su এর প্রায়শই টোস্ট বার্তা বা রুট ম্যানেজিং অ্যাপ্লিকেশনটির সাথে ইন্টারঅ্যাকশন হয় যা আপনি যা চান তা নাও হতে পারে। আপনার নিজের যুক্তির জন্য আপনি যথেষ্ট পরিমাণে কেবলমাত্র অস্তিত্ব হিসাবে বিবেচনা করতে পারেন। এটি এখনও কিছু এমুলেটরগুলিতে মিথ্যা ইতিবাচকতা দিতে পারে যার মধ্যে এটিতে এক্স এক্সিকিউটেবল তবে লকডাউন অ্যাক্সেস থাকতে পারে।
এআগস্ট

1
@ বিইংজেকি ইজ রুটআলভ্যালিটি সম্ভবত আপনার যা প্রয়োজন তা হল, তবে আমি যে বিষয়টিটি তৈরি করতে চাইছি তা হ'ল এর মতো একটি নাম বা এমনকি ডু এসইউইক্সবাদী ডিভাইস রুটেডের মতো পদ্ধতির নামের চেয়ে ভাল শব্দার্থ সরবরাহ করে যা একেবারেই সঠিক নয় right আপনি যদি এগিয়ে যাওয়ার আগে সত্যিই সম্পূর্ণ রুট অ্যাক্সেস যাচাই করতে চান তবে আপনার সাথে একটি কমান্ড চালানোর চেষ্টা করতে হবে যেমন রূট জিভেন
রশিম্পে

35

আপডেট 2017

আপনি এখন গুগল সাফিটনেট এপিআই দিয়ে এটি করতে পারেন । সেফটি নেট নেট অ্যাপ্লিকেশন অ্যাটেস্টেশন এপিআই সরবরাহ করে যা আপনাকে আপনার অ্যাপ্লিকেশনগুলি চালিত অ্যান্ড্রয়েড পরিবেশগুলির সুরক্ষা এবং সামঞ্জস্যতা মূল্যায়নে সহায়তা করে।

এই প্রমাণীকরণটি নির্দিষ্ট ডিভাইসটির সাথে টেম্পারার হয়েছে কিনা তা নির্ধারণ করতে সহায়তা করতে পারে বা অন্যভাবে সংশোধিত হতে পারে।

স্বীকৃতি এপিআই এর মতো একটি জেডাব্লুএস প্রতিক্রিয়া দেয়

{
  "nonce": "R2Rra24fVm5xa2Mg",
  "timestampMs": 9860437986543,
  "apkPackageName": "com.package.name.of.requesting.app",
  "apkCertificateDigestSha256": ["base64 encoded, SHA-256 hash of the
                                  certificate used to sign requesting app"],
  "apkDigestSha256": "base64 encoded, SHA-256 hash of the app's APK",
  "ctsProfileMatch": true,
  "basicIntegrity": true,
}

এই প্রতিক্রিয়াটি পার্স করা আপনাকে ডিভাইসটি রুটে রয়েছে কিনা তা নির্ধারণ করতে সহায়তা করতে পারে

শিকড় ডিভাইসগুলি ctsProfileMatch = মিথ্যা বলে মনে হচ্ছে।

আপনি এটি ক্লায়েন্টের পক্ষে করতে পারেন তবে সার্ভার সাইডে প্রতিক্রিয়া পার্স করার পরামর্শ দেওয়া হচ্ছে। সুরক্ষা নেট এপিআই সহ একটি মৌলিক ক্লায়েন্ট সার্ভার আর্কিটেকচারটি এর মতো দেখতে পাবেন: -

এখানে চিত্র বর্ণনা লিখুন


3
দুর্দান্ত তথ্য এবং অন্য প্রসঙ্গে আমি বিশ্বাস করি এটি সঠিক উত্তর হবে। দুর্ভাগ্যক্রমে ওপিএস প্রশ্নটি তার অ্যাপটিকে অনিরাপদ পরিবেশ থেকে রক্ষা করার বিষয়ে নয়, তবে তার অ্যাপ্লিকেশনটিতে কেবলমাত্র রুট বৈশিষ্ট্য সক্ষম করতে রুট সনাক্তকরণ নয়। ওপিএস উদ্দেশ্যে উদ্দেশ্যে এই প্রক্রিয়া অত্যধিক জটিল বলে মনে হচ্ছে।
আরম্পিম্প

31

জাভা স্তরে রুট চেক করা নিরাপদ সমাধান নয়। যদি আপনার অ্যাপ্লিকেশনটিতে কোনও শিকড়যুক্ত ডিভাইস চালনার জন্য সুরক্ষা সম্পর্কিত সমস্যা থাকে তবে দয়া করে এই সমাধানটি ব্যবহার করুন।

ফোনে রুটক্লকের মতো অ্যাপ না থাকলে কেভিনের উত্তরটি কাজ করে। ফোন রুট হয়ে গেলে এই জাতীয় অ্যাপ্লিকেশনগুলির হ্যান্ডল ওভার জাভা এপিআইগুলি থাকে এবং ফোন এড়াতে তারা এই এপিআইগুলিকে মক করে।

আমি কেভিনের উত্তরের ভিত্তিতে একটি নেটিভ লেভেল কোড লিখেছি, এটি রুটক্লুকের সাথেও কাজ করে! এছাড়াও এটি কোনও স্মৃতি ফাঁসির সমস্যা সৃষ্টি করে না।

#include <string.h>
#include <jni.h>
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include "android_log.h"
#include <errno.h>
#include <unistd.h>
#include <sys/system_properties.h>

JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod1(
        JNIEnv* env, jobject thiz) {


    //Access function checks whether a particular file can be accessed
    int result = access("/system/app/Superuser.apk",F_OK);

    ANDROID_LOGV( "File Access Result %d\n", result);

    int len;
    char build_tags[PROP_VALUE_MAX]; // PROP_VALUE_MAX from <sys/system_properties.h>.
    len = __system_property_get(ANDROID_OS_BUILD_TAGS, build_tags); // On return, len will equal (int)strlen(model_id).
    if(strcmp(build_tags,"test-keys") == 0){
        ANDROID_LOGV( "Device has test keys\n", build_tags);
        result = 0;
    }
    ANDROID_LOGV( "File Access Result %s\n", build_tags);
    return result;

}

JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod2(
        JNIEnv* env, jobject thiz) {
    //which command is enabled only after Busy box is installed on a rooted device
    //Outpput of which command is the path to su file. On a non rooted device , we will get a null/ empty path
    //char* cmd = const_cast<char *>"which su";
    FILE* pipe = popen("which su", "r");
    if (!pipe) return -1;
    char buffer[128];
    std::string resultCmd = "";
    while(!feof(pipe)) {
        if(fgets(buffer, 128, pipe) != NULL)
            resultCmd += buffer;
    }
    pclose(pipe);

    const char *cstr = resultCmd.c_str();
    int result = -1;
    if(cstr == NULL || (strlen(cstr) == 0)){
        ANDROID_LOGV( "Result of Which command is Null");
    }else{
        result = 0;
        ANDROID_LOGV( "Result of Which command %s\n", cstr);
        }
    return result;

}

JNIEXPORT int JNICALL Java_com_test_RootUtils_checkRootAccessMethod3(
        JNIEnv* env, jobject thiz) {


    int len;
    char build_tags[PROP_VALUE_MAX]; // PROP_VALUE_MAX from <sys/system_properties.h>.
    int result = -1;
    len = __system_property_get(ANDROID_OS_BUILD_TAGS, build_tags); // On return, len will equal (int)strlen(model_id).
    if(len >0 && strstr(build_tags,"test-keys") != NULL){
        ANDROID_LOGV( "Device has test keys\n", build_tags);
        result = 0;
    }

    return result;

}

আপনার জাভা কোডে, নেটিভ কলগুলি করার জন্য আপনাকে র‌্যাপার ক্লাস রুট ইউটিলস তৈরি করতে হবে

    public boolean checkRooted() {

       if( rootUtils.checkRootAccessMethod3()  == 0 || rootUtils.checkRootAccessMethod1()  == 0 || rootUtils.checkRootAccessMethod2()  == 0 )
           return true;
      return false;
     }

1
আমি মনে করি যে রুট সনাক্তকরণ দুটি বিভাগে পড়ে, মূল নির্ভর বৈশিষ্ট্যগুলি সক্ষম করে এবং তারপরে সুরক্ষিত ফোনগুলির সাহায্যে সুরক্ষা সংক্রান্ত সমস্যাগুলি হ্রাস করার চেষ্টা করার জন্য সুরক্ষা ভিত্তিক ব্যবস্থা গ্রহণ করে। রুট নির্ভর বৈশিষ্ট্যগুলির জন্য আমি কেভিনের উত্তরটি বেশ দুর্বল বলে মনে করি। এই উত্তরের প্রসঙ্গে এই পদ্ধতিগুলি আরও অর্থবোধ করে। যদিও আমি ব্যবহার না করার জন্য পদ্ধতি 2 পুনর্লিখন করব এবং পরিবর্তে "su" অনুসন্ধান করার জন্য PATH পরিবেশের পরিবর্তনশীলটির উপর পুনরাবৃত্তি করব। "যা" ফোনে থাকার নিশ্চয়তা নেই।

আপনি দয়া করে জাভাতে এই সি কোডটি কীভাবে ব্যবহার করবেন তার একটি উদাহরণ সরবরাহ করতে পারেন?
মিড

@ মিঃ অ্যান্ড্রয়েডে জাভা থেকে কীভাবে জেএনআই কল করবেন তা দয়া করে দেখুন।
অলোক কুলকারনী

এই পদ্ধতিটি রুটক্লোক অ্যাপ্লিকেশন ব্যবহার করে রুট সনাক্তকরণ বাইপাস প্রতিরোধ করে। এমন কোনও রুট বাইপাস কৌশল রয়েছে যা এই পদ্ধতিতে ব্যর্থ হয়?
নিধিন

20

http://code.google.com/p/roottools/

আপনি যদি জার ফাইলটি ব্যবহার করতে না চান তবে কেবল কোডটি ব্যবহার করুন:

public static boolean findBinary(String binaryName) {
        boolean found = false;
        if (!found) {
            String[] places = { "/sbin/", "/system/bin/", "/system/xbin/",
                    "/data/local/xbin/", "/data/local/bin/",
                    "/system/sd/xbin/", "/system/bin/failsafe/", "/data/local/" };
            for (String where : places) {
                if (new File(where + binaryName).exists()) {
                    found = true;

                    break;
                }
            }
        }
        return found;
    }

প্রোগ্রাম su ফোল্ডারটি সন্ধান করার চেষ্টা করবে:

private static boolean isRooted() {
        return findBinary("su");
    }

উদাহরণ:

if (isRooted()) {
   textView.setText("Device Rooted");

} else {
   textView.setText("Device Unrooted");
}

ধন্যবাদ! আমি এই ব্যবহার করছি checkRootMethod4()সঙ্গে কেভিন এর উত্তর
শেহেরিয়ার

1
== trueকোনও বুলিয়ান কখনও যুক্ত করবেন না, এটি কিছুই জুড়ে না এবং ভাল দেখাচ্ছে না।
minipif

2
@ স্মথ ব্লু কেন এটি হবে? এটি ডিভরিমটুনসারের সমাধান হিসাবে কোনও প্রক্রিয়া তৈরি করছে না।
এফডি_

1
আরও ভাল ধারণা
পাথের

1
if (isRooted())স্পষ্টভাবে সত্য লেখার পরিবর্তে ব্যবহার করুন, পরীক্ষা করুন । কোড লেখার ধরণগুলি অনুসরণ করা আরও ভাল
ব্লুওয়্যার

13

IsRootAv উপলভ্য () ব্যবহার করার পরিবর্তে আপনি isAccessGiven () ব্যবহার করতে পারেন। রুটটুলস উইকি থেকে সরাসরি :

if (RootTools.isAccessGiven()) {
    // your app has been granted root access
}

রুটটুলস.আইস অ্যাক্সেসজিভেন () কেবল কোনও ডিভাইসটি মূলযুক্ত কিনা তা পরীক্ষা করে না, এটি আপনার অ্যাপ্লিকেশনটির জন্য স কেও ডেকে আনে, অনুমতির অনুরোধ করে এবং যদি আপনার অ্যাপ্লিকেশনটিকে সফলভাবে রুট অনুমতি দেওয়া হয় তবে সত্য ফিরে আসে। আপনার অ্যাপ্লিকেশনটির প্রথম চেক হিসাবে এটি আপনার প্রয়োজন অনুসারে অ্যাক্সেস দেওয়া হবে তা নিশ্চিত করতে ব্যবহার করা যেতে পারে।

উল্লেখ


কিন্তু ব্যবহারকারীকে রুট অ্যাক্সেস দিতে হবে? সুতরাং যদি আমার উদ্দেশ্য যদি আমার অ্যাপ্লিকেশনটি চালানো থেকে থামানো হয় তবে যদি ডিভাইসটি রুট করা থাকে তবে আমার অপশনগুলি সত্যই সীমিত
নাসজ এনজোকা জুনিয়র

11

কিছু উদ্দেশ্যে পরিবর্তিত বিল্ডগুলি এই উদ্দেশ্যে সিস্টেম সম্পত্তি সেট করতে ব্যবহৃত হয় ro.modversion। জিনিসগুলি এগিয়ে গেছে বলে মনে হচ্ছে; আমার কয়েক মাস আগে থুডুড থেকে আমার বিল্ডটিতে এটি রয়েছে:

cmb@apollo:~$ adb -d shell getprop |grep build
[ro.build.id]: [CUPCAKE]
[ro.build.display.id]: [htc_dream-eng 1.5 CUPCAKE eng.TheDudeAbides.20090427.235325 test-keys]
[ro.build.version.incremental]: [eng.TheDude.2009027.235325]
[ro.build.version.sdk]: [3]
[ro.build.version.release]: [1.5]
[ro.build.date]: [Mon Apr 20 01:42:32 CDT 2009]
[ro.build.date.utc]: [1240209752]
[ro.build.type]: [eng]
[ro.build.user]: [TheDude]
[ro.build.host]: [ender]
[ro.build.tags]: [test-keys]
[ro.build.product]: [dream]
[ro.build.description]: [kila-user 1.1 PLAT-RC33 126986 ota-rel-keys,release-keys]
[ro.build.fingerprint]: [tmobile/kila/dream/trout:1.1/PLAT-RC33/126986:user/ota-rel-keys,release-keys]
[ro.build.changelist]: [17615# end build properties]

অন্যদিকে 1.5 এসডিকে থেকে এমুলেটর, 1.5 ইমেজটি চালাচ্ছে যার মূলও রয়েছে, সম্ভবত অ্যান্ড্রয়েড ডেভ ফোন 1 এর সমান (যা সম্ভবত আপনি অনুমতি দিতে চান) এবং এটিতে রয়েছে:

cmb@apollo:~$ adb -e shell getprop |grep build
[ro.build.id]: [CUPCAKE]
[ro.build.display.id]: [sdk-eng 1.5 CUPCAKE 148875 test-keys]
[ro.build.version.incremental]: [148875]
[ro.build.version.sdk]: [3]
[ro.build.version.release]: [1.5]
[ro.build.date]: [Thu May 14 18:09:10 PDT 2009]
[ro.build.date.utc]: [1242349750]
[ro.build.type]: [eng]
[ro.build.user]: [android-build]
[ro.build.host]: [undroid16.mtv.corp.google.com]
[ro.build.tags]: [test-keys]
[ro.build.product]: [generic]
[ro.build.description]: [sdk-eng 1.5 CUPCAKE 148875 test-keys]
[ro.build.fingerprint]: [generic/sdk/generic/:1.5/CUPCAKE/148875:eng/test-keys]

খুচরা বিল্ডগুলির ক্ষেত্রে, আমার হাতে কোনও হস্তক্ষেপ নেই, তবে বিভিন্ন অনুসন্ধানগুলি site:xda-developers.comতথ্যপূর্ণ। এখানে নেদারল্যান্ডসে একটি জি 1 রয়েছে , আপনি এটি দেখতে পাচ্ছেন ro.build.tagsনা test-keysএবং আমি মনে করি এটি সম্ভবত সবচেয়ে নির্ভরযোগ্য সম্পত্তি property


যে আকর্ষণীয় দেখায়, কিন্তু: এমুলেটর (এবং এডিপি) রুট করার অনুমতি কোনটাই না যদিও, তারা অ্যাপ্লিকেশন এটি ব্যবহার করার অনুমতি দেয় না, অর্থাত্: $ su কমান্ড app_29 $ Su Su: ইউআইডি 10029 su কমান্ড করার অনুমতি দেওয়া হয়নি
miracle2k

আহ, আমি মনে করি তারা না করত ... আপনি এটিকে গুগল ডট কম-এ শেষ করার জন্য রো.বিল্ড হস্ট (না) অনুসন্ধানের সাথে একত্রিত করতে পারেন, যদি তারা কেবল পরীক্ষাগুলি না রাখেন তবে এস কে ব্লক না করে ব্লক করেন block ব্যবহারকারী জিজ্ঞাসা। নতুন ডিভাইসগুলির জন্য বিল্ড হোস্টটি কী তা নির্ভর করে, যে জিনিসগুলি ফোন নয় ... সহজ নয়।
ক্রিস বোয়েল

11

স্কট এবং ম্যাথু দ্বারা রুটবিয়ার একটি মূল চেক অ্যান্ড্রয়েড লাইব্রেরি। ডিভাইসটি মূলযুক্ত কিনা তা নির্দেশ করতে এটি বিভিন্ন চেক ব্যবহার করে।

জাভা চেক

  • CheckRootManagementApps

  • CheckPotentiallyDangerousAppss

  • CheckRootCloakingApps

  • CheckTestKeys

  • checkForDangerousProps

  • checkForBusyBoxBinary

  • checkForSuBinary

  • checkSuExists

  • checkForRWSystem

নেটিভ চেক

এর কিছু নিজস্ব চেক চালানোর জন্য আমরা আমাদের স্থানীয় রুট পরীক্ষককে কল করি। নেটিভ চেকগুলি সাধারণত চাদর থেকে শক্ত হয়, তাই কিছু মূল ক্লোপ অ্যাপ্লিকেশন কেবল নির্দিষ্ট মূল শব্দগুলিতে নেটিভ লাইব্রেরিগুলি লোড করা অবরুদ্ধ করে।

  • checkForSuBinary

8

আমি রুট সনাক্তকরণের জন্য নেটিভ কোড ব্যবহার করার পরামর্শ দিই। এখানে একটি পরিপূর্ণ কাজ উদাহরণ

এখানে চিত্র বর্ণনা লিখুন

জাভা র‌্যাপার :

package com.kozhevin.rootchecks.util;


import android.support.annotation.NonNull;

import com.kozhevin.rootchecks.BuildConfig;

public class MeatGrinder {
    private final static String LIB_NAME = "native-lib";
    private static boolean isLoaded;
    private static boolean isUnderTest = false;

    private MeatGrinder() {

    }

    public boolean isLibraryLoaded() {
        if (isLoaded) {
            return true;
        }
        try {
            if(isUnderTest) {
                throw new UnsatisfiedLinkError("under test");
            }
            System.loadLibrary(LIB_NAME);
            isLoaded = true;
        } catch (UnsatisfiedLinkError e) {
            if (BuildConfig.DEBUG) {
                e.printStackTrace();
            }
        }
        return isLoaded;
    }

    public native boolean isDetectedDevKeys();

    public native boolean isDetectedTestKeys();

    public native boolean isNotFoundReleaseKeys();

    public native boolean isFoundDangerousProps();

    public native boolean isPermissiveSelinux();

    public native boolean isSuExists();

    public native boolean isAccessedSuperuserApk();

    public native boolean isFoundSuBinary();

    public native boolean isFoundBusyboxBinary();

    public native boolean isFoundXposed();

    public native boolean isFoundResetprop();

    public native boolean isFoundWrongPathPermission();

    public native boolean isFoundHooks();

    @NonNull
    public static MeatGrinder getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private static class InstanceHolder {
        private static final MeatGrinder INSTANCE = new MeatGrinder();
    }
}

জেএনআই মোড়ক (নেটিভ- lib.c) :

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isDetectedTestKeys(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isDetectedTestKeys();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isDetectedDevKeys(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isDetectedDevKeys();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isNotFoundReleaseKeys(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isNotFoundReleaseKeys();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundDangerousProps(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundDangerousProps();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isPermissiveSelinux(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isPermissiveSelinux();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isSuExists(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isSuExists();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isAccessedSuperuserApk(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isAccessedSuperuserApk();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundSuBinary(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundSuBinary();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundBusyboxBinary(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundBusyboxBinary();
}


JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundXposed(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundXposed();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundResetprop(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundResetprop();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundWrongPathPermission(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundWrongPathPermission();
}

JNIEXPORT jboolean JNICALL
Java_com_kozhevin_rootchecks_util_MeatGrinder_isFoundHooks(
        JNIEnv *env,
        jobject  this ) {

    return (jboolean) isFoundHooks();
}

ধ্রুবক:

// Comma-separated tags describing the build, like= "unsigned,debug".
const char *const ANDROID_OS_BUILD_TAGS = "ro.build.tags";

// A string that uniquely identifies this build. 'BRAND/PRODUCT/DEVICE:RELEASE/ID/VERSION.INCREMENTAL:TYPE/TAGS'.
const char *const ANDROID_OS_BUILD_FINGERPRINT = "ro.build.fingerprint";

const char *const ANDROID_OS_SECURE = "ro.secure";

const char *const ANDROID_OS_DEBUGGABLE = "ro.debuggable";
const char *const ANDROID_OS_SYS_INITD = "sys.initd";
const char *const ANDROID_OS_BUILD_SELINUX = "ro.build.selinux";
//see https://android.googlesource.com/platform/system/core/+/master/adb/services.cpp#86
const char *const SERVICE_ADB_ROOT = "service.adb.root";

const char * const MG_SU_PATH[] = {
        "/data/local/",
        "/data/local/bin/",
        "/data/local/xbin/",
        "/sbin/",
        "/system/bin/",
        "/system/bin/.ext/",
        "/system/bin/failsafe/",
        "/system/sd/xbin/",
        "/su/xbin/",
        "/su/bin/",
        "/magisk/.core/bin/",
        "/system/usr/we-need-root/",
        "/system/xbin/",
        0
};

const char * const MG_EXPOSED_FILES[] = {
        "/system/lib/libxposed_art.so",
        "/system/lib64/libxposed_art.so",
        "/system/xposed.prop",
        "/cache/recovery/xposed.zip",
        "/system/framework/XposedBridge.jar",
        "/system/bin/app_process64_xposed",
        "/system/bin/app_process32_xposed",
        "/magisk/xposed/system/lib/libsigchain.so",
        "/magisk/xposed/system/lib/libart.so",
        "/magisk/xposed/system/lib/libart-disassembler.so",
        "/magisk/xposed/system/lib/libart-compiler.so",
        "/system/bin/app_process32_orig",
        "/system/bin/app_process64_orig",
        0
};

const char * const MG_READ_ONLY_PATH[] = {
        "/system",
        "/system/bin",
        "/system/sbin",
        "/system/xbin",
        "/vendor/bin",
        "/sbin",
        "/etc",
        0
};

নেটিভ কোড থেকে মূল সনাক্তকরণ:

struct mntent *getMntent(FILE *fp, struct mntent *e, char *buf, int buf_len) {

    while (fgets(buf, buf_len, fp) != NULL) {
        // Entries look like "/dev/block/vda /system ext4 ro,seclabel,relatime,data=ordered 0 0".
        // That is: mnt_fsname mnt_dir mnt_type mnt_opts mnt_freq mnt_passno.
        int fsname0, fsname1, dir0, dir1, type0, type1, opts0, opts1;
        if (sscanf(buf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d",
                   &fsname0, &fsname1, &dir0, &dir1, &type0, &type1, &opts0, &opts1,
                   &e->mnt_freq, &e->mnt_passno) == 2) {
            e->mnt_fsname = &buf[fsname0];
            buf[fsname1] = '\0';
            e->mnt_dir = &buf[dir0];
            buf[dir1] = '\0';
            e->mnt_type = &buf[type0];
            buf[type1] = '\0';
            e->mnt_opts = &buf[opts0];
            buf[opts1] = '\0';
            return e;
        }
    }
    return NULL;
}


bool isPresentMntOpt(const struct mntent *pMnt, const char *pOpt) {
    char *token = pMnt->mnt_opts;
    const char *end = pMnt->mnt_opts + strlen(pMnt->mnt_opts);
    const size_t optLen = strlen(pOpt);
    while (token != NULL) {
        const char *tokenEnd = token + optLen;
        if (tokenEnd > end) break;
        if (memcmp(token, pOpt, optLen) == 0 &&
            (*tokenEnd == '\0' || *tokenEnd == ',' || *tokenEnd == '=')) {
            return true;
        }
        token = strchr(token, ',');
        if (token != NULL) {
            token++;
        }
    }
    return false;
}

static char *concat2str(const char *pString1, const char *pString2) {
    char *result;
    size_t lengthBuffer = 0;

    lengthBuffer = strlen(pString1) +
                   strlen(pString2) + 1;
    result = malloc(lengthBuffer);
    if (result == NULL) {
        GR_LOGW("malloc failed\n");
        return NULL;
    }
    memset(result, 0, lengthBuffer);
    strcpy(result, pString1);
    strcat(result, pString2);
    return result;
}

static bool
isBadPropertyState(const char *key, const char *badValue, bool isObligatoryProperty, bool isExact) {
    if (badValue == NULL) {
        GR_LOGE("badValue may not be NULL");
        return false;
    }
    if (key == NULL) {
        GR_LOGE("key may not be NULL");
        return false;
    }
    char value[PROP_VALUE_MAX + 1];
    int length = __system_property_get(key, value);
    bool result = false;
    /* A length 0 value indicates that the property is not defined */
    if (length > 0) {
        GR_LOGI("property:[%s]==[%s]", key, value);
        if (isExact) {
            if (strcmp(value, badValue) == 0) {
                GR_LOGW("bad value[%s] equals to [%s] in the property [%s]", value, badValue, key);
                result = true;
            }
        } else {
            if (strlen(value) >= strlen(badValue) && strstr(value, badValue) != NULL) {
                GR_LOGW("bad value[%s] found in [%s] in the property [%s]", value, badValue, key);
                result = true;
            }
        }
    } else {
        GR_LOGI("[%s] property not found", key);
        if (isObligatoryProperty) {
            result = true;
        }
    }
    return result;
}

bool isDetectedTestKeys() {
    const char *TEST_KEYS_VALUE = "test-keys";
    return isBadPropertyState(ANDROID_OS_BUILD_TAGS, TEST_KEYS_VALUE, true, false);
}

bool isDetectedDevKeys() {
    const char *DEV_KEYS_VALUE = "dev-keys";
    return isBadPropertyState(ANDROID_OS_BUILD_TAGS, DEV_KEYS_VALUE, true, false);
}

bool isNotFoundReleaseKeys() {
    const char *RELEASE_KEYS_VALUE = "release-keys";
    return !isBadPropertyState(ANDROID_OS_BUILD_TAGS, RELEASE_KEYS_VALUE, false, true);
}

bool isFoundWrongPathPermission() {

    bool result = false;
    FILE *file = fopen("/proc/mounts", "r");
    char mntent_strings[BUFSIZ];
    if (file == NULL) {
        GR_LOGE("setmntent");
        return result;
    }

    struct mntent ent = {0};
    while (NULL != getMntent(file, &ent, mntent_strings, sizeof(mntent_strings))) {
        for (size_t i = 0; MG_READ_ONLY_PATH[i]; i++) {
            if (strcmp((&ent)->mnt_dir, MG_READ_ONLY_PATH[i]) == 0 &&
                isPresentMntOpt(&ent, "rw")) {
                GR_LOGI("%s %s %s %s\n", (&ent)->mnt_fsname, (&ent)->mnt_dir, (&ent)->mnt_opts,
                        (&ent)->mnt_type);
                result = true;
                break;
            }
        }
        memset(&ent, 0, sizeof(ent));
    }
    fclose(file);
    return result;
}


bool isFoundDangerousProps() {
    const char *BAD_DEBUGGABLE_VALUE = "1";
    const char *BAD_SECURE_VALUE = "0";
    const char *BAD_SYS_INITD_VALUE = "1";
    const char *BAD_SERVICE_ADB_ROOT_VALUE = "1";

    bool result = isBadPropertyState(ANDROID_OS_DEBUGGABLE, BAD_DEBUGGABLE_VALUE, true, true) ||
                  isBadPropertyState(SERVICE_ADB_ROOT, BAD_SERVICE_ADB_ROOT_VALUE, false, true) ||
                  isBadPropertyState(ANDROID_OS_SECURE, BAD_SECURE_VALUE, true, true) ||
                  isBadPropertyState(ANDROID_OS_SYS_INITD, BAD_SYS_INITD_VALUE, false, true);

    return result;
}

bool isPermissiveSelinux() {
    const char *BAD_VALUE = "0";
    return isBadPropertyState(ANDROID_OS_BUILD_SELINUX, BAD_VALUE, false, false);
}

bool isSuExists() {
    char buf[BUFSIZ];
    char *str = NULL;
    char *temp = NULL;
    size_t size = 1;  // start with size of 1 to make room for null terminator
    size_t strlength;

    FILE *pipe = popen("which su", "r");
    if (pipe == NULL) {
        GR_LOGI("pipe is null");
        return false;
    }

    while (fgets(buf, sizeof(buf), pipe) != NULL) {
        strlength = strlen(buf);
        temp = realloc(str, size + strlength);  // allocate room for the buf that gets appended
        if (temp == NULL) {
            // allocation error
            GR_LOGE("Error (re)allocating memory");
            pclose(pipe);
            if (str != NULL) {
                free(str);
            }
            return false;
        } else {
            str = temp;
        }
        strcpy(str + size - 1, buf);
        size += strlength;
    }
    pclose(pipe);
    GR_LOGW("A size of the result from pipe is [%zu], result:\n [%s] ", size, str);
    if (str != NULL) {
        free(str);
    }
    return size > 1 ? true : false;
}

static bool isAccessedFile(const char *path) {
    int result = access(path, F_OK);
    GR_LOGV("[%s] has been accessed with result: [%d]", path, result);
    return result == 0 ? true : false;
}

static bool isFoundBinaryFromArray(const char *const *array, const char *binary) {
    for (size_t i = 0; array[i]; ++i) {
        char *checkedPath = concat2str(array[i], binary);
        if (checkedPath == NULL) { // malloc failed
            return false;
        }
        bool result = isAccessedFile(checkedPath);
        free(checkedPath);
        if (result) {
            return result;
        }
    }
    return false;
}

bool isAccessedSuperuserApk() {
    return isAccessedFile("/system/app/Superuser.apk");
}

bool isFoundResetprop() {
    return isAccessedFile("/data/magisk/resetprop");
}

bool isFoundSuBinary() {
    return isFoundBinaryFromArray(MG_SU_PATH, "su");
}

bool isFoundBusyboxBinary() {
    return isFoundBinaryFromArray(MG_SU_PATH, "busybox");
}

bool isFoundXposed() {
    for (size_t i = 0; MG_EXPOSED_FILES[i]; ++i) {
        bool result = isAccessedFile(MG_EXPOSED_FILES[i]);
        if (result) {
            return result;
        }
    }
    return false;
}

bool isFoundHooks() {
    bool result = false;
    pid_t pid = getpid();
    char maps_file_name[512];
    sprintf(maps_file_name, "/proc/%d/maps", pid);
    GR_LOGI("try to open [%s]", maps_file_name);
    const size_t line_size = BUFSIZ;
    char *line = malloc(line_size);
    if (line == NULL) {
        return result;
    }
    FILE *fp = fopen(maps_file_name, "r");
    if (fp == NULL) {
        free(line);
        return result;
    }
    memset(line, 0, line_size);
    const char *substrate = "com.saurik.substrate";
    const char *xposed = "XposedBridge.jar";
    while (fgets(line, line_size, fp) != NULL) {
        const size_t real_line_size = strlen(line);
        if ((real_line_size >= strlen(substrate) && strstr(line, substrate) != NULL) ||
            (real_line_size >= strlen(xposed) && strstr(line, xposed) != NULL)) {
            GR_LOGI("found in [%s]: [%s]", maps_file_name, line);
            result = true;
            break;
        }
    }
    free(line);
    fclose(fp);
    return result;
}

4
দুর্দান্ত সরঞ্জাম, ডিমা। অনেক ধন্যবাদ. এটি ম্যাজিককেও ধরে ফেলে।
বিশেষজ্ঞ

এই বাস্তব চুক্তি।
ওয়াহিদ আমিরি

Magisk Hide বৈশিষ্ট্যটি নিয়ে কাজ করে না
GeniDeveloper

এটি কীভাবে বাস্তবায়ন করতে পারে তার কোনও উইকি আছে? lol
ক্লাচ

@ ক্লাচ আমার পোস্টের প্রথম লাইনে কার্যকারী উদাহরণের (লিথুব) লিঙ্কটি রয়েছে
দিমা কোজভিনে

7

এখানে কিছু উত্তরের ভিত্তিতে আমার কোড এখানে দেওয়া হয়েছে:

 /**
   * Checks if the phone is rooted.
   * 
   * @return <code>true</code> if the phone is rooted, <code>false</code>
   * otherwise.
   */
  public static boolean isPhoneRooted() {

    // get from build info
    String buildTags = android.os.Build.TAGS;
    if (buildTags != null && buildTags.contains("test-keys")) {
      return true;
    }

    // check if /system/app/Superuser.apk is present
    try {
      File file = new File("/system/app/Superuser.apk");
      if (file.exists()) {
        return true;
      }
    } catch (Throwable e1) {
      // ignore
    }

    return false;
  }

7

@ কেভিনস এর উত্তরে, আমি সম্প্রতি তার সিস্টেমটি ব্যবহার করার সময় খুঁজে পেয়েছি যে, নেক্সাস .1.১ falseতিনটি পদ্ধতির জন্য ফিরে আসছিল - কোনও whichআদেশ নেই , না test-keysএবং SuperSUইনস্টল করা হয়নি /system/app

আমি এটি যুক্ত করেছি:

public static boolean checkRootMethod4(Context context) {
    return isPackageInstalled("eu.chainfire.supersu", context);     
}

private static boolean isPackageInstalled(String packagename, Context context) {
    PackageManager pm = context.getPackageManager();
    try {
        pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
        return true;
    } catch (NameNotFoundException e) {
        return false;
    }
}

এটি কিছু পরিস্থিতিতে (আপনার যদি গ্যারান্টযুক্ত রুট অ্যাক্সেসের প্রয়োজন হয় ) থেকে সামান্য কম কার্যকর হয় কারণ সুপারসইউয়ের পক্ষে এমন ডিভাইসগুলিতে ইনস্টল করা সম্পূর্ণ সম্ভব যেগুলিতে এসইউ অ্যাক্সেস নেই।

যাইহোক, এটা আছে সম্ভব SuperSU ইনস্টল কিন্তু এবং কাজ না মধ্যে /system/app, এই ক্ষেত্রে আউট ডিরেক্টরির এই অতিরিক্ত ক্ষেত্রে ইচ্ছার রুট (হা হা)।


আপনার ডিভাইসে ইনস্টল করা যেতে পারে এমন অন্যান্য রুট প্যাকেজগুলি হওয়ায় এটি ভাল উত্তর নয়। অন্যান্য কোড প্যাকেজগুলি হার্ড কোডিং কঠোর হবে কারণ আপনি আশা করতে পারেন এবং সেগুলি সব তালিকাভুক্ত করতে পারেন
ব্লুওয়্যার

5
    public static boolean isRootAvailable(){
            Process p = null;
            try{
               p = Runtime.getRuntime().exec(new String[] {"su"});
               writeCommandToConsole(p,"exit 0");
               int result = p.waitFor();
               if(result != 0)
                   throw new Exception("Root check result with exit command " + result);
               return true;
            } catch (IOException e) {
                Log.e(LOG_TAG, "Su executable is not available ", e);
            } catch (Exception e) {
                Log.e(LOG_TAG, "Root is unavailable ", e);
            }finally {
                if(p != null)
                    p.destroy();
            }
            return false;
        }
 private static String writeCommandToConsole(Process proc, String command, boolean ignoreError) throws Exception{
            byte[] tmpArray = new byte[1024];
            proc.getOutputStream().write((command + "\n").getBytes());
            proc.getOutputStream().flush();
            int bytesRead = 0;
            if(proc.getErrorStream().available() > 0){
                if((bytesRead = proc.getErrorStream().read(tmpArray)) > 1){
                    Log.e(LOG_TAG,new String(tmpArray,0,bytesRead));
                    if(!ignoreError)
                        throw new Exception(new String(tmpArray,0,bytesRead));
                }
            }
            if(proc.getInputStream().available() > 0){
                bytesRead = proc.getInputStream().read(tmpArray);
                Log.i(LOG_TAG, new String(tmpArray,0,bytesRead));
            }
            return new String(tmpArray);
        }

4

দুটি অতিরিক্ত ধারণা, আপনি যদি অ্যাপ্লিকেশন থেকে কোনও ডিভাইস রুট সক্ষম কিনা তা পরীক্ষা করতে চান:

  1. 'সু' বাইনারি উপস্থিত রয়েছে তা পরীক্ষা করুন: "যে সু" থেকে রান করুন Runtime.getRuntime().exec()
  2. /system/app/Superuser.apkঅবস্থানটিতে SuperUser.apk সন্ধান করুন

3

ব্যবহারকারী যদি তার অ্যাপ্লিকেশনগুলি ব্যবহার করে যা রুটক্লোকের মতো তার রুটটি আড়াল করে তবে এনডিকে দিয়ে সি ++ ব্যবহার করা সর্বোত্তম পদ্ধতি best আমি এই কোডটিকে রুটক্লাক দিয়ে পরীক্ষা করেছি এবং ব্যবহারকারীর এটি আড়াল করার চেষ্টা করা হলেও আমি রুটটি সনাক্ত করতে সক্ষম হয়েছি। সুতরাং আপনার সিপিপি ফাইলটি চাইবে:

#include <jni.h>
#include <string>


/**
 *
 * function that checks for the su binary files and operates even if 
 * root cloak is installed
 * @return integer 1: device is rooted, 0: device is not 
 *rooted
*/
extern "C"
JNIEXPORT int JNICALL


Java_com_example_user_root_1native_rootFunction(JNIEnv *env,jobject thiz){
const char *paths[] ={"/system/app/Superuser.apk", "/sbin/su", "/system/bin/su",
                      "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
                      "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su"};

int counter =0;
while (counter<9){
    if(FILE *file = fopen(paths[counter],"r")){
        fclose(file);
        return 1;
    }
    counter++;
}
return 0;
}

এবং আপনি নীচে আপনার জাভা কোড থেকে ফাংশন কল করবে

public class Root_detect {



   /**
    *
    * function that calls a native function to check if the device is 
    *rooted or not
    * @return boolean: true if the device is rooted, false if the 
    *device is not rooted
   */
   public boolean check_rooted(){

        int checker = rootFunction();

        if(checker==1){
           return true;
        }else {
           return false;
        }
   }
   static {
    System.loadLibrary("cpp-root-lib");//name of your cpp file
   }

   public native int rootFunction();
}

1
if [[ "`adb shell which su | grep -io "permission denied"`" != "permission denied" ]]; then
   echo "Yes. Rooted device."
 else
   echo "No. Device not rooted. Only limited tasks can be performed. Done."
    zenity --warning --title="Device Not Rooted" --text="The connected Android Device is <b>NOT ROOTED</b>. Only limited tasks can be performed." --no-wrap
fi

1

নেই নিরাপত্তা জাল প্রত্যায়ন API এর Google Play পরিষেবাগুলি যার দ্বারা আমরা ডিভাইস মূল্যায়ন এবং নির্ধারণ যদি তা না হয় মূলী / ক্ষতিগ্রস্ত পারবেন না।

রুটযুক্ত ডিভাইসগুলি মোকাবেলা করতে দয়া করে আমার উত্তরটি দেখুন:
https://stackoverflow.com/a/58304556/3908895


1

রুট অ্যাপস এবং সুন বাইনারি সনাক্তকারী সমস্তটি ভুলে যান। রুট ডেমন প্রক্রিয়াটি পরীক্ষা করুন। এটি টার্মিনাল থেকে করা যায় এবং আপনি কোনও অ্যাপের মধ্যে টার্মিনাল কমান্ড চালাতে পারেন। এই ওয়ান-লাইনারটি ব্যবহার করে দেখুন।

if [ ! -z "$(/system/bin/ps -A | grep -v grep | grep -c daemonsu)" ]; then echo "device is rooted"; else echo "device is not rooted"; fi

এটি অর্জনের জন্য আপনারও মূল অনুমতি দরকার নেই।


0

প্রকৃতপক্ষে এটি আকর্ষণীয় প্রশ্ন এবং এখনও পর্যন্ত কেউ পুরষ্কারের যোগ্য নয়। আমি নিম্নলিখিত কোড ব্যবহার করি:

  boolean isRooted() {
      try {
                ServerSocket ss = new ServerSocket(81);
                ss.close();
                                    return true;
            } catch (Exception e) {
                // not sure
            }
    return false;
  }

কোডটি অবশ্যই বুলেটপ্রুফ নয়, কারণ নেটওয়ার্ক উপলভ্য হতে পারে না তাই আপনি একটি ব্যতিক্রম পান। যদি এই পদ্ধতিটি সত্য হয় তবে 99% আপনি নিশ্চিত হতে পারেন, অন্যথায় কেবল 50% এটি নয়। নেটওয়ার্কিং অনুমতি এছাড়াও সমাধান নষ্ট করতে পারে।


আমি এটি পরীক্ষা করেছি এবং এটি আমার মূলযুক্ত ডিভাইসে সত্য হয় না।
21

আপনি কী ধরণের ব্যতিক্রম পাচ্ছেন তা দেখতে আকর্ষণীয়। আপনি পোর্ট ইতিমধ্যে আবদ্ধ ব্যতিক্রম পেতে পারেন, তবে আপনি যদি 1024 এর অধীনে পরিসীমাতে সার্ভার পোর্ট তৈরি করতে না পারেন তবে এটি মূলের হ্রাস পাবে, তারপরেও আপনার নির্দিষ্ট সীমাবদ্ধতা রয়েছে।
সিঙ্গাগার্ল

-1

রুটবক্সে আমার লাইব্রেরিটি ব্যবহার করা , এটি বেশ সহজ। নীচে প্রয়োজনীয় কোড পরীক্ষা করুন:

    //Pass true to <Shell>.start(...) call to run as superuser
    Shell shell = null;
    try {
            shell = Shell.start(true);
    } catch (IOException exception) {
            exception.printStackTrace();
    }
    if (shell == null)
            // We failed to execute su binary
            return;
    if (shell.isRoot()) {
            // Verified running as uid 0 (root), can continue with commands
            ...
    } else
            throw Exception("Unable to gain root access. Make sure you pressed Allow/Grant in superuser prompt.");
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.